Example #1
0
    def on_created(event):
        if event.is_directory:
            return

        path = event.src_path

        if not mimetypes.guess_type(path)[0].startswith('video'):
            return

        try:
            logging.info(f"Pulling subtitles for: {path}")
            video = scan_video(path)
            provider_pool = ProviderPool(
                providers=ENABLED_PROVIDERS,
                provider_configs=PROVIDER_CONFIGURATIONS)
            subtitles = provider_pool.list_subtitles(
                video=video, languages={Language('eng'),
                                        Language('nld')})
            best_subtitles = provider_pool.download_best_subtitles(
                subtitles=subtitles,
                video=video,
                languages={Language('eng'), Language('nld')})
            save_subtitles(video, best_subtitles)
            logging.info(f"Subtitles saved for: {path}")
        except Exception as e:
            logging.error(f"Error: {repr(e)}")
Example #2
0
def get_provider_pool():
    """Return the subliminal provider pool to be used.

    :return: subliminal provider pool to be used
    :rtype: subliminal.ProviderPool
    """
    logger.debug(u'Creating a new ProviderPool instance')
    provider_configs = {
        'addic7ed': {
            'username': app.ADDIC7ED_USER,
            'password': app.ADDIC7ED_PASS
        },
        'itasa': {
            'username': app.ITASA_USER,
            'password': app.ITASA_PASS
        },
        'legendastv': {
            'username': app.LEGENDASTV_USER,
            'password': app.LEGENDASTV_PASS
        },
        'opensubtitles': {
            'username': app.OPENSUBTITLES_USER,
            'password': app.OPENSUBTITLES_PASS
        }
    }
    return ProviderPool(providers=enabled_service_list(),
                        provider_configs=provider_configs)
Example #3
0
    def __init_instance():
        with SubtitleProviderPool._lock:
            providers = enabled_service_list()
            provider_configs = {
                'addic7ed': {
                    'username': sickbeard.ADDIC7ED_USER,
                    'password': sickbeard.ADDIC7ED_PASS
                },
                'itasa': {
                    'username': sickbeard.ITASA_USER,
                    'password': sickbeard.ITASA_PASS
                },
                'legendastv': {
                    'username': sickbeard.LEGENDASTV_USER,
                    'password': sickbeard.LEGENDASTV_PASS
                },
                'opensubtitles': {
                    'username': sickbeard.OPENSUBTITLES_USER,
                    'password': sickbeard.OPENSUBTITLES_PASS
                },
                'subscenter': {
                    'username': sickbeard.SUBSCENTER_USER,
                    'password': sickbeard.SUBSCENTER_PASS
                }
            }

            SubtitleProviderPool._instance = ProviderPool(
                providers=providers, provider_configs=provider_configs)
Example #4
0
    def download_callback(self, menuitem, files):
        # scan videos
        videos = []
        for f in files:
            # ignore non-writable locations
            if not f.can_write():
                continue

            # directories
            if f.is_directory():
                try:
                    scanned_videos = scan_videos(
                        f.get_location().get_path(),
                        subtitles=True,
                        embedded_subtitles=self.config.embedded_subtitles)
                except:
                    continue
                for video in scanned_videos:
                    if check_video(video,
                                   languages=self.config.languages,
                                   age=self.config.age,
                                   undefined=self.config.single):
                        videos.append(video)
                continue

            # other inputs
            try:
                video = scan_video(
                    f.get_location().get_path(),
                    subtitles=True,
                    embedded_subtitles=self.config.embedded_subtitles)
            except:
                continue
            if check_video(video,
                           languages=self.config.languages,
                           undefined=self.config.single):
                videos.append(video)

        # download best subtitles
        downloaded_subtitles = defaultdict(list)
        with ProviderPool(
                providers=self.config.providers,
                provider_configs=self.config.provider_configs) as pool:
            for v in videos:
                subtitles = pool.download_best_subtitles(
                    pool.list_subtitles(
                        v, self.config.languages - v.subtitle_languages),
                    v,
                    self.config.languages,
                    min_score=v.scores['hash'] * self.config.min_score / 100,
                    hearing_impaired=self.config.hearing_impaired,
                    only_one=self.config.single)
                downloaded_subtitles[v] = subtitles

        # save subtitles
        for v, subtitles in downloaded_subtitles.items():
            save_subtitles(v, subtitles, single=self.config.single)
Example #5
0
    def choose_callback(self, menuitem, files):
        # scan and check the video
        video = scan_video(files[0].get_location().get_path(),
                           subtitles=True,
                           embedded_subtitles=self.config.embedded_subtitles)
        if not check_video(video,
                           languages=self.config.languages,
                           undefined=self.config.single):
            return

        # list subtitles
        with ProviderPool(
                providers=self.config.providers,
                provider_configs=self.config.provider_configs) as pool:
            subtitles = pool.list_subtitles(video, self.config.languages)

        # load the interface
        builder = Gtk.Builder()
        builder.set_translation_domain('subliminal')
        builder.add_from_file(
            os.path.join(os.path.dirname(__file__), 'subliminal', 'ui',
                         'choose.glade'))

        # set the video filename
        video_filename = builder.get_object('video_filename_label')
        video_filename.set_text(files[0].get_name())

        # fill the subtitle liststore
        subtitle_liststore = builder.get_object('subtitle_liststore')
        for s in subtitles:
            matches = s.get_matches(
                video, hearing_impaired=self.config.hearing_impaired)
            scaled_score = compute_score(matches, video)
            if s.hearing_impaired == self.config.hearing_impaired:
                scaled_score -= video.scores['hearing_impaired']
            scaled_score *= 100 / video.scores['hash']
            subtitle_liststore.append([
                s.id,
                nice_language(s.language), scaled_score,
                s.provider_name.capitalize(), s.hearing_impaired, s.page_link,
                False
            ])
        subtitle_liststore.set_sort_column_id(2, Gtk.SortType.DESCENDING)

        # connect signals
        builder.connect_signals(ChooseHandler(self.config, video, subtitles))

        # display window
        window = builder.get_object('subtitle_window')
        window.show_all()
        Gtk.main()
