예제 #1
0
def scan_videos(videos, ignore_all=False, providers=None, skip_hashing=False):
    """
    receives a list of videos containing dictionaries returned by media_to_videos
    :param videos:
    :param kind: series or movies
    :return: dictionary of subliminal.video.scan_video, key=subliminal scanned video, value=plex file part
    """
    ret = {}
    for video in videos:
        intent = get_intent()
        force_refresh = intent.get("force", video["id"], video["series_id"], video["season_id"])
        Log.Debug("Determining force-refresh (video: %s, series: %s, season: %s), result: %s"
                  % (video["id"], video["series_id"], video["season_id"], force_refresh))

        hints = helpers.get_item_hints(video)
        video["plex_part"].fps = get_stream_fps(video["plex_part"].streams)
        p = providers or config.get_providers(media_type="series" if video["type"] == "episode" else "movies")
        scanned_video = prepare_video(video, ignore_all=force_refresh or ignore_all, hints=hints,
                                      rating_key=video["id"], providers=p,
                                      skip_hashing=skip_hashing)

        if not scanned_video:
            continue

        scanned_video.id = video["id"]
        part_metadata = video.copy()
        del part_metadata["plex_part"]
        scanned_video.plexapi_metadata = part_metadata
        scanned_video.ignore_all = force_refresh
        ret[scanned_video] = video["plex_part"]
    return ret
예제 #2
0
    def download_subtitle(self, subtitle, rating_key, mode="m"):
        from interface.menu_helpers import set_refresh_menu_state

        item_type = subtitle.item_type
        part_id = subtitle.part_id
        metadata = get_plex_metadata(rating_key, part_id, item_type)
        providers = config.get_providers(media_type="series" if item_type == "episode" else "movies")
        scanned_parts = scan_videos([metadata], ignore_all=True, providers=providers)
        video, plex_part = scanned_parts.items()[0]

        pre_download_hook(subtitle)

        # downloaded_subtitles = {subliminal.Video: [subtitle, subtitle, ...]}
        download_subtitles([subtitle], providers=providers,
                           provider_configs=config.provider_settings,
                           pool_class=config.provider_pool, throttle_callback=config.provider_throttle)

        post_download_hook(subtitle)

        # may be redundant
        subtitle.pack_data = None

        download_successful = False

        if subtitle.content:
            try:
                save_subtitles(scanned_parts, {video: [subtitle]}, mode=mode, mods=config.default_mods)
                if mode == "m":
                    Log.Debug(u"%s: Manually downloaded subtitle for: %s", self.name, rating_key)
                    track_usage("Subtitle", "manual", "download", 1)
                elif mode == "b":
                    Log.Debug(u"%s: Downloaded better subtitle for: %s", self.name, rating_key)
                    track_usage("Subtitle", "better", "download", 1)
                download_successful = True
                refresh_item(rating_key)

            except:
                Log.Error(u"%s: Something went wrong when downloading specific subtitle: %s",
                          self.name, traceback.format_exc())
            finally:
                set_refresh_menu_state(None)

                if download_successful:
                    # store item in history
                    from support.history import get_history
                    item_title = get_title_for_video_metadata(metadata, add_section_title=False)
                    history = get_history()
                    history.add(item_title, video.id, section_title=video.plexapi_metadata["section"],
                                subtitle=subtitle,
                                mode=mode)
                    history.destroy()

                    # clear missing subtitles menu data
                    if not scheduler.is_task_running("MissingSubtitles"):
                        scheduler.clear_task_data("MissingSubtitles")
        else:
            set_refresh_menu_state(u"%s: Subtitle download failed (%s)" % (self.name, rating_key))
        return download_successful
예제 #3
0
def scan_videos(videos, ignore_all=False, providers=None, skip_hashing=False):
    """
    receives a list of videos containing dictionaries returned by media_to_videos
    :param videos:
    :param kind: series or movies
    :return: dictionary of subliminal.video.scan_video, key=subliminal scanned video, value=plex file part
    """
    ret = {}
    for video in videos:
        intent = get_intent()
        force_refresh = intent.get("force", video["id"], video["series_id"],
                                   video["season_id"])
        Log.Debug(
            "Determining force-refresh (video: %s, series: %s, season: %s), result: %s"
            % (video["id"], video["series_id"], video["season_id"],
               force_refresh))

        hints = helpers.get_item_hints(video)
        video["plex_part"].fps = get_stream_fps(video["plex_part"].streams)
        p = providers or config.get_providers(
            media_type="series" if video["type"] == "episode" else "movies")
        scanned_video = prepare_video(video,
                                      ignore_all=force_refresh or ignore_all,
                                      hints=hints,
                                      rating_key=video["id"],
                                      providers=p,
                                      skip_hashing=skip_hashing)

        if not scanned_video:
            continue

        scanned_video.id = video["id"]
        part_metadata = video.copy()
        del part_metadata["plex_part"]
        scanned_video.plexapi_metadata = part_metadata
        scanned_video.ignore_all = force_refresh
        ret[scanned_video] = video["plex_part"]
    return ret
