示例#1
0
文件: yt_url.py 项目: jojo260/enigma2
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
示例#2
0
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
示例#3
0
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)
示例#5
0
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