MyTube: Move youtube client wrapper to systemplugins-tubelib for easier reuse
[enigma2-plugins.git] / mytube / src / MyTubeService.py
1 # -*- coding: iso-8859-1 -*-
2 from enigma import ePythonMessagePump
3 from Components.config import config
4 from Tools.Log import Log
5
6
7 from __init__ import decrypt_block
8 from ThreadQueue import ThreadQueue
9
10 from twisted.web import client
11 from twisted.internet import reactor
12 from urllib2 import Request, URLError, urlopen as urlopen2
13 from socket import gaierror, error
14 import os, socket, httplib
15 from urllib import quote, unquote_plus, unquote, urlencode
16 from httplib import HTTPConnection, CannotSendRequest, BadStatusLine, HTTPException
17
18 from urlparse import parse_qs, parse_qsl
19 from threading import Thread
20
21 HTTPConnection.debuglevel = 1
22
23 from Plugins.SystemPlugins.TubeLib.youtube.Base import buildYoutube
24 from Plugins.SystemPlugins.TubeLib.youtube.Search import Search
25 from Plugins.SystemPlugins.TubeLib.youtube.Videos import Videos
26 from Plugins.SystemPlugins.TubeLib.youtube.VideoCategories import VideoCategories
27
28 def validate_cert(cert, key):
29         buf = decrypt_block(cert[8:], key)
30         if buf is None:
31                 return None
32         return buf[36:107] + cert[139:196]
33
34 def get_rnd():
35         try:
36                 rnd = os.urandom(8)
37                 return rnd
38         except:
39                 return None
40
41 class GoogleSuggestions():
42         def __init__(self):
43                 self.hl = "en"
44                 self.conn = None
45
46         def prepareQuery(self):
47                 self.prepQuerry = "/complete/search?output=chrome&client=chrome&"
48                 if self.hl is not None:
49                         self.prepQuerry = self.prepQuerry + "hl=" + self.hl + "&"
50                 self.prepQuerry = self.prepQuerry + "jsonp=self.gotSuggestions&q="
51                 print "[MyTube - GoogleSuggestions] prepareQuery:",self.prepQuerry
52
53         def getSuggestions(self, queryString):
54                 self.prepareQuery()
55                 if queryString is not "":
56                         query = self.prepQuerry + quote(queryString)
57                         self.conn = HTTPConnection("google.com")
58                         try:
59                                 self.conn = HTTPConnection("google.com")
60                                 self.conn.request("GET", query, "", {"Accept-Encoding": "UTF-8"})
61                         except (CannotSendRequest, gaierror, error):
62                                 self.conn.close()
63                                 print "[MyTube - GoogleSuggestions] Can not send request for suggestions"
64                                 return None
65                         else:
66                                 try:
67                                         response = self.conn.getresponse()
68                                 except BadStatusLine:
69                                         self.conn.close()
70                                         print "[MyTube - GoogleSuggestions] Can not get a response from google"
71                                         return None
72                                 else:
73                                         if response.status == 200:
74                                                 data = response.read()
75                                                 header = response.getheader("Content-Type", "text/xml; charset=ISO-8859-1")
76                                                 charset = "ISO-8859-1"
77                                                 try:
78                                                         charset = header.split(";")[1].split("=")[1]
79                                                         print "[MyTube - GoogleSuggestions] Got charset %s" %charset
80                                                 except:
81                                                         print "[MyTube - GoogleSuggestions] No charset in Header, falling back to %s" %charset
82                                                 data = data.decode(charset).encode("utf-8")
83                                                 self.conn.close()
84                                                 return data
85                                         else:
86                                                 self.conn.close()
87                                                 return None
88                 else:
89                         return None
90
91 class MyTubePlayerService():
92 #       Do not change the client_id and developer_key in the login-section!
93 #       ClientId: ytapi-dream-MyTubePlayer-i0kqrebg-0
94 #       DeveloperKey: AI39si4AjyvU8GoJGncYzmqMCwelUnqjEMWTFCcUtK-VUzvWygvwPO-sadNwW5tNj9DDCHju3nnJEPvFy4WZZ6hzFYCx8rJ6Mw
95
96         cached_auth_request = {}
97         current_auth_token = None
98         yt_service = None
99
100         def __init__(self):
101                 print "[MyTube] MyTubePlayerService - init"
102                 self.feedentries = []
103                 self.feed = None
104                 self._youtube = None
105                 self._currentQuery = None
106                 self._categories = []
107                 self._categoriesQuery = None
108
109         def startService(self):
110                 print "[MyTube] MyTubePlayerService - startService"
111                 self._youtube = buildYoutube()
112                 self.loadCategories()
113                 #TODO Login
114                 # yt_service is reinit on every feed build; cache here to not reauth. remove init every time?
115 #               if self.current_auth_token is not None:
116 #                       print "[MyTube] MyTubePlayerService - auth_cached"
117 #                       self.yt_service.SetClientLoginToken(self.current_auth_token)
118                 
119 #               self.loggedIn = False
120                 #os.environ['http_proxy'] = 'http://169.229.50.12:3128'
121                 #proxy = os.environ.get('http_proxy')
122                 #print "FOUND ENV PROXY-->",proxy
123                 #for a in os.environ.keys():
124                 #       print a
125
126         def stopService(self):
127                 print "[MyTube] MyTubePlayerService - stopService"
128
129         def getLoginTokenOnCurl(self, email, pw):
130
131                 opts = {
132                   'service':'youtube',
133                   'accountType': 'HOSTED_OR_GOOGLE',
134                   'Email': email,
135                   'Passwd': pw,
136                   'source': self.yt_service.client_id,
137                 }
138                 
139                 print "[MyTube] MyTubePlayerService - Starting external curl auth request"
140                 result = os.popen('curl -s -k -X POST "%s" -d "%s"' % (gdata.youtube.service.YOUTUBE_CLIENTLOGIN_AUTHENTICATION_URL , urlencode(opts))).read()
141                 
142                 return result
143
144         def supportsSSL(self):
145                 return 'HTTPSConnection' in dir(httplib)
146
147         def getFormattedTokenRequest(self, email, pw):
148                 return dict(parse_qsl(self.getLoginTokenOnCurl(email, pw).strip().replace('\n', '&')))
149         
150         def getAuthedUsername(self):
151                 # on external curl we can get real username
152                 if self.cached_auth_request.get('YouTubeUser') is not None:
153                         return self.cached_auth_request.get('YouTubeUser')
154
155                 if self.is_auth() is False:
156                         return ''
157
158                 # current gdata auth class save doesnt save realuser
159                 return 'Logged In'
160
161         def auth_user(self, username, password):
162                 #todo auth_user
163 #               print "[MyTube] MyTubePlayerService - auth_use - " + str(username)
164 #
165 ##              if self.yt_service is None:
166 ##                      self.startService()
167 #               
168 ##              if self.current_auth_token is not None:
169 ##                      print "[MyTube] MyTubePlayerService - auth_cached"
170 ##                      self.yt_service.SetClientLoginToken(self.current_auth_token)
171 ##                      return
172 #
173 #               if self.supportsSSL() is False:
174 #                       print "[MyTube] MyTubePlayerService - HTTPSConnection not found trying external curl"
175 #                       self.cached_auth_request = self.getFormattedTokenRequest(username, password)
176 #                       if self.cached_auth_request.get('Auth') is None:
177 #                               raise Exception('Got no auth token from curl; you need curl and valid youtube login data')
178 #                       
179 #                       self.yt_service.SetClientLoginToken(self.cached_auth_request.get('Auth'))
180 #               else:
181 #                       print "[MyTube] MyTubePlayerService - Using regularly ProgrammaticLogin for login"
182 #                       self.yt_service.email = username
183 #                       self.yt_service.password  = password
184 #                       self.yt_service.ProgrammaticLogin()
185 #                       
186 #               # double check login: reset any token on wrong logins
187 #               if self.is_auth() is False:
188 #                       print "[MyTube] MyTubePlayerService - auth_use - auth not possible resetting"
189 #                       self.resetAuthState()
190 #                       return
191 #
192 #               print "[MyTube] MyTubePlayerService - Got successful login"
193 #               self.current_auth_token = self.auth_token()
194                 pass
195
196         def resetAuthState(self):
197                 print "[MyTube] MyTubePlayerService - resetting auth"
198                 self.cached_auth_request = {}
199                 self.current_auth_token = None
200
201 #               if self.yt_service is None:
202 #                       return
203 #
204 #               self.yt_service.current_token = None
205 #               self.yt_service.token_store.remove_all_tokens()
206
207         def is_auth(self):
208                 return False
209 #               if self.current_auth_token is not None:
210 #                       return True             
211 #               
212 #               if self.yt_service.current_token is None:
213 #                       return False
214                 
215 #               return self.yt_service.current_token.get_token_string() != 'None'
216
217         def auth_token(self):
218                 return ""
219 #               return self.yt_service.current_token.get_token_string()
220
221         def getCategories(self):
222                 return self._categories
223
224         def loadCategories(self):
225                 categories = VideoCategories(self._youtube)
226                 self._categoriesQuery = categories.list(self._onCategoriesReady)
227
228         def _onCategoriesReady(self, success, data):
229                 if success:
230                         self._categories = data
231                 else:
232                         Log.w(data)
233
234         def getFeed(self, callback = None, errorback = None, chart=None, videoCategoryId=None, ids=[]):
235                 Log.i()
236                 self.feedentries = []
237                 self._currentQuery = Videos(self._youtube)
238                 return self._currentQuery.list(callback, chart=chart, videoCategoryId=videoCategoryId, ids=ids)
239
240         def search(self, searchTerm=None, startIndex=1, maxResults=50,
241                                         orderby=Search.ORDER_RELEVANCE, time='all_time',
242                                         lr="", categories="", relatedToVideoId=None,
243                                         safeSearch=Search.SAFE_SEARCH_NONE, channelId=None,
244                                         callback=None):
245                 Log.d()
246                 self._currentQuery = Search(self._youtube)
247                 return self._currentQuery.list(callback, searchTerm=searchTerm, order=orderby, maxResults=maxResults, relatedToVideoId=relatedToVideoId, channelId=channelId, safeSearch=safeSearch)
248
249         def SubscribeToUser(self, username):
250                 try:
251                         new_subscription = self.yt_service.AddSubscriptionToChannel(username_to_subscribe_to=username)
252         
253                         if isinstance(new_subscription, gdata.youtube.YouTubeSubscriptionEntry):
254                                 print '[MyTube] MyTubePlayerService: New subscription added'
255                                 return _('New subscription added')
256                         
257                         return _('Unknown error')
258                 except gdata.service.RequestError as req:
259                         return str('Error: ' + str(req[0]["body"]))
260                 except Exception as e:
261                         return str('Error: ' + e)
262         
263         def addToFavorites(self, video_id):
264                 try:
265                         video_entry = self.yt_service.GetYouTubeVideoEntry(video_id=video_id)
266                         response = self.yt_service.AddVideoEntryToFavorites(video_entry)
267                         
268                         # The response, if succesfully posted is a YouTubeVideoEntry
269                         if isinstance(response, gdata.youtube.YouTubeVideoEntry):
270                                 print '[MyTube] MyTubePlayerService: Video successfully added to favorites'
271                                 return _('Video successfully added to favorites')       
272         
273                         return _('Unknown error')
274                 except gdata.service.RequestError as req:
275                         return str('Error: ' + str(req[0]["body"]))
276                 except Exception as e:
277                         return str('Error: ' + e)
278         
279         def getTitle(self):
280                 return ""
281
282         def getEntries(self):
283                 return self.feedentries
284
285         def itemCount(self):
286                 return ""
287
288         def getTotalResults(self):
289                 return self._currentQuery and self._currentQuery.getTotalResults()
290
291         def hasNextPage(self):
292                 return self._currentQuery and self._currentQuery.hasNextPage()
293
294         def getNextPage(self):
295                 return self._currentQuery and self._currentQuery.nextPage()
296
297         def getCurrentPage(self):
298                 return 1
299
300 myTubeService = MyTubePlayerService()
301