feat(NetflixHTTPSubResourceHandler): Fixed issue with missing sleep declaration in...
[plugin.video.netflix.git] / resources / lib / NetflixHttpSubRessourceHandler.py
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3 # Module: NetflixHttpSubRessourceHandler
4 # Created on: 07.03.2017
5
6 from urllib2 import urlopen, URLError
7 from time import sleep
8
9 class NetflixHttpSubRessourceHandler:
10     """ Represents the callable internal server routes & translates/executes them to requests for Netflix"""
11
12     def __init__ (self, kodi_helper, netflix_session):
13         """Sets up credentials & video_list_cache cache
14         Assigns the netflix_session/kodi_helper instacnes
15         Does the initial login if we have user data
16
17         Parameters
18         ----------
19         kodi_helper : :obj:`KodiHelper`
20             instance of the KodiHelper class
21
22         netflix_session : :obj:`NetflixSession`
23             instance of the NetflixSession class
24         """
25         self.kodi_helper = kodi_helper
26         self.netflix_session = netflix_session
27         self.credentials = self.kodi_helper.get_credentials()
28         self.profiles = []
29         self.prefetch_login()
30         self.video_list_cache = {}
31         self.lolomo = None
32
33     def prefetch_login (self):
34         """Check if we have stored credentials.
35         If so, do the login before the user requests it
36         If that is done, we cache the profiles
37         """
38         if self._network_availble():
39             if self.credentials['email'] != '' and self.credentials['password'] != '':
40                 if self.netflix_session.is_logged_in(account=self.credentials):
41                     self.netflix_session.refresh_session_data(account=self.credentials)
42                     self.profiles = self.netflix_session.profiles
43                 else:
44                     self.netflix_session.login(account=self.credentials)
45                     self.profiles = self.netflix_session.profiles
46             else:
47                 self.profiles = []
48         else:
49             sleep(1)
50             self.prefetch_login()
51
52     def is_logged_in (self, params):
53         """Existing login proxy function
54
55         Parameters
56         ----------
57         params : :obj:`dict` of :obj:`str`
58             Request params
59
60         Returns
61         -------
62         :obj:`Requests.Response`
63             Response of the remote call
64         """
65         if self.credentials['email'] == '' or self.credentials['password'] == '':
66             return False
67         return self.netflix_session.is_logged_in(account=self.credentials)
68
69     def logout (self, params):
70         """Logout proxy function
71
72         Parameters
73         ----------
74         params : :obj:`dict` of :obj:`str`
75             Request params
76
77         Returns
78         -------
79         :obj:`Requests.Response`
80             Response of the remote call
81         """
82         self.profiles = []
83         self.credentials = {'email': '', 'password': ''}
84         self.lolomo = None
85         return self.netflix_session.logout()
86
87     def login (self, params):
88         """Logout proxy function
89
90         Parameters
91         ----------
92         params : :obj:`dict` of :obj:`str`
93             Request params
94
95         Returns
96         -------
97         :obj:`Requests.Response`
98             Response of the remote call
99         """
100         email = params.get('email', [''])[0]
101         password = params.get('password', [''])[0]
102         if email != '' and password != '':
103             self.credentials = {'email': email, 'password': password}
104             _ret = self.netflix_session.login(account=self.credentials)
105             self.profiles = self.netflix_session.profiles
106             return _ret
107         return None
108
109     def list_profiles (self, params):
110         """Returns the cached list of profiles
111
112         Parameters
113         ----------
114         params : :obj:`dict` of :obj:`str`
115             Request params
116
117         Returns
118         -------
119         :obj:`dict` of :obj:`str`
120             List of profiles
121         """
122         return self.profiles
123
124     def get_esn (self, params):
125         """ESN getter function
126
127         Parameters
128         ----------
129         params : :obj:`dict` of :obj:`str`
130             Request params
131
132         Returns
133         -------
134         :obj:`str`
135             Exracted ESN
136         """
137         return self.netflix_session.esn
138
139     def fetch_video_list_ids (self, params):
140         """Video list ids proxy function (caches video lists)
141
142         Parameters
143         ----------
144         params : :obj:`dict` of :obj:`str`
145             Request params
146
147         Returns
148         -------
149         :obj:`list`
150             Transformed response of the remote call
151         """
152         cached_list = self.video_list_cache.get(self.netflix_session.user_data['guid'], None)
153         if cached_list != None:
154             self.kodi_helper.log('Serving cached list for user: ' + self.netflix_session.user_data['guid'])
155             return cached_list
156         video_list_ids_raw = self.netflix_session.fetch_video_list_ids()
157         if 'error' in video_list_ids_raw:
158             return video_list_ids_raw
159         return self.netflix_session.parse_video_list_ids(response_data=video_list_ids_raw)
160
161     def fetch_video_list_ids_for_kids (self, params):
162         """Video list ids proxy function (thanks to Netflix that we need to use a different API for Kids profiles)
163
164         Parameters
165         ----------
166         params : :obj:`dict` of :obj:`str`
167             Request params
168
169         Returns
170         -------
171         :obj:`list`
172             Transformed response of the remote call
173         """
174         if self.lolomo == None:
175             self.lolomo = self.netflix_session.get_lolomo_for_kids()
176         response = self.netflix_session.fetch_lists_for_kids(lolomo=self.lolomo)
177         return response
178
179     def fetch_video_list (self, params):
180         """Video list proxy function
181
182         Parameters
183         ----------
184         params : :obj:`dict` of :obj:`str`
185             Request params
186
187         Returns
188         -------
189         :obj:`list`
190             Transformed response of the remote call
191         """
192         list_id = params.get('list_id', [''])[0]
193         raw_video_list = self.netflix_session.fetch_video_list(list_id=list_id)
194         if 'error' in raw_video_list:
195             return raw_video_list
196         # parse the video list ids
197         if 'videos' in raw_video_list.get('value', {}).keys():
198             return self.netflix_session.parse_video_list(response_data=raw_video_list)
199         return []
200
201     def fetch_episodes_by_season (self, params):
202         """Episodes for season proxy function
203
204         Parameters
205         ----------
206         params : :obj:`dict` of :obj:`str`
207             Request params
208
209         Returns
210         -------
211         :obj:`list`
212             Transformed response of the remote call
213         """
214         raw_episode_list = self.netflix_session.fetch_episodes_by_season(season_id=params.get('season_id')[0])
215         if 'error' in raw_episode_list:
216             return raw_episode_list
217         return self.netflix_session.parse_episodes_by_season(response_data=raw_episode_list)
218
219     def fetch_seasons_for_show (self, params):
220         """Season for show proxy function
221
222         Parameters
223         ----------
224         params : :obj:`dict` of :obj:`str`
225             Request params
226
227         Returns
228         -------
229         :obj:`list`
230             Transformed response of the remote call
231         """
232         show_id = params.get('show_id', [''])[0]
233         raw_season_list = self.netflix_session.fetch_seasons_for_show(id=show_id)
234         if 'error' in raw_season_list:
235             return raw_season_list
236         # check if we have sesons, announced shows that are not available yet have none
237         if 'seasons' not in raw_season_list.get('value', {}):
238               return []
239         return self.netflix_session.parse_seasons(id=show_id, response_data=raw_season_list)
240
241     def rate_video (self, params):
242         """Video rating proxy function
243
244         Parameters
245         ----------
246         params : :obj:`dict` of :obj:`str`
247             Request params
248
249         Returns
250         -------
251         :obj:`Requests.Response`
252             Response of the remote call
253         """
254         video_id = params.get('video_id', [''])[0]
255         rating = params.get('rating', [''])[0]
256         return self.netflix_session.rate_video(video_id=video_id, rating=rating)
257
258     def remove_from_list (self, params):
259         """Remove from my list proxy function
260
261         Parameters
262         ----------
263         params : :obj:`dict` of :obj:`str`
264             Request params
265
266         Returns
267         -------
268         :obj:`Requests.Response`
269             Response of the remote call
270         """
271         video_id = params.get('video_id', [''])[0]
272         return self.netflix_session.remove_from_list(video_id=video_id)
273
274     def add_to_list (self, params):
275         """Add to my list proxy function
276
277         Parameters
278         ----------
279         params : :obj:`dict` of :obj:`str`
280             Request params
281
282         Returns
283         -------
284         :obj:`Requests.Response`
285             Response of the remote call
286         """
287         video_id = params.get('video_id', [''])[0]
288         return self.netflix_session.add_to_list(video_id=video_id)
289
290     def fetch_metadata (self, params):
291         """Metadata proxy function
292
293         Parameters
294         ----------
295         params : :obj:`dict` of :obj:`str`
296             Request params
297
298         Returns
299         -------
300         :obj:`Requests.Response`
301             Response of the remote call
302         """
303         video_id = params.get('video_id', [''])[0]
304         return self.netflix_session.fetch_metadata(id=video_id)
305
306     def switch_profile (self, params):
307         """Switch profile proxy function
308
309         Parameters
310         ----------
311         params : :obj:`dict` of :obj:`str`
312             Request params
313
314         Returns
315         -------
316         :obj:`Requests.Response`
317             Response of the remote call
318         """
319         profile_id = params.get('profile_id', [''])[0]
320         self.lolomo = None
321         return self.netflix_session.switch_profile(profile_id=profile_id, account=self.credentials)
322
323     def get_user_data (self, params):
324         """User data getter function
325
326         Parameters
327         ----------
328         params : :obj:`dict` of :obj:`str`
329             Request params
330
331         Returns
332         -------
333         :obj:`str`
334             Exracted User Data
335         """
336         return self.netflix_session.user_data
337
338     def search (self, params):
339         """Search proxy function
340
341         Parameters
342         ----------
343         params : :obj:`dict` of :obj:`str`
344             Request params
345
346         Returns
347         -------
348         :obj:`list`
349             Transformed response of the remote call
350         """
351         term = params.get('term', [''])[0]
352         has_search_results = False
353         raw_search_results = self.netflix_session.fetch_search_results(search_str=term)
354         # check for any errors
355         if 'error' in raw_search_results:
356             return raw_search_results
357
358         # determine if we found something
359         if 'search' in raw_search_results['value']:
360             for key in raw_search_results['value']['search'].keys():
361                 if self.netflix_session._is_size_key(key=key) == False:
362                     has_search_results = raw_search_results['value']['search'][key]['titles']['length'] > 0
363                     if has_search_results == False:
364                         if raw_search_results['value']['search'][key].get('suggestions', False) != False:
365                             for entry in raw_search_results['value']['search'][key]['suggestions']:
366                                 if self.netflix_session._is_size_key(key=entry) == False:
367                                     if raw_search_results['value']['search'][key]['suggestions'][entry]['relatedvideos']['length'] > 0:
368                                         has_search_results = True
369
370         # display that we haven't found a thing
371         if has_search_results == False:
372             return []
373
374         # list the search results
375         search_results = self.netflix_session.parse_search_results(response_data=raw_search_results)
376         # add more menaingful data to the search results
377         raw_search_contents = self.netflix_session.fetch_video_list_information(video_ids=search_results.keys())
378         # check for any errors
379         if 'error' in raw_search_contents:
380             return raw_search_contents
381         return self.netflix_session.parse_video_list(response_data=raw_search_contents)
382
383     def _network_availble(self):
384         """Check if the network is available
385         Returns
386         -------
387         bool
388             Network can be accessed
389         """
390         try:
391             urlopen('http://216.58.192.142', timeout=1)
392             return True
393         except URLError as err:
394             return False