Пример #1
0
 def get_url(self, url):
     """
     Perform a GET request to the Premiumize API
     :param url: URI to perform request again
     :type url: str
     :return: JSON response
     :rtype: dict
     """
     if self.headers["Authorization"] == "Bearer ":
         g.log("User is not authorised to make PM requests", "warning")
         return None
     url = "https://www.premiumize.me/api{}".format(url)
     req = self.session.get(url, timeout=10, headers=self.headers)
     req = self._error_handler(req)
     return req.json()
Пример #2
0
 def get_json(self, url, **params):
     response = self.get(url, **params)
     if response is None:
         return None
     try:
         return self._handle_response(params.get("language"),
                                      self._flatten(response.json()))
     except (ValueError, AttributeError):
         traceback.print_exc()
         g.log(
             "Failed to receive JSON from Tvdb response - response: {}".
             format(response),
             "error",
         )
         return None
Пример #3
0
 def getPlayingFile(self):
     """
     Fetches the path to the playing file else returns None
     :return: Path to file
     :rtype: str/None
     """
     g.log("123")
     if self.isPlaying():
         try:
             return xbmc.Player().getPlayingFile()
         except RuntimeError:
             # seems that we have a racing condition between isPlaying() and getPlayingFile()
             return None
     else:
         return None
Пример #4
0
    def _get_adaptive_sources(self, info, provider):
        provider_name = provider[1].upper()
        try:
            self.sources_information["remainingProviders"].append(provider_name)
            provider_module = importlib.import_module('{}.{}'.format(provider[0], provider[1]))
            if not hasattr(provider_module, "sources"):
                g.log('Invalid provider, Source Class missing')
                return
            provider_source = provider_module.sources()

            if not hasattr(provider_source, self.media_type):
                g.log('Skipping provider: {} - Does not support {} types'.format(provider_name, self.media_type),
                      'warning')
                return

            self.running_providers.append(provider_source)

            if self.media_type == 'episode':
                simple_info = self._build_simple_show_info(info)
                results = provider_source.episode(simple_info, info)
            else:
                try:
                    results = provider_source.movie(info['info']['title'],
                                                    g.UNICODE(info['info']['year']),
                                                    info['info'].get('imdb_id'))
                except TypeError:
                    results = provider_source.movie(info['info']['title'],
                                                    g.UNICODE(info['info']['year']))

            if results is None:
                self.sources_information["remainingProviders"].remove(provider_name)
                return

            if self.canceled:
                return

            if len(results) > 0:
                # Begin filling in optional dictionary returns
                for result in results:
                    self._process_adaptive_source(result, provider_name, provider)

                self.sources_information['adaptiveSources'] += results

            self.running_providers.remove(provider_source)

            return
        finally:
            self.sources_information["remainingProviders"].remove(provider_name)
Пример #5
0
    def get_url(self, url, fail_check=False):
        original_url = url
        url = self.base_url + url
        if not self.token:
            g.log("No Real Debrid Token Found")
            return None

        response = self.session.get(url, timeout=5)

        if not self._is_response_ok(response) and not fail_check:
            self.try_refresh_token()
            response = self.get_url(original_url, fail_check=True)
        try:
            return response.json()
        except (ValueError, AttributeError):
            return response
Пример #6
0
 def onNotification(self, sender, method, data):
     if method == "System.OnWake":
         g.log("System.OnWake notification received" "info")
         xbmc.executebuiltin(
             'RunPlugin("plugin://plugin.video.seren/?action=runMaintenance")'
         )
         xbmc.executebuiltin(
             'RunPlugin("plugin://plugin.video.seren/?action=torrentCacheCleanup")'
         )
         if not g.wait_for_abort(
                 15
         ):  # Sleep to make sure tokens refreshed during maintenance
             xbmc.executebuiltin(
                 'RunPlugin("plugin://plugin.video.seren/?action=syncTraktActivities")'
             )
     return
