bittorrent media source

This commit is contained in:
zuckerberg 2021-09-24 12:45:07 -04:00
parent 5bf607fed9
commit 72995c0d3a
3 changed files with 59 additions and 7 deletions

View File

@ -4,5 +4,5 @@ pkgs.python3Packages.buildPythonApplication {
pname = "radio";
src = self;
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 ];
}

View File

@ -12,6 +12,8 @@ import os
import pip
import signal
import json
import shutil
import glob
from logger import logger
from threading import Thread, main_thread
from time import sleep
@ -81,6 +83,37 @@ def getVideoInfo(url):
except:
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
class YtdlpDownloader(Thread, StreamSource):
def __init__(self, url, cb):

View File

@ -26,13 +26,31 @@ class Radio(object):
# plays the next song in the queue
def play(self):
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
if self.playingUrl.startswith("magnet:?"):
# it's a torrent
downloader.mountTorrent(self.playingUrl)
self.playingUrl = downloader.getTorrentMedia()
if self.playingUrl is None:
# this torrent is unplayable, skip it
downloader.umountTorrent()
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
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)
@ -60,6 +78,7 @@ class Radio(object):
self.transcoder.stop()
self.buffer.stop()
self.playingUrl = None
downloader.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