예제 #4
0
    def run(self):
        super(SearchAllRecentlyAddedMissing, self).run()

        self.running = True
        self.prepare()

        from support.history import get_history
        history = get_history()

        now = datetime.datetime.now()
        min_score_series = int(
            Prefs["subtitles.search.minimumTVScore2"].strip())
        min_score_movies = int(
            Prefs["subtitles.search.minimumMovieScore2"].strip())
        series_providers = config.get_providers(media_type="series")
        movie_providers = config.get_providers(media_type="movies")

        is_recent_str = Prefs["scheduler.item_is_recent_age"]
        num, ident = is_recent_str.split()

        max_search_days = 0
        if ident == "days":
            max_search_days = int(num)
        elif ident == "weeks":
            max_search_days = int(num) * 7

        subtitle_storage = get_subtitle_storage()
        recent_files = subtitle_storage.get_recent_files(
            age_days=max_search_days)

        self.items_searching = len(recent_files)

        download_count = 0
        videos_with_downloads = 0

        config.init_subliminal_patches()

        Log.Info(u"%s: Searching for subtitles for %s items", self.name,
                 self.items_searching)

        def skip_item():
            self.items_searching = self.items_searching - 1
            self.percentage = int(
                self.items_done * 100 /
                self.items_searching) if self.items_searching > 0 else 100

        # search for subtitles in viable items
        try:
            for fn in recent_files:
                stored_subs = subtitle_storage.load(filename=fn)
                if not stored_subs:
                    Log.Debug("Skipping item %s because storage is empty", fn)
                    skip_item()
                    continue

                video_id = stored_subs.video_id

                # added_date <= max_search_days?
                if stored_subs.added_at + datetime.timedelta(
                        days=max_search_days) <= now:
                    Log.Debug("Skipping item %s because it's too old",
                              video_id)
                    skip_item()
                    continue

                if stored_subs.item_type == "episode":
                    min_score = min_score_series
                    providers = series_providers
                else:
                    min_score = min_score_movies
                    providers = movie_providers

                parts = []
                plex_item = get_item(video_id)

                if not plex_item:
                    Log.Info(u"%s: Item %s unknown, skipping", self.name,
                             video_id)
                    skip_item()
                    continue

                if not is_wanted(video_id, item=plex_item):
                    skip_item()
                    continue

                for media in plex_item.media:
                    parts += media.parts

                downloads_per_video = 0
                hit_providers = False
                for part in parts:
                    part_id = part.id

                    try:
                        metadata = get_plex_metadata(video_id, part_id,
                                                     stored_subs.item_type)
                    except PartUnknownException:
                        Log.Info(u"%s: Part %s:%s unknown, skipping",
                                 self.name, video_id, part_id)
                        continue

                    if not metadata:
                        Log.Info(u"%s: Part %s:%s unknown, skipping",
                                 self.name, video_id, part_id)
                        continue

                    Log.Debug(u"%s: Looking for missing subtitles: %s",
                              self.name, get_item_title(plex_item))
                    scanned_parts = scan_videos([metadata],
                                                providers=providers)

                    downloaded_subtitles = download_best_subtitles(
                        scanned_parts,
                        min_score=min_score,
                        providers=providers)
                    hit_providers = downloaded_subtitles is not None
                    download_successful = False

                    if downloaded_subtitles:
                        downloaded_any = any(downloaded_subtitles.values())
                        if not downloaded_any:
                            continue

                        try:
                            save_subtitles(scanned_parts,
                                           downloaded_subtitles,
                                           mode="a",
                                           mods=config.default_mods)
                            Log.Debug(
                                u"%s: Downloaded subtitle for item with missing subs: %s",
                                self.name, video_id)
                            download_successful = True
                            refresh_item(video_id)
                            track_usage("Subtitle", "manual", "download", 1)
                        except:
                            Log.Error(
                                u"%s: Something went wrong when downloading specific subtitle: %s",
                                self.name, traceback.format_exc())
                        finally:
                            scanned_parts = None
                            try:
                                item_title = get_title_for_video_metadata(
                                    metadata, add_section_title=False)
                                if download_successful:
                                    # store item in history
                                    for video, video_subtitles in downloaded_subtitles.items(
                                    ):
                                        if not video_subtitles:
                                            continue

                                        for subtitle in video_subtitles:
                                            downloads_per_video += 1
                                            history.add(
                                                item_title,
                                                video.id,
                                                section_title=metadata[
                                                    "section"],
                                                thumb=video.plexapi_metadata[
                                                    "super_thumb"],
                                                subtitle=subtitle,
                                                mode="a")

                                    downloaded_subtitles = None
                            except:
                                Log.Error(u"%s: DEBUG HIT: %s", self.name,
                                          traceback.format_exc())

                        Log.Debug(u"%s: Waiting %s seconds before continuing",
                                  self.name, self.PROVIDER_SLACK)
                        Thread.Sleep(self.PROVIDER_SLACK)

                download_count += downloads_per_video

                if downloads_per_video:
                    videos_with_downloads += 1

                self.items_done = self.items_done + 1
                self.percentage = int(
                    self.items_done * 100 /
                    self.items_searching) if self.items_searching > 0 else 100

                stored_subs = None

                if downloads_per_video:
                    Log.Debug(
                        u"%s: Subtitles have been downloaded, "
                        u"waiting %s seconds before continuing", self.name,
                        self.DL_PROVIDER_SLACK)
                    Thread.Sleep(self.DL_PROVIDER_SLACK)
                else:
                    if hit_providers:
                        Log.Debug(u"%s: Waiting %s seconds before continuing",
                                  self.name, self.PROVIDER_SLACK)
                        Thread.Sleep(self.PROVIDER_SLACK)
        finally:
            subtitle_storage.destroy()
            history.destroy()

        if download_count:
            Log.Debug(
                u"%s: done. Missing subtitles found for %s/%s items (%s subs downloaded)",
                self.name, videos_with_downloads, self.items_searching,
                download_count)
        else:
            Log.Debug(u"%s: done. No subtitles found for %s items", self.name,
                      self.items_searching)