Example #6
0
    def on_subtitles_treeview_row_activated(self, treeview, path, view_column):
        model = treeview.get_model()
        iter = model.get_iter(path)

        # return if already downloaded
        if model.get_value(iter, 6):
            return

        # get the subtitle object
        subtitle = self.subtitles[model.get_value(iter, 3).lower() + '-' +
                                  model.get_value(iter, 0)]

        # download the subtitle
        with ProviderPool(
                providers=self.config.providers,
                provider_configs=self.config.provider_configs) as pool:
            pool.download_subtitle(subtitle)

        # save the subtitle
        save_subtitles(self.video, [subtitle], single=self.config.single)

        # mark the subtitle as downloaded
        model.set_value(iter, 6, True)
Example #7
0
    def subtitles_download_in_pp():  # pylint: disable=too-many-locals, too-many-branches
        logger.log(u'Checking for needed subtitles in Post-Process folder', logger.INFO)

        providers = enabled_service_list()
        provider_configs = {'addic7ed': {'username': sickbeard.ADDIC7ED_USER,
                                         'password': sickbeard.ADDIC7ED_PASS},
                            'legendastv': {'username': sickbeard.LEGENDASTV_USER,
                                           'password': sickbeard.LEGENDASTV_PASS},
                            'opensubtitles': {'username': sickbeard.OPENSUBTITLES_USER,
                                              'password': sickbeard.OPENSUBTITLES_PASS}}

        pool = ProviderPool(providers=providers, provider_configs=provider_configs)

        # Search for all wanted languages
        languages = {from_code(language) for language in wanted_languages()}
        if not languages:
            return

        run_post_process = False
        # Check if PP folder is set
        if sickbeard.TV_DOWNLOAD_DIR and os.path.isdir(sickbeard.TV_DOWNLOAD_DIR):

            for root, _, files in os.walk(sickbeard.TV_DOWNLOAD_DIR, topdown=False):
                rar_files = [x for x in files if isRarFile(x)]
                if rar_files and sickbeard.UNPACK:
                    video_files = [x for x in files if isMediaFile(x)]
                    if u'_UNPACK' not in root and (not video_files or root == sickbeard.TV_DOWNLOAD_DIR):
                        logger.log(u'Found rar files in post-process folder: {}'.format(rar_files), logger.DEBUG)
                        result = processTV.ProcessResult()
                        processTV.unRAR(root, rar_files, False, result)
                elif rar_files and not sickbeard.UNPACK:
                    logger.log(u'Unpack is disabled. Skipping: {}'.format(rar_files), logger.WARNING)

            for root, _, files in os.walk(sickbeard.TV_DOWNLOAD_DIR, topdown=False):
                for video_filename in sorted(files):
                    try:
                        # Remove non release groups from video file. Needed to match subtitles
                        new_video_filename = remove_non_release_groups(video_filename)
                        if new_video_filename != video_filename:
                            os.rename(video_filename, new_video_filename)
                            video_filename = new_video_filename
                    except Exception as error:
                        logger.log(u'Couldn\'t remove non release groups from video file. Error: {}'.format
                                   (ex(error)), logger.DEBUG)
                    if isMediaFile(video_filename):
                        try:
                            video = subliminal.scan_video(os.path.join(root, video_filename),
                                                          subtitles=False, embedded_subtitles=False)
                            subtitles_list = pool.list_subtitles(video, languages)

                            for provider in providers:
                                if provider in pool.discarded_providers:
                                    logger.log(u'Could not search in {} provider. Discarding for now'.format(provider), logger.DEBUG)

                            if not subtitles_list:
                                logger.log(u'No subtitles found for {}'.format
                                           (os.path.join(root, video_filename)), logger.DEBUG)
                                continue

                            logger.log(u'Found subtitle(s) canditate(s) for {}'.format(video_filename), logger.INFO)
                            hearing_impaired = sickbeard.SUBTITLES_HEARING_IMPAIRED
                            user_score = 213 if sickbeard.SUBTITLES_PERFECT_MATCH else 204
                            found_subtitles = pool.download_best_subtitles(subtitles_list, video, languages=languages,
                                                                           hearing_impaired=hearing_impaired,
                                                                           min_score=user_score,
                                                                           only_one=not sickbeard.SUBTITLES_MULTI)

                            for subtitle in subtitles_list:
                                score = subliminal.score.compute_score(subtitle, video, hearing_impaired=sickbeard.SUBTITLES_HEARING_IMPAIRED)
                                logger.log(u'[{}] Subtitle score for {} is: {} (min={})'.format
                                           (subtitle.provider_name, subtitle.id, score, user_score), logger.DEBUG)

                            downloaded_languages = set()
                            for subtitle in found_subtitles:
                                logger.log(u'Found subtitle for {} in {} provider with language {}'.format
                                           (os.path.join(root, video_filename), subtitle.provider_name,
                                            subtitle.language.opensubtitles), logger.DEBUG)
                                subliminal.save_subtitles(video, found_subtitles, directory=root,
                                                          single=not sickbeard.SUBTITLES_MULTI)

                                subtitles_multi = not sickbeard.SUBTITLES_MULTI
                                subtitle_path = subliminal.subtitle.get_subtitle_path(video.name,
                                                                                      None if subtitles_multi else
                                                                                      subtitle.language)
                                if root is not None:
                                    subtitle_path = os.path.join(root, os.path.split(subtitle_path)[1])
                                sickbeard.helpers.chmodAsParent(subtitle_path)
                                sickbeard.helpers.fixSetGroupID(subtitle_path)

                                downloaded_languages.add(subtitle.language.opensubtitles)

                            # Don't run post processor unless at least one file has all of the needed subtitles
                            if not needs_subtitles(downloaded_languages):
                                run_post_process = True
                        except Exception as error:
                            logger.log(u'Error occurred when downloading subtitles for: {}. Error: {}'.format
                                       (os.path.join(root, video_filename), ex(error)))
            if run_post_process:
                logger.log(u'Starting post-process with default settings now that we found subtitles')
                processTV.processDir(sickbeard.TV_DOWNLOAD_DIR)