Пример #7
0
    def rebuild_database(self):
        g.log("Rebuilding database: {}".format(self._db_file))
        with SQLiteConnection(self._db_file) as sqlite:
            with sqlite.transaction():
                database_schema = sqlite._connection.execute(
                    "SELECT m.name from sqlite_master m where type = 'table'"
                ).fetchall()
                sqlite._connection.execute("PRAGMA foreign_keys = OFF")
                for q in ["DROP TABLE IF EXISTS [{}]".format(t["name"]) for t in database_schema]:
                    sqlite._connection.execute(q)
                sqlite._connection.execute("PRAGMA foreign_keys = ON")

            sqlite._connection.execute("VACUUM")

            with sqlite.transaction():
                self._create_tables(sqlite._connection)
Пример #8
0
 def _handle_response(self, response, art_type, season=None):
     try:
         if response:
             result = {}
             result.update(
                 {'art': self._handle_art(response, art_type, season)})
             result.update({
                 'info':
                 self._normalize_info(self.meta_objects[art_type], response)
             })
             return result
     except (ValueError, AttributeError):
         g.log(
             'Failed to receive JSON from FanartTv response - response: {}'.
             format(response), 'error')
         return None
Пример #9
0
 def mark_show_collected(self, show_id, collected):
     """
     Sets collected status for all items of a given show
     :param show_id: ID of show to update
     :type show_id: int
     :param collected: Status of collection (1=True, 0=False)
     :type collected: int
     :return: None
     :rtype: None
     """
     g.log("Marking show {} as collected in sync database".format(show_id), "debug")
     self._mill_if_needed([{"trakt_id": show_id}])
     self.execute_sql(
         "UPDATE episodes SET collected=?, collected_at=? WHERE trakt_show_id=?",
         (collected, self._get_datetime_now(), show_id),
     )
Пример #10
0
 def _try_detect_type(self, item):
     item_types = [
         ("list", lambda x: "item_count" in x and "sort_by" in x),
         ("mixedepisode", lambda x: "show" in x and "episode" in x),
         ("mixedseason", lambda x: "show" in x and "season" in x),
         (
             "movie",
             lambda x: "title" in x and "year" in x and "network" not in x,
         ),
         ("show",
          lambda x: "title" in x and "year" in x and "network" in x),
         (
             "episode",
             lambda x: "number" in x and
             ("season" in x or ("last_watched_at" in x and "plays" in x) or
              ("collected_at" in x)),
         ), ("season", lambda x: "number" in x),
         ("playback", lambda x: "paused_at" in x),
         ("playbackhistory", lambda x: "action" in x),
         ("user_rating", lambda x: "rated_at" in x),
         ("calendar", lambda x: "first_aired" in x),
         ("cast", lambda x: "cast" in x),
         ("genre", lambda x: "name" in x and "slug" in x),
         ("network", lambda x: "name" in x),
         ("alias", lambda x: "title" in x and "country" in x),
         ("translation", lambda x: "title" in x and "language" in x),
         ("people", lambda x: "character" in x and "characters" in x),
         ("anticipated", lambda x: "list_count" in x),
         ("box_office", lambda x: "revenue" in x),
         ("collected", lambda x: "watcher_count" in x and "collected_count"
          in x and "play_count" in x),
         ("lists", lambda x: "like_count" in x and "comment_count" in x),
         ("updated",
          lambda x: "updated_at" in x and ("movie" in x or "show" in x)),
         ("trending", lambda x: "watchers" in x),
         ("sync_activities", lambda x: "all" in x),
         ("sync_watched", lambda x: "last_watched_at" in x),
         ("sync_collected", lambda x: "last_collected_at" in x)
     ]
     for item_type in item_types:
         if item_type[1](item):
             item.update({"type": item_type[0]})
             break
     if "type" not in item:
         g.log("Error detecting trakt item type for: {}".format(item),
               "error")
     return item
