radio api
This commit is contained in:
parent
72706c2b6a
commit
802c364525
@ -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 ];
|
||||||
}
|
}
|
@ -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
22
nullsrc.py
Normal 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
113
radio.py
@ -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()
|
23
setup.py
23
setup.py
@ -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']
|
||||||
|
},
|
||||||
)
|
)
|
@ -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
|
||||||
|
Loading…
x
Reference in New Issue
Block a user