Example #8
0
def download_subtitles(subtitles_info):  # pylint: disable=too-many-locals, too-many-branches, too-many-statements
    existing_subtitles = subtitles_info['subtitles']

    if not needs_subtitles(existing_subtitles):
        logger.log(u'Episode already has all needed subtitles, skipping {} {}'.format
                   (subtitles_info['show_name'], episode_num(subtitles_info['season'], subtitles_info['episode']) or
                    episode_num(subtitles_info['season'], subtitles_info['episode'], numbering='absolute')), logger.DEBUG)
        return existing_subtitles, None

    # Check if we really need subtitles
    languages = get_needed_languages(existing_subtitles)
    if not languages:
        logger.log(u'No subtitles needed for {} {}'.format
                   (subtitles_info['show_name'], episode_num(subtitles_info['season'], subtitles_info['episode']) or
                    episode_num(subtitles_info['season'], subtitles_info['episode'], numbering='absolute')), logger.DEBUG)
        return existing_subtitles, None

    subtitles_path = get_subtitles_path(subtitles_info['location'])
    video_path = subtitles_info['location']
    
    # Perfect match = hash score - hearing impaired score - resolution score (subtitle for 720p its the same for 1080p)
    # Perfect match = 215 -1 -1 = 213
    # No-perfect match = hash score - hearing impaired score - resolution score - release_group score
    # No-perfect match = 215 -1 -1 -9 = 204
    # From latest subliminal code:
    # episode_scores = {'hash': 215, 'series': 108, 'year': 54, 'season': 18, 'episode': 18, 'release_group': 9,
    #                   'format': 4, 'audio_codec': 2, 'resolution': 1, 'hearing_impaired': 1, 'video_codec': 1}
    user_score = 213 if sickbeard.SUBTITLES_PERFECT_MATCH else 204

    video = get_video(video_path, subtitles_path=subtitles_path)
    if not video:
        logger.log(u'Exception caught in subliminal.scan_video for {} {}'.format
                   (subtitles_info['show_name'], episode_num(subtitles_info['season'], subtitles_info['episode']) or
                    episode_num(subtitles_info['season'], subtitles_info['episode'], numbering='absolute')), logger.DEBUG)
        return existing_subtitles, None

    providers = enabled_service_list()
    provider_configs = {'addic7ed': {'username': sickbeard.ADDIC7ED_USER,
                                     'password': sickbeard.ADDIC7ED_PASS},
                        'legendastv': {'username': sickbeard.LEGENDASTV_USER,
                                       'password': sickbeard.LEGENDASTV_PASS},
                        'opensubtitles': {'username': sickbeard.OPENSUBTITLES_USER,
                                          'password': sickbeard.OPENSUBTITLES_PASS}}

    pool = ProviderPool(providers=providers, provider_configs=provider_configs)

    try:
        subtitles_list = pool.list_subtitles(video, languages)

        for provider in providers:
            if provider in pool.discarded_providers:
                logger.log(u'Could not search in {} provider. Discarding for now'.format(provider), logger.DEBUG)

        if not subtitles_list:
            logger.log(u'No subtitles found for {} {}'.format
                       (subtitles_info['show_name'], episode_num(subtitles_info['season'], subtitles_info['episode']) or
                        episode_num(subtitles_info['season'], subtitles_info['episode'], numbering='absolute')), logger.DEBUG)
            return existing_subtitles, None

        for subtitle in subtitles_list:
            score = subliminal.score.compute_score(subtitle, video, hearing_impaired=sickbeard.SUBTITLES_HEARING_IMPAIRED)
            logger.log(u'[{}] Subtitle score for {} is: {} (min={})'.format
                       (subtitle.provider_name, subtitle.id, score, user_score), logger.DEBUG)

        found_subtitles = pool.download_best_subtitles(subtitles_list, video, languages=languages,
                                                       hearing_impaired=sickbeard.SUBTITLES_HEARING_IMPAIRED,
                                                       min_score=user_score, only_one=not sickbeard.SUBTITLES_MULTI)

        subliminal.save_subtitles(video, found_subtitles, directory=subtitles_path,
                                  single=not sickbeard.SUBTITLES_MULTI)
    except IOError as error:
        if 'No space left on device' in ex(error):
            logger.log(u'Not enough space on the drive to save subtitles', logger.WARNING)
        else:
            logger.log(traceback.format_exc(), logger.WARNING)
    except Exception:
        logger.log(u'Error occurred when downloading subtitles for: {}'.format(video_path))
        logger.log(traceback.format_exc(), logger.ERROR)
        return existing_subtitles, None

    for subtitle in found_subtitles:
        subtitle_path = subliminal.subtitle.get_subtitle_path(video.name,
                                                              None if not sickbeard.SUBTITLES_MULTI else
                                                              subtitle.language)
        if subtitles_path is not None:
            subtitle_path = os.path.join(subtitles_path, os.path.split(subtitle_path)[1])

        sickbeard.helpers.chmodAsParent(subtitle_path)
        sickbeard.helpers.fixSetGroupID(subtitle_path)

        if sickbeard.SUBTITLES_HISTORY:
            logger.log(u'history.logSubtitle {}, {}'.format
                       (subtitle.provider_name, subtitle.language.opensubtitles), logger.DEBUG)

            history.logSubtitle(subtitles_info['show_indexerid'], subtitles_info['season'],
                                subtitles_info['episode'], subtitles_info['status'], subtitle)

        if sickbeard.SUBTITLES_EXTRA_SCRIPTS and isMediaFile(video_path) and not sickbeard.EMBEDDED_SUBTITLES_ALL:
            run_subs_extra_scripts(subtitles_info, subtitle, video, single=not sickbeard.SUBTITLES_MULTI)

    new_subtitles = sorted({subtitle.language.opensubtitles for subtitle in found_subtitles})
    current_subtitles = sorted({subtitle for subtitle in new_subtitles + existing_subtitles}) if existing_subtitles else new_subtitles
    if not sickbeard.SUBTITLES_MULTI and len(found_subtitles) == 1:
        new_code = found_subtitles[0].language.opensubtitles
        if new_code not in existing_subtitles:
            current_subtitles.remove(new_code)
        current_subtitles.append('und')

    return current_subtitles, new_subtitles