예제 #5
0
    def list_subtitles(self,
                       rating_key,
                       item_type,
                       part_id,
                       language,
                       skip_wrong_fps=True,
                       metadata=None,
                       scanned_parts=None,
                       air_date_cutoff=None):

        if not metadata:
            metadata = get_plex_metadata(rating_key, part_id, item_type)

        if not metadata:
            return

        providers = config.get_providers(
            media_type="series" if item_type == "episode" else "movies")
        if not scanned_parts:
            scanned_parts = scan_videos([metadata],
                                        ignore_all=True,
                                        providers=providers)
            if not scanned_parts:
                Log.Error(u"%s: Couldn't list available subtitles for %s",
                          self.name, rating_key)
                return

        video, plex_part = scanned_parts.items()[0]
        refine_video(video, refiner_settings=config.refiner_settings)

        if air_date_cutoff is not None and metadata["item"].year and \
            metadata["item"].year + air_date_cutoff < datetime.date.today().year:
            Log.Debug(
                "Skipping searching for subtitles: %s, it aired over %s year(s) ago.",
                rating_key, air_date_cutoff)
            return

        config.init_subliminal_patches()

        provider_settings = config.provider_settings
        if not skip_wrong_fps:
            provider_settings["opensubtitles"]["skip_wrong_fps"] = False

        if item_type == "episode":
            min_score = 240
            if video.is_special:
                min_score = 180
        else:
            min_score = 60

        languages = {Language.fromietf(language)}

        available_subs = list_all_subtitles(
            [video],
            languages,
            providers=providers,
            provider_configs=provider_settings,
            pool_class=config.provider_pool,
            throttle_callback=config.provider_throttle,
            language_hook=language_hook)

        use_hearing_impaired = Prefs['subtitles.search.hearingImpaired'] in (
            "prefer", "force HI")

        # sort subtitles by score
        unsorted_subtitles = []
        for s in available_subs[video]:
            Log.Debug(u"%s: Starting score computation for %s", self.name, s)
            try:
                matches = s.get_matches(video)
            except AttributeError:
                Log.Error(u"%s: Match computation failed for %s: %s",
                          self.name, s, traceback.format_exc())
                continue

            # skip wrong season/episodes
            if item_type == "episode":
                can_verify_series = True
                if not s.hash_verifiable and "hash" in matches:
                    can_verify_series = False

                if can_verify_series and not {"series", "season", "episode"
                                              }.issubset(matches):
                    if "series" not in matches:
                        s.wrong_series = True
                    else:
                        s.wrong_season_ep = True

            unsorted_subtitles.append(
                (s,
                 compute_score(matches,
                               s,
                               video,
                               hearing_impaired=use_hearing_impaired),
                 matches))
        scored_subtitles = sorted(unsorted_subtitles,
                                  key=operator.itemgetter(1),
                                  reverse=True)

        subtitles = []
        for subtitle, score, matches in scored_subtitles:
            # check score
            if score < min_score and not subtitle.wrong_series:
                Log.Info(u'%s: Score %d is below min_score (%d)', self.name,
                         score, min_score)
                continue
            subtitle.score = score
            subtitle.matches = matches
            subtitle.part_id = part_id
            subtitle.item_type = item_type
            subtitles.append(subtitle)
        return subtitles
