bittorrent media source
This commit is contained in:
parent
5bf607fed9
commit
72995c0d3a
@ -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 flask requests pkgs.ffmpeg ];
|
propagatedBuildInputs = with pkgs.python3Packages; [ pip ffmpeg-python flask requests pkgs.ffmpeg pkgs.btfs ];
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,8 @@ import os
|
|||||||
import pip
|
import pip
|
||||||
import signal
|
import signal
|
||||||
import json
|
import json
|
||||||
|
import shutil
|
||||||
|
import glob
|
||||||
from logger import logger
|
from logger import logger
|
||||||
from threading import Thread, main_thread
|
from threading import Thread, main_thread
|
||||||
from time import sleep
|
from time import sleep
|
||||||
@ -81,6 +83,37 @@ def getVideoInfo(url):
|
|||||||
except:
|
except:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
fuseTorrentLocation = "~/torrent"
|
||||||
|
btfsDataLocation = "~/btfs-data"
|
||||||
|
|
||||||
|
def mountTorrent(magnet):
|
||||||
|
umountTorrent()
|
||||||
|
os.mkdir(fuseTorrentLocation)
|
||||||
|
o = subprocess.Popen([
|
||||||
|
"btfs",
|
||||||
|
"-o", "auto_unmount", # unmount if process is killed
|
||||||
|
"--data-directory=" + btfsDataLocation,
|
||||||
|
magnet,
|
||||||
|
fuseTorrentLocation
|
||||||
|
])
|
||||||
|
o.communicate() # wait for it to finish
|
||||||
|
|
||||||
|
def umountTorrent():
|
||||||
|
o = subprocess.Popen([
|
||||||
|
"fusermount",
|
||||||
|
"-u", fuseTorrentLocation
|
||||||
|
])
|
||||||
|
o.communicate() # wait for it to finish
|
||||||
|
os.rmdir(fuseTorrentLocation)
|
||||||
|
shutil.rmtree(btfsDataLocation)
|
||||||
|
|
||||||
|
def getTorrentMedia():
|
||||||
|
files = glob.glob(fuseTorrentLocation + '/**/*', recursive=True)
|
||||||
|
files = [f for f in files if f.endswith(".acc") or f.endswith(".avi") or f.endswith(".mid") or f.endswith(".midi") or f.endswith(".mp3") or f.endswith(".mp4") or f.endswith(".mpeg") or f.endswith(".oga") or f.endswith(".ogv") or f.endswith(".opus") or f.endswith(".ts") or f.endswith(".wav") or f.endswith(".weba") or f.endswith(".webm") or f.endswith(".3gp") or f.endswith(".3g2")]
|
||||||
|
if len(files) == 0:
|
||||||
|
return None
|
||||||
|
return files[0] # just the first one I guess...
|
||||||
|
|
||||||
# Downloads using yt-dlp
|
# Downloads using yt-dlp
|
||||||
class YtdlpDownloader(Thread, StreamSource):
|
class YtdlpDownloader(Thread, StreamSource):
|
||||||
def __init__(self, url, cb):
|
def __init__(self, url, cb):
|
||||||
|
31
radio.py
31
radio.py
@ -26,13 +26,31 @@ class Radio(object):
|
|||||||
# plays the next song in the queue
|
# plays the next song in the queue
|
||||||
def play(self):
|
def play(self):
|
||||||
self.playingUrl = self.queue.get()
|
self.playingUrl = self.queue.get()
|
||||||
info = downloader.getVideoInfo(self.playingUrl)
|
|
||||||
if info is None:
|
# determine what downloader needs to be used and create the downloader
|
||||||
return self.play()
|
if self.playingUrl.startswith("magnet:?"):
|
||||||
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
|
# it's a torrent
|
||||||
self.downloader = downloader.DirectDownloader(self.playingUrl, self.downloadFinished)
|
downloader.mountTorrent(self.playingUrl)
|
||||||
|
self.playingUrl = downloader.getTorrentMedia()
|
||||||
|
if self.playingUrl is None:
|
||||||
|
# this torrent is unplayable, skip it
|
||||||
|
downloader.umountTorrent()
|
||||||
|
return self.play()
|
||||||
|
else:
|
||||||
|
self.downloader = downloader.DirectDownloader(self.playingUrl, self.downloadFinished)
|
||||||
else:
|
else:
|
||||||
self.downloader = downloader.YtdlpDownloader(self.playingUrl, self.downloadFinished)
|
# 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.transcoder = transcoder.Transcoder(self.downloader)
|
||||||
self.buffer = buffer.Buffer(self.transcoder)
|
self.buffer = buffer.Buffer(self.transcoder)
|
||||||
self.uploader.setUpstream(self.buffer)
|
self.uploader.setUpstream(self.buffer)
|
||||||
@ -60,6 +78,7 @@ class Radio(object):
|
|||||||
self.transcoder.stop()
|
self.transcoder.stop()
|
||||||
self.buffer.stop()
|
self.buffer.stop()
|
||||||
self.playingUrl = None
|
self.playingUrl = None
|
||||||
|
downloader.umountTorrent() # make sure torrent is unmounted
|
||||||
|
|
||||||
# downloader callback function, called when the downloader is finished
|
# downloader callback function, called when the downloader is finished
|
||||||
# but may still have bytes left that need to be read and played
|
# but may still have bytes left that need to be read and played
|
||||||
|
Loading…
x
Reference in New Issue
Block a user