Example #9
0
    def subtitles_download_in_pp():  # pylint: disable=too-many-locals, too-many-branches
        logger.log(u'Checking for needed subtitles in Post-Process folder', logger.INFO)

        providers = enabled_service_list()
        provider_configs = {'addic7ed': {'username': sickbeard.ADDIC7ED_USER,
                                         'password': sickbeard.ADDIC7ED_PASS},
                            'legendastv': {'username': sickbeard.LEGENDASTV_USER,
                                           'password': sickbeard.LEGENDASTV_PASS},
                            'opensubtitles': {'username': sickbeard.OPENSUBTITLES_USER,
                                              'password': sickbeard.OPENSUBTITLES_PASS}}

        pool = ProviderPool(providers=providers, provider_configs=provider_configs)

        # Search for all wanted languages
        languages = {from_code(language) for language in wanted_languages()}
        if not languages:
            return

        run_post_process = False
        # Check if PP folder is set
        if sickbeard.TV_DOWNLOAD_DIR and ek(os.path.isdir, sickbeard.TV_DOWNLOAD_DIR):
            for root, _, files in ek(os.walk, sickbeard.TV_DOWNLOAD_DIR, topdown=False):
                for video_filename in sorted(files):
                    try:
                        # Remove non release groups from video file. Needed to match subtitles
                        new_video_filename = remove_non_release_groups(video_filename)
                        if new_video_filename != video_filename:
                            os.rename(video_filename, new_video_filename)
                            video_filename = new_video_filename
                    except Exception as error:
                        logger.log(u'Could not remove non release groups from video file. Error: %r'
                                   % ex(error), logger.DEBUG)
                    if isMediaFile(video_filename):
                        try:
                            video = subliminal.scan_video(os.path.join(root, video_filename),
                                                          subtitles=False, embedded_subtitles=False)
                            subtitles_list = pool.list_subtitles(video, languages)

                            if not subtitles_list:
                                logger.log(u'No subtitles found for %s'
                                           % ek(os.path.join, root, video_filename), logger.DEBUG)
                                continue

                            logger.log(u'Found subtitle(s) canditate(s) for %s' % video_filename, logger.INFO)
                            hearing_impaired = sickbeard.SUBTITLES_HEARING_IMPAIRED
                            user_score = 132 if sickbeard.SUBTITLES_PERFECT_MATCH else 111
                            found_subtitles = pool.download_best_subtitles(subtitles_list, video, languages=languages,
                                                                           hearing_impaired=hearing_impaired,
                                                                           min_score=user_score,
                                                                           only_one=not sickbeard.SUBTITLES_MULTI)

                            for subtitle in subtitles_list:
                                matches = subtitle.get_matches(video, hearing_impaired=sickbeard.SUBTITLES_HEARING_IMPAIRED)
                                score = subliminal.subtitle.compute_score(matches, video)
                                logger.log(u"[%s] Subtitle score for %s is: %s (min=%s)"
                                           % (subtitle.provider_name, subtitle.id, score, user_score), logger.DEBUG)

                            downloaded_languages = set()
                            for subtitle in found_subtitles:
                                logger.log(u"Found subtitle for %s in %s provider with language %s"
                                           % (os.path.join(root, video_filename), subtitle.provider_name,
                                              subtitle.language.opensubtitles), logger.DEBUG)
                                subliminal.save_subtitles(video, found_subtitles, directory=root,
                                                          single=not sickbeard.SUBTITLES_MULTI)

                                subtitles_multi = not sickbeard.SUBTITLES_MULTI
                                subtitle_path = subliminal.subtitle.get_subtitle_path(video.name,
                                                                                      None if subtitles_multi else
                                                                                      subtitle.language)
                                if root is not None:
                                    subtitle_path = ek(os.path.join, root, ek(os.path.split, subtitle_path)[1])
                                sickbeard.helpers.chmodAsParent(subtitle_path)
                                sickbeard.helpers.fixSetGroupID(subtitle_path)

                                downloaded_languages.add(subtitle.language.opensubtitles)

                            # Don't run post processor unless at least one file has all of the needed subtitles
                            if not needs_subtitles(downloaded_languages):
                                run_post_process = True
                        except Exception as error:
                            logger.log(u"Error occurred when downloading subtitles for: %s. Error: %r"
                                       % (os.path.join(root, video_filename), ex(error)))
            if run_post_process:
                logger.log(u"Starting post-process with default settings now that we found subtitles")
                processTV.processDir(sickbeard.TV_DOWNLOAD_DIR)