예제 #6
0
    def update(self, metadata, media, lang):
        if not config.enable_agent:
            Log.Debug("Skipping Sub-Zero agent(s)")
            return

        Log.Debug("Sub-Zero %s, %s update called" %
                  (config.version, self.agent_type))
        intent = get_intent()

        if not media:
            Log.Error(
                "Called with empty media, something is really wrong with your setup!"
            )
            return

        item_ids = []
        try:
            config.init_subliminal_patches()
            videos = media_to_videos(media, kind=self.agent_type)

            # find local media
            update_local_media(metadata, media, media_type=self.agent_type)

            # media ignored?
            use_any_parts = False
            for video in videos:
                if is_ignored(video["id"]):
                    Log.Debug(u"Ignoring %s" % video)
                    continue
                use_any_parts = True

            if not use_any_parts:
                Log.Debug(u"Nothing to do.")
                return

            try:
                use_score = int(Prefs[self.score_prefs_key].strip())
            except ValueError:
                Log.Error(
                    "Please only put numbers into the scores setting. Exiting")
                return

            set_refresh_menu_state(media, media_type=self.agent_type)

            # scanned_video_part_map = {subliminal.Video: plex_part, ...}
            providers = config.get_providers(media_type=self.agent_type)
            try:
                scanned_video_part_map = scan_videos(videos,
                                                     providers=providers)
            except IOError, e:
                Log.Exception(
                    "Permission error, please check your folder/file permissions. Exiting."
                )
                if cast_bool(Prefs["check_permissions"]):
                    config.permissions_ok = False
                    config.missing_permissions = e.message
                return

            # auto extract embedded
            if config.embedded_auto_extract:
                if config.plex_transcoder:
                    agent_extract_embedded(scanned_video_part_map)
                else:
                    Log.Warning(
                        "Plex Transcoder not found, can't auto extract")

            # clear missing subtitles menu data
            if not scheduler.is_task_running("MissingSubtitles"):
                scheduler.clear_task_data("MissingSubtitles")

            downloaded_subtitles = None

            # debounce for self.debounce seconds
            now = datetime.datetime.now()
            if "last_call" in Dict:
                last_call = Dict["last_call"]
                if last_call + datetime.timedelta(seconds=self.debounce) > now:
                    wait = self.debounce - (now - last_call).seconds
                    if wait >= 1:
                        Log.Debug("Waiting %s seconds until continuing", wait)
                        Thread.Sleep(wait)

            # downloaded_subtitles = {subliminal.Video: [subtitle, subtitle, ...]}
            try:
                downloaded_subtitles = download_best_subtitles(
                    scanned_video_part_map,
                    min_score=use_score,
                    throttle_time=self.debounce,
                    providers=providers)
            except:
                Log.Exception(
                    "Something went wrong when downloading subtitles")

            if downloaded_subtitles is not None:
                Dict["last_call"] = datetime.datetime.now()

            item_ids = get_media_item_ids(media, kind=self.agent_type)

            downloaded_any = False
            if downloaded_subtitles:
                downloaded_any = any(downloaded_subtitles.values())

            if downloaded_any:
                save_successful = False
                try:
                    save_successful = save_subtitles(scanned_video_part_map,
                                                     downloaded_subtitles,
                                                     mods=config.default_mods)
                except:
                    Log.Exception("Something went wrong when saving subtitles")

                track_usage("Subtitle", "refreshed", "download", 1)

                # store SZ meta info even if download wasn't successful
                if not save_successful:
                    self.store_blank_subtitle_metadata(scanned_video_part_map)

                else:
                    for video, video_subtitles in downloaded_subtitles.items():
                        # store item(s) in history
                        for subtitle in video_subtitles:
                            item_title = get_title_for_video_metadata(
                                video.plexapi_metadata,
                                add_section_title=False)
                            history = get_history()
                            history.add(item_title,
                                        video.id,
                                        section_title=video.
                                        plexapi_metadata["section"],
                                        subtitle=subtitle)
                            history.destroy()
            else:
                # store SZ meta info even if we've downloaded none
                self.store_blank_subtitle_metadata(scanned_video_part_map)

            update_local_media(metadata, media, media_type=self.agent_type)
