#!/usr/bin/python ''' Youtube browser module for SVPlayer (c) 2011-2015 Jan ONDREJ (SAL) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. ''' import sys, os, time, socket, random, array, urllib2, urllib, cookielib, json from urllib2 import urlopen from PIL import Image from StringIO import StringIO from sgtk import * import players from config import fifo_filename, cookies_filename, youtube, \ youtube_player_rows, youtube_player_columns, \ recorder_path, svplayer_history, history_filename # load youtube-dl from /usr/bin sys.path.insert(0, "/usr/bin/youtube-dl") sys.path.insert(1, os.path.join(os.path.dirname(__file__), "youtube-dl")) from youtube_dl.extractor import YoutubeIE from youtube_dl.YoutubeDL import YoutubeDL youtube_api_key = "AIzaSyCkYG-J7q0dFmFMtZKy8EMxnVqyM89A1ok" youtube_api_url = "https://www.googleapis.com/youtube/v3/search?" youtube_default_opts = dict( part = "snippet", type = "video", safeSearch = "strict", key = youtube_api_key ) youtube_history = svplayer_history(history_filename) def totime(sec): if sec is None: return "" sec = int(sec) if sec>=3600: return "%d:%02d:%02d" % (sec/3600, sec/60%60, sec%60) return "%d:%02d" % (sec/60%60, sec%60) def thumbnail_image(content, label_text, duration=None): box1 = Gtk.VBox() box1.set_border_width(2) im = Image.open(StringIO(content)) im = im.resize((300, 180), Image.ANTIALIAS) buff = StringIO() im.save(buff, "ppm") loader = GdkPixbuf.PixbufLoader.new_with_type('pnm') loader.write(buff.getvalue()) loader.close() image = Gtk.Image() image.set_from_pixbuf(loader.get_pixbuf()) box1.pack_start(image) image.show() text = label_text[:25] if duration: text += "\n[%ss]" % totime(duration) label = Gtk.Label(text) box1.pack_start(label) label.show() box1.show() return box1, label class SvpYoutubeIE(YoutubeIE): _formats = dict([ (k,v) for k,v in YoutubeIE._formats.items() if v.get('height', 0)<1080 ]) class FileUrl(YoutubeDL): def __init__(self, *args, **kw): self.urls = [] YoutubeDL.__init__(self, *args, **kw) def process_info(self, info_dict): #print "Process info:", info_dict self.info_dict = info_dict if info_dict.get('requested_formats') is not None: for f in info_dict['requested_formats']: self.urls.append(f['url'] + f.get('play_path', '')) print 'YTDL URL:', self.urls[-1] else: self.urls.append(info_dict['url']) CSS_DATA = """\ GtkButton { background-color: #B00606; background-image: -gtk-gradient (linear, left top, left bottom, from (#b00606), color-stop (0.5, lighter (#b00606)), to (#b00505) ); } GtkButton GtkLabel { color: white; } """ css_provider = Gtk.CssProvider() css_provider.load_from_data(CSS_DATA) class youtube_player: def __init__(self, player, rows=youtube_player_rows, columns=youtube_player_columns): #self.default_style = None self.rows = rows self.displayed_rows = rows self.columns = columns self.mainbox = Gtk.VBox() self.player = player self.related = None self.vbox = None def search(self, search_text): youtube_history.push(search_text) opts = youtube_default_opts.copy() opts['q'] = search_text yt = json.load(urllib2.urlopen(youtube_api_url+urllib.urlencode(opts))) print "Youtube found:", len(yt["items"]) self.add_vbox(yt["items"][:]) return yt["items"] def search_related(self): if not self.related: return self.add_vbox(self.related[:]) def search_history(self, rows=4): entries = [] for search_text in youtube_history.get(0, rows): #print "Youtube found:", len(yt.entry) opts = youtube_default_opts opts['q'] = search_text yt = json.load(urllib2.urlopen(youtube_api_url+urllib.urlencode(opts))) print "Youtube found:", len(yt["items"]) if yt['items']: entries.extend(yt['items'][0:self.columns*3]) # randomize order random.shuffle(entries) self.add_vbox(entries, rows) def update_related(self, href): # search for related if '&' in href: parsed = dict( [x.split('=', 1) for x in href.split('?', 1)[1].split('&')] ) video_id = parsed['v'] else: video_id = href #print 'VID:', video_id try: opts = youtube_default_opts.copy() opts['relatedToVideoId'] = video_id yt = json.load(urllib2.urlopen(youtube_api_url+urllib.urlencode(opts))) self.related = yt['items'] except urllib2.HTTPError, err: print "YouTube related error:", err print youtube_api_url+"type=video&relatedToVideoId="+video_id def remove_vbox(self): if self.vbox: self.mainbox.remove(self.vbox) self.mainbox.hide() self.vbox = None def add_vbox(self, entries, rows=None): self.index = 0 self.entries = entries[:] self.buttons = [] self.labels = [] self.remove_vbox() self.mainbox.show() self.vbox = Gtk.VBox() self.vbox.show() self.mainbox.add(self.vbox) for y in range(rows or self.rows): hbox = Gtk.HButtonBox() hbox.show() self.vbox.pack_start(hbox, fill=True) for x in range(self.columns): if not entries: break entry = entries.pop(0) thumbnail_url = entry['snippet']['thumbnails']['default']['url'] title = entry['snippet']['title'] href = entry['id']['videoId'] #print "Loading img:", thumbnail_url try: imgcontent = urlopen(thumbnail_url, timeout=2).read() except urllib2.URLError, e: print "ERROR downloading thumbnail %s: %s" % (thumbnail_url, e) imgcontent = None button = Gtk.Button() button.modify_bg(Gtk.STATE_NORMAL, COLOR_BLACK) data = dict( href = href, title = title, duration = None # no info over v3 API ) button.connect("clicked", self.play_gst, data) #button.connect("clicked", self.play_mplayer, entry) th_box, th_label = thumbnail_image(imgcontent, title) button.add(th_box) button.set_size_request(320, 240) button.show() self.buttons.append(button) self.labels.append(th_label) hbox.pack_start(button, fill=True) self.vbox.set_focus_chain([]) self.displayed_rows = rows or self.rows self.go() def go(self, x=0, y=0): if self.buttons: self.buttons[self.index].get_style_context().remove_provider( css_provider) self.labels[self.index].get_style_context().remove_provider( css_provider) self.index += x + y*self.columns max_items = self.displayed_rows*self.columns if self.index<0: self.index = max_items+self.index elif self.index>=max_items: self.index -= max_items print "INDEX:", self.index, max_items, x, y if self.buttons: self.buttons[self.index].grab_focus() self.buttons[self.index].get_style_context().add_provider( css_provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION) self.labels[self.index].get_style_context().add_provider( css_provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION) def keyboard(self, widget=None, event=None, key=None): if key is None: key = Gtk.gdk.keyval_name(event.keyval) if (key=="Down" or key=="REW_m") and self.displayed_rows>1: self.go(0, 1) return True elif (key=="Up" or key=="FF_m") and self.displayed_rows>1: self.go(0, -1) return True elif key=="Right" or key=="FF_s" or key=="Down": self.go(1) return True elif key=="Left" or key=="REW_s" or key=="Up": self.go(-1) return True elif key=='R': self.download() return True return False def pushkey(self, key): self.keyboard(key=key) def download(self): url = self.entries[self.index].link[0].href os.system( "youtube-dl -c -o '%s/%%(title)s-%%(id)s.%%(ext)s' %s &" % (recorder_path, url) ) def play_vlc(self, widget, data=None): href = data['href'] self.remove_vbox() self.update_related(href) url = self.get_url(href, data['title']) # connect to host self.player( [data['title']], [url], media=youtube, player=players.VLCWidget, ) def play_gst(self, widget, data=None): href = data['href'] self.mainbox.remove(self.vbox) self.vbox = None self.mainbox.hide() self.update_related(href) url = self.get_url(href, data['title']) self.player( [data['title']], [url], media=youtube, player=players.GSTWidget, ) def get_url(self, video_id, title=None): # use youtube-dl to extract url fd = FileUrl(dict( forceurl=True, skip_download=True, #simulate=True, quiet=True, outtmpl=u'%(id)s.%(ext)s', youtube_include_dash_manifest=False, format='all' )) #fd.add_info_extractor(SvpYoutubeIE()) fd.download([video_id]) if not fd.urls: print "ERROR: No URL for", href return print "Playing youtube: %s [%s]" % ( title, totime(fd.info_dict.get('duration', 0)) ) return fd.urls[-1] if __name__ == "__main__": print "TEST" yt = YouTubeService().YouTubeQuery(YouTubeVideoQuery( text_query=sys.argv[1]) ) #socket.setdefaulttimeout(None) print "Youtube found:", len(yt.entry), yt.entry url = yt.entry[0].link[0].href print url