radio api

This commit is contained in:
zuckerberg 2021-06-01 19:30:59 -04:00
parent 72706c2b6a
commit 802c364525
6 changed files with 134 additions and 30 deletions

View File

@ -4,5 +4,5 @@ pkgs.python3Packages.buildPythonApplication {
pname = "radio";
src = self;
version = "0.1";
propagatedBuildInputs = with pkgs.python3Packages; [ pip ffmpeg-python ];
propagatedBuildInputs = with pkgs.python3Packages; [ pip ffmpeg-python flask ];
}

View File

@ -64,7 +64,7 @@ class Downloader(Thread):
if self.isAlive():
os.killpg(os.getpgid(self.popen.pid), signal.SIGTERM)
self.popen.stdout.close()
self.popen.wait()
# self.popen.wait()
self.exit = True
# checks to see if the current download has finished

22
nullsrc.py Normal file
View File

@ -0,0 +1,22 @@
import ffmpeg
from logger import logger
# A null audio source
class NullSrc(object):
def __init__(self):
self.process = ( ffmpeg
.input('anullsrc', format='lavfi')
.output('pipe:', format='mp3')
.run_async(pipe_stdout=True, pipe_stderr=True)
)
logger.add(self.process.stderr, "nullsrc.log")
def stop(self):
self.process.stdout.close()
self.process.stderr.close()
# self.process.wait()
def getStream(self):
return self.process.stdout

113
radio.py
View File

@ -1,29 +1,102 @@
import downloader
import uploader
import transcoder
import nullsrc
from time import sleep
from flask import Flask, request
from queue import Queue
app = Flask(__name__)
class Radio(object):
def __init__(self):
self.downloader = None
self.transcoder = None
self.uploader = uploader.Uploader()
self.playingUrl = None
self.nullsrc = False
self.queue = Queue()
# plays the next song in the queue
def play(self):
self.stopPlaying()
self.nullsrc = False
self.playingUrl = self.queue.get()
self.downloader = downloader.Downloader(self.playingUrl, self.downloadFinished)
self.transcoder = transcoder.Transcoder(self.downloader)
self.uploader.setUpstream(self.transcoder)
def playNullSrc(self):
self.stopPlaying()
self.nullsrc = True
self.playingUrl = None
self.downloader = nullsrc.NullSrc()
self.transcoder = transcoder.Transcoder(self.downloader)
self.uploader.setUpstream(self.transcoder)
def isPlaying(self):
return not self.playingUrl is None
# blocks the caller until the uploader and trancoder recieve no more data
# if this is a livestream, the end might never come!
def blockUntilDonePlaying(self):
if not self.nullsrc:
self.transcoder.listener.blockUntilEmpty()
self.uploader.listener.blockUntilEmpty()
# add to queue or play right now if queue is empty
def addToQueue(self,url):
self.queue.put(url)
def playIfSongAvailable(self):
if not self.isPlaying():
if self.queue.empty():
self.playNullSrc()
else:
self.play()
# stops playing immediately and cleans up
def stopPlaying(self):
if not self.downloader is None:
self.downloader.stop()
if not self.transcoder is None:
self.transcoder.stop()
self.playingUrl = None
# downloader callback function, called when the downloader is finished
# but may still have bytes left that need to be read and played
def downloadFinished(self):
self.blockUntilDonePlaying()
self.stopPlaying()
self.playIfSongAvailable()
r = Radio()
@app.route('/play', methods=['POST'])
def queueNext():
next = request.form['url']
r.addToQueue(next)
r.playIfSongAvailable()
return "Added"
@app.route('/skip', methods=['POST'])
def skipCurrent():
r.stopPlaying()
r.playIfSongAvailable()
return "Skipped"
@app.route('/current', methods=['GET'])
def current():
return r.playingUrl or 'nothing'
@app.route('/queue', methods=['GET'])
def queue():
return str(list(r.queue.queue))
def run():
def cb():
global d
global t
global u
print("----------------FINISHED-----------")
t.listener.blockUntilEmpty()
u.listener.blockUntilEmpty()
d.stop()
t.stop()
d = downloader.Downloader('https://www.youtube.com/watch?v=BQQ3qZ9FC70', cb)
t = transcoder.Transcoder(d)
u.setUpstream(t)
u = uploader.Uploader()
d = downloader.Downloader('https://www.youtube.com/watch?v=kgBcg4uBd9Q', cb)
t = transcoder.Transcoder(d)
u.setUpstream(t)
while True:
sleep(1)
r.addToQueue('https://www.youtube.com/watch?v=BaW_jenozKc')
r.playIfSongAvailable()
app.run(host="0.0.0.0")
if __name__ == "__main__":
run()

View File

@ -1,12 +1,21 @@
from setuptools import setup
requires = ["pip","ffmpeg-python"]
requires = ["pip","ffmpeg-python","flask"]
setup(
name='radio',
version='0.1',
py_modules=['radio','downloader','uploader','logger','util','stream_listener','transcoder'],
entry_points={
'console_scripts': ['radio = radio:run']
},
name='radio',
version='0.1',
py_modules=[
'radio',
'downloader',
'uploader',
'logger',
'util',
'stream_listener',
'transcoder',
'nullsrc'
],
entry_points={
'console_scripts': ['radio = radio:run']
},
)

View File

@ -20,7 +20,7 @@ class Transcoder(object):
self.process.stdin.close()
self.process.stdout.close()
self.process.stderr.close()
self.process.wait()
# self.process.wait()
def getStream(self):
return self.process.stdout