-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathradio.py
126 lines (105 loc) · 3.55 KB
/
radio.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
import downloader
import uploader
import transcoder
import torrent
import buffer
from time import sleep
from flask import Flask, request
from queue import Queue
import json
import requests
import sys
app = Flask(__name__)
host = sys.argv[1]
stream = sys.argv[2]
class Radio(object):
def __init__(self):
self.downloader = None
self.transcoder = None
self.buffer = None
self.uploader = uploader.Uploader(host, stream)
self.playingUrl = None
self.queue = Queue()
# plays the next song in the queue
def play(self):
self.playingUrl = self.queue.get()
# determine what downloader needs to be used and create the downloader
if self.playingUrl.startswith("magnet:?"):
# it's a torrent
torrent.mountTorrent(self.playingUrl)
self.playingUrl = torrent.getTorrentMedia()
if self.playingUrl is None:
# this torrent is unplayable, skip it
torrent.umountTorrent()
return self.play()
else:
self.downloader = downloader.DirectDownloader(self.playingUrl, self.downloadFinished)
else:
# assume http/https
info = downloader.getVideoInfo(self.playingUrl)
if info is None:
# this url is unplayable, skip it
return self.play()
elif ("direct" in info and info["direct"] == True) or ("format_id" in info and info["format_id"] == "rtmp"): # stdout for rtmp in ytdl is broken
# direct source
self.downloader = downloader.DirectDownloader(self.playingUrl, self.downloadFinished)
else:
# requires youtube-dl
self.downloader = downloader.YtdlpDownloader(self.playingUrl, self.downloadFinished)
self.transcoder = transcoder.Transcoder(self.downloader)
self.buffer = buffer.Buffer(self.transcoder)
self.uploader.setUpstream(self.buffer)
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):
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() and not self.queue.empty():
self.play()
# stops playing immediately and cleans up
def stopPlaying(self):
self.downloader.stop()
self.transcoder.stop()
self.buffer.stop()
self.playingUrl = None
torrent.umountTorrent() # make sure torrent is unmounted
# 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()
def listenerCount(self):
r = requests.get("http://" + host + "/status-json.xsl")
return json.loads(r.text)['icestats']['source']['listeners']
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))
@app.route('/listeners', methods=['GET'])
def listeners():
return str(r.listenerCount())
def run():
app.run(host="0.0.0.0", port=int(sys.argv[3]))
if __name__ == "__main__":
run()