#~DamnVid-module:youtube

class DamnModule_YouTube(DamnVideoModule):
	def __init__(self,uri,parent=None):
		DamnVideoModule.__init__(self,uri)
		self.name='youtube'
		self.regex = {
			'url': re.compile('^https?://(?:[-_\w]+\.)*(?:youtu\.be|youtube\.\w+.*(?:v|(?:video_)?id))[/=]([-_\w]{6,})',re.IGNORECASE),
			'playlist': re.compile('^https?://(?:[-_\w]+\.)*youtube\.\w+.*[?&](?:playlist|list|play_list)[/=]([-_\w]{6,})',re.IGNORECASE),
			'title': (re.compile('(?:^|&)title=([^&]+)',re.IGNORECASE),re.compile('<meta[^<>]*name="?title"?[^<>]*content="\s*([^"<>]+)\s*"', re.IGNORECASE),re.compile('<title>\s*YouTube\s*-*\s*([^<>]+?)\s*</title>', re.IGNORECASE),self.regex['title']),
			'ticket': (re.compile(r'[\'"]url_encoded_fmt_stream_map[\'"]?\s*:\s*[\'"]([^\'"]+)[\'"]',re.IGNORECASE), re.compile(r'[\'"]fmt_map[\'"]?\s*:\s*[\'"]([^\'"]+)[\'"]',re.IGNORECASE), re.compile(r'\\(.)')),
			'YouTube_replaceHost': re.compile('^(https?://)[^/]+', re.IGNORECASE)
		}
		self.YouTube_PreferredFormats = (38, 37, 22, 35, 34, 18, 5, 17, 45, 44, 43)
		self.hd=None
		self.playlist=False
		self.valid=self.regex['url'].search(uri)
		if self.valid:
			self.id='yt:'+self.valid.group(1)
			self.link='http://www.youtube.com/watch?v='+self.valid.group(1)
		else:
			self.valid=self.regex['playlist'].search(uri)
			if self.valid:
				self.id='yp:'+self.valid.group(1)
				self.playlist=True
				self.link='http://www.youtube.com/view_play_list?p='+self.id[3:]
	def getTitle(self):
		if self.playlist:
			return None
		if self.title is None:
			html=DamnURLGetAll(self.link, onerror='')
			gottitle = False
			res=self.regex['title'][1].search(html)
			if res:
				self.title=DamnUnicode(DamnHtmlEntities(res.group(1))).replace(u'&#39;', u'\'')
				gottitle = True
			else:
				res=self.regex['title'][2].search(html)
				if res:
					self.title=DamnUnicode(DamnHtmlEntities(res.group(1))).replace(u'&#39;', u'\'')
					gottitle = True
				else:
					res=self.regex['title'][3].search(html)
					if res:
						self.title=DamnUnicode(DamnHtmlEntities(res.group(1))).replace(u'&#39;', u'\'')
						gottitle = True
			self.YouTube_GetTicket(html)
			if not gottitle:
				html=DamnURLGetAll('http://www.youtube.com/get_video_info?video_id='+self.id[3:], onerror='')
				gottitle = False
				res=self.regex['title'][0].search(html)
				if res:
					try:
						self.title=DamnUnicode(urllib2.unquote(res.group(1).replace('+','%20')))
					except:
						pass # Happens with unicode errors and stuff
				self.YouTube_GetTicket(html)
		return DamnVideoModule.getTitle(self)
	def YouTube_URLQuery2Dict(self, query):
		query = DamnUnicode(query)
		if query[0] == u'?':
			query = query[1:]
		urlParams = query.split(u'&')
		d = {}
		for u in urlParams:
			param = u.split(u'=')
			if len(param) == 2:
				d[DamnUnicode(urllib.unquote(param[0]))] = DamnUnicode(urllib.unquote(param[1]))
		return d
	def YouTube_GetTicket(self, html):
		resUrlEncoded = self.regex['ticket'][0].search(html)
		resfmt = self.regex['ticket'][1].search(html)
		availableFmts = {}
		def addUrl(fmt, url):
			fmt = str(int(fmt))
			if fmt not in availableFmts:
				availableFmts[fmt] = []
			availableFmts[fmt].append(url)
		fmtHeights = {}
		if resfmt is not None:
			allFmts = self.regex['ticket'][2].sub(r'\1', DamnUnicode(resfmt.group(1)).decode('unicode_escape')).split(u',')
			for fmt in allFmts:
				try:
					fmt = DamnUnicode(fmt).split('/')
					availableFmts.append(int(fmt[0]))
					fmtHeights[fmt[0]] = int(fmt[1].split('x')[1])
				except:
					pass
		if resUrlEncoded is not None:
			allUrlsSplit = DamnUnicode(resUrlEncoded.group(1)).split(u',')
			for u in allUrlsSplit:
				params = self.YouTube_URLQuery2Dict(self.regex['ticket'][2].sub(r'\1', u.decode('unicode_escape')))
				fmt = -1
				if 'itag' in params:
					fmt = int(params['itag'])
				if 'url' in params:
					if 'sig' in params:
						params['url'] += '&signature=' + urllib.quote(params['sig'])
					addUrl(fmt, params['url'])
					if 'fallback_host' in params:
						addUrl(fmt, self.regex['YouTube_replaceHost'].sub(DamnUnicode(r'\1') + params['fallback_host'], params['url']))
					if 'quality' in params:
						if (self.hd is None or self.hd == u'720') and params['quality'] != u'hd720' and u'hd' in params['quality']:
							self.hd = u'1080'
						elif self.hd is None and params['quality'] == u'hd720':
							self.hd = u'720'
		cleanUrls = []
		knownFormats = []
		for i in self.YouTube_PreferredFormats:
			if str(i) in availableFmts:
				cleanUrls.extend(availableFmts[str(i)])
				knownFormats.append(str(i))
		for f in availableFmts:
			if f not in knownFormats:
				cleanUrls.extend(availableFmts[f])
		self.newTicket(cleanUrls)
	def getProfile(self):
		if self.playlist:
			return None
		if self.hd:
			return self.pref('profilehd'+self.hd)
		return self.pref('profile')
	def getOutdir(self):
		if self.playlist:
			return None
		if self.hd:
			return self.pref('outdirhd'+self.hd)
		return self.pref('outdir')
	def getIcon(self):
		if self.playlist:
			return None
		if self.hd:
			return DamnGetListIcon('youtubehd')
		return DamnGetListIcon('youtube')
	def renewTicket(self):
		if self.playlist:
			return None
		if self.ticket is None or self.ticketdate+60<time.time():
			self.YouTube_GetTicket(DamnURLGetAll(self.link, onerror=''))
	def getDownload(self):
		if self.playlist:
			return None
		self.renewTicket()
		if type(self.ticket) is type([]):
			return self.ticket
		if self.hd == '720':
			return 'http://www.youtube.com/get_video?video_id='+self.id[3:]+'&t='+self.ticket+'&fmt=22'
		elif self.hd == '1080':
			return 'http://www.youtube.com/get_video?video_id='+self.id[3:]+'&t='+self.ticket+'&fmt=37'
		return DamnURLPicker(['http://www.youtube.com/get_video?video_id='+self.id[3:]+'&t='+self.ticket+'&fmt=18','http://www.youtube.com/get_video?video_id='+self.id[3:]+'&t='+self.ticket],True)
	def addVid(self,parent):
		if not self.playlist:
			return DamnVideoModule.addVid(self,parent)
		playlist = DV.youtube_service.GetYouTubeVideoFeed('https://gdata.youtube.com/feeds/api/playlists/'+self.id[3:]+'?v=2&max-results='+str(self.pref('maxplaylist')))
		for i in playlist.entry:
			try:
				self.__class__(i.media.player.url).addVid(parent)
			except:
				pass # Might fail for a number of reasons (private video, video is down, etc)
		if len(playlist.entry) == 50 and int(self.pref('maxplaylist')) == 50:
			# Add all videos until there is no more
			startIndex = 50
			keepGoing = True
			while len(playlist.entry) == 50:
				playlist = DV.youtube_service.GetYouTubeVideoFeed('https://gdata.youtube.com/feeds/api/playlists/'+self.id[3:]+'?v=2&max-results='+str(self.pref('maxplaylist'))+'&start-index='+str(startIndex))
				for i in playlist.entry:
					try:
						self.__class__(i.media.player.url).addVid(parent)
					except:
						pass
				startIndex += 50
