From 5ff5a4a6d2b904336838bea29d13e437264e69a4 Mon Sep 17 00:00:00 2001 From: Manuel Cortez Date: Fri, 16 Feb 2018 17:58:57 -0600 Subject: [PATCH] youtube: Started code for playback from youtube. Not functionnal, yet --- src/audio_services/services.py | 4 ++ src/controller/buffersController.py | 3 ++ src/controller/mainController.py | 2 + src/sound.py | 60 ++++++++++++++++++++--------- src/youtube_utils.py | 29 ++++++++++++++ 5 files changed, 80 insertions(+), 18 deletions(-) create mode 100644 src/youtube_utils.py diff --git a/src/audio_services/services.py b/src/audio_services/services.py index a3bea842..b0725238 100644 --- a/src/audio_services/services.py +++ b/src/audio_services/services.py @@ -28,5 +28,9 @@ def convert_soundcloud (url): else: raise TypeError('%r is not streamable' % url) +@matches_url ('https://www.youtube.com/watch') +def convert_long_youtube(url): + return "youtube-url" + def convert_generic_audio(url): return url diff --git a/src/controller/buffersController.py b/src/controller/buffersController.py index 610e72c7..98446782 100644 --- a/src/controller/buffersController.py +++ b/src/controller/buffersController.py @@ -17,6 +17,7 @@ import config import sound import languageHandler import logging +import youtube_utils from twitter import compose, utils from mysc.thread_utils import call_threaded from twython import TwythonError @@ -623,6 +624,8 @@ class baseBufferController(bufferController): def audio(self, url='', *args, **kwargs): if hasattr(sound.URLPlayer,'stream') and sound.URLPlayer.stream.is_playing == True: return sound.URLPlayer.stop_audio(delete=True) + elif sound.URLPlayer.mode == "youtube": + return sound.URLPlayer.stop_audio() tweet = self.get_tweet() if tweet == None: return urls = utils.find_urls(tweet) diff --git a/src/controller/mainController.py b/src/controller/mainController.py index 525ea027..f3a350ba 100644 --- a/src/controller/mainController.py +++ b/src/controller/mainController.py @@ -2,6 +2,7 @@ import platform system = platform.system() import application +import youtube_utils if system == "Windows": from update import updater from wxUI import (view, dialogs, commonMessageDialogs, sysTrayIcon) @@ -655,6 +656,7 @@ class Controller(object): self.exit_() def exit_(self, *args, **kwargs): + youtube_utils.stop() for i in self.buffers: i.save_positions() log.debug("Exiting...") log.debug("Saving global configuration...") diff --git a/src/sound.py b/src/sound.py index 7ae5cabb..26507b89 100644 --- a/src/sound.py +++ b/src/sound.py @@ -10,6 +10,7 @@ import sound_lib import subprocess import platform import output +import youtube_utils system = platform.system() from mysc.repeating_timer import RepeatingTimer from mysc.thread_utils import call_threaded @@ -99,6 +100,7 @@ class URLStream(object): self.url = url self.prepared = False log.debug("URL Player initialized") + self.mode = "generic" def prepare(self, url): log.debug("Preparing URL: %s" % (url,)) @@ -109,11 +111,19 @@ class URLStream(object): log.debug("Expanded URL: %s" % (self.url,)) if self.url != None: transformer = audio_services.find_url_transformer(self.url) - self.url = transformer(self.url) + transformed_url = transformer(self.url) + if transformed_url == "youtube-url": + self.url = youtube_utils.get_video_url(url) + self.mode = "youtube" + else: + self.url = transformed_url + self.mode = "generic" log.debug("Transformed URL: %s. Prepared" % (self.url,)) self.prepared = True def seek(self,step): + if self.mode == "youtube": + return pos=self.stream.get_position() pos=self.stream.bytes_to_seconds(pos) pos+=step @@ -123,6 +133,11 @@ class URLStream(object): self.stream.set_position(pos) def playpause(self): + if self.mode == "youtube": + if youtube_utils.player != None: + youtube_utils.player.kill() + self.mode = "generic" + youtube_utils.player = None if self.stream.is_playing==True: self.stream.pause() else: @@ -137,28 +152,37 @@ class URLStream(object): elif stream != None: self.stream=stream if self.prepared == True: - self.stream = sound_lib.stream.URLStream(url=self.url) - if hasattr(self,'stream'): - self.stream.volume = float(volume) - self.stream.play() - log.debug("played") - self.prepared=False + if self.mode == "youtube": + youtube_utils.play_video(self.url) + else: + self.stream = sound_lib.stream.URLStream(url=self.url) + if hasattr(self,'stream'): + self.stream.volume = float(volume) + self.stream.play() + log.debug("played") + self.prepared=False def stop_audio(self,delete=False): - if hasattr(self, "stream"): + if self.mode == "youtube": + youtube_utils.stop() + self.prepared = False output.speak(_(u"Stopped."), True) - try: - self.stream.stop() - log.debug("Stopped audio stream.") - except: - log.exception("Exception while stopping stream.") - if delete: - del self.stream - log.debug("Deleted audio stream.") - self.prepared=False return True else: - return False + if hasattr(self, "stream"): + output.speak(_(u"Stopped."), True) + try: + self.stream.stop() + log.debug("Stopped audio stream.") + except: + log.exception("Exception while stopping stream.") + if delete: + del self.stream + log.debug("Deleted audio stream.") + self.prepared=False + return True + else: + return False @staticmethod def delete_old_tempfiles(): diff --git a/src/youtube_utils.py b/src/youtube_utils.py new file mode 100644 index 00000000..cf9f6d73 --- /dev/null +++ b/src/youtube_utils.py @@ -0,0 +1,29 @@ +# -*- coding: utf-8 -*- +import subprocess +import youtube_dl + +player = None # Let's control player from here + +def get_video_url(url): + ydl = youtube_dl.YoutubeDL({'quiet': True, 'format': '251', 'outtmpl': u'%(id)s%(ext)s'}) + with ydl: + result = ydl.extract_info(url, download=False) + if 'entries' in result: + video = result['entries'][0] + else: + video = result + return video["url"] + +def play_video(url): + global player + if player != None: + player.kill() + player = None + player = subprocess.Popen(["ffplay.exe", "-i", url, "-nodisp", "-vn", "-hide_banner"], stderr=subprocess.PIPE, stdout=subprocess.PIPE, stdin=subprocess.PIPE) + return player + +def stop(): + global player + if player != None: + player.kill() + player = None