def _do_search_request(self, request_params): censored_params = request_params.copy() censored_key = censored_params['apikey'] censored_params['apikey'] = "{}{}{}".format(censored_key[0:2], "*" * 26, censored_key[-4:]) log.debug('Making a request to Jackett using params %s', repr(censored_params)) search_resp = self._session.get("all/results/torznab", params=request_params) if search_resp.status_code != httplib.OK: notify(translation(32700).format(search_resp.reason), image=get_icon_path()) log.error("Jackett returned %s", search_resp.reason) return [] err = self.get_error(search_resp.content) if err is not None: notify(translation(32700).format(err["description"]), image=get_icon_path()) log.error("got code %s: %s", err["code"], err["description"]) return [] log.debug("Jackett returned below response") log.debug("===============================") log.debug(search_resp.content) log.debug("===============================") return self._parse_items(search_resp.content)
def search_movie(self, title, year, imdb_id): if "search_tags" not in self._caps: notify(translation(32701), image=get_icon_path()) return [] movie_search_caps = self._caps["search_tags"]['movie-search'] if not movie_search_caps['enabled']: notify(translation(32702).format("movie"), image=get_icon_path()) log.warning( "Jackett has no movie capabilities, please add a indexer that has movie capabilities. " "Falling back to query search...") return self.search_query(title + u' ' + year) # todo what values are possible for imdb_id? movie_params = movie_search_caps["params"] request_params = {"t": "movie", "apikey": self._api_key} has_imdb_caps = 'imdbid' in movie_params log.debug("movie search; imdb_id=%s, has_imdb_caps=%s", imdb_id, has_imdb_caps) if imdb_id and has_imdb_caps: request_params["imdbid"] = imdb_id else: request_params["q"] = title + u' ' + year log.debug("searching movie with query=%s", request_params["q"]) return self._do_search_request(request_params)
def search_shows(self, title, season=None, episode=None, imdb_id=None): if "search_tags" not in self._caps: notify(translation(32701), image=get_icon_path()) return [] tv_search_caps = self._caps["search_tags"]['tv-search'] if not tv_search_caps['enabled']: notify(translation(32702).format("show"), image=get_icon_path()) log.warning( "Jackett has no tvsearch capabilities, please add a indexer that has tvsearch capabilities. " "Falling back to query search...") title_ep = title if bool(season): title_ep = "{} S{:0>2}".format(title_ep, season) if bool(episode): title_ep = "{}E{:0>2}".format(title_ep, episode) results = self.search_query(title_ep) if get_setting("search_season_on_episode", bool) and bool(season) and bool(episode): season_query = re.escape("{:0>2}".format(season)) results = results + self._filter_season( self.search_query("{} S{}".format(title, season_query)), season) return results # todo what values are possible for imdb_id? tv_params = tv_search_caps["params"] request_params = {"t": "tvsearch", "apikey": self._api_key} has_imdb_caps = 'imdbid' in tv_params log.debug("movie search; imdb_id=%s, has_imdb_caps=%s", imdb_id, has_imdb_caps) if imdb_id and has_imdb_caps: request_params["imdbid"] = imdb_id else: log.debug("searching tv show with query=%s, season=%s, episode=%s", title, season, episode) request_params["q"] = title if bool(season) and 'season' in tv_params: request_params["season"] = season if bool(episode) and 'ep' in tv_params: request_params["ep"] = episode results = self._do_search_request(request_params) if get_setting( "search_season_on_episode", bool ) and 'season' in request_params and 'ep' in request_params: del request_params['ep'] results = results + self._filter_season( self._do_search_request(request_params), season) return results
def search_jackett(payload, method): jackett = get_client() if jackett is None: utils.notify(utils.translation(32603), image=utils.get_icon_path()) return [] log.debug("Processing %s with Jackett", method) if method == 'movie': res = jackett.search_movie(payload["search_title"], payload['year'], payload["imdb_id"]) elif method == 'season': res = jackett.search_season(payload["search_title"], payload["season"], payload["imdb_id"]) elif method == 'episode': res = jackett.search_episode(payload["search_title"], payload["season"], payload["episode"], payload["imdb_id"]) elif method == 'anime': log.warning("jackett provider does not yet support anime search") res = [] log.info("anime payload=%s", repr(payload)) # client.search_query(payload["search_title"], payload["season"], payload["episode"], payload["imdb_id"]) else: res = jackett.search_query(payload["search_title"]) log.debug("%s search returned %d results", method, len(res)) res = filter_results(method, res) return sort_results(res)
def get_client(): host = urlparse(get_setting('host')) if host.netloc == '' or host.scheme == '': log.warning("Host %s is invalid. Can't return anything", get_setting('host')) utils.notify(utils.translation(32600), image=utils.get_icon_path()) return None api_key = get_setting('api_key') if len(api_key) != 32: utils.notify(utils.translation(32601), image=utils.get_icon_path()) return None else: log.debug("jackett host: %s", host) log.debug("jackett api_key: %s%s%s", api_key[0:2], "*" * 26, api_key[-4:]) return Jackett(host=host.geturl(), api_key=api_key)
def tray(): app = QtGui.QApplication(['NSAway']) style = app.style() ico = QtGui.QIcon(get_icon_path("good.ico")) w = QtGui.QWidget() trayIcon = SystemTrayIcon(ico, w) trayIcon.show() sys.exit(app.exec_())
def search_query(self, query): if not self._caps["search_tags"]['search']: notify(translation(32702).format("query"), image=get_icon_path()) log.warning( "Jackett has no search capabilities, please add a indexer that has search capabilities." ) return [] request_params = {"apikey": self._api_key, "q": query} return self._do_search_request(request_params)
def get_caps(self): caps_resp = self._session.get("all/results/torznab", params={ "t": "caps", "apikey": self._api_key }) if caps_resp.status_code != httplib.OK: notify(translation(32700).format(caps_resp.reason), image=get_icon_path()) log.error("Jackett return %s", caps_resp.reason) set_setting('settings_validated', caps_resp.reason) return err = self.get_error(caps_resp.content) if err is not None: notify(translation(32700).format(err["description"]), image=get_icon_path()) log.error("got code %s: %s", err["code"], err["description"]) set_setting('settings_validated', err["description"]) return set_setting('settings_validated', 'Success') xml = ET.ElementTree(ET.fromstring(caps_resp.content)).getroot() # todo handle gracefully, doesn't exist for individual trackers # self._caps["limits"] = xml.find("limits").attrib self._caps["search_tags"] = {} for type_tag in xml.findall('searching/*'): self._caps["search_tags"][type_tag.tag] = { "enabled": type_tag.attrib["available"] == "yes", "params": [ p for p in type_tag.attrib['supportedParams'].split(",") if p ], } log.info("Found capabilities: %s", repr(self._caps))
def validate_client(): p_dialog = xbmcgui.DialogProgressBG() try: p_dialog.create('Elementum [COLOR FFFF6B00]Jackett[/COLOR]', utils.translation(32005)) get_client() if get_setting("settings_validated") == "Success": utils.notify(utils.translation(32006), image=utils.get_icon_path()) utils.ADDON.openSettings() finally: p_dialog.close() del p_dialog
def search(payload, method="general"): """ Main search entrypoint Args: payload (dict): Search payload from Quasar. method (str): Type of search, can be ``general``, ``movie``, ``show``, ``season`` or ``anime`` Returns: list: All filtered results in the format Quasar expects """ log.debug("Searching with payload (%s): %s" % (method, repr(payload))) if method == 'general': payload = {'title': payload} global request_time global provider_names global provider_results global available_providers provider_names = [] provider_results = [] available_providers = 0 request_time = time.time() providers = get_enabled_providers() if len(providers) == 0: notify(translation(32060), image=get_icon_path()) log.error("No providers enabled") return [] log.info( "Burstin' with %s" % ", ".join([definitions[provider]['name'] for provider in providers])) if get_setting("use_cloudhole", bool): clearance, user_agent = get_cloudhole_clearance(get_cloudhole_key()) set_setting('clearance', clearance) set_setting('user_agent', user_agent) if get_setting('kodi_language', bool): kodi_language = xbmc.getLanguage(xbmc.ISO_639_1) if not kodi_language: log.warning("Kodi returned empty language code...") elif 'titles' not in payload or not payload['titles']: log.info("No translations available...") elif payload['titles'] and kodi_language not in payload['titles']: log.info("No '%s' translation available..." % kodi_language) p_dialog = xbmcgui.DialogProgressBG() p_dialog.create('Quasar [COLOR FFFF6B00]Burst[/COLOR]', translation(32061)) for provider in providers: available_providers += 1 provider_names.append(definitions[provider]['name']) task = Thread(target=run_provider, args=(provider, payload, method)) task.start() providers_time = time.time() total = float(available_providers) # Exit if all providers have returned results or timeout reached, check every 100ms while time.time() - providers_time < timeout and available_providers > 0: timer = time.time() - providers_time log.debug("Timer: %ds / %ds" % (timer, timeout)) if timer > timeout: break message = translation( 32062 ) % available_providers if available_providers > 1 else translation( 32063) p_dialog.update(int((total - available_providers) / total * 100), message=message) time.sleep(0.25) p_dialog.close() del p_dialog if available_providers > 0: message = u', '.join(provider_names) message = message + translation(32064) log.warning(message.encode('utf-8')) notify(message, ADDON_ICON) log.debug("all provider_results: %s" % repr(provider_results)) filtered_results = apply_filters(provider_results) log.debug("all filtered_results: %s" % repr(filtered_results)) log.info("Providers returned %d results in %s seconds" % (len(filtered_results), round(time.time() - request_time, 2))) return filtered_results
def search(payload, method="general"): """ Main search entrypoint Args: payload (dict): Search payload from Quasar. method (str): Type of search, can be ``general``, ``movie``, ``show``, ``season`` or ``anime`` Returns: list: All filtered results in the format Quasar expects """ log.debug("Searching with payload (%s): %s" % (method, repr(payload))) if method == 'general': payload = { 'title': payload } global request_time global provider_names global provider_results global available_providers provider_names = [] provider_results = [] available_providers = 0 request_time = time.time() providers = get_enabled_providers() if len(providers) == 0: notify(translation(32060), image=get_icon_path()) log.error("No providers enabled") return [] log.info("Burstin' with %s" % ", ".join([definitions[provider]['name'] for provider in providers])) if get_setting("use_cloudhole", bool): clearance, user_agent = get_cloudhole_clearance(get_cloudhole_key()) set_setting('clearance', clearance) set_setting('user_agent', user_agent) if get_setting('kodi_language', bool): kodi_language = xbmc.getLanguage(xbmc.ISO_639_1) if not kodi_language: log.warning("Kodi returned empty language code...") elif 'titles' not in payload or not payload['titles']: log.info("No translations available...") elif payload['titles'] and kodi_language not in payload['titles']: log.info("No '%s' translation available..." % kodi_language) p_dialog = xbmcgui.DialogProgressBG() p_dialog.create('Quasar [COLOR FFFF6B00]Burst[/COLOR]', translation(32061)) for provider in providers: available_providers += 1 provider_names.append(definitions[provider]['name']) task = Thread(target=run_provider, args=(provider, payload, method)) task.start() providers_time = time.time() total = float(available_providers) # Exit if all providers have returned results or timeout reached, check every 100ms while time.time() - providers_time < timeout and available_providers > 0: timer = time.time() - providers_time log.debug("Timer: %ds / %ds" % (timer, timeout)) if timer > timeout: break message = translation(32062) % available_providers if available_providers > 1 else translation(32063) p_dialog.update(int((total - available_providers) / total * 100), message=message) time.sleep(0.25) p_dialog.close() del p_dialog if available_providers > 0: message = u', '.join(provider_names) message = message + translation(32064) log.warning(message.encode('utf-8')) notify(message, ADDON_ICON) log.debug("all provider_results: %s" % repr(provider_results)) filtered_results = apply_filters(provider_results) log.debug("all filtered_results: %s" % repr(filtered_results)) log.info("Providers returned %d results in %s seconds" % (len(filtered_results), round(time.time() - request_time, 2))) return filtered_results
def update_tray_icon(tray,status): # status can only be (good, alert) tray.setIcon(QtGui.QIcon(get_icon_path(status+".ico")))
def process(provider, generator, filtering, has_special, verify_name=True, verify_size=True): """ Method for processing provider results using its generator and Filtering class instance Args: provider (str): Provider ID generator (function): Generator method, can be either ``extract_torrents`` or ``extract_from_api`` filtering (Filtering): Filtering class instance has_special (bool): Whether title contains special chars verify_name (bool): Whether to double-check the results' names match the query or not verify_size (bool): Whether to check the results' file sizes """ log.debug("execute_process for %s with %s" % (provider, repr(generator))) definition = definitions[provider] definition = get_alias(definition, get_setting("%s_alias" % provider)) client = Client() token = None logged_in = False token_auth = False if get_setting("use_cloudhole", bool): client.clearance = get_setting('clearance') client.user_agent = get_setting('user_agent') if get_setting('kodi_language', bool): kodi_language = xbmc.getLanguage(xbmc.ISO_639_1) if kodi_language: filtering.kodi_language = kodi_language language_exceptions = get_setting('language_exceptions') if language_exceptions.strip().lower(): filtering.language_exceptions = re.split(r',\s?', language_exceptions) log.debug("[%s] Queries: %s" % (provider, filtering.queries)) log.debug("[%s] Extras: %s" % (provider, filtering.extras)) for query, extra in zip(filtering.queries, filtering.extras): log.debug("[%s] Before keywords - Query: %s - Extra: %s" % (provider, repr(query), repr(extra))) if has_special: # Removing quotes, surrounding {title*} keywords, when title contains special chars query = re.sub("[\"']({title.*?})[\"']", '\\1', query) query = filtering.process_keywords(provider, query) extra = filtering.process_keywords(provider, extra) if 'charset' in definition and 'utf' not in definition[ 'charset'].lower(): try: query = urllib.quote(query.encode(definition['charset'])) extra = urllib.quote(extra.encode(definition['charset'])) except: pass log.debug("[%s] After keywords - Query: %s - Extra: %s" % (provider, repr(query), repr(extra))) if not query: return filtering.results url_search = filtering.url.replace('QUERY', query) if extra: url_search = url_search.replace('EXTRA', extra) else: url_search = url_search.replace('EXTRA', '') url_search = url_search.replace(' ', definition['separator']) # MagnetDL fix... url_search = url_search.replace('FIRSTLETTER', query[:1]) # Creating the payload for POST method payload = dict() for key, value in filtering.post_data.iteritems(): if 'QUERY' in value: payload[key] = filtering.post_data[key].replace('QUERY', query) else: payload[key] = filtering.post_data[key] # Creating the payload for GET method data = None if filtering.get_data: data = dict() for key, value in filtering.get_data.iteritems(): if 'QUERY' in value: data[key] = filtering.get_data[key].replace('QUERY', query) else: data[key] = filtering.get_data[key] log.debug("- %s query: %s" % (provider, repr(query))) log.debug("-- %s url_search before token: %s" % (provider, repr(url_search))) log.debug("--- %s using POST payload: %s" % (provider, repr(payload))) log.debug("----%s filtering with post_data: %s" % (provider, repr(filtering.post_data))) # Set search's "title" in filtering to double-check results' names if 'filter_title' in definition and definition['filter_title']: filtering.filter_title = True filtering.title = query if token: log.info('[%s] Reusing existing token' % provider) url_search = url_search.replace('TOKEN', token) elif 'token' in definition: token_url = definition['base_url'] + definition['token'] log.debug("Getting token for %s at %s" % (provider, repr(token_url))) client.open(token_url.encode('utf-8')) try: token_data = json.loads(client.content) except: log.error('%s: Failed to get token for %s' % (provider, repr(url_search))) return filtering.results log.debug("Token response for %s: %s" % (provider, repr(token_data))) if 'token' in token_data: token = token_data['token'] log.debug("Got token for %s: %s" % (provider, repr(token))) url_search = url_search.replace('TOKEN', token) else: log.warning('%s: Unable to get token for %s' % (provider, repr(url_search))) if logged_in: log.info("[%s] Reusing previous login" % provider) elif token_auth: log.info("[%s] Reusing previous token authorization" % provider) elif 'private' in definition and definition['private']: username = get_setting('%s_username' % provider) password = get_setting('%s_password' % provider) passkey = get_setting('%s_passkey' % provider) if not username and not password and not passkey: for addon_name in ('script.magnetic.%s' % provider, 'script.magnetic.%s-mc' % provider): for setting in ('username', 'password'): try: value = xbmcaddon.Addon(addon_name).getSetting( setting) set_setting('%s_%s' % (provider, setting), value) if setting == 'username': username = value if setting == 'password': password = value except: pass if passkey: logged_in = True client.passkey = passkey url_search = url_search.replace('PASSKEY', passkey) elif 'login_object' in definition and definition['login_object']: logged_in = False login_object = definition['login_object'].replace( 'USERNAME', '"%s"' % username).replace('PASSWORD', '"%s"' % password) # TODO generic flags in definitions for those... if provider == 'lostfilm': client.open(definition['root_url'] + '/v_search.php?c=110&s=1&e=1') if client.content == 'log in first': pass else: log.info('[%s] Login successful' % provider) logged_in = True if 'token_auth' in definition: # log.debug("[%s] logging in with: %s" % (provider, login_object)) if client.open(definition['root_url'] + definition['token_auth'], post_data=eval(login_object)): try: token_data = json.loads(client.content) except: log.error('%s: Failed to get token from %s' % (provider, definition['token_auth'])) return filtering.results log.debug("Token response for %s: %s" % (provider, repr(token_data))) if 'token' in token_data: client.token = token_data['token'] log.debug("Auth token for %s: %s" % (provider, repr(client.token))) else: log.error('%s: Unable to get auth token for %s' % (provider, repr(url_search))) return filtering.results log.info('[%s] Token auth successful' % provider) token_auth = True else: log.error("[%s] Token auth failed with response: %s" % (provider, repr(client.content))) return filtering.results elif not logged_in and client.login( definition['root_url'] + definition['login_path'], eval(login_object), definition['login_failed']): log.info('[%s] Login successful' % provider) logged_in = True elif not logged_in: log.error("[%s] Login failed: %s", provider, client.status) log.debug("[%s] Failed login content: %s", provider, repr(client.content)) notify(translation(32089), image=get_icon_path()) return filtering.results if logged_in: if provider == 'lostfilm': log.info('[%s] Search lostfilm serial ID...', provider) url_search = fix_lf(url_search) client.open(url_search.encode('utf-8'), post_data=payload, get_data=data) search_info = re.search(r'PlayEpisode\((.*?)\)">', client.content) if search_info: series_details = re.search( '\'(\d+)\',\'(\d+)\',\'(\d+)\'', search_info.group(1)) client.open(definition['root_url'] + '/v_search.php?c=%s&s=%s&e=%s' % (series_details.group(1), series_details.group(2), series_details.group(3))) redirect_url = re.search(ur'url=(.*?)">', client.content) if redirect_url is not None: url_search = redirect_url.group(1) else: log.info('[%s] Not found ID in %s' % (provider, url_search)) return filtering.results log.info("> %s search URL: %s" % (definition['name'].rjust(longest), url_search)) client.open(url_search.encode('utf-8'), post_data=payload, get_data=data) filtering.results.extend( generate_payload(provider, generator(provider, client), filtering, verify_name, verify_size)) return filtering.results
def _parse_item(self, item): result = { "name": None, "provider": "Unknown", "size": "Unknown", "uri": None, "seeds": "0", "peers": "0", "info_hash": "", "language": None, # todo would be nice to assign correct icons but that can be very time consuming due to the number # of indexers in Jackett "icon": get_icon_path(), "_size_bytes": -1 } for ref in item: tag = ref.tag attrib = ref.attrib if tag == "{" + self._torznab_ns + "}attr": val = attrib["value"] if isinstance(val, str): val = val.decode("utf-8") if "name" in attrib and "value" in attrib and attrib["name"] and val and \ attrib["name"] in self._torznab_elementum_mappings["torznab_attrs"]: json = self._torznab_elementum_mappings["torznab_attrs"][ attrib["name"]] result[json] = val continue if ref.tag in self._torznab_elementum_mappings[ "tags"] and ref.text is not None: json = self._torznab_elementum_mappings["tags"][ref.tag] val = ref.text.strip() if isinstance(val, str): val = val.decode("utf-8") result[json] = val # if we didn't get a magnet uri, attempt to resolve the magnet uri. # todo for some reason Elementum cannot resolve the link that gets proxied through Jackett. # So we will resolve it manually for Elementum for now. # In actuality, this should be fixed within Elementum if result["uri"] is None: link = item.find('link') jackett_uri = "" if link is not None: jackett_uri = link.text else: enclosure = item.find('enclosure') if enclosure is not None: jackett_uri = enclosure.attrib['url'] if jackett_uri != "": result["uri"] = get_magnet_from_jackett(jackett_uri) if result["name"] is None or result["uri"] is None: log.warning("Could not parse item; name = %s; uri = %s", result["name"], result["uri"]) log.debug("Failed item is: %s", ElementTree.tostring(item, encoding='utf8')) return None # result["name"] = result["name"].decode("utf-8") # might be needed for non-english items result["seeds"] = int(result["seeds"]) result["peers"] = int(result["peers"]) resolution = get_resolution(result["name"]) result["resolution"] = utils.resolutions.keys()[::-1].index(resolution) result["_resolution"] = resolution result["release_type"] = get_release_type(result["name"]) if result["size"] != "Unknown": result["_size_bytes"] = int(result["size"]) result["size"] = human_size(result["_size_bytes"]) return result
def process(provider, generator, filtering, has_special, verify_name=True, verify_size=True): """ Method for processing provider results using its generator and Filtering class instance Args: provider (str): Provider ID generator (function): Generator method, can be either ``extract_torrents`` or ``extract_from_api`` filtering (Filtering): Filtering class instance has_special (bool): Whether title contains special chars verify_name (bool): Whether to double-check the results' names match the query or not verify_size (bool): Whether to check the results' file sizes """ log.debug("execute_process for %s with %s" % (provider, repr(generator))) definition = definitions[provider] definition = get_alias(definition, get_setting("%s_alias" % provider)) client = Client(info=filtering.info) logged_in = False if get_setting('kodi_language', bool): kodi_language = xbmc.getLanguage(xbmc.ISO_639_1) if kodi_language: filtering.kodi_language = kodi_language language_exceptions = get_setting('language_exceptions') if language_exceptions.strip().lower(): filtering.language_exceptions = re.split(r',\s?', language_exceptions) log.debug("[%s] Queries: %s" % (provider, filtering.queries)) log.debug("[%s] Extras: %s" % (provider, filtering.extras)) for query, extra in zip(filtering.queries, filtering.extras): log.debug("[%s] Before keywords - Query: %s - Extra: %s" % (provider, repr(query), repr(extra))) if has_special: # Removing quotes, surrounding {title*} keywords, when title contains special chars query = re.sub("[\"']({title.*?})[\"']", '\\1', query) query = filtering.process_keywords(provider, query) extra = filtering.process_keywords(provider, extra) if 'charset' in definition and 'utf' not in definition[ 'charset'].lower(): try: query = urllib.quote(query.encode(definition['charset'])) extra = urllib.quote(extra.encode(definition['charset'])) except: pass log.debug("[%s] After keywords - Query: %s - Extra: %s" % (provider, repr(query), repr(extra))) if not query: return filtering.results query = urllib.quote(query.encode('utf-8')) url_search = filtering.url.replace('QUERY', query) if extra: url_search = url_search.replace('EXTRA', extra) else: url_search = url_search.replace('EXTRA', '') url_search = url_search.replace(' ', definition['separator']) if 'post_data' in definition and not filtering.post_data: filtering.post_data = eval(definition['post_data']) # Creating the payload for POST method payload = dict() for key, value in filtering.post_data.iteritems(): if 'QUERY' in value: payload[key] = filtering.post_data[key].replace('QUERY', query) else: payload[key] = filtering.post_data[key] # Creating the payload for GET method data = None if filtering.get_data: data = dict() for key, value in filtering.get_data.iteritems(): if 'QUERY' in value: data[key] = filtering.get_data[key].replace('QUERY', query) else: data[key] = filtering.get_data[key] log.debug("- %s query: %s" % (provider, repr(query))) log.debug("-- %s url_search before token: %s" % (provider, repr(url_search))) log.debug("--- %s using POST payload: %s" % (provider, repr(payload))) log.debug("----%s filtering with post_data: %s" % (provider, repr(filtering.post_data))) # Set search's "title" in filtering to double-check results' names if 'filter_title' in definition and definition['filter_title']: filtering.filter_title = True filtering.title = query if logged_in: log.info("[%s] Reusing previous login" % provider) elif 'private' in definition and definition['private']: username = get_setting('%s_username' % provider) password = get_setting('%s_password' % provider) if 'login_object' in definition and definition['login_object']: logged_in = False try: login_object = definition['login_object'].replace( 'USERNAME', '"%s"' % username).replace('PASSWORD', '"%s"' % password) except Exception, e: log.error("[{0}] Make login_object fail: {1}".format( provider, e)) return filtering.results # TODO generic flags in definitions for those... if provider == 'lostfilm': client.open(definition['root_url'] + '/v_search.php?c=110&s=1&e=1') if u'Вход. – LostFilm.TV.' in client.content: pass else: log.info('[%s] Login successful' % provider) logged_in = True if not logged_in and client.login( definition['root_url'] + definition['login_path'], eval(login_object), definition['login_failed']): log.info('[%s] Login successful' % provider) logged_in = True elif not logged_in: log.error("[%s] Login failed: %s", provider, client.status) log.debug("[%s] Failed login content: %s", provider, repr(client.content)) notify(translation(32089).format(provider), image=get_icon_path()) return filtering.results if logged_in: if provider == 'lostfilm': log.info('[%s] Search lostfilm serial ID...', provider) url_search = fix_lf(url_search) client.open(url_search.encode('utf-8'), post_data=payload, get_data=data) series_details = re.search( r'"mark-rate-pane" rel="(\d+),(\d+),(\d+)">', client.content) if series_details: client.open(definition['root_url'] + '/v_search.php?a=%s%s%s' % (series_details.group(1), series_details.group(2).zfill(3), series_details.group(3).zfill(3))) redirect_url = re.search(ur'url=(.*?)">', client.content) if redirect_url is not None: url_search = redirect_url.group(1) else: log.info('[%s] Not found ID in %s' % (provider, url_search)) return filtering.results log.info("> %s search URL: %s" % (definition['name'].rjust(longest), url_search)) client.open(url_search, post_data=payload, get_data=data) filtering.results.extend( generate_payload(provider, generator(provider, client), filtering, verify_name, verify_size))
def search(payload, method="general"): """ Main search entrypoint Args: payload (dict): Search payload from Elementum. method (str): Type of search, can be ``general``, ``movie``, ``show``, ``season`` or ``anime`` Returns: list: All filtered results in the format Elementum expects """ log.debug("Searching with payload (%s): %s" % (method, repr(payload))) if method == 'general': if 'query' in payload: payload['title'] = payload['query'] payload['titles'] = {'source': payload['query']} else: payload = { 'title': payload, 'titles': { 'source': payload }, } payload['titles'] = dict( (k.lower(), v) for k, v in payload['titles'].iteritems()) # If titles[] exists in payload and there are special chars in titles[source] # then we set a flag to possibly modify the search query payload['has_special'] = 'titles' in payload and \ bool(payload['titles']) and \ 'source' in payload['titles'] and \ any(c in payload['titles']['source'] for c in special_chars) if payload['has_special']: log.debug( "Query title contains special chars, so removing any quotes in the search query" ) if 'proxy_url' not in payload: payload['proxy_url'] = '' if 'internal_proxy_url' not in payload: payload['internal_proxy_url'] = '' if 'elementum_url' not in payload: payload['elementum_url'] = '' if 'silent' not in payload: payload['silent'] = False if 'skip_auth' not in payload: payload['skip_auth'] = False global request_time global provider_names global provider_results global available_providers provider_names = [] provider_results = [] available_providers = 0 request_time = time.time() providers = get_enabled_providers(method) if len(providers) == 0: if not payload['silent']: notify(translation(32060), image=get_icon_path()) log.error("No providers enabled") return [] log.info( "Burstin' with %s" % ", ".join([definitions[provider]['name'] for provider in providers])) if get_setting('kodi_language', bool): kodi_language = xbmc.getLanguage(xbmc.ISO_639_1) if not kodi_language: log.warning("Kodi returned empty language code...") elif 'titles' not in payload or not payload['titles']: log.info("No translations available...") elif payload['titles'] and kodi_language not in payload['titles']: log.info("No '%s' translation available..." % kodi_language) p_dialog = xbmcgui.DialogProgressBG() if not payload['silent']: p_dialog.create('Elementum [COLOR FFFF6B00]Burst[/COLOR]', translation(32061)) for provider in providers: available_providers += 1 provider_names.append(definitions[provider]['name']) task = Thread(target=run_provider, args=(provider, payload, method)) task.start() providers_time = time.time() total = float(available_providers) # Exit if all providers have returned results or timeout reached, check every 100ms while time.time() - providers_time < timeout and available_providers > 0: timer = time.time() - providers_time log.debug("Timer: %ds / %ds" % (timer, timeout)) if timer > timeout: break message = translation( 32062 ) % available_providers if available_providers > 1 else translation( 32063) if not payload['silent']: p_dialog.update(int((total - available_providers) / total * 100), message=message) time.sleep(0.25) if not payload['silent']: p_dialog.close() del p_dialog if available_providers > 0: message = u', '.join(provider_names) message = message + translation(32064) log.warning(message.encode('utf-8')) if not payload['silent']: notify(message, ADDON_ICON) log.debug("all provider_results: %s" % repr(provider_results)) filtered_results = apply_filters(provider_results) log.debug("all filtered_results: %s" % repr(filtered_results)) log.info("Providers returned %d results in %s seconds" % (len(filtered_results), round(time.time() - request_time, 2))) return filtered_results
def update_tray_icon(tray, status): # status can only be (good, alert) tray.setIcon(QtGui.QIcon(get_icon_path(status + ".ico")))