Example #10
0
def download_subtitles(subtitles_info):  # pylint: disable=too-many-locals, too-many-branches, too-many-statements
    existing_subtitles = subtitles_info['subtitles']

    if not needs_subtitles(existing_subtitles):
        logger.log(u'Episode already has all needed subtitles, skipping %s S%02dE%02d'
                   % (subtitles_info['show_name'], subtitles_info['season'], subtitles_info['episode']), logger.DEBUG)
        return existing_subtitles, None

    # Check if we really need subtitles
    languages = get_needed_languages(existing_subtitles)
    if not languages:
        logger.log(u'No subtitles needed for %s S%02dE%02d'
                   % (subtitles_info['show_name'], subtitles_info['season'],
                      subtitles_info['episode']), logger.DEBUG)
        return existing_subtitles, None

    subtitles_path = get_subtitles_path(subtitles_info['location']).encode(sickbeard.SYS_ENCODING)
    video_path = subtitles_info['location'].encode(sickbeard.SYS_ENCODING)
    user_score = 132 if sickbeard.SUBTITLES_PERFECT_MATCH else 111

    video = get_video(video_path, subtitles_path=subtitles_path)
    if not video:
        logger.log(u'Exception caught in subliminal.scan_video for %s S%02dE%02d'
                   % (subtitles_info['show_name'], subtitles_info['season'],
                      subtitles_info['episode']), logger.DEBUG)
        return existing_subtitles, None

    providers = enabled_service_list()
    provider_configs = {'addic7ed': {'username': sickbeard.ADDIC7ED_USER,
                                     'password': sickbeard.ADDIC7ED_PASS},
                        'legendastv': {'username': sickbeard.LEGENDASTV_USER,
                                       'password': sickbeard.LEGENDASTV_PASS},
                        'opensubtitles': {'username': sickbeard.OPENSUBTITLES_USER,
                                          'password': sickbeard.OPENSUBTITLES_PASS}}

    pool = ProviderPool(providers=providers, provider_configs=provider_configs)

    try:
        subtitles_list = pool.list_subtitles(video, languages)
        if not subtitles_list:
            logger.log(u'No subtitles found for %s S%02dE%02d on any provider'
                       % (subtitles_info['show_name'], subtitles_info['season'],
                          subtitles_info['episode']), logger.DEBUG)
            return existing_subtitles, None

        for subtitle in subtitles_list:
            matches = subtitle.get_matches(video, hearing_impaired=sickbeard.SUBTITLES_HEARING_IMPAIRED)
            score = subliminal.subtitle.compute_score(matches, video)
            logger.log(u"[%s] Subtitle score for %s is: %s (min=%s)"
                       % (subtitle.provider_name, subtitle.id, score, user_score), logger.DEBUG)

        found_subtitles = pool.download_best_subtitles(subtitles_list, video, languages=languages,
                                                       hearing_impaired=sickbeard.SUBTITLES_HEARING_IMPAIRED,
                                                       min_score=user_score, only_one=not sickbeard.SUBTITLES_MULTI)

        subliminal.save_subtitles(video, found_subtitles, directory=subtitles_path,
                                  single=not sickbeard.SUBTITLES_MULTI)
    except IOError as error:
        if 'No space left on device' in ex(error):
            logger.log(u'Not enough space on the drive to save subtitles', logger.WARNING)
        else:
            logger.log(traceback.format_exc(), logger.WARNING)
    except Exception:
        logger.log(u"Error occurred when downloading subtitles for: %s" % video_path)
        logger.log(traceback.format_exc(), logger.ERROR)
        return existing_subtitles, None

    for subtitle in found_subtitles:
        subtitle_path = subliminal.subtitle.get_subtitle_path(video.name,
                                                              None if not sickbeard.SUBTITLES_MULTI else
                                                              subtitle.language)
        if subtitles_path is not None:
            subtitle_path = ek(os.path.join, subtitles_path, ek(os.path.split, subtitle_path)[1])

        sickbeard.helpers.chmodAsParent(subtitle_path)
        sickbeard.helpers.fixSetGroupID(subtitle_path)

        if sickbeard.SUBTITLES_HISTORY:
            logger.log(u'history.logSubtitle %s, %s' %
                       (subtitle.provider_name, subtitle.language.opensubtitles), logger.DEBUG)

            history.logSubtitle(subtitles_info['show_indexerid'], subtitles_info['season'],
                                subtitles_info['episode'], subtitles_info['status'], subtitle)

        if sickbeard.SUBTITLES_EXTRA_SCRIPTS and isMediaFile(video_path) and not sickbeard.EMBEDDED_SUBTITLES_ALL:
            run_subs_extra_scripts(subtitles_info, subtitle, video, single=not sickbeard.SUBTITLES_MULTI)

    new_subtitles = sorted({subtitle.language.opensubtitles for subtitle in found_subtitles})
    current_subtitles = sorted({subtitle for subtitle in new_subtitles + existing_subtitles}) if existing_subtitles else new_subtitles
    if not sickbeard.SUBTITLES_MULTI and len(found_subtitles) == 1:
        new_code = found_subtitles[0].language.opensubtitles
        if new_code not in existing_subtitles:
            current_subtitles.remove(new_code)
        current_subtitles.append('und')

    return current_subtitles, new_subtitles
Example #11
0
def test_provider_pool_iter(mock_providers):
    pool = ProviderPool()
    assert len(list(pool)) == 0
    pool['tvsubtitles']
    assert len(list(pool)) == 1
Example #12
0
def test_provider_pool_del_keyerror():
    pool = ProviderPool()
    with pytest.raises(KeyError):
        del pool['addic7ed']