def account_premium_status_checks():
    """
    Updates premium status settings to reflect current state and advises users of expiries if enabled
    :return: None
    :rtype: None
    """
    def set_settings_status(debrid_provider, status):
        """
        Ease of use method to set premium status setting
        :param debrid_provider: setting prefix for debrid provider
        :type debrid_provider: str
        :param is_premium: Status of premium status
        :type is_premium: bool
        :return: None
        :rtype: None
        """
        g.set_setting("{}.premiumstatus".format(debrid_provider),
                      status.title())

    def display_expiry_notification(display_debrid_name):
        """
        Ease of use method to notify user of expiry of debrid premium status
        :param display_debrid_name: Debrid providers full display name
        :type display_debrid_name: str
        :return: None
        :rtype: None
        """
        if g.get_bool_setting("general.accountNotifications"):
            g.notification(
                "{}".format(g.ADDON_NAME),
                g.get_language_string(30036).format(display_debrid_name),
            )

    valid_debrid_providers = [
        ("Real Debrid", real_debrid.RealDebrid, "rd"),
        ("Premiumize", premiumize.Premiumize, "premiumize"),
        ("All Debrid", all_debrid.AllDebrid, "alldebrid"),
    ]

    for service in valid_debrid_providers:
        service_module = service[1]()
        if service_module.is_service_enabled():
            status = service_module.get_account_status()
            if status == "expired":
                display_expiry_notification(service[0])
            g.log("{}: {}".format(service[0], status))
            set_settings_status(service[2], status)
Пример #12
0
 def execute_sql(self, query, data=None):
     retries = 0
     self._register_pickler_adapters()
     monitor = xbmc.Monitor()
     with self._get_connection() as connection:
         while not retries == 50 and not monitor.abortRequested(
         ) and not self._exit:
             try:
                 if isinstance(query, list) or isinstance(
                         query, types.GeneratorType):
                     if g.PLATFORM == 'xbox':
                         results = []
                         for i in query:
                             results.append(
                                 self._execute_query(
                                     data, connection.cursor(), i))
                             connection.commit()
                         return results
                     else:
                         return [
                             self._execute_query(data, connection.cursor(),
                                                 i) for i in query
                         ]
                 return self._execute_query(data, connection.cursor(),
                                            query)
             except sqlite3.OperationalError as error:
                 if "database is locked" in str(error):
                     g.log(
                         "database is locked waiting: {}".format(
                             self._db_file),
                         "warning",
                     )
                     monitor.waitForAbort(0.1)
                 else:
                     self._log_error(query, data)
                     raise
             except (RuntimeError, InterfaceError):
                 if retries >= 2:
                     self._log_error(query, data)
                     raise
                 monitor.waitForAbort(0.1)
             except:
                 self._log_error(query, data)
                 raise
             retries += 1
         connection.commit()
         return None
Пример #13
0
    def resolve_single_source(self,
                              source,
                              item_information,
                              pack_select=False,
                              silent=False):
        """
        Resolves source to a streamable object
        :param source: Item to attempt to resolve
        :param item_information: Metadata on item intended to be played
        :param pack_select: Set to True to force manual file selection
        :return: streamable URL or dictionary of adaptive source information
        """

        stream_link = None

        try:
            if source["type"] == "Adaptive":
                stream_link = source

            elif source["type"] == "torrent":
                stream_link = self._resolve_debrid_source(
                    self.resolvers[source["debrid_provider"]],
                    source,
                    item_information,
                    pack_select,
                )

                if not stream_link and self.torrent_resolve_failure_style == 1 and not pack_select and not silent:
                    if xbmcgui.Dialog().yesno(g.ADDON_NAME,
                                              g.get_language_string(30519)):
                        stream_link = self._resolve_debrid_source(
                            self.resolvers[source["debrid_provider"]],
                            source,
                            item_information,
                            True,
                        )

            elif source["type"] == "hoster" or source["type"] == "cloud":
                stream_link = self._resolve_hoster_or_cloud(
                    source, item_information)

            if stream_link:
                return stream_link
            else:
                g.log("Failed to resolve source: {}".format(source), "error")
        except ResolverFailure as e:
            g.log('Failed to resolve source: {}'.format(e))
