Mytube: workaround newest youtube change in the returned url to get the right youtube...
[vuplus_dvbapp-plugin] / mytube / src / MyTubeService.py
1 # -*- coding: iso-8859-1 -*-
2 from __init__ import _
3 import gdata.youtube
4 import gdata.youtube.service
5 from gdata.service import BadAuthentication
6 from Tools.LoadPixmap import LoadPixmap
7 from Components.config import config, Config, ConfigSelection, ConfigText, getConfigListEntry, ConfigSubsection, ConfigYesNo, ConfigIP, ConfigNumber
8 from Components.ConfigList import ConfigListScreen
9 from Components.config import KEY_DELETE, KEY_BACKSPACE, KEY_LEFT, KEY_RIGHT, KEY_HOME, KEY_END, KEY_TOGGLEOW, KEY_ASCII, KEY_TIMEOUT
10
11 from twisted.web import client
12 from twisted.internet import reactor
13 from urllib2 import Request, URLError, HTTPError, urlopen as urlopen2
14 from socket import gaierror,error
15 import re, os, sys, socket
16 import urllib
17 from urllib import FancyURLopener, quote
18 import cookielib
19 from httplib import HTTPConnection,CannotSendRequest,BadStatusLine,HTTPException
20 HTTPConnection.debuglevel = 1
21
22 std_headers = {
23         'User-Agent': 'Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.1.2) Gecko/20090729 Firefox/3.5.2',
24         'Accept-Charset': 'ISO-8859-1,utf-8;q=0.7,*;q=0.7',
25         'Accept': 'text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5',
26         'Accept-Language': 'en-us,en;q=0.5',
27 }
28
29 #config.plugins.mytube = ConfigSubsection()
30 #config.plugins.mytube.general = ConfigSubsection()
31 #config.plugins.mytube.general.useHTTPProxy = ConfigYesNo(default = False)
32 #config.plugins.mytube.general.ProxyIP = ConfigIP(default=[0,0,0,0])
33 #config.plugins.mytube.general.ProxyPort = ConfigNumber(default=8080)
34
35 class MyOpener(FancyURLopener):
36         version = 'Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.0.12) Gecko/20070731 Ubuntu/dapper-security Firefox/1.5.0.12'
37
38
39 class GoogleSuggestions():
40         def __init__(self, callback, ds = None, json = None, hl = None):
41                 self.callback = callback
42                 self.conn = HTTPConnection("google.com")
43                 self.prepQuerry = "/complete/search?"
44                 if ds is not None:
45                         self.prepQuerry = self.prepQuerry + "ds=" + ds + "&"
46                 if json is not None:
47                         self.prepQuerry = self.prepQuerry + "json=" + json + "&"
48                 if hl is not None:
49                         self.prepQuerry = self.prepQuerry + "hl=" + hl + "&"
50                 self.prepQuerry = self.prepQuerry + "jsonp=self.gotSuggestions&q="
51
52         def gotSuggestions(self, suggestslist):
53                 self.callback(suggestslist)
54
55         def getSuggestions(self, querryString):
56                 if querryString is not "":
57                         querry = self.prepQuerry + quote(querryString)
58                         try:
59                                 self.conn.request("GET", querry)
60                         except (CannotSendRequest, gaierror, error):
61                                 print "[YTB] Can not send request for suggestions"
62                                 self.callback(None)
63                         else:
64                                 try:
65                                         response = self.conn.getresponse()
66                                 except BadStatusLine:
67                                         print "[YTB] Can not get a response from google"
68                                         self.callback(None)
69                                 else:
70                                         if response.status == 200:
71                                                 data = response.read()
72                                                 exec data
73                                         else:
74                                                 self.callback(None)
75                         self.conn.close()
76                 else:
77                         self.callback(None)
78
79
80 class MyTubeFeedEntry():
81         def __init__(self, feed, entry, favoritesFeed = False):
82                 self.feed = feed
83                 self.entry = entry
84                 self.favoritesFeed = favoritesFeed
85                 self.thumbnail = {}
86                 self.myopener = MyOpener()
87                 urllib.urlopen = MyOpener().open
88                 """if config.plugins.mytube.general.useHTTPProxy.value is True:
89                         proxy = {'http': 'http://'+str(config.plugins.mytube.general.ProxyIP.getText())+':'+str(config.plugins.mytube.general.ProxyPort.value)}
90                         self.myopener = MyOpener(proxies=proxy)
91                         urllib.urlopen = MyOpener(proxies=proxy).open
92                 else:
93                         self.myopener = MyOpener()
94                         urllib.urlopen = MyOpener().open"""
95                 
96         def isPlaylistEntry(self):
97                 return False
98
99         def getTubeId(self):
100                 #print "[MyTubeFeedEntry] getTubeId"
101                 ret = None
102                 if self.entry.media.player:
103                         split = self.entry.media.player.url.split("=")
104                         ret = split.pop()
105                         if ret == 'youtube_gdata':
106                                 tmpval=split.pop()
107                                 if tmpval.endswith("&feature"):
108                                         ret = tmpval.strip("&feature")
109                 return ret
110
111         def getTitle(self):
112                 #print "[MyTubeFeedEntry] getTitle",self.entry.media.title.text
113                 return self.entry.media.title.text
114
115         def getDescription(self):
116                 #print "[MyTubeFeedEntry] getDescription"
117                 if self.entry.media is not None and self.entry.media.description is not None:
118                         return self.entry.media.description.text
119                 return "not vailable"
120
121         def getThumbnailUrl(self, index = 0):
122                 #print "[MyTubeFeedEntry] getThumbnailUrl"
123                 if index < len(self.entry.media.thumbnail):
124                         return self.entry.media.thumbnail[index].url
125                 return None
126
127         def getPublishedDate(self):
128                 if self.entry.published is not None:
129                         return self.entry.published.text
130                 return "unknown"
131
132         def getViews(self):
133                 if self.entry.statistics is not None:
134                         return self.entry.statistics.view_count
135                 return "not available"
136         
137         def getDuration(self):
138                 if self.entry.media is not None and self.entry.media.duration is not None:
139                         return self.entry.media.duration.seconds
140                 else:
141                         return 0
142
143         def getRatingAverage(self):
144                 if self.entry.rating is not None:
145                         return self.entry.rating.average
146                 return 0
147
148
149         def getNumRaters(self):
150                 if self.entry.rating is not None:
151                         return self.entry.rating.num_raters
152                 return ""       
153
154         def getAuthor(self):
155                 authors = []
156                 for author in self.entry.author:
157                         authors.append(author.name.text)
158                 author = ", ".join(authors)
159                 return author
160
161         def PrintEntryDetails(self):
162                 EntryDetails = { 'Title': None, 'TubeID': None, 'Published': None, 'Published': None, 'Description': None, 'Category': None, 'Tags': None, 'Duration': None, 'Views': None, 'Rating': None, 'Thumbnails': None}
163                 EntryDetails['Title'] = self.entry.media.title.text
164                 EntryDetails['TubeID'] = self.getTubeId()
165                 EntryDetails['Description'] = self.getDescription()
166                 EntryDetails['Category'] = self.entry.media.category[0].text
167                 EntryDetails['Tags'] = self.entry.media.keywords.text
168                 EntryDetails['Published'] = self.getPublishedDate()
169                 EntryDetails['Views'] = self.getViews()
170                 EntryDetails['Duration'] = self.getDuration()
171                 EntryDetails['Rating'] = self.getNumRaters()
172                 EntryDetails['RatingAverage'] = self.getRatingAverage()
173                 EntryDetails['Author'] = self.getAuthor()
174                 # show thumbnails
175                 list = []
176                 for thumbnail in self.entry.media.thumbnail:
177                         print 'Thumbnail url: %s' % thumbnail.url
178                         list.append(str(thumbnail.url))
179                 EntryDetails['Thumbnails'] = list
180                 #print EntryDetails
181                 return EntryDetails
182
183
184         def getVideoUrl(self):
185                 mrl = None
186                 isHDAvailable = False
187                 video_id = str(self.getTubeId())
188                 watch_url = "http://www.youtube.com/watch?v=" + video_id
189                 watchrequest = Request(watch_url, None, std_headers)
190                 try:
191                         print "trying to find out if a HD Stream is available"
192                         watchvideopage = urlopen2(watchrequest).read()
193                 except (urllib2.URLError, httplib.HTTPException, socket.error), err:
194                         print "[MyTube] Error: Unable to retrieve watchpage"
195                         print "[MyTube] Error code: ", str(err)
196                         print "[MyTube] No valid mp4-url found"
197                         return mrl
198
199                 if "isHDAvailable = true" in watchvideopage:
200                         isHDAvailable = True
201                         print "HD AVAILABLE"
202                 else:
203                         print "HD Stream NOT AVAILABLE"
204
205                 # Get video info
206                 info_url = 'http://www.youtube.com/get_video_info?&video_id=%s&el=detailpage&ps=default&eurl=&gl=US&hl=en' % video_id
207                 inforequest = Request(info_url, None, std_headers)
208                 try:
209                         print "getting video_info_webpage",info_url
210                         infopage = urlopen2(inforequest).read()
211                 except (urllib2.URLError, httplib.HTTPException, socket.error), err:
212                         print "[MyTube] Error: Unable to retrieve infopage"
213                         print "[MyTube] Error code: ", str(err)
214                         print "[MyTube] No valid mp4-url found"
215                         return mrl
216
217                 mobj = re.search(r'(?m)&token=([^&]+)(?:&|$)', infopage)
218                 if mobj is None:
219                         # was there an error ?
220                         mobj = re.search(r'(?m)&reason=([^&]+)(?:&|$)', infopage)
221                         if mobj is None:
222                                 print 'ERROR: unable to extract "t" parameter for unknown reason'
223                         else:
224                                 reason = urllib.unquote_plus(mobj.group(1))
225                                 print 'ERROR: YouTube said: %s' % reason.decode('utf-8')
226                         return mrl
227         
228                 token = urllib.unquote(mobj.group(1))
229                 myurl = 'http://www.youtube.com/get_video?video_id=%s&t=%s&eurl=&el=detailpage&ps=default&gl=US&hl=en' % (video_id, token)
230                 if isHDAvailable is True:
231                         mrl = '%s&fmt=%s' % (myurl, '22')
232                         print "[MyTube] GOT HD URL: ", mrl
233                 else:
234                         mrl = '%s&fmt=%s' % (myurl, '18')
235                         print "[MyTube] GOT SD URL: ", mrl
236
237                 return mrl
238
239         def getRelatedVideos(self):
240                 print "[MyTubeFeedEntry] getResponseVideos()"
241                 for link in self.entry.link:
242                         #print "Related link: ", link.rel.endswith
243                         if link.rel.endswith("video.related"):
244                                 print "Found Related: ", link.href
245                                 return link.href
246
247         def getResponseVideos(self):
248                 print "[MyTubeFeedEntry] getResponseVideos()"
249                 for link in self.entry.link:
250                         #print "Responses link: ", link.rel.endswith
251                         if link.rel.endswith("video.responses"):
252                                 print "Found Responses: ", link.href
253                                 return link.href
254
255 class MyTubePlayerService():
256 #       Do not change the client_id and developer_key in the login-section!
257 #       ClientId: ytapi-dream-MyTubePlayer-i0kqrebg-0
258 #       DeveloperKey: AI39si4AjyvU8GoJGncYzmqMCwelUnqjEMWTFCcUtK-VUzvWygvwPO-sadNwW5tNj9DDCHju3nnJEPvFy4WZZ6hzFYCx8rJ6Mw
259         def __init__(self):
260                 print "[MyTube] MyTubePlayerService - init"
261                 self.feedentries = []
262                 self.feed = None
263                 
264         def startService(self):
265                 print "[MyTube] MyTubePlayerService - startService"
266                 self.yt_service = gdata.youtube.service.YouTubeService()
267                 self.yt_service.developer_key = 'AI39si4AjyvU8GoJGncYzmqMCwelUnqjEMWTFCcUtK-VUzvWygvwPO-sadNwW5tNj9DDCHju3nnJEPvFy4WZZ6hzFYCx8rJ6Mw'
268                 self.yt_service.client_id = 'ytapi-dream-MyTubePlayer-i0kqrebg-0'
269                 self.loggedIn = False
270                 #os.environ['http_proxy'] = 'http://169.229.50.12:3128'
271                 #proxy = os.environ.get('http_proxy')
272                 #print "FOUND ENV PROXY-->",proxy
273                 #for a in os.environ.keys():
274                 #       print a
275
276         def stopService(self):
277                 print "[MyTube] MyTubePlayerService - stopService"
278                 del self.ytService
279                 self.loggedIn = False
280
281         def isLoggedIn(self):
282                 return self.loggedIn
283
284         def getFeed(self, url):
285                 print "[MyTube] MyTubePlayerService - getFeed:",url
286                 self.feedentries = []
287                 self.feed = self.yt_service.GetYouTubeVideoFeed(url)
288                 for entry in self.feed.entry:
289                         MyFeedEntry = MyTubeFeedEntry(self, entry)
290                         self.feedentries.append(MyFeedEntry)
291                 return self.feed                        
292
293         def search(self, searchTerms, startIndex = 1, maxResults = 25,
294                                         orderby = "relevance", racy = "include", 
295                                         author = "", lr = "", categories = "", sortOrder = "ascending"):
296                 print "[MyTube] MyTubePlayerService - search()"
297                 self.feedentries = []
298                 query = gdata.youtube.service.YouTubeVideoQuery()
299                 query.vq = searchTerms
300                 query.orderby = orderby
301                 query.racy = racy
302                 query.sortorder = sortOrder
303                 if lr is not None:
304                         query.lr = lr
305                 if categories[0] is not None:
306                         query.categories = categories
307                 query.start_index = startIndex
308                 query.max_results = maxResults
309                 try:
310                         feed = self.yt_service.YouTubeQuery(query)
311                 except gaierror:
312                         feed = None
313                 if feed is not None:
314                         self.feed = feed
315                         for entry in self.feed.entry:
316                                 MyFeedEntry = MyTubeFeedEntry(self, entry)
317                                 self.feedentries.append(MyFeedEntry)
318                 return self.feed                
319
320         def getTitle(self):
321                 return self.feed.title.text
322
323         def getEntries(self):
324                 return self.feedentries
325
326         def itemCount(self):
327                 return self.feed.items_per_page.text
328
329         def getTotalResults(self):
330                 return self.feed.total_results.text
331         
332         def getNextFeedEntriesURL(self):
333                 for link in self.feed.link:
334                         if link.rel == "next":
335                                 return link.href
336                 return None
337
338
339 myTubeService = MyTubePlayerService()