Example #13
0
def download(obj, provider, language, age, directory, encoding, single, force,
             hearing_impaired, min_score, verbose, path):
    """Download best subtitles.

    PATH can be an directory containing videos, a video file path or a video file name. It can be used multiple times.

    If an existing subtitle is detected (external or embedded) in the correct language, the download is skipped for
    the associated video.

    """
    # process parameters
    language = set(language)

    # scan videos
    videos = []
    ignored_videos = []
    errored_paths = []
    with click.progressbar(path,
                           label='Collecting videos',
                           item_show_func=lambda p: p or '') as bar:
        for p in bar:
            logger.debug('Collecting path %s', p)

            # non-existing
            if not os.path.exists(p):
                try:
                    video = Video.fromname(p)
                except:
                    logger.exception(
                        'Unexpected error while collecting non-existing path %s',
                        p)
                    errored_paths.append(p)
                    continue
                videos.append(video)
                continue

            # directories
            if os.path.isdir(p):
                try:
                    scanned_videos = scan_videos(p,
                                                 subtitles=not force,
                                                 embedded_subtitles=not force,
                                                 subtitles_dir=directory)
                except:
                    logger.exception(
                        'Unexpected error while collecting directory path %s',
                        p)
                    errored_paths.append(p)
                    continue
                for video in scanned_videos:
                    if check_video(video,
                                   languages=language,
                                   age=age,
                                   undefined=single):
                        videos.append(video)
                    else:
                        ignored_videos.append(video)
                continue

            # other inputs
            try:
                video = scan_video(p,
                                   subtitles=not force,
                                   embedded_subtitles=not force,
                                   subtitles_dir=directory)
            except:
                logger.exception('Unexpected error while collecting path %s',
                                 p)
                errored_paths.append(p)
                continue
            if check_video(video,
                           languages=language,
                           age=age,
                           undefined=single):
                videos.append(video)
            else:
                ignored_videos.append(video)

    # output errored paths
    if verbose > 0:
        for p in errored_paths:
            click.secho('%s errored' % p, fg='red')

    # output ignored videos
    if verbose > 1:
        for video in ignored_videos:
            click.secho(
                '%s ignored - subtitles: %s / age: %d day%s' %
                (os.path.split(video.name)[1],
                 ', '.join(str(s) for s in video.subtitle_languages)
                 or 'none', video.age.days, 's' if video.age.days > 1 else ''),
                fg='yellow')

    # report collected videos
    click.echo('%s video%s collected / %s video%s ignored / %s error%s' % (
        click.style(
            str(len(videos)), bold=True, fg='green' if videos else None),
        's' if len(videos) > 1 else '',
        click.style(str(len(ignored_videos)),
                    bold=True,
                    fg='yellow' if ignored_videos else None),
        's' if len(ignored_videos) > 1 else '',
        click.style(str(len(errored_paths)),
                    bold=True,
                    fg='red' if errored_paths else None),
        's' if len(errored_paths) > 1 else '',
    ))

    # exit if no video collected
    if not videos:
        return

    # download best subtitles
    downloaded_subtitles = defaultdict(list)
    with ProviderPool(providers=provider,
                      provider_configs=obj['provider_configs']) as pool:
        with click.progressbar(
                videos,
                label='Downloading subtitles',
                item_show_func=lambda v: os.path.split(v.name)[1]
                if v is not None else '') as bar:
            for v in bar:
                subtitles = pool.download_best_subtitles(
                    pool.list_subtitles(v, language - v.subtitle_languages),
                    v,
                    language,
                    min_score=v.scores['hash'] * min_score / 100,
                    hearing_impaired=hearing_impaired,
                    only_one=single)
                downloaded_subtitles[v] = subtitles

    # save subtitles
    total_subtitles = 0
    for v, subtitles in downloaded_subtitles.items():
        saved_subtitles = save_subtitles(v,
                                         subtitles,
                                         single=single,
                                         directory=directory,
                                         encoding=encoding)
        total_subtitles += len(saved_subtitles)

        if verbose > 0:
            click.echo(
                '%s subtitle%s downloaded for %s' %
                (click.style(str(len(saved_subtitles)), bold=True), 's' if
                 len(saved_subtitles) > 1 else '', os.path.split(v.name)[1]))

        if verbose > 1:
            for s in saved_subtitles:
                matches = s.get_matches(v, hearing_impaired=hearing_impaired)
                score = compute_score(matches, v)

                # score color
                score_color = None
                if isinstance(v, Movie):
                    if score < v.scores['title']:
                        score_color = 'red'
                    elif score < v.scores['title'] + v.scores[
                            'year'] + v.scores['release_group']:
                        score_color = 'yellow'
                    else:
                        score_color = 'green'
                elif isinstance(v, Episode):
                    if score < v.scores['series'] + v.scores[
                            'season'] + v.scores['episode']:
                        score_color = 'red'
                    elif score < (v.scores['series'] + v.scores['season'] +
                                  v.scores['episode'] +
                                  v.scores['release_group']):
                        score_color = 'yellow'
                    else:
                        score_color = 'green'

                # scale score from 0 to 100 taking out preferences
                scaled_score = score
                if s.hearing_impaired == hearing_impaired:
                    scaled_score -= v.scores['hearing_impaired']
                scaled_score *= 100 / v.scores['hash']

                # echo some nice colored output
                click.echo(
                    '  - [{score}] {language} subtitle from {provider_name} (match on {matches})'
                    .format(score=click.style('{:5.1f}'.format(scaled_score),
                                              fg=score_color,
                                              bold=score >= v.scores['hash']),
                            language=s.language.name
                            if s.language.country is None else '%s (%s)' %
                            (s.language.name, s.language.country.name),
                            provider_name=s.provider_name,
                            matches=', '.join(
                                sorted(matches, key=v.scores.get,
                                       reverse=True))))

    if verbose == 0:
        click.echo('Downloaded %s subtitle%s' %
                   (click.style(str(total_subtitles), bold=True),
                    's' if total_subtitles > 1 else ''))
