class youtubeUrl: def __init__(self, session): self.callBack = None self.errBack = None self.session = session self.error = "" self.useProxy = False puser = "******" ppass = "******" self.yt_tw_agent_hlp = TwAgentHelper(use_proxy=self.useProxy, p_user=puser, p_pass=ppass, use_cookies=True) mp_globals.proxy = self.useProxy def addCallback(self, cbFunc): self.callBack = cbFunc def addErrback(self, errFunc): self.errBack = errFunc def dataError(self, error): self.error = self.error % str(error) self.errReturn() def errReturn(self, url=None): del self.yt_tw_agent_hlp if self.errBack == None: self.session.openWithCallback(self.cbYTErr, MessageBox, str(self.error), MessageBox.TYPE_INFO, timeout=10) else: self.errBack(self.error) def cbYTErr(self, res): return def getVideoUrl(self, url, videoPrio=2): # this part is from mtube plugin if not self.callBack: self.error = '[YoutubeURL] Error: no callBack set' self.errReturn() if videoPrio == 0: self.VIDEO_FMT_PRIORITY_MAP = { '38': 5, #MP4 Original (HD) # '37' : 5, #MP4 1080p (HD) '22': 4, #MP4 720p (HD) '35': 2, #FLV 480p '18': 1, #MP4 360p '34': 3, #FLV 360p } elif videoPrio == 1: self.VIDEO_FMT_PRIORITY_MAP = { '38': 5, #MP4 Original (HD) # '37' : 5, #MP4 1080p (HD) '22': 4, #MP4 720p (HD) '35': 1, #FLV 480p '18': 2, #MP4 360p '34': 3, #FLV 360p } else: self.VIDEO_FMT_PRIORITY_MAP = { '38': 2, #MP4 Original (HD) # '37' : 1, #MP4 1080p (HD) '22': 1, #MP4 720p (HD) '35': 3, #FLV 480p '18': 4, #MP4 360p '34': 5, #FLV 360p } self.video_url = None self.video_id = url self.videoPrio = videoPrio # Getting video webpage #URLs for YouTube video pages will change from the format http://www.youtube.com/watch?v=ylLzyHk54Z0 to http://www.youtube.com/watch#!v=ylLzyHk54Z0. watch_url = 'http://www.youtube.com/watch?v=%s&safeSearch=none' % self.video_id self.error = "[YoutubeURL] Error: Unable to retrieve watchpage:\n%s" self.yt_tw_agent_hlp.getWebPage(self.parseVInfo, self.dataError, watch_url, False) def parseVInfo(self, videoinfo): flashvars = self.extractFlashVars(videoinfo, 0) if not flashvars.has_key(u"url_encoded_fmt_stream_map"): # Attempt to see if YouTube has issued an error message if 'reason' not in flashvars: pc = False if 'ypc-offer-title' in videoinfo: pc = True msg = re.search('ypc-offer-title">.*?<a.*?">(.*?)</a', videoinfo, re.S) self.error = '[YoutubeURL] Error: Paid Content' if msg: self.error += ': "%s"' % msg.group(1) else: msg = re.search('class="message">(.*?)</', videoinfo, re.S) if msg: self.error = '[YoutubeURL] Error: %s' % msg.group( 1).strip() else: self.error = '[YoutubeURL] Error: unable to extract "url_encoded_fmt_stream_map" parameter for unknown reason' if not pc and 'og:restrictions:age' in videoinfo: el = '&el=embedded' info_url = ( 'http://www.youtube.com/get_video_info?&video_id=%s%s&ps=default&eurl=&gl=US&hl=en' % (self.video_id, el)) self.error = "[YoutubeURL] Error: Unable to retrieve videoinfo page:\n%s" self.yt_tw_agent_hlp.getWebPage(self.parseVInfo2, self.dataError, info_url, False) return else: reason = unquote_plus(videoinfo['reason'][0]) self.error = '[YoutubeURL] Error: YouTube said: %s' % reason.decode( 'utf-8') self.errReturn(self.video_url) else: links = {} for url_desc in flashvars[u"url_encoded_fmt_stream_map"].split( u","): url_desc_map = parse_qs(url_desc) if not (url_desc_map.has_key(u"url") or url_desc_map.has_key(u"stream")): continue key = int(url_desc_map[u"itag"][0]) url = u"" if url_desc_map.has_key(u"url"): url = urllib.unquote(url_desc_map[u"url"][0]) elif url_desc_map.has_key(u"conn") and url_desc_map.has_key( u"stream"): url = urllib.unquote(url_desc_map[u"conn"][0]) if url.rfind("/") < len(url) - 1: url = url + "/" url = url + urllib.unquote(url_desc_map[u"stream"][0]) elif url_desc_map.has_key( u"stream") and not url_desc_map.has_key(u"conn"): url = urllib.unquote(url_desc_map[u"stream"][0]) if url_desc_map.has_key(u"sig"): url = url + u"&signature=" + url_desc_map[u"sig"][0] elif url_desc_map.has_key(u"s"): sig = url_desc_map[u"s"][0] flashvars = self.extractFlashVars(videoinfo, 1) js = flashvars[u"js"] url = url + u"&signature=" + decryptor.decryptSignature( sig, js) try: links[self.VIDEO_FMT_PRIORITY_MAP[str(key)]] = url except KeyError: print 'skipping', key, 'fmt not in priority videos' continue try: self.video_url = links[sorted( links.iterkeys())[0]].encode('utf-8') del self.yt_tw_agent_hlp self.callBack(self.video_url) except (KeyError, IndexError): self.error = "[YoutubeURL] Error: no video url found" self.errReturn(self.video_url) def parseVInfo2(self, videoinfo): videoinfo = parse_qs(videoinfo) if not videoinfo.has_key(u"url_encoded_fmt_stream_map"): self.error = '[YoutubeURL] Error: unable to extract "url_encoded_fmt_stream_map" parameter for unknown reason' self.errReturn(self.video_url) else: video_fmt_map = {} fmt_infomap = {} tmp_fmtUrlDATA = videoinfo['url_encoded_fmt_stream_map'][0].split( ',') for fmtstring in tmp_fmtUrlDATA: fmturl = fmtid = fmtsig = "" if videoinfo.has_key('url_encoded_fmt_stream_map'): try: for arg in fmtstring.split('&'): if arg.find('=') >= 0: key, value = arg.split('=') if key == 'itag': if len(value) > 3: value = value[:2] fmtid = value elif key == 'url': fmturl = value elif key == 'sig': fmtsig = value if fmtid != "" and fmturl != "" and self.VIDEO_FMT_PRIORITY_MAP.has_key( fmtid): video_fmt_map[ self.VIDEO_FMT_PRIORITY_MAP[fmtid]] = { 'fmtid': fmtid, 'fmturl': unquote_plus(fmturl), 'fmtsig': fmtsig } fmt_infomap[int(fmtid)] = "%s&signature=%s" % ( unquote_plus(fmturl), fmtsig) fmturl = fmtid = fmtsig = "" except: self.error = "[YoutubeURL] Error parsing fmtstring: %s" % fmtstring self.errReturn(self.video_url) return else: (fmtid, fmturl) = fmtstring.split('|') if self.VIDEO_FMT_PRIORITY_MAP.has_key(fmtid) and fmtid != "": video_fmt_map[self.VIDEO_FMT_PRIORITY_MAP[fmtid]] = { 'fmtid': fmtid, 'fmturl': unquote_plus(fmturl) } fmt_infomap[int(fmtid)] = unquote_plus(fmturl) if video_fmt_map and len(video_fmt_map): print "[youtubeUrl] found best available video format:", video_fmt_map[ sorted(video_fmt_map.iterkeys())[0]]['fmtid'] best_video = video_fmt_map[sorted(video_fmt_map.iterkeys())[0]] if best_video['fmtsig']: self.video_url = "%s&signature=%s" % ( best_video['fmturl'].split(';')[0], best_video['fmtsig']) else: self.video_url = "%s" % ( best_video['fmturl'].split(';')[0]) del self.yt_tw_agent_hlp self.callBack(self.video_url) else: self.error = "[YoutubeURL] Error: no video url found" self.errReturn(self.video_url) def removeAdditionalEndingDelimiter(self, data): pos = data.find("};") if pos != -1: data = data[:pos + 1] return data def extractFlashVars(self, data, assets): flashvars = {} found = False for line in data.split("\n"): if line.strip().find(";ytplayer.config = ") > 0: found = True p1 = line.find(";ytplayer.config = ") + len( ";ytplayer.config = ") - 1 p2 = line.rfind(";") if p1 <= 0 or p2 <= 0: continue data = line[p1 + 1:p2] break data = self.removeAdditionalEndingDelimiter(data) if found: data = json.loads(data) if assets: flashvars = data["assets"] else: flashvars = data["args"] return flashvars
class youtubeUrl(object): def __init__(self, session): self.__callBack = None self.errBack = None self.session = session self.error = "" self.playing = False #self.useProxy = config.mediaportal.premiumize_use.value and config.mediaportal.sp_use_yt_with_proxy.value and mp_globals.premium_yt_proxy_host self.useProxy = config.mediaportal.premiumize_use.value and config.mediaportal.sp_use_yt_with_proxy.value if mp_globals.yt_dwnld_agent: mp_globals.yt_dwnld_agent.cancelDownload(self.initDownloadAgent) else: self.initDownloadAgent() self.tw_agent_hlp = TwAgentHelper(gzip_decoding=True, redir_agent=True) mp_globals.premiumize = self.useProxy self.retryParse = False def initDownloadAgent(self): print 'initDownloadAgent:' mp_globals.yt_dwnld_agent = None if self.useProxy: #proxyhost = mp_globals.premium_yt_proxy_host #proxyport = mp_globals.premium_yt_proxy_port proxyhost = 'nl.premiumize.me' proxyport = 82 puser = config.mediaportal.premiumize_username.value ppass = config.mediaportal.premiumize_password.value mp_globals.yt_dwnld_agent = TwDownloadAgent(use_proxy=self.useProxy, proxy_host=proxyhost, proxy_port=proxyport, p_user=puser, p_pass=ppass, gzip_decoding=True, redir_agent=True) else: mp_globals.yt_dwnld_agent = TwDownloadAgent(gzip_decoding=True, redir_agent=True) def callBack(self, url): print 'callBack:' self.error = '[YoutubeURL] Playback error:' self.tw_agent_hlp.getRedirectedUrl(url, True).addCallback(self.getRedirect).addErrback(self.dataError) def getRedirect(self, url): print 'getRedirect:' if mp_globals.yt_dwnld_agent and url and 'Forbidden' in url and self.video_url.startswith('http'): if config.mediaportal.premiumize_yt_buffering_opt.value != 'off': self.downloadStream() else: self.dataError(url) elif mp_globals.yt_dwnld_agent and config.mediaportal.premiumize_yt_buffering_opt.value == 'all': self.downloadStream() else: self.__callBack(url) def downloadStream(self): print 'downloadStream:' self.error = '[YoutubeURL] Buffering error:' mp_globals.yt_dwnld_lastnum = (mp_globals.yt_dwnld_lastnum + 1) % 2 mp_globals.yt_dwnld_agent.downloadPage(self.video_url, 'yt_downloaded_file_%d' % mp_globals.yt_dwnld_lastnum, self.playFile).addCallback(self.playFile).addErrback(self.dataError) def playFile(self, data): print 'playFile:',data if data: m = re.search('File="(.*?)" buffering="(.*?)"', data) if m: filepath = m.group(1) buffering = m.group(2) if buffering: if 'canceled' == buffering: print 'Buffering canceled' self.session.open(MessageBoxExt, _('Buffering canceled'), MessageBoxExt.TYPE_INFO, timeout=3) elif 'ready' != buffering: print 'Buffering finished' if filepath and not self.playing: self.playing = True self.__callBack(filepath) def addCallback(self, cbFunc): self.__callBack = cbFunc def addErrback(self, errFunc): self.errBack = errFunc def dataError(self, error): print 'dataError:' self.error += str(error) self.errReturn() def errReturn(self, url=None): mp_globals.yt_dwnld_agent = None if self.errBack == None: self.session.openWithCallback(self.cbYTErr, MessageBoxExt,str(self.error), MessageBoxExt.TYPE_INFO, timeout=10) else: self.errBack(self.error) def cbYTErr(self, res): return def getVideoUrl(self, url, videoPrio=2): # portions of this part is from mtube plugin if not self.__callBack: self.error = '[YoutubeURL] Error: no callBack set' self.errReturn() if videoPrio == 0: self.VIDEO_FMT_PRIORITY_MAP = { '38' : 5, #MP4 Original (HD) # '37' : 5, #MP4 1080p (HD) '22' : 4, #MP4 720p (HD) '35' : 2, #FLV 480p '18' : 1, #MP4 360p '34' : 3, #FLV 360p } elif videoPrio == 1: self.VIDEO_FMT_PRIORITY_MAP = { '38' : 5, #MP4 Original (HD) # '37' : 5, #MP4 1080p (HD) '22' : 4, #MP4 720p (HD) '35' : 1, #FLV 480p '18' : 2, #MP4 360p '34' : 3, #FLV 360p } else: self.VIDEO_FMT_PRIORITY_MAP = { '38' : 2, #MP4 Original (HD) # '37' : 1, #MP4 1080p (HD) '22' : 1, #MP4 720p (HD) '35' : 3, #FLV 480p '18' : 4, #MP4 360p '34' : 5, #FLV 360p } self.video_url = None self.video_id = url self.videoPrio = videoPrio # Getting video webpage #URLs for YouTube video pages will change from the format http://www.youtube.com/watch?v=ylLzyHk54Z0 to http://www.youtube.com/watch#!v=ylLzyHk54Z0. #watch_url = 'http://www.youtube.com/watch?v=%s&gl=US&safeSearch=none&noredirect=1'%self.video_id watch_url = 'http://www.youtube.com/watch?v=%s&gl=US'%self.video_id self.error = "[YoutubeURL] Error: Unable to retrieve watchpage:\n%s\n" % watch_url print watch_url if mp_globals.yt_dwnld_agent: mp_globals.yt_dwnld_agent.getWebPage(watch_url).addCallback(self.parseVInfo, watch_url).addErrback(self.dataError) else: self.tw_agent_hlp.getWebPage(watch_url).addCallback(self.parseVInfo, watch_url).addErrback(self.dataError) def parseVInfo(self, videoinfo, watch_url): flashvars = self.extractFlashVars(videoinfo, 0) if not flashvars.has_key(u"url_encoded_fmt_stream_map"): if self.useProxy and not self.retryParse: self.retryParse = True self.tw_agent_hlp.getWebPage(watch_url).addCallback(self.parseVInfo, watch_url).addErrback(self.dataError) else: self.checkFlashvars(flashvars, videoinfo, True) else: links = {} for url_desc in flashvars[u"url_encoded_fmt_stream_map"].split(u","): url_desc_map = parse_qs(url_desc) if not (url_desc_map.has_key(u"url") or url_desc_map.has_key(u"stream")): continue key = int(url_desc_map[u"itag"][0]) url = u"" if url_desc_map.has_key(u"url"): url = urllib.unquote(url_desc_map[u"url"][0]) elif url_desc_map.has_key(u"conn") and url_desc_map.has_key(u"stream"): url = urllib.unquote(url_desc_map[u"conn"][0]) if url.rfind("/") < len(url) -1: url = url + "/" url = url + urllib.unquote(url_desc_map[u"stream"][0]) elif url_desc_map.has_key(u"stream") and not url_desc_map.has_key(u"conn"): url = urllib.unquote(url_desc_map[u"stream"][0]) if url_desc_map.has_key(u"sig"): url = url + u"&signature=" + url_desc_map[u"sig"][0] elif url_desc_map.has_key(u"s"): sig = url_desc_map[u"s"][0] flashvars = self.extractFlashVars(videoinfo, 1) if isVEVODecryptor: signature = decryptor.decryptSignature(sig, flashvars[u"js"]) else: signature = None if not signature: self.error = "[YoutubeURL] Error: cannot decrypt signature!" self.errReturn(None) return else: url += u"&signature=" + signature try: links[self.VIDEO_FMT_PRIORITY_MAP[str(key)]] = url except KeyError: print 'skipping',key,'fmt not in priority videos' continue if not links: url = flashvars.get('hlsvp','') print 'hlsvp:',str(url) if url: links[0] = url try: self.video_url = links[sorted(links.iterkeys())[0]].encode('utf-8') self.callBack(self.video_url) except (KeyError,IndexError): self.error = "[YoutubeURL] Error: no video url found" self.errReturn(self.video_url) def parseVInfo2(self, videoinfo): print 'parseVInfo2:' flashvars = parse_qs(videoinfo) if not flashvars.has_key(u"url_encoded_fmt_stream_map"): self.checkFlashvars(flashvars, videoinfo) else: print 'parsing...' video_fmt_map = {} fmt_infomap = {} tmp_fmtUrlDATA = flashvars['url_encoded_fmt_stream_map'][0].split(',') for fmtstring in tmp_fmtUrlDATA: fmturl = fmtid = fmtsig = "" if flashvars.has_key('url_encoded_fmt_stream_map'): try: for arg in fmtstring.split('&'): if arg.find('=') >= 0: key, value = arg.split('=') if key == 'itag': if len(value) > 3: value = value[:2] fmtid = value elif key == 'url': fmturl = value elif key == 'sig': fmtsig = value if fmtid != "" and fmturl != "" and self.VIDEO_FMT_PRIORITY_MAP.has_key(fmtid): video_fmt_map[self.VIDEO_FMT_PRIORITY_MAP[fmtid]] = { 'fmtid': fmtid, 'fmturl': unquote_plus(fmturl), 'fmtsig': fmtsig } fmt_infomap[int(fmtid)] = "%s&signature=%s" %(unquote_plus(fmturl), fmtsig) fmturl = fmtid = fmtsig = "" except: self.error = "[YoutubeURL] Error parsing fmtstring: %s" % fmtstring self.errReturn(self.video_url) return else: (fmtid,fmturl) = fmtstring.split('|') if self.VIDEO_FMT_PRIORITY_MAP.has_key(fmtid) and fmtid != "": video_fmt_map[self.VIDEO_FMT_PRIORITY_MAP[fmtid]] = { 'fmtid': fmtid, 'fmturl': unquote_plus(fmturl) } fmt_infomap[int(fmtid)] = unquote_plus(fmturl) if video_fmt_map and len(video_fmt_map): print "[youtubeUrl] found best available video format:",video_fmt_map[sorted(video_fmt_map.iterkeys())[0]]['fmtid'] best_video = video_fmt_map[sorted(video_fmt_map.iterkeys())[0]] if best_video['fmtsig']: self.video_url = "%s&signature=%s" %(best_video['fmturl'].split(';')[0], best_video['fmtsig']) else: self.video_url = "%s" %(best_video['fmturl'].split(';')[0]) self.callBack(self.video_url) else: self.error = "[YoutubeURL] Error: no video url found" self.errReturn(self.video_url) def checkFlashvars(self, flashvars, videoinfo, get_info2=False): # Attempt to see if YouTube has issued an error message if not flashvars.has_key(u"reason"): from imports import decodeHtml pc = False if 'ypc-offer-title' in videoinfo: msg = re.search('ypc-offer-title">.*?<a.*?">(.*?)</a', videoinfo, re.S) if msg: pc = True self.error = '[YoutubeURL] Error: Paid Content' self.error += '\n: "%s"' % msg.group(1) elif 'itemprop="paid" content="True"' in videoinfo: msg = re.search('dir="ltr" title="(.*?)"', videoinfo, re.S) if msg: pc = True self.error = '[YoutubeURL] Error: Paid Content' self.error += ':\n"%s"' % decodeHtml(msg.group(1)) msg = re.search('class="message">(.*?)</', videoinfo, re.S) if msg: txt = msg.group(1).strip() msg = re.search('class="submessage">(.*?)</', videoinfo, re.S) if msg: txt += '\n' + msg.group(1).strip() if not pc: self.error = '[YoutubeURL] Error: %s' % txt else: self.error += txt elif not pc: print 'videoinfo:',videoinfo self.error = '[YoutubeURL] Error: unable to extract "url_encoded_fmt_stream_map" parameter for unknown reason' if not pc and get_info2 and 'og:restrictions:age' in videoinfo: el = '&el=embedded' info_url = ('http://www.youtube.com/get_video_info?&video_id=%s%s&ps=default&eurl=&gl=US&hl=en' % (self.video_id, el)) self.error = "[YoutubeURL] Error: Unable to retrieve videoinfo page:\n%s\n" % info_url if mp_globals.yt_dwnld_agent: mp_globals.yt_dwnld_agent.getWebPage(info_url).addCallback(self.parseVInfo2).addErrback(self.dataError) else: self.tw_agent_hlp.getWebPage(info_url).addCallback(self.parseVInfo2).addErrback(self.dataError) return else: reason = unquote_plus(flashvars['reason'][0]) self.error = '[YoutubeURL] Error: YouTube said: %s' % reason.decode('utf-8') self.errReturn(self.video_url) def removeAdditionalEndingDelimiter(self, data): pos = data.find("};") if pos != -1: data = data[:pos + 1] return data def normalizeUrl(self, url): if url[0:2] == "//": url = "http:" + url return url def extractFlashVars(self, data, assets): flashvars = {} found = False for line in data.split("\n"): if line.strip().find(";ytplayer.config = ") > 0: found = True p1 = line.find(";ytplayer.config = ") + len(";ytplayer.config = ") - 1 p2 = line.rfind(";") if p1 <= 0 or p2 <= 0: continue data = line[p1 + 1:p2] break data = self.removeAdditionalEndingDelimiter(data) if found: data = json.loads(data) if assets: flashvars = data["assets"] else: flashvars = data["args"] for k in ["html", "css", "js"]: if k in flashvars: flashvars[k] = self.normalizeUrl(flashvars[k]) return flashvars
class youtubeUrl(object): def __init__(self, session): global playing self.__callBack = None self.errBack = None self.session = session self.error = "" self.yt_dwnld_agent = None self.useProxy = (config.mediaportal.sp_use_yt_with_proxy.value == 'proxy') and (config.mediaportal.yt_proxy_host.value != 'example_proxy.com!') self.initDownloadAgent() self.tw_agent_hlp = TwAgentHelper(gzip_decoding=True, followRedirect=True, headers=headers) mp_globals.premiumize = self.useProxy playing = False def initDownloadAgent(self): self.proxyurl = None if self.useProxy: proxyhost = config.mediaportal.yt_proxy_host.value proxyport = config.mediaportal.yt_proxy_port.value self.puser = config.mediaportal.yt_proxy_username.value self.ppass = config.mediaportal.yt_proxy_password.value if '/noconnect' in proxyhost: proxyhost, option = proxyhost.split('/')[-2:] else: option = '' if not proxyhost.startswith('http'): self.proxyurl = 'http://%s:%s/%s' % (proxyhost, proxyport, option) else: self.proxyurl = '%s:%s/%s' % (proxyhost, proxyport, option) else: self.puser = None self.ppass = None self.yt_dwnld_agent = TwAgentHelper(proxy_url=self.proxyurl, p_user=self.puser, p_pass=self.ppass, gzip_decoding=True, followRedirect=True, headers=headers) def addCallback(self, cbFunc): self.__callBack = cbFunc def addErrback(self, errFunc): self.errBack = errFunc def dataError(self, error): self.error += str(error) self.errReturn() def errReturn(self, url=None): if self.errBack == None: self.session.openWithCallback(self.cbYTErr, MessageBoxExt,str(self.error), MessageBoxExt.TYPE_INFO, timeout=10) else: self.errBack(self.error) def cbYTErr(self, res): return def getVideoUrl(self, url, videoPrio=2, dash=False, fmt_map=None): # portions of this part is from mtube plugin if not self.__callBack: self.error = '[YoutubeURL] Error: no callBack set' self.errReturn() if fmt_map != None: self.VIDEO_FMT_PRIORITY_MAP = fmt_map elif videoPrio == 0: self.VIDEO_FMT_PRIORITY_MAP = { '38' : 5, #MP4 Original (HD) '37' : 5, #MP4 1080p (HD) '22' : 4, #MP4 720p (HD) '35' : 2, #FLV 480p '18' : 1, #MP4 360p '34' : 3, #FLV 360p } elif videoPrio == 1: self.VIDEO_FMT_PRIORITY_MAP = { '38' : 5, #MP4 Original (HD) '37' : 5, #MP4 1080p (HD) '22' : 4, #MP4 720p (HD) '35' : 1, #FLV 480p '18' : 2, #MP4 360p '34' : 3, #FLV 360p } else: self.VIDEO_FMT_PRIORITY_MAP = { '38' : 2, #MP4 Original (HD) '37' : 1, #MP4 1080p (HD) '22' : 1, #MP4 720p (HD) '35' : 3, #FLV 480p '18' : 4, #MP4 360p '34' : 5, #FLV 360p } self.video_url = None self.video_id = url self.videoPrio = videoPrio self.dash = dash # Getting video webpage #URLs for YouTube video pages will change from the format #http://www.youtube.com/watch?v=ylLzyHk54Z0 to http://www.youtube.com/watch#!v=ylLzyHk54Z0. watch_url = 'https://www.youtube.com/watch?v=%s&gl=US&hl=en&has_verified=1&bpctr=9999999999' % self.video_id self.error = "[YoutubeURL] Error: Unable to retrieve watchpage:\n%s\n" % watch_url self.yt_dwnld_agent.getWebPage(watch_url).addCallback(self.parseVInfo, watch_url).addErrback(self.dataError) def parseVInfo(self, videoinfo, watch_url): flashvars = self.extractFlashVars(videoinfo, 0) if not flashvars.has_key(u"url_encoded_fmt_stream_map"): self.checkFlashvars(flashvars, videoinfo, True) else: links = {} encoded_url_map = flashvars[u"url_encoded_fmt_stream_map"] if self.dash: encoded_url_map += flashvars.get('adaptive_fmts', []) for url_desc in encoded_url_map.split(u","): url_desc_map = parse_qs(url_desc) if not (url_desc_map.has_key(u"url") or url_desc_map.has_key(u"stream")): continue try: key = int(url_desc_map[u"itag"][0]) except ValueError: continue url = u"" if url_desc_map.has_key(u"url"): url = urllib.unquote(url_desc_map[u"url"][0]) elif url_desc_map.has_key(u"conn") and url_desc_map.has_key(u"stream"): url = urllib.unquote(url_desc_map[u"conn"][0]) if url.rfind("/") < len(url) -1: url = url + "/" url = url + urllib.unquote(url_desc_map[u"stream"][0]) elif url_desc_map.has_key(u"stream") and not url_desc_map.has_key(u"conn"): url = urllib.unquote(url_desc_map[u"stream"][0]) if url_desc_map.has_key(u"sig"): url = url + u"&signature=" + url_desc_map[u"sig"][0] elif url_desc_map.has_key(u"s"): sig = url_desc_map[u"s"][0] flashvars = self.extractFlashVars(videoinfo, 1) if isVEVODecryptor: signature = decryptor.decryptSignature(sig, flashvars[u"js"]) else: signature = None if not signature: self.error = "[YoutubeURL] Error: cannot decrypt url" self.errReturn(None) return else: url += u"&signature=" + signature try: links[self.VIDEO_FMT_PRIORITY_MAP[str(key)]] = url except KeyError: continue if not links: url = flashvars.get('hlsvp','') if url: links[0] = url try: self.video_url = links[sorted(links.iterkeys())[0]].encode('utf-8') #self.__callBack(self.video_url) self.callBack(self.video_url) except (KeyError,IndexError): self.error = "[YoutubeURL] Error: no video url found" self.errReturn(self.video_url) def parseVInfo2(self, videoinfo): flashvars = parse_qs(videoinfo) if not flashvars.has_key(u"url_encoded_fmt_stream_map"): if 'hlsvp=' in videoinfo: url = urllib.unquote(re.search('hlsvp=(.*?\.m3u8)', videoinfo).group(1)) self.__callBack(url) else: self.checkFlashvars(flashvars, videoinfo) else: video_fmt_map = {} fmt_infomap = {} tmp_fmtUrlDATA = flashvars['url_encoded_fmt_stream_map'][0].split(',') for fmtstring in tmp_fmtUrlDATA: fmturl = fmtid = fmtsig = "" if flashvars.has_key('url_encoded_fmt_stream_map'): try: for arg in fmtstring.split('&'): if arg.find('=') >= 0: key, value = arg.split('=') if key == 'itag': if len(value) > 3: value = value[:2] fmtid = value elif key == 'url': fmturl = value elif key == 'sig': fmtsig = value if fmtid != "" and fmturl != "" and self.VIDEO_FMT_PRIORITY_MAP.has_key(fmtid): video_fmt_map[self.VIDEO_FMT_PRIORITY_MAP[fmtid]] = { 'fmtid': fmtid, 'fmturl': unquote_plus(fmturl), 'fmtsig': fmtsig } fmt_infomap[int(fmtid)] = "%s&signature=%s" %(unquote_plus(fmturl), fmtsig) fmturl = fmtid = fmtsig = "" except: self.error = "[YoutubeURL] Error parsing fmtstring: %s" % fmtstring self.errReturn(self.video_url) return else: (fmtid,fmturl) = fmtstring.split('|') if self.VIDEO_FMT_PRIORITY_MAP.has_key(fmtid) and fmtid != "": video_fmt_map[self.VIDEO_FMT_PRIORITY_MAP[fmtid]] = { 'fmtid': fmtid, 'fmturl': unquote_plus(fmturl) } fmt_infomap[int(fmtid)] = unquote_plus(fmturl) if video_fmt_map and len(video_fmt_map): best_video = video_fmt_map[sorted(video_fmt_map.iterkeys())[0]] if best_video['fmtsig']: self.video_url = "%s&signature=%s" %(best_video['fmturl'].split(';')[0], best_video['fmtsig']) else: self.video_url = "%s" %(best_video['fmturl'].split(';')[0]) #self.__callBack(self.video_url) self.callBack(self.video_url) else: self.error = "[YoutubeURL] Error: no video url found" self.errReturn(self.video_url) def checkFlashvars(self, flashvars, videoinfo, get_info2=False): # Attempt to see if YouTube has issued an error message if not flashvars.has_key(u"reason"): from imports import decodeHtml pc = False if 'ypc-offer-title' in videoinfo: msg = re.search('ypc-offer-title">.*?<a.*?">(.*?)</a', videoinfo, re.S) if msg: pc = True self.error = '[YoutubeURL] Error: Paid Content' self.error += '\n: "%s"' % msg.group(1) elif 'itemprop="paid" content="True"' in videoinfo: msg = re.search('dir="ltr" title="(.*?)"', videoinfo, re.S) if msg: pc = True self.error = '[YoutubeURL] Error: Paid Content' self.error += ':\n"%s"' % decodeHtml(msg.group(1)) msg = re.search('class="message">(.*?)</', videoinfo, re.S) if msg: txt = msg.group(1).strip() msg = re.search('class="submessage">(.*?)</', videoinfo, re.S) if msg: txt += '\n' + msg.group(1).strip() if not pc: self.error = '[YoutubeURL] Error: %s' % txt else: self.error += txt elif not pc: self.error = '[YoutubeURL] Error: unable to extract "url_encoded_fmt_stream_map" parameter for unknown reason' if not pc and get_info2 and 'og:restrictions:age' in videoinfo: el = '&el=embedded' info_url = ('https://www.youtube.com/get_video_info?video_id=%s%s&ps=default&eurl=&gl=US&hl=en' % (self.video_id, el)) self.error = "[YoutubeURL] Error: Unable to retrieve videoinfo page:\n%s\n" % info_url self.yt_dwnld_agent.getWebPage(info_url).addCallback(self.parseVInfo2).addErrback(self.dataError) return else: from imports import stripAllTags reason = unquote_plus(flashvars['reason'][0]) self.error = '[YoutubeURL] Error: YouTube said: %s' % stripAllTags(str(reason)) self.errReturn(self.video_url) def removeAdditionalEndingDelimiter(self, data): pos = data.find("};") if pos != -1: data = data[:pos + 1] return data def normalizeUrl(self, url): if url[0:2] == "//": url = "https:" + url return url def extractFlashVars(self, data, assets): flashvars = {} found = False for line in data.split("\n"): if line.strip().find(";ytplayer.config = ") > 0: found = True p1 = line.find(";ytplayer.config = ") + len(";ytplayer.config = ") - 1 p2 = line.rfind(";") if p1 <= 0 or p2 <= 0: continue data = line[p1 + 1:p2] break data = self.removeAdditionalEndingDelimiter(data) if found: data = json.loads(data) if assets: flashvars = data["assets"] else: flashvars = data["args"] for k in ["html", "css", "js"]: if k in flashvars: flashvars[k] = self.normalizeUrl(flashvars[k]) return flashvars def callBack(self, url): if url.startswith('http') and not '.m3u8' in url: self.error = '[YoutubeURL] Playback error:' return self.tw_agent_hlp.getRedirectedUrl(url, True).addCallback(self.getRedirect, url).addErrback(self.dataError) else: self.__callBack(url) def getRedirect(self, redir_url, url): if 'Forbidden' in redir_url: if self.useProxy: self.__callBack(url, buffering=True, proxy=(self.proxyurl, self.puser, self.ppass)) else: self.dataError(redir_url) else: self.__callBack(url)
class youtubeUrl(object): def __init__(self, session): global playing self.__callBack = None self.errBack = None self.session = session self.error = "" self.yt_dwnld_agent = None self.useProxy = ( config.mediaportal.sp_use_yt_with_proxy.value == 'proxy') and ( config.mediaportal.yt_proxy_host.value != 'example_proxy.com!') self.initDownloadAgent() self.tw_agent_hlp = TwAgentHelper(gzip_decoding=True, followRedirect=True, headers=headers) mp_globals.premiumize = self.useProxy playing = False def initDownloadAgent(self): self.proxyurl = None if self.useProxy: proxyhost = config.mediaportal.yt_proxy_host.value proxyport = config.mediaportal.yt_proxy_port.value self.puser = config.mediaportal.yt_proxy_username.value self.ppass = config.mediaportal.yt_proxy_password.value if '/noconnect' in proxyhost: proxyhost, option = proxyhost.split('/')[-2:] else: option = '' if not proxyhost.startswith('http'): self.proxyurl = 'http://%s:%s/%s' % (proxyhost, proxyport, option) else: self.proxyurl = '%s:%s/%s' % (proxyhost, proxyport, option) else: self.puser = None self.ppass = None self.yt_dwnld_agent = TwAgentHelper(proxy_url=self.proxyurl, p_user=self.puser, p_pass=self.ppass, gzip_decoding=True, followRedirect=True, headers=headers) def addCallback(self, cbFunc): self.__callBack = cbFunc def addErrback(self, errFunc): self.errBack = errFunc def dataError(self, error): self.error += str(error) self.errReturn() def errReturn(self, url=None): if self.errBack == None: self.session.openWithCallback(self.cbYTErr, MessageBoxExt, str(self.error), MessageBoxExt.TYPE_INFO, timeout=10) else: self.errBack(self.error) def cbYTErr(self, res): return def getVideoUrl(self, url, videoPrio=2, dash=None, fmt_map=None): dash = config.mediaportal.youtubeenabledash.value # portions of this part is from mtube plugin if not self.__callBack: self.error = '[YoutubeURL] Error: no callBack set' self.errReturn() if fmt_map != None: self.VIDEO_FMT_PRIORITY_MAP = fmt_map elif videoPrio == 0: #360p self.VIDEO_FMT_PRIORITY_MAP = { '18': 1, #MP4 360p '34': 2, #FLV 360p } elif videoPrio == 1: #480p self.VIDEO_FMT_PRIORITY_MAP = { '135': 1, #MP4 480p (DASH) '35': 2, #FLV 480p '18': 3, #MP4 360p '34': 4, #FLV 360p } elif videoPrio == 2: #720p self.VIDEO_FMT_PRIORITY_MAP = { '22': 1, #MP4 720p '135': 2, #MP4 480p (DASH) '35': 3, #FLV 480p '18': 4, #MP4 360p '34': 5, #FLV 360p } elif videoPrio == 3: #1080p self.VIDEO_FMT_PRIORITY_MAP = { '299': 3, #MP4 1080p60 (DASH) '137': 4, #MP4 1080p (DASH) '22': 5, #MP4 720p '135': 6, #MP4 480p (DASH) '35': 7, #FLV 480p '18': 8, #MP4 360p '34': 9, #FLV 360p } if config.mediaportal.youtubeenablevp9.value: self.VIDEO_FMT_PRIORITY_MAP.update({ '303': 1, #VP9 1080p60 (DASH) '248': 2, #VP9 1080p (DASH) }) elif videoPrio == 4: #1440p self.VIDEO_FMT_PRIORITY_MAP = { '299': 5, #MP4 1080p60 (DASH) '137': 6, #MP4 1080p (DASH) '22': 7, #MP4 720p '135': 8, #MP4 480p (DASH) '35': 9, #FLV 480p '18': 10, #MP4 360p '34': 11, #FLV 360p } if config.mediaportal.youtubeenablevp9.value: self.VIDEO_FMT_PRIORITY_MAP.update({ '308': 1, #VP9 1440p60 (DASH) '271': 2, #VP9 1440p (DASH) '303': 3, #VP9 1080p60 (DASH) '248': 4, #VP9 1080p (DASH) }) elif videoPrio == 5: #2160p self.VIDEO_FMT_PRIORITY_MAP = { '299': 7, #MP4 1080p60 (DASH) '137': 8, #MP4 1080p (DASH) '22': 9, #MP4 720p '135': 10, #MP4 480p (DASH) '35': 11, #FLV 480p '18': 12, #MP4 360p '34': 13, #FLV 360p } if config.mediaportal.youtubeenablevp9.value: self.VIDEO_FMT_PRIORITY_MAP.update({ '315': 1, #VP9 2160p60 (DASH) '313': 2, #VP9 2160p (DASH) '308': 3, #VP9 1440p60 (DASH) '271': 4, #VP9 1440p (DASH) '303': 5, #VP9 1080p60 (DASH) '248': 6, #VP9 1080p (DASH) }) self.AUDIO_FMT_PRIORITY_MAP = { '258': 1, #AAC '256': 2, #AAC '141': 3, #AAC ABR256 '140': 4, #AAC ABR128 '139': 5, #AAC ABR48 '172': 6, #VORBIS 256 '171': 7, #VORBIS 128 } self.video_url = None self.audio_url = None self.video_id = url self.videoPrio = videoPrio self.dash = dash # Getting video webpage #URLs for YouTube video pages will change from the format #http://www.youtube.com/watch?v=ylLzyHk54Z0 to http://www.youtube.com/watch#!v=ylLzyHk54Z0. watch_url = 'https://www.youtube.com/watch?v=%s&gl=US&hl=en&has_verified=1&bpctr=9999999999' % self.video_id self.error = "[YoutubeURL] Error: Unable to retrieve watchpage:\n%s\n" % watch_url self.yt_dwnld_agent.getWebPage(watch_url).addCallback( self.parseVInfo, watch_url).addErrback(self.dataError) def parseVInfo(self, videoinfo, watch_url): flashvars = self.extractFlashVars(videoinfo, 0) if not flashvars.has_key(u"url_encoded_fmt_stream_map"): self.checkFlashvars(flashvars, videoinfo, True) else: links = {} audio = {} encoded_url_map = "" if self.dash: try: encoded_url_map += u"," + flashvars.get( 'adaptive_fmts', []) except: pass encoded_url_map += u"," + flashvars[u"url_encoded_fmt_stream_map"] for url_desc in encoded_url_map.split(u","): url_desc_map = parse_qs(url_desc) if not (url_desc_map.has_key(u"url") or url_desc_map.has_key(u"stream")): continue try: key = int(url_desc_map[u"itag"][0]) except ValueError: continue url = u"" if url_desc_map.has_key(u"url"): url = urllib.unquote(url_desc_map[u"url"][0]) elif url_desc_map.has_key(u"conn") and url_desc_map.has_key( u"stream"): url = urllib.unquote(url_desc_map[u"conn"][0]) if url.rfind("/") < len(url) - 1: url = url + "/" url = url + urllib.unquote(url_desc_map[u"stream"][0]) elif url_desc_map.has_key( u"stream") and not url_desc_map.has_key(u"conn"): url = urllib.unquote(url_desc_map[u"stream"][0]) if url_desc_map.has_key(u"sig"): url = url + u"&signature=" + url_desc_map[u"sig"][0] elif url_desc_map.has_key(u"s"): sig = url_desc_map[u"s"][0] flashvars = self.extractFlashVars(videoinfo, 1) signature = decryptor.decryptSignature( sig, flashvars[u"js"]) if not signature: self.error = "[YoutubeURL] Error: cannot decrypt url" self.errReturn(None) return else: url += u"&signature=" + signature try: links[self.VIDEO_FMT_PRIORITY_MAP[str(key)]] = url except KeyError: try: audio[self.AUDIO_FMT_PRIORITY_MAP[str(key)]] = url except KeyError: continue url = flashvars.get('hlsvp', '') if url: links = {} links[0] = url #print "#####################################################################################" #try: # for i in links: # type = re.search('.*?itag=(\d+)', links[i]).group(1) # print type + "\t" + links[i] #except: # pass #print "#####################################################################################" try: self.video_url = links[sorted( links.iterkeys())[0]].encode('utf-8') try: if int( re.search('.*?itag=(\d+)', self.video_url).group(1)) > 100: self.audio_url = audio[sorted( audio.iterkeys())[0]].encode('utf-8') #print "#####################################################################################" #for i in audio: # type = re.search('.*?itag=(\d+)', audio[i]).group(1) # print type + "\t" + audio[i] #print "#####################################################################################" except: pass #self.__callBack(self.video_url) self.callBack(self.video_url, self.audio_url) except (KeyError, IndexError): self.error = "[YoutubeURL] Error: no video url found" self.errReturn(self.video_url) def parseVInfo2(self, videoinfo): flashvars = parse_qs(videoinfo) if not flashvars.has_key(u"url_encoded_fmt_stream_map"): if 'hlsvp=' in videoinfo: url = urllib.unquote( re.search('hlsvp=(.*?\.m3u8)', videoinfo).group(1)) self.__callBack(url) else: self.checkFlashvars(flashvars, videoinfo) else: video_fmt_map = {} fmt_infomap = {} tmp_fmtUrlDATA = flashvars['url_encoded_fmt_stream_map'][0].split( ',') for fmtstring in tmp_fmtUrlDATA: fmturl = fmtid = fmtsig = "" if flashvars.has_key('url_encoded_fmt_stream_map'): try: for arg in fmtstring.split('&'): if arg.find('=') >= 0: key, value = arg.split('=') if key == 'itag': if len(value) > 3: value = value[:2] fmtid = value elif key == 'url': fmturl = value elif key == 'sig': fmtsig = value if fmtid != "" and fmturl != "" and self.VIDEO_FMT_PRIORITY_MAP.has_key( fmtid): video_fmt_map[ self.VIDEO_FMT_PRIORITY_MAP[fmtid]] = { 'fmtid': fmtid, 'fmturl': unquote_plus(fmturl), 'fmtsig': fmtsig } fmt_infomap[int(fmtid)] = "%s&signature=%s" % ( unquote_plus(fmturl), fmtsig) fmturl = fmtid = fmtsig = "" except: self.error = "[YoutubeURL] Error parsing fmtstring: %s" % fmtstring self.errReturn(self.video_url) return else: (fmtid, fmturl) = fmtstring.split('|') if self.VIDEO_FMT_PRIORITY_MAP.has_key(fmtid) and fmtid != "": video_fmt_map[self.VIDEO_FMT_PRIORITY_MAP[fmtid]] = { 'fmtid': fmtid, 'fmturl': unquote_plus(fmturl) } fmt_infomap[int(fmtid)] = unquote_plus(fmturl) if video_fmt_map and len(video_fmt_map): best_video = video_fmt_map[sorted(video_fmt_map.iterkeys())[0]] if best_video['fmtsig']: self.video_url = "%s&signature=%s" % ( best_video['fmturl'].split(';')[0], best_video['fmtsig']) else: self.video_url = "%s" % ( best_video['fmturl'].split(';')[0]) #self.__callBack(self.video_url) self.callBack(self.video_url) else: self.error = "[YoutubeURL] Error: no video url found" self.errReturn(self.video_url) def checkFlashvars(self, flashvars, videoinfo, get_info2=False): # Attempt to see if YouTube has issued an error message if not flashvars.has_key(u"reason"): from imports import decodeHtml pc = False if 'ypc-offer-title' in videoinfo: msg = re.search('ypc-offer-title">.*?<a.*?">(.*?)</a', videoinfo, re.S) if msg: pc = True self.error = '[YoutubeURL] Error: Paid Content' self.error += '\n: "%s"' % msg.group(1) elif 'itemprop="paid" content="True"' in videoinfo: msg = re.search('dir="ltr" title="(.*?)"', videoinfo, re.S) if msg: pc = True self.error = '[YoutubeURL] Error: Paid Content' self.error += ':\n"%s"' % decodeHtml(msg.group(1)) msg = re.search('class="message">(.*?)</', videoinfo, re.S) if msg: txt = msg.group(1).strip() msg = re.search('class="submessage">(.*?)</', videoinfo, re.S) if msg: txt += '\n' + msg.group(1).strip() if not pc: self.error = '[YoutubeURL] Error: %s' % decodeHtml(txt) else: self.error += txt elif not pc: self.error = '[YoutubeURL] Error: unable to extract "url_encoded_fmt_stream_map" parameter for unknown reason' if not pc and get_info2 and 'og:restrictions:age' in videoinfo: el = '&el=embedded' info_url = ( 'https://www.youtube.com/get_video_info?video_id=%s%s&ps=default&eurl=&gl=US&hl=en' % (self.video_id, el)) self.error = "[YoutubeURL] Error: Unable to retrieve videoinfo page:\n%s\n" % info_url self.yt_dwnld_agent.getWebPage(info_url).addCallback( self.parseVInfo2).addErrback(self.dataError) return else: from imports import stripAllTags reason = unquote_plus(flashvars['reason'][0]) self.error = '[YoutubeURL] Error: YouTube said: %s' % stripAllTags( str(reason)) self.errReturn(self.video_url) def removeAdditionalEndingDelimiter(self, data): pos = data.find("};") if pos != -1: data = data[:pos + 1] return data def normalizeUrl(self, url): if url[0:2] == "//": url = "https:" + url return url def extractFlashVars(self, data, assets): flashvars = {} found = False for line in data.split("\n"): if line.strip().find(";ytplayer.config = ") > 0: found = True p1 = line.find(";ytplayer.config = ") + len( ";ytplayer.config = ") - 1 p2 = line.rfind(";") if p1 <= 0 or p2 <= 0: continue data = line[p1 + 1:p2] break data = self.removeAdditionalEndingDelimiter(data) if found: data = json.loads(data) if assets: flashvars = data["assets"] else: flashvars = data["args"] for k in ["html", "css", "js"]: if k in flashvars: flashvars[k] = self.normalizeUrl(flashvars[k]) return flashvars def callBack(self, url, suburi=None): if suburi and not '.m3u8' in url: self.__callBack(url, suburi=suburi) elif url.startswith('http') and not '.m3u8' in url: self.error = '[YoutubeURL] Playback error:' try: return self.tw_agent_hlp.getRedirectedUrl( url, True).addCallback(self.getRedirect, url).addErrback(self.dataError) except: self.__callBack(url) else: self.yt_dwnld_agent.getWebPage(url).addCallback( self.parseM3U8Playlist).addErrback(self.dataError) def parseM3U8Playlist(self, data): bandwith_list = [] match_sec_m3u8 = re.findall('BANDWIDTH=(\d+).*?\n(.*?m3u8)', data, re.S) videoPrio = int(config.mediaportal.youtubeprio.value) if videoPrio >= 3: bw = int(match_sec_m3u8[-1][0]) elif videoPrio == 2: bw = int(match_sec_m3u8[-1][0]) / 2 elif videoPrio == 1: bw = int(match_sec_m3u8[-1][0]) / 3 else: bw = int(match_sec_m3u8[-1][0]) / 4 for each in match_sec_m3u8: bandwith, url = each bandwith_list.append((int(bandwith), url)) _, best = min((abs(int(x[0]) - bw), x) for x in bandwith_list) url = best[1] url = url.replace('%2F', '%252F').replace('%3D', '%253D').replace( '%2B', '%252B').replace('%3B', '%253B') self.__callBack(url) def getRedirect(self, redir_url, url): if 'Forbidden' in redir_url: if self.useProxy: self.__callBack(url, buffering=True, proxy=(self.proxyurl, self.puser, self.ppass)) else: self.dataError(redir_url) else: self.__callBack(url)
class youtubeUrl: def __init__(self, session): self.callBack = None self.errBack = None self.session = session self.error = "" self.useProxy = False puser = "******" ppass = "******" self.yt_tw_agent_hlp = TwAgentHelper(use_proxy=self.useProxy, p_user=puser, p_pass=ppass, use_cookies=True) mp_globals.proxy = self.useProxy def addCallback(self, cbFunc): self.callBack = cbFunc def addErrback(self, errFunc): self.errBack = errFunc def dataError(self, error): self.error = self.error % str(error) self.errReturn() def errReturn(self, url=None): del self.yt_tw_agent_hlp if self.errBack == None: self.session.openWithCallback(self.cbYTErr, MessageBox,str(self.error), MessageBox.TYPE_INFO, timeout=10) else: self.errBack(self.error) def cbYTErr(self, res): return def getVideoUrl(self, url, videoPrio=2): # this part is from mtube plugin if not self.callBack: self.error = '[YoutubeURL] Error: no callBack set' self.errReturn() if videoPrio == 0: self.VIDEO_FMT_PRIORITY_MAP = { '38' : 5, #MP4 Original (HD) # '37' : 5, #MP4 1080p (HD) '22' : 4, #MP4 720p (HD) '35' : 2, #FLV 480p '18' : 1, #MP4 360p '34' : 3, #FLV 360p } elif videoPrio == 1: self.VIDEO_FMT_PRIORITY_MAP = { '38' : 5, #MP4 Original (HD) # '37' : 5, #MP4 1080p (HD) '22' : 4, #MP4 720p (HD) '35' : 1, #FLV 480p '18' : 2, #MP4 360p '34' : 3, #FLV 360p } else: self.VIDEO_FMT_PRIORITY_MAP = { '38' : 2, #MP4 Original (HD) # '37' : 1, #MP4 1080p (HD) '22' : 1, #MP4 720p (HD) '35' : 3, #FLV 480p '18' : 4, #MP4 360p '34' : 5, #FLV 360p } self.video_url = None self.video_id = url self.videoPrio = videoPrio # Getting video webpage #URLs for YouTube video pages will change from the format http://www.youtube.com/watch?v=ylLzyHk54Z0 to http://www.youtube.com/watch#!v=ylLzyHk54Z0. watch_url = 'http://www.youtube.com/watch?v=%s&safeSearch=none'%self.video_id self.error = "[YoutubeURL] Error: Unable to retrieve watchpage:\n%s" self.yt_tw_agent_hlp.getWebPage(self.parseVInfo, self.dataError, watch_url, False) def parseVInfo(self, videoinfo): flashvars = self.extractFlashVars(videoinfo, 0) if not flashvars.has_key(u"url_encoded_fmt_stream_map"): # Attempt to see if YouTube has issued an error message if 'reason' not in flashvars: pc = False if 'ypc-offer-title' in videoinfo: pc = True msg = re.search('ypc-offer-title">.*?<a.*?">(.*?)</a', videoinfo, re.S) self.error = '[YoutubeURL] Error: Paid Content' if msg: self.error += ': "%s"' % msg.group(1) else: msg = re.search('class="message">(.*?)</', videoinfo, re.S) if msg: self.error = '[YoutubeURL] Error: %s' % msg.group(1).strip() else: self.error = '[YoutubeURL] Error: unable to extract "url_encoded_fmt_stream_map" parameter for unknown reason' if not pc and 'og:restrictions:age' in videoinfo: el = '&el=embedded' info_url = ('http://www.youtube.com/get_video_info?&video_id=%s%s&ps=default&eurl=&gl=US&hl=en' % (self.video_id, el)) self.error = "[YoutubeURL] Error: Unable to retrieve videoinfo page:\n%s" self.yt_tw_agent_hlp.getWebPage(self.parseVInfo2, self.dataError, info_url, False) return else: reason = unquote_plus(videoinfo['reason'][0]) self.error = '[YoutubeURL] Error: YouTube said: %s' % reason.decode('utf-8') self.errReturn(self.video_url) else: links = {} for url_desc in flashvars[u"url_encoded_fmt_stream_map"].split(u","): url_desc_map = parse_qs(url_desc) if not (url_desc_map.has_key(u"url") or url_desc_map.has_key(u"stream")): continue key = int(url_desc_map[u"itag"][0]) url = u"" if url_desc_map.has_key(u"url"): url = urllib.unquote(url_desc_map[u"url"][0]) elif url_desc_map.has_key(u"conn") and url_desc_map.has_key(u"stream"): url = urllib.unquote(url_desc_map[u"conn"][0]) if url.rfind("/") < len(url) -1: url = url + "/" url = url + urllib.unquote(url_desc_map[u"stream"][0]) elif url_desc_map.has_key(u"stream") and not url_desc_map.has_key(u"conn"): url = urllib.unquote(url_desc_map[u"stream"][0]) if url_desc_map.has_key(u"sig"): url = url + u"&signature=" + url_desc_map[u"sig"][0] elif url_desc_map.has_key(u"s"): sig = url_desc_map[u"s"][0] flashvars = self.extractFlashVars(videoinfo, 1) js = flashvars[u"js"] url = url + u"&signature=" + decryptor.decryptSignature(sig, js) try: links[self.VIDEO_FMT_PRIORITY_MAP[str(key)]] = url except KeyError: print 'skipping',key,'fmt not in priority videos' continue try: self.video_url = links[sorted(links.iterkeys())[0]].encode('utf-8') del self.yt_tw_agent_hlp self.callBack(self.video_url) except (KeyError,IndexError): self.error = "[YoutubeURL] Error: no video url found" self.errReturn(self.video_url) def parseVInfo2(self, videoinfo): videoinfo = parse_qs(videoinfo) if not videoinfo.has_key(u"url_encoded_fmt_stream_map"): self.error = '[YoutubeURL] Error: unable to extract "url_encoded_fmt_stream_map" parameter for unknown reason' self.errReturn(self.video_url) else: video_fmt_map = {} fmt_infomap = {} tmp_fmtUrlDATA = videoinfo['url_encoded_fmt_stream_map'][0].split(',') for fmtstring in tmp_fmtUrlDATA: fmturl = fmtid = fmtsig = "" if videoinfo.has_key('url_encoded_fmt_stream_map'): try: for arg in fmtstring.split('&'): if arg.find('=') >= 0: key, value = arg.split('=') if key == 'itag': if len(value) > 3: value = value[:2] fmtid = value elif key == 'url': fmturl = value elif key == 'sig': fmtsig = value if fmtid != "" and fmturl != "" and self.VIDEO_FMT_PRIORITY_MAP.has_key(fmtid): video_fmt_map[self.VIDEO_FMT_PRIORITY_MAP[fmtid]] = { 'fmtid': fmtid, 'fmturl': unquote_plus(fmturl), 'fmtsig': fmtsig } fmt_infomap[int(fmtid)] = "%s&signature=%s" %(unquote_plus(fmturl), fmtsig) fmturl = fmtid = fmtsig = "" except: self.error = "[YoutubeURL] Error parsing fmtstring: %s" % fmtstring self.errReturn(self.video_url) return else: (fmtid,fmturl) = fmtstring.split('|') if self.VIDEO_FMT_PRIORITY_MAP.has_key(fmtid) and fmtid != "": video_fmt_map[self.VIDEO_FMT_PRIORITY_MAP[fmtid]] = { 'fmtid': fmtid, 'fmturl': unquote_plus(fmturl) } fmt_infomap[int(fmtid)] = unquote_plus(fmturl) if video_fmt_map and len(video_fmt_map): print "[youtubeUrl] found best available video format:",video_fmt_map[sorted(video_fmt_map.iterkeys())[0]]['fmtid'] best_video = video_fmt_map[sorted(video_fmt_map.iterkeys())[0]] if best_video['fmtsig']: self.video_url = "%s&signature=%s" %(best_video['fmturl'].split(';')[0], best_video['fmtsig']) else: self.video_url = "%s" %(best_video['fmturl'].split(';')[0]) del self.yt_tw_agent_hlp self.callBack(self.video_url) else: self.error = "[YoutubeURL] Error: no video url found" self.errReturn(self.video_url) def removeAdditionalEndingDelimiter(self, data): pos = data.find("};") if pos != -1: data = data[:pos + 1] return data def extractFlashVars(self, data, assets): flashvars = {} found = False for line in data.split("\n"): if line.strip().find(";ytplayer.config = ") > 0: found = True p1 = line.find(";ytplayer.config = ") + len(";ytplayer.config = ") - 1 p2 = line.rfind(";") if p1 <= 0 or p2 <= 0: continue data = line[p1 + 1:p2] break data = self.removeAdditionalEndingDelimiter(data) if found: data = json.loads(data) if assets: flashvars = data["assets"] else: flashvars = data["args"] return flashvars