""" urlresolver XBMC Addon Copyright (C) 2018 jsergio This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . """ import re import urllib import json import urllib2 from lib import helpers from urlresolver import common from urlresolver.common import i18n from urlresolver.resolver import UrlResolver, ResolverError logger = common.log_utils.Logger.get_logger(__name__) logger.disable() CLIENT_ID = '854653386' USER_AGENT = 'URLResolver for Kodi/%s' % common.addon_version FORMATS = common.VIDEO_FORMATS base_url = 'https://www.premiumize.me' api_path = '%s/api' % base_url direct_dl_path = '%s/transfer/directdl' % api_path list_folders_path = '%s/folder/list' % api_path create_folder_path = '%s/folder/create' % api_path delete_folder_path = '%s/folder/delete' % api_path list_transfers_path = '%s/transfer/list' % api_path create_transfer_path = '%s/transfer/create' % api_path delete_transfer_path = '%s/transfer/delete' % api_path clear_finished_path = '%s/transfer/clearfinished' % api_path check_cache_path = '%s/cache/check' % api_path list_services_path = '%s/services/list' % api_path folder_name = 'urlresolver' token_path = '%s/token' % base_url # noinspection PyBroadException class PremiumizeMeResolver(UrlResolver): name = "Premiumize.me" domains = ["*"] media_url = None def __init__(self): self.hosts = [] self.patterns = [] self.net = common.Net() self.headers = {'User-Agent': USER_AGENT, 'Authorization': 'Bearer %s' % self.get_setting('token')} def get_media_url(self, host, media_id, cached_only=False): torrent = False cached = self.__check_cache(media_id) media_id_lc = media_id.lower() if cached: logger.log_debug('Premiumize.me: %s is readily available to stream' % media_id) if media_id_lc.endswith('.torrent') or media_id_lc.startswith('magnet:'): torrent = True elif media_id_lc.endswith('.torrent') or media_id_lc.startswith('magnet:'): if self.get_setting('cached_only') == 'true' or cached_only: raise ResolverError('Premiumize.me: Cached torrents only allowed to be initiated') torrent = True logger.log_debug('Premiumize.me: initiating transfer to cloud for %s' % media_id) self.__initiate_transfer(media_id) self.__clear_finished() # self.__delete_folder() link = self.__direct_dl(media_id, torrent=torrent) if link is not None: logger.log_debug('Premiumize.me: Resolved to %s' % link) return link + helpers.append_headers(self.headers) raise ResolverError('Link Not Found') def get_url(self, host, media_id): return media_id def get_host_and_id(self, url): return 'premiumize.me', url @common.cache.cache_method(cache_limit=8) def get_all_hosters(self): try: response = self.net.http_GET(list_services_path, headers=self.headers).content result = json.loads(response) aliases = result.get('aliases', {}) patterns = result.get('regexpatterns', {}) tldlist = [] for tlds in aliases.values(): for tld in tlds: tldlist.append(tld) if self.get_setting('torrents') == 'true': tldlist.extend([u'torrent', u'magnet']) regex_list = [] for regexes in patterns.values(): for regex in regexes: try: regex_list.append(re.compile(regex)) except: common.logger.log_warning('Throwing out bad Premiumize regex: %s' % regex) logger.log_debug('Premiumize.me patterns: %s regex: (%d) hosts: %s' % (patterns, len(regex_list), tldlist)) return tldlist, regex_list except Exception as e: logger.log_error('Error getting Premiumize hosts: %s' % e) return [], [] def valid_url(self, url, host): if url and self.get_setting('torrents') == 'true': url_lc = url.lower() if url_lc.endswith('.torrent') or url_lc.startswith('magnet:'): return True if not self.patterns or not self.hosts: self.hosts, self.patterns = self.get_all_hosters() if url: if not url.endswith('/'): url += '/' for pattern in self.patterns: if pattern.findall(url): return True elif host: if host.startswith('www.'): host = host.replace('www.', '') if any(host in item for item in self.hosts): return True return False def __check_cache(self, media_id): try: url = '%s?items[]=%s' % (check_cache_path, media_id) result = self.net.http_GET(url, headers=self.headers).content result = json.loads(result) if 'status' in result: if result.get('status') == 'success': response = result.get('response', False) if isinstance(response, list): return response[0] except: pass return False def __create_transfer(self, media_id): folder_id = self.__create_folder() if not folder_id == "": try: data = urllib.urlencode({'src': media_id, 'folder_id': folder_id}) response = self.net.http_POST(create_transfer_path, form_data=data, headers=self.headers).content result = json.loads(response) if 'status' in result: if result.get('status') == 'success': logger.log_debug('Transfer successfully started to the Premiumize.me cloud') return result.get('id', "") except: pass return "" def __list_transfer(self, transfer_id): if not transfer_id == "": try: response = self.net.http_GET(list_transfers_path, headers=self.headers).content result = json.loads(response) if 'status' in result: if result.get('status') == 'success': for item in result.get("transfers"): if item.get('id') == transfer_id: return item except: pass return {} def __delete_transfer(self, transfer_id): if not transfer_id == "": try: data = urllib.urlencode({'id': transfer_id}) response = self.net.http_POST(delete_transfer_path, form_data=data, headers=self.headers).content result = json.loads(response) if 'status' in result: if result.get('status') == 'success': logger.log_debug('Transfer ID "%s" deleted from the Premiumize.me cloud' % transfer_id) return True except: pass return False def __initiate_transfer(self, media_id, interval=5): transfer_id = self.__create_transfer(media_id) transfer_info = self.__list_transfer(transfer_id) if transfer_info: line1 = transfer_info.get('name') line2 = 'Saving torrent to the Premiumize Cloud' line3 = transfer_info.get('message') with common.kodi.ProgressDialog('URL Resolver Premiumize Transfer', line1, line2, line3) as pd: while not transfer_info.get('status') == 'seeding': common.kodi.sleep(1000 * interval) transfer_info = self.__list_transfer(transfer_id) line1 = transfer_info.get('name') line3 = transfer_info.get('message') logger.log_debug(line3) pd.update(int(float(transfer_info.get('progress')) * 100), line1=line1, line3=line3) if pd.is_canceled(): self.__delete_transfer(transfer_id) # self.__delete_folder() raise ResolverError('Transfer ID %s canceled by user' % transfer_id) elif transfer_info.get('status') == 'stalled': # not sure on this value self.__delete_transfer(transfer_id) # self.__delete_folder() raise ResolverError('Transfer ID %s has stalled' % transfer_id) common.kodi.sleep(1000 * interval) # allow api time to generate the stream_link self.__delete_transfer(transfer_id) # just in case __clear_finished() doesnt work return def __direct_dl(self, media_id, torrent=False): try: data = urllib.urlencode({'src': media_id}) response = self.net.http_POST(direct_dl_path, form_data=data, headers=self.headers).content result = json.loads(response) if 'status' in result: if result.get('status') == 'success': if torrent: _videos = [] for items in result.get("content"): if any(items.get('path').lower().endswith(x) for x in FORMATS) and not items.get("link", "") == "": _videos.append(items) try: return max(_videos, key=lambda x: x.get('size')).get('link', None) except ValueError: raise ResolverError('Failed to locate largest video file') else: return result.get('location', None) else: raise ResolverError('Link Not Found: Error Code: %s' % result.get('status')) else: raise ResolverError('Unexpected Response Received') except: pass return None def __list_folders(self): try: response = self.net.http_GET(list_folders_path, headers=self.headers).content result = json.loads(response) if 'status' in result: if result.get('status') == 'success': for items in result.get("content"): if items.get('type') == 'folder' and items.get("name") == folder_name: return items.get("id", "") except: pass return "" def __create_folder(self): folder_id = self.__list_folders() if folder_id == "": try: data = urllib.urlencode({'name': folder_name}) response = self.net.http_POST(create_folder_path, form_data=data, headers=self.headers).content result = json.loads(response) if 'status' in result: if result.get('status') == 'success': logger.log_debug('Folder named "%s" created on the Premiumize.me cloud' % folder_name) return result.get('id', "") except: pass return "" else: return folder_id def __delete_folder(self): folder_id = self.__list_folders() if not folder_id == "": try: data = urllib.urlencode({'id': folder_id}) response = self.net.http_POST(delete_folder_path, form_data=data, headers=self.headers).content result = json.loads(response) if 'status' in result: if result.get('status') == 'success': logger.log_debug('Folder named "%s" deleted from the Premiumize.me cloud' % folder_name) return True except: pass return False def __clear_finished(self): try: result = self.net.http_POST(clear_finished_path, form_data={}, headers=self.headers).content result = json.loads(result) if 'status' in result: if result.get('status') == 'success': logger.log_debug('Finished transfers successfully cleared from the Premiumize.me cloud') return True except: pass return False # SiteAuth methods def login(self): if not self.get_setting('token'): self.authorize_resolver() def authorize_resolver(self): data = {'response_type': 'device_code', 'client_id': CLIENT_ID} js_result = json.loads(self.net.http_POST(token_path, form_data=data, headers=self.headers).content) line1 = 'Go to URL: %s' % js_result.get('verification_uri') line2 = 'When prompted enter: %s' % js_result.get('user_code') with common.kodi.CountdownDialog('URL Resolver Premiumize Authorization', line1, line2, countdown=120, interval=js_result.get('interval', 5)) as cd: result = cd.start(self.__get_token, [js_result.get('device_code')]) # cancelled if result is None: return return result def __get_token(self, device_code): try: data = {'grant_type': 'device_code', 'client_id': CLIENT_ID, 'code': device_code} logger.log_debug('Authorizing Premiumize.me: %s' % CLIENT_ID) js_result = json.loads(self.net.http_POST(token_path, form_data=data, headers=self.headers).content) logger.log_debug('Authorizing Premiumize.me Result: |%s|' % js_result) self.set_setting('token', js_result['access_token']) except urllib2.HTTPError as e: try: js_result = json.loads(e.read()) if 'error' in js_result: msg = js_result.get('error') else: msg = 'Unknown Error (1)' except: msg = 'Unknown Error (2)' logger.log_debug('Premiumize.me Authorization Failed: %s' % msg) return False except Exception as e: logger.log_debug('Exception during PM auth: %s' % e) return False else: return True def reset_authorization(self): self.set_setting('token', '') @classmethod def _is_enabled(cls): return cls.get_setting('enabled') == 'true' and cls.get_setting('token') @classmethod def get_settings_xml(cls): xml = super(cls, cls).get_settings_xml() xml.append('' % (cls.__name__, i18n('torrents'))) xml.append('' % (cls.__name__, i18n('cached_only'))) xml.append('' % (cls.__name__, i18n('auth_my_account'))) xml.append('' % (cls.__name__, i18n('reset_my_auth'))) xml.append('' % cls.__name__) return xml @classmethod def isUniversal(cls): return True