DamnRegisterModule({
	'name':'youtube',
	'title':'YouTube',
	'type':'video',
	'version':'1.9902',
	'minversion':'1.7',
	'author':{
		'name':'Etienne Perot',
		'email':'admin@biringa.com',
		'url':'http://biringa.com/'
	},
	'icon':{
		'small':'youtube.png',
		'large':'youtube-large.png',
	},
	'about':{
		'short':'DamnVid module for YouTube, YouTube HD, and YouTube playlists.',
		'long':"""This is a video plugin for DamnVid that adds YouTube video downloading capabilities.
YouTube HD (720p/1080p) is also supported, as well as playlist batch downloading.""",
		'url':'http://code.google.com/p/damnvid/wiki/Modules'
	},
	'sites':[
		{
			'title':'YouTube',
			'icon':'youtube.png',
			'url':'http://www.youtube.com/browse'
		},
		{
			'title':'YouTube HD',
			'icon':'youtubehd.png',
			'url':'http://www.youtube.com/browse?s=mphd'
		}
	],
	'class':DamnModule_YouTube,
	'preferences':{
		'profile':{
			'name':'Default profile',
			'type':DV.preference_type_profile,
			'kind':'profile',
			'strict':True,
			'default':3
		},
		'profilehd720':{
			'name':'Default profile for 720p videos',
			'type':DV.preference_type_profile,
			'kind':'profile',
			'strict':True,
			'default':-1
		},
		'profilehd1080':{
			'name':'Default profile for 1080p videos',
			'type':DV.preference_type_profile,
			'kind':'profile',
			'strict':True,
			'default':-1
		},
		'outdir':{
			'name':'Output directory',
			'type':DV.preference_type_misc,
			'kind':'dir',
			'strict':True,
			'default':'?DAMNVID_MY_VIDEOS?/DamnVid/YouTube/'
		},
		'outdirhd720':{
			'name':'Output directory for 720p videos',
			'type':DV.preference_type_misc,
			'kind':'dir',
			'strict':True,
			'default':'?DAMNVID_MY_VIDEOS?/DamnVid/High-definition/'
		},
		'outdirhd1080':{
			'name':'Output directory for 1080p videos',
			'type':DV.preference_type_misc,
			'kind':'dir',
			'strict':True,
			'default':'?DAMNVID_MY_VIDEOS?/DamnVid/High-definition/'
		},
		'maxplaylist':{
			'name':'Maximum videos from playlists',
			'type':DV.preference_type_misc,
			'kind':'int:1-50',
			'strict':True,
			'default':'50'
		}
	},
	'preferences_order':['profile','outdir','profilehd720','outdirhd720','profilehd1080','outdirhd1080','maxplaylist'],
	'register':{
		'listicons':{
			'youtube':'youtube.png',
			'youtubehd':'youtubehd.png'
		}
	}
})