예제 #7
0
    def update(self, metadata, media, lang):
        if not config.enable_agent:
            Log.Debug("Skipping Sub-Zero agent(s)")
            return

        Log.Debug("Sub-Zero %s, %s update called" % (config.version, self.agent_type))

        if not media:
            Log.Error("Called with empty media, something is really wrong with your setup!")
            return

        intent = get_intent()

        item_ids = []
        try:
            config.init_subliminal_patches()
            all_videos = media_to_videos(media, kind=self.agent_type)

            # media ignored?
            ignore_parts_cleanup = []
            videos = []
            for video in all_videos:
                if not is_wanted(video["id"], item=video["item"]):
                    Log.Debug(u'Skipping "%s"' % video["filename"])
                    ignore_parts_cleanup.append(video["path"])
                    continue
                videos.append(video)

            # find local media
            update_local_media(all_videos, ignore_parts_cleanup=ignore_parts_cleanup)

            if not videos:
                Log.Debug(u"Nothing to do.")
                return

            try:
                use_score = int(Prefs[self.score_prefs_key].strip())
            except ValueError:
                Log.Error("Please only put numbers into the scores setting. Exiting")
                return

            set_refresh_menu_state(media, media_type=self.agent_type)

            # scanned_video_part_map = {subliminal.Video: plex_part, ...}
            providers = config.get_providers(media_type=self.agent_type)
            try:
                scanned_video_part_map = scan_videos(videos, providers=providers)
            except IOError, e:
                Log.Exception("Permission error, please check your folder/file permissions. Exiting.")
                if cast_bool(Prefs["check_permissions"]):
                    config.permissions_ok = False
                    config.missing_permissions = e.message
                return

            # auto extract embedded
            if config.embedded_auto_extract:
                if config.plex_transcoder:
                    agent_extract_embedded(scanned_video_part_map)
                else:
                    Log.Warn("Plex Transcoder not found, can't auto extract")

            # clear missing subtitles menu data
            if not scheduler.is_task_running("MissingSubtitles"):
                scheduler.clear_task_data("MissingSubtitles")

            downloaded_subtitles = None

            # debounce for self.debounce seconds
            now = datetime.datetime.now()
            if "last_call" in Dict:
                last_call = Dict["last_call"]
                if last_call + datetime.timedelta(seconds=self.debounce) > now:
                    wait = self.debounce - (now - last_call).seconds
                    if wait >= 1:
                        Log.Debug("Waiting %s seconds until continuing", wait)
                        Thread.Sleep(wait)

            # downloaded_subtitles = {subliminal.Video: [subtitle, subtitle, ...]}
            try:
                downloaded_subtitles = download_best_subtitles(scanned_video_part_map, min_score=use_score,
                                                               throttle_time=self.debounce, providers=providers)
            except:
                Log.Exception("Something went wrong when downloading subtitles")

            if downloaded_subtitles is not None:
                Dict["last_call"] = datetime.datetime.now()

            item_ids = get_media_item_ids(media, kind=self.agent_type)

            downloaded_any = False
            if downloaded_subtitles:
                downloaded_any = any(downloaded_subtitles.values())

            if downloaded_any:
                save_successful = False
                try:
                    save_successful = save_subtitles(scanned_video_part_map, downloaded_subtitles,
                                                     mods=config.default_mods)
                except:
                    Log.Exception("Something went wrong when saving subtitles")

                track_usage("Subtitle", "refreshed", "download", 1)

                # store SZ meta info even if download wasn't successful
                if not save_successful:
                    self.store_blank_subtitle_metadata(scanned_video_part_map)

                else:
                    for video, video_subtitles in downloaded_subtitles.items():
                        # store item(s) in history
                        for subtitle in video_subtitles:
                            history = get_history()
                            item_title = get_title_for_video_metadata(video.plexapi_metadata, add_section_title=False)
                            history.add(item_title, video.id, section_title=video.plexapi_metadata["section"],
                                        thumb=video.plexapi_metadata["super_thumb"],
                                        subtitle=subtitle)
                            history.destroy()
            else:
                # store SZ meta info even if we've downloaded none
                self.store_blank_subtitle_metadata(scanned_video_part_map)

            update_local_media(videos)