def run_maintenance(): """ Entry point for background maintenance cycle :return: None :rtype: None """ g.log("Performing Maintenance") # ADD COMMON HOUSE KEEPING ITEMS HERE # # Refresh API tokens try: refresh_apis() except Exception as e: g.log("Failed to update API keys: {}".format(e), 'error') try: account_premium_status_checks() except Exception as e: g.log("Failed to check account status: {}".format(e), 'error') ProviderInstallManager() update_provider_packages() update_themes() # Check Premiumize Fair Usage for cleanup if g.get_bool_setting("premiumize.enabled") and g.get_bool_setting( "premiumize.autodelete"): try: premiumize_transfer_cleanup() except Exception as e: g.log("Failed to cleanup PM transfers: {}".format(e), 'error') # clean_deprecated_settings() cache.Cache().check_cleanup()
def _apply_size_limits(self): if g.get_bool_setting("general.enablesizelimit"): if self.media_type == "episode": size_limit = g.get_int_setting( "general.sizelimit.episode") * 1024 size_minimum = int( g.get_float_setting("general.sizeminimum.episode") * 1024) else: size_limit = g.get_int_setting( "general.sizelimit.movie") * 1024 size_minimum = int( g.get_float_setting("general.sizeminimum.movie") * 1024) self._filter_all_by_methods([ lambda i: size_limit >= int(i.get("size", 0)) >= size_minimum ]) if g.get_bool_setting("general.sizeperminlimit"): if self.media_type == "episode": sizepermin_limit = g.get_int_setting( "general.sizeperminlimit.episode") else: sizepermin_limit = g.get_int_setting( "general.sizeperminlimit.movie") self._filter_all_by_methods([ lambda i: (int(i.get('size', 0)) / self.duration) < sizepermin_limit ])
def __init__(self, ): super(TraktSyncDatabase, self).__init__(g.TRAKT_SYNC_DB_PATH, schema, migrate_db_lock) self.metadataHandler = MetadataHandler() self.trakt_api = TraktAPI() self.activities = {} self.item_list = [] self.base_date = "1970-01-01T00:00:00" self.task_queue = ThreadPool() self.mill_task_queue = ThreadPool() self.parent_task_queue = ThreadPool() self.refresh_activities() # If you make changes to the required meta in any indexer that is cached in this database # You will need to update the below version number to match the new addon version # This will ensure that the metadata required for operations is available self.last_meta_update = "2.0.0" if self.activities is None: self.clear_all_meta(False) self.set_base_activities() if self.activities is not None: self._check_database_version() self.notification_prefix = "{}: Trakt".format(g.ADDON_NAME) self.hide_unaired = g.get_bool_setting("general.hideUnAired") self.hide_specials = g.get_bool_setting("general.hideSpecials") self.hide_watched = g.get_bool_setting("general.hideWatched") self.date_delay = g.get_bool_setting("general.datedelay") self.page_limit = g.get_int_setting("item.limit")
def _hosters_enabled(): if (g.get_bool_setting('premiumize.hosters') and g.premiumize_enabled()) \ or (g.get_bool_setting('rd.hosters') and g.real_debrid_enabled()) \ or (g.get_bool_setting('alldebrid.hosters') and g.all_debrid_enabled()): return True else: return False
def display_dialog(self): """ Handles the initiating of dialogs and deciding which dialog to display if required :return: None :rtype: None """ try: self.playing_file = self.getPlayingFile() except RuntimeError: g.log("Kodi did not return a playing file, killing playback dialogs", "error") return if g.PLAYLIST.size() > 0 and g.PLAYLIST.getposition() != ( g.PLAYLIST.size() - 1 ): if g.get_bool_setting("smartplay.stillwatching") and self._still_watching_calc(): target = self._show_still_watching elif g.get_bool_setting("smartplay.playingnextdialog"): target = self._show_playing_next else: return if self.playing_file != self.getPlayingFile(): return if not self.isPlayingVideo(): return if not self._is_video_window_open(): return target()
def get_debrid_priorities(): """ Gets priorities of each debrid provider :return: Returns a list of dictionaries providing priorities of each debrid provider """ p = [] if g.get_bool_setting('premiumize.enabled'): p.append({ 'slug': 'premiumize', 'priority': g.get_int_setting('premiumize.priority') }) if g.get_bool_setting('realdebrid.enabled'): p.append({ 'slug': 'real_debrid', 'priority': g.get_int_setting('rd.priority') }) if g.get_bool_setting('alldebrid.enabled'): p.append({ 'slug': 'all_debrid', 'priority': g.get_int_setting('alldebrid.priority') }) p = sorted(p, key=lambda i: i['priority']) return p
def sort_sources(self, torrents=None, hosters=None, cloud=None): """Takes in multiple optional lists of sources and sorts them according to Seren's sort settings :param torrents: list of torrent sources :type torrents: list :param hosters: list of hoster sources :type hosters: list :param cloud: list of cloud sources :type cloud: list :return: sorted list of sources :rtype: list """ torrents = torrents if torrents else [] hosters = hosters if hosters else [] cloud = cloud if cloud else [] self.torrent_list = deepcopy(torrents) self.hoster_list = deepcopy(hosters) self.cloud_files = deepcopy(cloud) self._do_filters() if (len(self.torrent_list + self.hoster_list + self.cloud_files) == 0 and len(torrents + hosters + cloud) > 0): response = None if not g.get_bool_setting('general.tempSilent'): response = xbmcgui.Dialog().yesno(g.ADDON_NAME, g.get_language_string(30510)) if response or g.get_bool_setting('general.tempSilent'): self.torrent_list = deepcopy(torrents) self.hoster_list = deepcopy(hosters) self.cloud_files = deepcopy(cloud) return self._do_sorts()
def _size_sort(self): if g.get_bool_setting("general.sizesort"): self._apply_sort_to_all_types( key=lambda k: int(k["size"]), reverse=not g.get_bool_setting("general.reversesizesort"), ) else: random.shuffle(self.torrent_list)
def __init__(self): self.date_delay = g.get_bool_setting("general.datedelay") self.title_appends_mixed = g.get_setting("general.appendtitles") self.title_appends_general = g.get_setting( "general.appendepisodegeneral") self.flatten_episodes = g.get_bool_setting("general.flatten.episodes") self.page_limit = g.get_int_setting("item.limit") self.hide_unaired = g.get_bool_setting("general.hideUnAired") self.list_title_appends = g.get_setting("general.appendListTitles")
def home(self): g.add_directory_item(g.get_language_string(30242), action='cacheAssistStatus') if g.get_bool_setting('premiumize.enabled'): g.add_directory_item(g.get_language_string(30243), action='premiumize_transfers') if g.get_bool_setting('realdebrid.enabled'): g.add_directory_item(g.get_language_string(30244), action='realdebridTransfers') g.close_directory(self.view_type)
def _prem_terminate(self): # pylint: disable=method-hidden if self.canceled: monkey_requests.PRE_TERM_BLOCK = True return True if g.get_bool_setting('preem.cloudfiles') and len( self.sources_information["cloudFiles"]) > 0: monkey_requests.PRE_TERM_BLOCK = True return True if g.get_bool_setting('preem.adaptiveSources') and len( self.sources_information["adaptiveSources"]) > 0: monkey_requests.PRE_TERM_BLOCK = True return True if not g.get_bool_setting('preem.enabled'): return False prem_min = self._get_pre_term_min() pre_term_log_string = 'Pre-emptively Terminated' approved_resolutions = source_utils.get_accepted_resolution_list() prem_resolutions = approved_resolutions[prem_min:] limit = g.get_int_setting('preem.limit') type = g.get_int_setting('preem.type') try: if type == 0 and len( self._get_sources_by_resolution( prem_resolutions, "torrentCacheSources")) >= limit: g.log(pre_term_log_string, 'info') monkey_requests.PRE_TERM_BLOCK = True return True if type == 1 and len( self._get_sources_by_resolution(prem_resolutions, "hosterSources")) >= limit: g.log(pre_term_log_string, 'info') monkey_requests.PRE_TERM_BLOCK = True return True if type == 2: # Terminating on both hosters and torrents sources = self._get_sources_by_resolution( prem_resolutions, "hosterSources") sources.append( self._get_sources_by_resolution(prem_resolutions, "torrentCacheSources")) if len(sources) >= limit: g.log(pre_term_log_string, 'info') monkey_requests.PRE_TERM_BLOCK = True return True except (ValueError, KeyError, IndexError): pass return False
def shows_by_actor(self, actor): if not actor: k = xbmc.Keyboard("", g.get_language_string(30013)) k.doModal() query = k.getText() if k.isConfirmed() else None del k if not query: g.cancel_directory() return else: query = tools.unquote(actor) if g.get_bool_setting("searchHistory"): SearchHistory().add_search_history("showActor", query) query = g.deaccent_string(query) query = query.replace(" ", "-") query = tools.quote_plus(query) self.list_builder.show_list_builder( self.trakt.get_json_paged("people/{}/shows".format(query), extended="full", page=g.PAGE), hide_watched=False, hide_unaired=False, )
def my_shows_collection(self): paginate = not g.get_bool_setting("general.paginatecollection") sort = "title" if paginate else False trakt_list = self.trakt_database.get_collected_shows(g.PAGE) self.list_builder.show_list_builder(trakt_list, no_paging=paginate, sort=sort)
def _user_cloud_inspection(self): self.sources_information["remainingProviders"].append("Cloud Inspection") try: thread_pool = ThreadPool() if self.media_type == "episode": simple_info = self._build_simple_show_info(self.item_information) else: simple_info = None cloud_scrapers = [ {"setting": "premiumize.cloudInspection", "provider": PremiumizeCloudScaper, "enabled": g.premiumize_enabled()}, {"setting": "rd.cloudInspection", "provider": RealDebridCloudScraper, "enabled": g.real_debrid_enabled()}, {"setting": "alldebrid.cloudInspection", "provider": AllDebridCloudScraper, "enabled": g.all_debrid_enabled()}, ] for cloud_scraper in cloud_scrapers: if cloud_scraper["enabled"] and g.get_bool_setting(cloud_scraper["setting"]): thread_pool.put(cloud_scraper["provider"](self._prem_terminate).get_sources, self.item_information, simple_info) sources = thread_pool.wait_completion() self.sources_information["cloudFiles"] = sources if sources else [] finally: self.sources_information["remainingProviders"].remove("Cloud Inspection")
def post(self, url, post_data=None, **params): if not g.get_bool_setting(AD_ENABLED_KEY) or not self.apikey: return params.update({"agent": self.agent_identifier, "apikey": self.apikey}) return self.session.post( tools.urljoin(self.base_url, url), data=post_data, params=params )
def _resolve_hoster_or_cloud(self, source, item_information): stream_link = None if not source.get("url", False): return if source["type"] == "cloud" and source["debrid_provider"] == "premiumize": selected_file = Premiumize().item_details(source["url"]) if g.get_bool_setting("premiumize.transcoded"): stream_link = selected_file["stream_link"] else: stream_link = selected_file["link"] return stream_link if "provider_imports" in source: source = self._handle_provider_imports_resolving(source) if "debrid_provider" in source: stream_link = self._handle_debrid_hoster_resolving(source, item_information) elif source["url"].startswith("http"): stream_link = self._test_direct_url(source) elif xbmcvfs.exists(source["url"]): stream_link = source["url"] if stream_link is None: return if stream_link.endswith(".rar"): return return stream_link
def __init__(self, item_information): """ Handles sorting of sources according to users preference """ self.item_information = item_information self.mediatype = self.item_information['info']['mediatype'] # Filter settings self.resolution_set = get_accepted_resolution_set() self.disable_dv = False self.disable_hdr = False self.filter_set = self._get_filters() # Size filter settings self.enable_size_limit = g.get_bool_setting("general.enablesizelimit") setting_mediatype = g.MEDIA_EPISODE if self.mediatype == g.MEDIA_EPISODE else g.MEDIA_MOVIE self.size_limit = g.get_int_setting("general.sizelimit.{}".format(setting_mediatype)) * 1024 self.size_minimum = int(g.get_float_setting("general.sizeminimum.{}".format(setting_mediatype)) * 1024) # Sort Settings self.quality_priorities = { "4K": 3, "1080p": 2, "720p": 1, "SD": 0 } # Sort Methods self._get_sort_methods()
def display_intro_dialog(self): """ Handles the initiating of skip intro dialog :return: None :rtype: None """ try: self.playing_file = self.getPlayingFile() except RuntimeError: g.log( "Kodi did not return a playing file, killing playback dialogs", "error") return if g.get_bool_setting("skip.intro.dialog"): target = self._show_skip_intro else: return if self.playing_file != self.getPlayingFile(): return if not self.isPlayingVideo(): return if not self._is_video_window_open(): return target()
def _build_cache_assist(self): if len(self.sources_information["allTorrents"]) == 0: return valid_packages = ['show', 'season', 'single'] if self.media_type == 'episode' and self.item_information['is_airing']: valid_packages.remove('show') if int(self.item_information['info']['season']) >= int( self.item_information['season_count']): valid_packages.remove('season') sources = [i for i in self.sources_information['allTorrents'].values() if i['package'] in valid_packages] if g.get_bool_setting("general.autocache") and g.get_int_setting('general.cacheAssistMode') == 0: sources = self._get_best_torrent_to_cache(sources) if sources: action_args = tools.quote(json.dumps(sources)) xbmc.executebuiltin( 'RunPlugin({}?action=cacheAssist&action_args={})'.format(g.BASE_URL, action_args)) elif not self.silent: confirmation = xbmcgui.Dialog().yesno('{} - {}'.format(g.ADDON_NAME, g.get_language_string(30325)), g.get_language_string(30056)) if confirmation: window = ManualCacheWindow(*SkinManager().confirm_skin_path('manual_caching.xml'), item_information=self.item_information, sources=sources) window.doModal() del window
def _common_menu_builder(self, trakt_list, content_type, action="getSources", **params): if len(trakt_list) == 0: g.log("We received no titles to build a list", "warning") g.cancel_directory() return list_items = [] smart_play = params.pop("smart_play", False) no_paging = params.pop("no_paging", False) sort = params.pop("sort", False) prepend_date = params.pop("prepend_date", False) mixed_list = params.pop("mixed_list", False) next_args = params.pop("next_args", None) params.pop("hide_unaired", None) params.pop("hide_watched", None) try: params["bulk_add"] = True list_items = [ g.add_directory_item(item.get("name"), action=action, menu_item=item, action_args=item.get("args"), **params) for item in self._post_process_list(trakt_list, prepend_date, mixed_list) if item is not None ] if smart_play: return list_items else: xbmcplugin.addDirectoryItems(g.PLUGIN_HANDLE, list_items, len(list_items)) except Exception as e: g.log_stacktrace() if not smart_play: g.cancel_directory() raise e finally: if not smart_play: if (not (g.FROM_WIDGET and g.get_bool_setting("general.widget.hide_next")) and not no_paging and len(list_items) >= self.page_limit): g.REQUEST_PARAMS["page"] = g.PAGE + 1 if next_args: g.REQUEST_PARAMS["action_args"] = next_args elif g.REQUEST_PARAMS.get("action_args") is not None: g.REQUEST_PARAMS["action_args"] = g.REQUEST_PARAMS.get( "action_args") params = g.REQUEST_PARAMS params.update({"special_sort": "bottom"}) g.add_directory_item(g.get_language_string(30016), **params) g.close_directory(content_type, sort=sort)
def get_unfinished_collected_shows(self, page=1): """ Returns a list of shows the user has collected but not completed watching :param page: Page to request :type page: int :return: List of show objects :rtype: list """ paginate = g.get_bool_setting("general.paginatecollection") sort = g.get_int_setting("general.sortcollection") sort_direction = g.get_int_setting("general.sortcollection.direction") query = """select m.id as trakt_id, value as trakt_object from shows_meta as m inner join( select ep.trakt_show_id, max(ep.collected_at) as collected_at from episodes as ep where ep.season != 0 and ep.watched = 0 and ep.collected = 1 GROUP BY ep.trakt_show_id HAVING count(*) > 0) as u on u.trakt_show_id = m.id and m.type='trakt'""" if sort_direction == 0: sort_direction = "asc" elif sort_direction == 1: sort_direction = "desc" if sort == 0: query += " ORDER BY collected_at " + sort_direction if paginate and not sort == 1: query += " LIMIT {} OFFSET {}".format(self.page_limit, self.page_limit * (page - 1)) return self.execute_sql(query).fetchall()
def get_mixed_episode_list(self, trakt_items, **params): """ Returns a list of mixed episodes from different or same show :param trakt_items: List of show & episodes object pairs :type trakt_items: list :return: List of episode objects with full meta :rtype: list """ g.log("Fetching mixed episode list from sync database", "debug") self._try_update_mixed_episodes(trakt_items) in_predicate = ",".join([ str(i["trakt_id"]) for i in trakt_items if i["trakt_id"] is not None ]) if g.get_bool_setting("general.showRemainingUnwatched"): query = """SELECT e.trakt_id, e.info, e.cast, e.art, e.args, e.watched as play_count, b.resume_time as resume_time, b.percent_played as percent_played, se.watched_episodes, se.unwatched_episodes, se.episode_count FROM episodes as e INNER JOIN seasons se on e.trakt_season_id = se.trakt_id LEFT JOIN bookmarks as b on e.Trakt_id = b.Trakt_id WHERE e.trakt_id in ({})""".format( in_predicate) else: query = """SELECT e.trakt_id, e.info, e.cast, e.art, e.args, e.watched as play_count, b.resume_time as resume_time, b.percent_played as percent_played FROM episodes as e LEFT JOIN bookmarks as b on e.Trakt_id = b.Trakt_id WHERE e.trakt_id in ({})""".format(in_predicate) if params.pop("hide_unaired", self.hide_unaired): query += " AND Datetime(e.air_date) < Datetime('now') " if params.pop("hide_specials", self.hide_specials): query += " AND e.season != 0" if params.pop("hide_watched", self.hide_watched): query += " AND e.watched = 0" return MetadataHandler.sort_list_items( self.execute_sql(query).fetchall(), trakt_items)
def check_for_addon_update(): """ Perform checks for addon updates and notify user of any available updates :return: None :rtype: None """ if not g.get_bool_setting("general.checkAddonUpdates"): return if "-" in g.VERSION: g.set_setting("addon.updateCheckTimeStamp", g.UNICODE(time.time())) return update_timestamp = g.get_float_setting("addon.updateCheckTimeStamp") if time.time() > (update_timestamp + (24 * (60 * 60))): repo_xml = requests.get( "https://github.com/Newf276/Newf276/raw/master/packages/addons.xml" ) if not repo_xml.status_code == 200: g.log( "Could not connect to repo XML, status: {}".format( repo_xml.status_code ), "error", ) return try: xml = tools.ElementTree.fromstring(repo_xml.text) for dir_tag in xml.iterfind("./addon[@id='repository.Newf276']/extension/dir"): minversion = dir_tag.get('minversion') maxversion = dir_tag.get('maxversion') if ( ( minversion is None and maxversion is None ) or ( minversion and maxversion and tools.compare_version_numbers(minversion, g.KODI_FULL_VERSION, include_same=True) and tools.compare_version_numbers(g.KODI_FULL_VERSION, maxversion, include_same=True) ) or ( maxversion is None and minversion and tools.compare_version_numbers(minversion, g.KODI_FULL_VERSION, include_same=True) ) or ( minversion is None and maxversion and tools.compare_version_numbers(g.KODI_FULL_VERSION, maxversion, include_same=True) ) ): repo_version = _get_latest_repo_version(dir_tag.find('info').text) if tools.compare_version_numbers(g.CLEAN_VERSION, repo_version): xbmcgui.Dialog().ok( g.ADDON_NAME, g.get_language_string(30199).format(repo_version) ) except tools.ElementTree.ParseError as pe: g.log("Could not parse repo XML", "error") finally: g.set_setting("addon.updateCheckTimeStamp", str(time.time()))
def get_collected_shows(self, page=1, force_all=False): """ Returns all shows marked as collected from the database :param page: Page to pull :type page: int :param force_all: Enforce pulling of all items :type force_all: bool :return: List of show records :rtype: list """ paginate = g.get_bool_setting("general.paginatecollection") sort = g.get_int_setting("general.sortcollection") sort_direction = g.get_int_setting("general.sortcollection.direction") query = """select e.trakt_show_id as trakt_id, m.value as trakt_object from episodes as e left join shows as sh on sh.trakt_id = e.trakt_show_id left join shows_meta as m on m.id = e.trakt_show_id and m.type='trakt' where e.collected = 1 group by e.trakt_show_id""" if sort_direction == 0: sort_direction = "asc" elif sort_direction == 1: sort_direction = "desc" if sort == 0: query += " ORDER BY max(e.collected_at) " + sort_direction if paginate and not (force_all or sort == 1): query += " LIMIT {} OFFSET {}".format(self.page_limit, self.page_limit * (page - 1)) return self.execute_sql(query).fetchall()
def update_themes(): """ Performn checks for any theme updates :return: None :rtype: None """ if g.get_bool_setting("skin.updateAutomatic"): SkinManager().check_for_updates(silent=True)
def is_service_enabled(): """ Check to confirm api is enabled in Seren :return: :rtype: """ return (g.get_bool_setting("premiumize.enabled") and g.get_setting(PM_TOKEN_KEY) is not None)
def my_movie_collection(self): paginate = not g.get_bool_setting("general.paginatecollection") sort = "title" if paginate else False self.list_builder.movie_menu_builder( self.movies_database.get_collected_movies(g.PAGE), no_paging=paginate, sort=sort, )
def __init__(self): super(SerenPlayer, self).__init__() self._trakt_api = trakt.TraktAPI() self.trakt_id = None self.mediatype = None self.offset = None self.playing_file = None self.scrobbling_enabled = g.get_bool_setting("trakt.scrobbling") self.item_information = None self.smart_playlists = g.get_bool_setting("smartplay.playlistcreate") self.default_action = g.get_int_setting("smartplay.defaultaction") self.smart_module = None self.current_time = 0 self.total_time = 0 self.watched_percentage = 0 self.ignoreSecondsAtStart = g.get_int_setting( "trakt.ignoreSecondsAtStart") self.min_time_before_scrape = max(self.total_time * 0.2, 600) self.playCountMinimumPercent = g.get_int_setting( "trakt.playCountMinimumPercent") self.intro_dialog_enabled = g.get_bool_setting("skip.intro.dialog") self.intro_dialog_delay = g.get_int_setting("skip.intro.dialog.delay") self.playing_next_dialog_enabled = g.get_bool_setting( "smartplay.playingnextdialog") self.still_watching_dialog_enabled = g.get_bool_setting( "smartplay.stillwatching") self.intro_dialog_open_time = g.get_int_setting("skip.intro.open.time") self.pre_scrape_enabled = g.get_bool_setting("smartPlay.preScrape") self.playing_next_time = g.get_int_setting("playingnext.time") self.skip_intro = g.get_bool_setting("skip.intro") self.skip_intro_from = g.get_int_setting("skip.intro.from") self.skip_intro_to = g.get_int_setting("skip.intro.to") self.force_skip = g.get_bool_setting("skip.intro.force") self.bookmark_sync = bookmark.TraktSyncDatabase() self.trakt_enabled = True if g.get_setting("trakt.auth", "") else False self._running_path = None # Flags self.default_pause = False self.default_exit = False self.resumed = False self.playback_started = False self.playback_error = False self.playback_ended = False self.playback_stopped = False self.scrobbled = False self.scrobble_started = False self._force_marked_watched = False self.intro_dialog_triggered = False self.playing_next_dialog_triggered = False self.still_watching_dialog_triggered = False self.pre_scrape_initiated = False self.playback_timestamp = 0 self.intro_skipped = False
def get(self, url, **params): if not g.get_bool_setting(AD_ENABLED_KEY): return params.update({ "agent": self.agent_identifier, "apikey": self.apikey if not params.pop("reauth", None) else None} ) return self.session.get(tools.urljoin(self.base_url, url), params=params)
def _do_post_processing(self, item_information, torrent): if g.get_bool_setting("premiumize.addToCloud"): transfer = self.debrid_module.create_transfer(torrent["magnet"]) if transfer.get("id"): self.transfer_class.add_premiumize_transfer(transfer["id"]) else: xbmcgui.Dialog().notification(g.ADDON_NAME, g.get_language_string(30508)) g.log(transfer, "error")