Example #14
0
    def subtitles_download_in_pp():  # pylint: disable=too-many-locals, too-many-branches, too-many-statements
        logger.log(u'Checking for needed subtitles in Post-Process folder', logger.INFO)

        providers = enabled_service_list()
        provider_configs = {'addic7ed': {'username': sickbeard.ADDIC7ED_USER,
                                         'password': sickbeard.ADDIC7ED_PASS},
                            'itasa': {'username': sickbeard.ITASA_USER,
                                      'password': sickbeard.ITASA_PASS},
                            'legendastv': {'username': sickbeard.LEGENDASTV_USER,
                                           'password': sickbeard.LEGENDASTV_PASS},
                            'opensubtitles': {'username': sickbeard.OPENSUBTITLES_USER,
                                              'password': sickbeard.OPENSUBTITLES_PASS}}

        pool = ProviderPool(providers=providers, provider_configs=provider_configs)

        # Search for all wanted languages
        languages = {from_code(language) for language in wanted_languages()}
        if not languages:
            return

        # Dict of language exceptions to use with subliminal
        language_exceptions = {'pt-br': 'pob'}

        run_post_process = False
        # Check if PP folder is set
        if sickbeard.TV_DOWNLOAD_DIR and os.path.isdir(sickbeard.TV_DOWNLOAD_DIR):

            for root, _, files in os.walk(sickbeard.TV_DOWNLOAD_DIR, topdown=False):
                rar_files = [rar_file for rar_file in files if isRarFile(rar_file)]
                if rar_files and sickbeard.UNPACK:
                    video_files = [video_file for video_file in files if isMediaFile(video_file)]
                    if u'_UNPACK' not in root and (not video_files or root == sickbeard.TV_DOWNLOAD_DIR):
                        logger.log(u'Found rar files in post-process folder: {0}'.format(rar_files), logger.DEBUG)
                        result = processTV.ProcessResult()
                        processTV.unRAR(root, rar_files, False, result)
                elif rar_files and not sickbeard.UNPACK:
                    logger.log(u'Unpack is disabled. Skipping: {0}'.format(rar_files), logger.WARNING)

            for root, _, files in os.walk(sickbeard.TV_DOWNLOAD_DIR, topdown=False):
                for filename in sorted(files):
                    try:
                        # Remove non release groups from video file. Needed to match subtitles
                        new_filename = remove_non_release_groups(filename)
                        if new_filename != filename:
                            os.rename(filename, new_filename)
                            filename = new_filename
                    except Exception as error:
                        logger.log(u"Couldn't remove non release groups from video file. Error: {0}".format
                                   (ex(error)), logger.DEBUG)

                    # Delete unwanted subtitles before downloading new ones
                    if sickbeard.SUBTITLES_MULTI and sickbeard.SUBTITLES_KEEP_ONLY_WANTED and filename.rpartition('.')[2] in subtitle_extensions:
                        subtitle_language = filename.rsplit('.', 2)[1].lower()
                        if len(subtitle_language) == 2 and subtitle_language in language_converters['opensubtitles'].codes:
                            subtitle_language = Language.fromcode(subtitle_language, 'alpha2').opensubtitles
                        elif subtitle_language in language_exceptions:
                            subtitle_language = language_exceptions.get(subtitle_language, subtitle_language)
                        elif subtitle_language not in language_converters['opensubtitles'].codes:
                            subtitle_language = 'unknown'
                        if subtitle_language not in sickbeard.SUBTITLES_LANGUAGES:
                            try:
                                os.remove(os.path.join(root, filename))
                                logger.log(u"Deleted '{0}' because we don't want subtitle language '{1}'. We only want '{2}' language(s)".format
                                           (filename, subtitle_language, ','.join(sickbeard.SUBTITLES_LANGUAGES)), logger.DEBUG)
                            except Exception as error:
                                logger.log(u"Couldn't delete subtitle: {0}. Error: {1}".format(filename, ex(error)), logger.DEBUG)

                    if isMediaFile(filename) and processTV.subtitles_enabled(filename):
                        try:
                            video = get_video(os.path.join(root, filename), subtitles=False, embedded_subtitles=False)
                            subtitles_list = pool.list_subtitles(video, languages)

                            for provider in providers:
                                if provider in pool.discarded_providers:
                                    logger.log(u'Could not search in {0} provider. Discarding for now'.format(provider), logger.DEBUG)

                            if not subtitles_list:
                                logger.log(u'No subtitles found for {0}'.format
                                           (os.path.join(root, filename)), logger.DEBUG)
                                continue

                            logger.log(u'Found subtitle(s) canditate(s) for {0}'.format(filename), logger.INFO)
                            hearing_impaired = sickbeard.SUBTITLES_HEARING_IMPAIRED
                            user_score = 213 if sickbeard.SUBTITLES_PERFECT_MATCH else 198
                            found_subtitles = pool.download_best_subtitles(subtitles_list, video, languages=languages,
                                                                           hearing_impaired=hearing_impaired,
                                                                           min_score=user_score,
                                                                           only_one=not sickbeard.SUBTITLES_MULTI)

                            for subtitle in subtitles_list:
                                score = subliminal.score.compute_score(subtitle, video, hearing_impaired=sickbeard.SUBTITLES_HEARING_IMPAIRED)
                                logger.log(u'[{0}] Subtitle score for {1} is: {2} (min={3})'.format
                                           (subtitle.provider_name, subtitle.id, score, user_score), logger.DEBUG)

                            downloaded_languages = set()
                            for subtitle in found_subtitles:
                                logger.log(u'Found subtitle for {0} in {1} provider with language {2}'.format
                                           (os.path.join(root, filename), subtitle.provider_name,
                                            subtitle.language.opensubtitles), logger.INFO)
                                subliminal.save_subtitles(video, found_subtitles, directory=root,
                                                          single=not sickbeard.SUBTITLES_MULTI)

                                subtitles_multi = not sickbeard.SUBTITLES_MULTI
                                subtitle_path = subliminal.subtitle.get_subtitle_path(video.name,
                                                                                      None if subtitles_multi else
                                                                                      subtitle.language)
                                if root is not None:
                                    subtitle_path = os.path.join(root, os.path.split(subtitle_path)[1])
                                sickbeard.helpers.chmodAsParent(subtitle_path)
                                sickbeard.helpers.fixSetGroupID(subtitle_path)

                                downloaded_languages.add(subtitle.language.opensubtitles)

                            # Don't run post processor unless at least one file has all of the needed subtitles
                            if not needs_subtitles(downloaded_languages):
                                run_post_process = True
                        except Exception as error:
                            logger.log(u'Error occurred when downloading subtitles for: {0}. Error: {1}'.format
                                       (os.path.join(root, filename), ex(error)))
            if run_post_process:
                logger.log(u'Starting post-process with default settings now that we found subtitles')
                processTV.processDir(sickbeard.TV_DOWNLOAD_DIR)