Пример #14
0
 def mark_show_watched(self, show_id, watched):
     """
     Mark watched status for all items of a show
     :param show_id: Trakt ID of the show to update
     :type show_id: int
     :param watched: 1 for watched 0 for unwatched
     :type watched: int
     :return: None
     :rtype: None
     """
     g.log("Marking show {} as watched in sync database".format(show_id), "debug")
     self._mill_if_needed([{"trakt_id": show_id}])
     self.execute_sql(
         "UPDATE episodes SET watched=?, last_watched_at=? WHERE trakt_show_id=?",
         (watched, self._get_datetime_now(), show_id),
     )
     self._update_shows_statistics_from_show_id(show_id)
Пример #15
0
    def get_episode_list(
        self,
        trakt_show_id,
        trakt_season_id=None,
        trakt_id=None,
        minimum_episode=None,
        **params
    ):
        """
        Retrieves a list of episodes or a given season with full meta
        :param trakt_show_id: Trakt ID of show
        :type trakt_show_id: int
        :param trakt_season_id:  Trakt ID of season
        :type trakt_season_id: int
        :param trakt_id: Optional Trakt ID of single episode to pull
        :type trakt_id: int
        :param hide_unaired: Optional hiding of un-aired items
        :type hide_unaired: bool
        :param minimum_episode: Optional minimum episode to set as a floor
        :type minimum_episode: int
        :return: List of episode objects with full meta
        :rtype: list
        """
        g.log("Fetching Episode list from sync database", "debug")
        self._try_update_episodes(trakt_show_id, trakt_season_id, trakt_id)
        g.log("Updated required episodes", "debug")
        statement = """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 """

        if trakt_season_id is not None:
            statement += "e.trakt_season_id = {} ".format(trakt_season_id)
        elif trakt_id is not None:
            statement += "e.trakt_id = {} ".format(trakt_id)
        else:
            statement += "e.trakt_show_id = {} ".format(trakt_show_id)
        if params.pop("hide_unaired", self.hide_unaired):
            statement += " AND Datetime(e.air_date) < Datetime('now') "
        if params.pop("self.hide_specials", self.hide_specials):
            statement += " AND e.season != 0"
        if params.pop("hide_watched", self.hide_watched):
            statement += " AND e.watched = 0"
        if minimum_episode:
            statement += " AND e.number >= {}".format(int(minimum_episode))
        statement += " order by e.season, e.number "
        return self.execute_sql(statement).fetchall()
Пример #16
0
    def _update_status(self, chunk_size):
        """
        Updates feedback information
        :return:
        """

        self._bytes_consumed += chunk_size
        self.progress = int(
            (float(self._bytes_consumed) / self.file_size) * 100)
        self.speed = self._bytes_consumed / (time.time() - self._start_time)
        self.remaining_seconds = (
            float(self.file_size - self._bytes_consumed) / self.speed)
        g.log("Speed: {} | Remaining Time: {} | Progress: {}".format(
            self.get_display_speed(),
            self.get_remainging_time_display(),
            self.progress,
        ))
Пример #17
0
 def post_url(self, url, data):
     """
     Perform a POST request to the Premiumize API
     :param url: URI to perform request again
     :type url: str
     :param data: POST data to send with request
     :type data: dict
     :return: JSON response
     :rtype: dict
     """
     if self.headers["Authorization"] == "Bearer ":
         g.log("User is not authorised to make PM requests", "warning")
         return None
     url = "https://www.premiumize.me/api{}".format(url)
     req = self.session.post(url, headers=self.headers, data=data, timeout=10)
     req = self._error_handler(req)
     return req.json()
Пример #18
0
 def _select_files(self):
     if not self.file_keys:
         raise GeneralCachingFailure(
             "Unable to select any relevent files for torrent"
             )
     g.log(
         "Selecting files: {} - Transfer ID: {}".format(
             self.file_keys, self.transfer_id
             )
         )
     response = self.debrid.torrent_select(
         self.transfer_id, ",".join(self.file_keys)
         )
     if "error" in response:
         raise FailureAtRemoteParty(
             "Unable to select torrent files - {}".format(response)
             )
Пример #19
0
 def get_json(self, **params):
     response = self.get(**params)
     if response is None:
         return None
     try:
         if not response.content:
             return None
         return self._handle_response(
             xml_to_dict.parse(response.text).get("root", {}).get("movie"))
     except (ValueError, AttributeError):
         g.log_stacktrace()
         g.log(
             "Failed to receive JSON from OMDb response - response: {}".
             format(response),
             "error",
         )
         return None
