forked from platypush/platypush
Use a filesystem FIFO for YouTube media content instead of playing the *.googlevideo.com URL directly
Google Video URLs now return 403 if played directly. Let youtube-dl handle the heavylifting and use a FIFO to stream the media
This commit is contained in:
parent
f69a7e422b
commit
09991b2e8a
2 changed files with 29 additions and 19 deletions
|
@ -42,6 +42,7 @@ class MediaPlugin(Plugin):
|
|||
# A media plugin can either be local or remote (e.g. control media on
|
||||
# another device)
|
||||
_is_local = True
|
||||
_youtube_fifo = os.path.join(tempfile.gettempdir(), 'youtube_video.sock')
|
||||
|
||||
_NOT_IMPLEMENTED_ERR = NotImplementedError(
|
||||
'This method must be implemented in a derived class')
|
||||
|
@ -137,6 +138,7 @@ class MediaPlugin(Plugin):
|
|||
|
||||
self.media_dirs.add(self.download_dir)
|
||||
self._videos_queue = []
|
||||
self._youtube_proc = None
|
||||
|
||||
@staticmethod
|
||||
def _torrent_event_handler(evt_queue):
|
||||
|
@ -157,12 +159,20 @@ class MediaPlugin(Plugin):
|
|||
"""
|
||||
|
||||
if resource.startswith('youtube:') \
|
||||
or resource.startswith('https://youtu.be/') \
|
||||
or resource.startswith('https://www.youtube.com/watch?v='):
|
||||
m = re.match('youtube:video:(.*)', resource)
|
||||
if not m:
|
||||
m = re.match('https://youtu.be/(.*)', resource)
|
||||
if m:
|
||||
resource = 'https://www.youtube.com/watch?v={}'.format(m.group(1))
|
||||
|
||||
if self.__class__.__name__ == 'MediaChromecastPlugin':
|
||||
# The Chromecast has already its native way to handle YouTube
|
||||
return resource
|
||||
|
||||
resource = self.get_youtube_url(resource).output
|
||||
self.stream_youtube_to_fifo(resource)
|
||||
resource = 'file://' + self._youtube_fifo
|
||||
elif resource.startswith('magnet:?'):
|
||||
self.logger.info('Downloading torrent {} to {}'.format(
|
||||
resource, self.download_dir))
|
||||
|
@ -458,6 +468,24 @@ class MediaPlugin(Plugin):
|
|||
|
||||
return results
|
||||
|
||||
def stream_youtube_to_fifo(self, url):
|
||||
if self._youtube_proc:
|
||||
self.logger.info('Terminating existing YouTube process')
|
||||
self._youtube_proc.terminate()
|
||||
self._youtube_proc = None
|
||||
|
||||
if os.path.exists(self._youtube_fifo):
|
||||
os.unlink(self._youtube_fifo)
|
||||
|
||||
os.mkfifo(self._youtube_fifo, 0o644)
|
||||
|
||||
def _youtube_dl_thread():
|
||||
self._youtube_proc = subprocess.Popen(['youtube-dl', '-f', 'best', '-o', self._youtube_fifo, url])
|
||||
self._youtube_proc.wait()
|
||||
self._youtube_proc = None
|
||||
|
||||
threading.Thread(target=_youtube_dl_thread).start()
|
||||
|
||||
@action
|
||||
def get_youtube_url(self, url):
|
||||
m = re.match('youtube:video:(.*)', url)
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import os
|
||||
import re
|
||||
import threading
|
||||
|
||||
from platypush.context import get_bus
|
||||
|
@ -102,19 +101,6 @@ class MediaMpvPlugin(MediaPlugin):
|
|||
|
||||
return callback
|
||||
|
||||
@staticmethod
|
||||
def _get_youtube_link(resource):
|
||||
base_url = 'https://youtu.be/'
|
||||
regexes = ['^https://(www\.)?youtube.com/watch\?v=([^?&#]+)',
|
||||
'^https://(www\.)?youtu.be.com/([^?&#]+)',
|
||||
'^(youtube:video):([^?&#]+)']
|
||||
|
||||
for regex in regexes:
|
||||
m = re.search(regex, resource)
|
||||
if m:
|
||||
return base_url + m.group(2)
|
||||
return None
|
||||
|
||||
@action
|
||||
def execute(self, cmd, **args):
|
||||
"""
|
||||
|
@ -150,10 +136,6 @@ class MediaMpvPlugin(MediaPlugin):
|
|||
|
||||
if resource.startswith('file://'):
|
||||
resource = resource[7:]
|
||||
else:
|
||||
yt_resource = self._get_youtube_link(resource)
|
||||
if yt_resource:
|
||||
resource = yt_resource
|
||||
|
||||
self._player.play(resource)
|
||||
return self.status()
|
||||
|
|
Loading…
Reference in a new issue