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"; pname = "radio";
src = self; src = self;
version = "0.1"; 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(): if self.isAlive():
os.killpg(os.getpgid(self.popen.pid), signal.SIGTERM) os.killpg(os.getpgid(self.popen.pid), signal.SIGTERM)
self.popen.stdout.close() self.popen.stdout.close()
self.popen.wait() # self.popen.wait()
self.exit = True self.exit = True
# checks to see if the current download has finished # 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 downloader
import uploader import uploader
import transcoder import transcoder
import nullsrc
from time import sleep 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 run():
def cb(): r.addToQueue('https://www.youtube.com/watch?v=BaW_jenozKc')
global d r.playIfSongAvailable()
global t app.run(host="0.0.0.0")
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)
if __name__ == "__main__": if __name__ == "__main__":
run() run()

View File

@ -1,12 +1,21 @@
from setuptools import setup from setuptools import setup
requires = ["pip","ffmpeg-python"] requires = ["pip","ffmpeg-python","flask"]
setup( setup(
name='radio', name='radio',
version='0.1', version='0.1',
py_modules=['radio','downloader','uploader','logger','util','stream_listener','transcoder'], py_modules=[
entry_points={ 'radio',
'console_scripts': ['radio = radio:run'] '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.stdin.close()
self.process.stdout.close() self.process.stdout.close()
self.process.stderr.close() self.process.stderr.close()
self.process.wait() # self.process.wait()
def getStream(self): def getStream(self):
return self.process.stdout return self.process.stdout