Пример #20
0
    def getControlList(self, control_id):
        """Get and check the control for the ControlList type.

        :param control_id: Control id to get nd check for ControlList
        :type control_id: int
        :return: The checked control
        :rtype: xbmcgui.ControlList
        """
        try:
            control = self.getControl(control_id)
        except RuntimeError as e:
            g.log('Control does not exist {}'.format(control_id), 'error')
            g.log(e)
        if not isinstance(control, xbmcgui.ControlList):
            raise AttributeError("Control with Id {} should be of type ControlList".format(control_id))

        return control
Пример #21
0
    def _keep_alive(self):
        for i in range(0, 480):
            g.log("waiting")
            self._running_path = self.getPlayingFile()
            if self._is_file_playing() or self._playback_has_stopped():
                break
            xbmc.sleep(250)

        self.total_time = self.getTotalTime()

        if self.offset and not self.resumed:
            self.seekTime(self.offset)
            self.resumed = True

        self._log_debug_information()
        self._add_subtitle_if_needed()
        xbmc.sleep(5000)

        while self._is_file_playing() and not g.abort_requested():

            self._update_progress()

            if not self.scrobble_started:
                self._trakt_start_watching()

            time_left = int(self.total_time) - int(self.current_time)

            if self.min_time_before_scrape > time_left and not self.pre_scrape_initiated:
                self._handle_pre_scrape()

            if (self.watched_percentage >=
                    self.playCountMinimumPercent) and not self.scrobbled:
                self._trakt_stop_watching()
                self._handle_bookmark()

            if self.dialogs_enabled and not self.dialogs_triggered:
                if time_left <= self.playing_next_time:
                    xbmc.executebuiltin(
                        'RunPlugin("plugin://plugin.video.seren/?action=runPlayerDialogs")'
                    )
                    self.dialogs_triggered = True

            xbmc.sleep(100)

        self._end_playback()
Пример #22
0
 def download(self, request, **extra):
     """
     Downloads requested subtitle
     :param request: Selected subtitle from search results
     :type request: dict
     :param extra: Kwargs, set settings to settings to request to use
     :type extra: dict
     :return: Path to subtitle
     :rtype: str
     """
     try:
         settings = extra.pop("settings", None)
         return self.service.download(request, settings)
     except (OSError, IOError):
         g.log("Unable to download subtitle, file already exists", "error")
     except Exception as e:
         g.log("Unknown error acquiring subtitle: {}".format(e), "error")
         g.log_stacktrace()
Пример #23
0
    def token_request(self):
        if not self.client_secret:
            return

        url = self.oauth_url + self.token_url
        response = self.session.post(
            url,
            data={
                "client_id": self.client_id,
                "client_secret": self.client_secret,
                "code": self.device_code,
                "grant_type": "http://oauth.net/grant_type/device/1.0",
            },
        ).json()
        self._save_settings(response)
        self._save_user_status()
        xbmcgui.Dialog().ok(g.ADDON_NAME, "Real Debrid " + g.get_language_string(30020))
        g.log("Authorised Real Debrid successfully", "info")
Пример #24
0
 def mark_episode_unwatched(self, show_id, season, number):
     """
     Mark an individual episode item as unwatched
     :param show_id: ID of show to update
     :type show_id: int
     :param season: Season number of episode
     :type season: int
     :param number: Episode number to update
     :type number: int
     :return: None
     :rtype: None
     """
     g.log("Marking episode {} S{}E{} as unwatched in sync database".format(show_id, season, number), "debug")
     self.execute_sql(
         "UPDATE episodes SET watched=0 WHERE trakt_show_id=? and season=? and number=?",
         (show_id, season, number),
     )
     self._update_shows_statistics_from_show_id(show_id)