Example #15
0
def download_subtitles(subtitles_info):  # pylint: disable=too-many-locals, too-many-branches, too-many-statements
    existing_subtitles = subtitles_info['subtitles']

    if not needs_subtitles(existing_subtitles):
        logger.log(
            u'Episode already has all needed subtitles, skipping {} {}'.format(
                subtitles_info['show_name'],
                episode_num(subtitles_info['season'],
                            subtitles_info['episode'])
                or episode_num(subtitles_info['season'],
                               subtitles_info['episode'],
                               numbering='absolute')), logger.DEBUG)
        return existing_subtitles, None

    # Check if we really need subtitles
    languages = get_needed_languages(existing_subtitles)
    if not languages:
        logger.log(
            u'No subtitles needed for {} {}'.format(
                subtitles_info['show_name'],
                episode_num(subtitles_info['season'],
                            subtitles_info['episode'])
                or episode_num(subtitles_info['season'],
                               subtitles_info['episode'],
                               numbering='absolute')), logger.DEBUG)
        return existing_subtitles, None

    try:
        subtitles_path = get_subtitles_path(subtitles_info['location']).encode(
            sickbeard.SYS_ENCODING)
        video_path = subtitles_info['location'].encode(sickbeard.SYS_ENCODING)
    except UnicodeEncodeError as error:
        logger.log(
            u'An error occurred while encoding \'{}\' with your current locale. '
            'Rename the file or try a different locale. Error: {}'.format(
                subtitles_info['location'], ex(error)), logger.WARNING)
        return existing_subtitles, None
    user_score = 367 if sickbeard.SUBTITLES_PERFECT_MATCH else 352

    video = get_video(video_path, subtitles_path=subtitles_path)
    if not video:
        logger.log(
            u'Exception caught in subliminal.scan_video for {} {}'.format(
                subtitles_info['show_name'],
                episode_num(subtitles_info['season'],
                            subtitles_info['episode'])
                or episode_num(subtitles_info['season'],
                               subtitles_info['episode'],
                               numbering='absolute')), logger.DEBUG)
        return existing_subtitles, None

    providers = enabled_service_list()
    provider_configs = {
        'addic7ed': {
            'username': sickbeard.ADDIC7ED_USER,
            'password': sickbeard.ADDIC7ED_PASS
        },
        'legendastv': {
            'username': sickbeard.LEGENDASTV_USER,
            'password': sickbeard.LEGENDASTV_PASS
        },
        'opensubtitles': {
            'username': sickbeard.OPENSUBTITLES_USER,
            'password': sickbeard.OPENSUBTITLES_PASS
        }
    }

    pool = ProviderPool(providers=providers, provider_configs=provider_configs)

    try:
        subtitles_list = pool.list_subtitles(video, languages)
        if not subtitles_list:
            logger.log(
                u'No subtitles found for {} {}'.format(
                    subtitles_info['show_name'],
                    episode_num(subtitles_info['season'],
                                subtitles_info['episode'])
                    or episode_num(subtitles_info['season'],
                                   subtitles_info['episode'],
                                   numbering='absolute')), logger.DEBUG)
            return existing_subtitles, None

        for subtitle in subtitles_list:
            score = subliminal.score.compute_score(
                subtitle,
                video,
                hearing_impaired=sickbeard.SUBTITLES_HEARING_IMPAIRED)
            logger.log(
                u'[{}] Subtitle score for {} is: {} (min={})'.format(
                    subtitle.provider_name, subtitle.id, score, user_score),
                logger.DEBUG)

        found_subtitles = pool.download_best_subtitles(
            subtitles_list,
            video,
            languages=languages,
            hearing_impaired=sickbeard.SUBTITLES_HEARING_IMPAIRED,
            min_score=user_score,
            only_one=not sickbeard.SUBTITLES_MULTI)

        subliminal.save_subtitles(video,
                                  found_subtitles,
                                  directory=subtitles_path,
                                  single=not sickbeard.SUBTITLES_MULTI)
    except IOError as error:
        if 'No space left on device' in ex(error):
            logger.log(u'Not enough space on the drive to save subtitles',
                       logger.WARNING)
        else:
            logger.log(traceback.format_exc(), logger.WARNING)
    except Exception:
        logger.log(u'Error occurred when downloading subtitles for: {}'.format(
            video_path))
        logger.log(traceback.format_exc(), logger.ERROR)
        return existing_subtitles, None

    for subtitle in found_subtitles:
        subtitle_path = subliminal.subtitle.get_subtitle_path(
            video.name,
            None if not sickbeard.SUBTITLES_MULTI else subtitle.language)
        if subtitles_path is not None:
            subtitle_path = ek(os.path.join, subtitles_path,
                               ek(os.path.split, subtitle_path)[1])

        sickbeard.helpers.chmodAsParent(subtitle_path)
        sickbeard.helpers.fixSetGroupID(subtitle_path)

        if sickbeard.SUBTITLES_HISTORY:
            logger.log(
                u'history.logSubtitle {}, {}'.format(
                    subtitle.provider_name, subtitle.language.opensubtitles),
                logger.DEBUG)

            history.logSubtitle(subtitles_info['show_indexerid'],
                                subtitles_info['season'],
                                subtitles_info['episode'],
                                subtitles_info['status'], subtitle)

        if sickbeard.SUBTITLES_EXTRA_SCRIPTS and isMediaFile(
                video_path) and not sickbeard.EMBEDDED_SUBTITLES_ALL:
            run_subs_extra_scripts(subtitles_info,
                                   subtitle,
                                   video,
                                   single=not sickbeard.SUBTITLES_MULTI)

    new_subtitles = sorted(
        {subtitle.language.opensubtitles
         for subtitle in found_subtitles})
    current_subtitles = sorted(
        {subtitle
         for subtitle in new_subtitles +
         existing_subtitles}) if existing_subtitles else new_subtitles
    if not sickbeard.SUBTITLES_MULTI and len(found_subtitles) == 1:
        new_code = found_subtitles[0].language.opensubtitles
        if new_code not in existing_subtitles:
            current_subtitles.remove(new_code)
        current_subtitles.append('und')

    return current_subtitles, new_subtitles