Пример #25
0
    def wrapper(*args, **kwarg):
        try:
            response = func(*args, **kwarg)
            if response.status_code in [200, 201]:
                return response

            g.log('FanartTv returned a {} ({}): while requesting {}'.format(response.status_code,
                                                                            FanartTv.http_codes[response.status_code],
                                                                            response.url), 'error')
            return None
        except requests.exceptions.ConnectionError:
            return None
        except:
            xbmcgui.Dialog().notification(g.ADDON_NAME, g.get_language_string(30025).format('Fanart'))
            if g.get_global_setting("run.mode") == "test":
                raise
            else:
                g.log_stacktrace()
            return None
Пример #26
0
 def mark_season_watched(self, show_id, season, watched):
     """
      Mark watched status for all items of a season
     :param show_id: Trakt ID of the show to update
     :type show_id: int
     :param season: Season number to mark
     :type season: int
     :param watched: 1 for watched 0 for unwatched
     :type watched: int
     :return: None
     :rtype: None
     """
     g.log("Marking season {} as watched in sync database".format(season), "debug")
     self.execute_sql(
         "UPDATE episodes SET watched=?, last_watched_at=?"
         " WHERE trakt_show_id=? AND season=?",
         (watched, self._get_datetime_now(), show_id, season),
     )
     self._update_shows_statistics_from_show_id(show_id)
Пример #27
0
def do_version_change():
    if g.get_setting("seren.version") == g.CLEAN_VERSION:
        return

    g.log("Clearing cache on Seren version change", "info")
    g.clear_cache(silent=True)

    g.set_setting("seren.version", g.CLEAN_VERSION)

    # Reuselanguageinvoker update.  This should be last to execute as it can do a profile reload.

    # Disable the restoration of reuselanguageinvoker addon.xml based on settings value on upgrade.
    # It can still be toggled in settings, although initially it will be the release default value.
    # This is due to the fact that we still don't recommend having this enabled due to Kodi hard crashes.
    # maintenance.toggle_reuselanguageinvoker(
    #     True if g.get_setting("reuselanguageinvoker") == "Enabled" else False)
    g.set_setting(
        "reuselanguageinvoker.status", "Disabled"
    )  # This ensures setting is reflected as disabled on version change
Пример #28
0
    def pre_scrape():
        """
        Checks whether a item exists in the current playlist after current item and then pre-fetches results
        :return:
        :rtype:
        """
        next_position = g.PLAYLIST.getposition() + 1
        if next_position >= g.PLAYLIST.size():
            return

        url = g.PLAYLIST[  # pylint: disable=unsubscriptable-object
            next_position].getPath()

        if not url:
            return

        url = url.replace("getSources", "preScrape")
        g.set_runtime_setting("tempSilent", True)
        g.log("Running Pre-Scrape: {}".format(url))
        xbmc.executebuiltin('RunPlugin("{}")'.format(url))
Пример #29
0
    def _failure_cleanup(meta_location, package_name, folders):
        # In the event of a failure to install package this function will revert changes made

        g.log("Reverting changes")
        try:
            if xbmcvfs.exists("{}.temp".format(meta_location)):
                os.remove(meta_location)
                os.rename("{}.temp".format(meta_location), meta_location)
        except Exception:
            pass

        for folder in folders:
            folder_path = os.path.join(g.ADDON_USERDATA_PATH,
                                       folder.strip("/"), package_name)
            if xbmcvfs.exists("{}.temp".format(folder_path)):
                try:
                    shutil.rmtree(folder_path)
                except Exception:
                    pass
                os.rename("{}.temp".format(folder_path), folder_path)
Пример #30
0
    def _extract_zip(self, skin_meta):
        try:
            file_path = [i for i in self._file_list if i.endswith("resources/skins/")][
                0
            ]
            file_path = file_path.split("resources/")[0]
        except IndexError:
            file_path = ""

        if "{}resources/".format(file_path) not in self._file_list:
            g.log('Theme Folder Structure Invalid: Missing folder "Resources"')
            xbmcgui.Dialog().ok(g.ADDON_NAME, g.get_language_string(30231))
            raise Exception

        skin_path = os.path.join(g.SKINS_PATH, skin_meta["skin_name"])
        self._extract_zip_members(
            [i for i in self._file_list if i.startswith(file_path) and i != file_path],
            skin_path,
        )
        self._destroy_created_temp_items()