Example #1
0
def get_subtitle_list(movie_title, source_language_code,
                      destination_language_code):
    video = Video.fromname(movie_title)
    return list_subtitles(
        [video], {
            Language.fromalpha2(source_language_code),
            Language.fromalpha2(destination_language_code)
        }, FreePool)[video]
Example #2
0
def save_on_disk(title, source_subtitle, destination_subtitle):
    try:
        os.makedirs('assets/subtitles/' + title)
    except:
        pass
    save_subtitles(Video.fromname(title),
                   [source_subtitle, destination_subtitle],
                   directory='assets/subtitles/' + title)
Example #3
0
def find_video(name):
    """ Input: name of the file (movie or episode)
        Output: returns the video object corresponding to the name
        Throws: ValueError
    """

    video = Video.fromname(name)
    return video
Example #4
0
 def filter_video_files(files):
     videos = []
     for fil in files:
         _, ext = os.path.splitext(fil)
         if ext in [".jpeg", ".jpg", ".nfo", ".srt", ".sub", ".nbz"]:
             log.debug("Ignoring %s because of extension: %s", fil, ext)
             continue
         videos.append(Video.fromname(fil))
     return videos
Example #5
0
def subliminal():
    parser = subliminal_parser()
    args = parser.parse_args()

    # parse paths
    try:
        args.paths = [p.decode('utf-8') for p in args.paths]
    except UnicodeDecodeError:
        parser.error('argument paths: encodings is not utf-8: %r' % args.paths)

    # parse languages
    try:
        args.languages = {babelfish.Language.fromalpha2(l) for l in args.languages}
    except babelfish.Error:
        parser.error('argument -l/--languages: codes are not ISO-639-1: %r' % args.languages)

    # parse age
    if args.age is not None:
        match = re.match(r'^(?:(?P<weeks>\d+?)w)?(?:(?P<days>\d+?)d)?(?:(?P<hours>\d+?)h)?$', args.age)
        if not match:
            parser.error('argument -a/--age: invalid age: %r' % args.age)
        args.age = datetime.timedelta(**match.groupdict())

    # setup verbosity
    if args.verbose:
        logging.basicConfig(level=logging.DEBUG)
    elif not args.quiet:
        logging.basicConfig(level=logging.WARN)

    # configure cache
    cache_region.configure('dogpile.cache.dbm', arguments={'filename': os.path.expanduser(args.cache_file)})

    # scan videos
    videos = scan_videos([p for p in args.paths if os.path.exists(p)], subtitles=not args.force, age=args.age)

    # guess videos
    videos.extend([Video.fromguess(os.path.split(p)[1], guessit.guess_file_info(p, 'autodetect')) for p in args.paths
                   if not os.path.exists(p)])

    # download best subtitles
    subtitles = download_best_subtitles(videos, args.languages, providers=args.providers, provider_configs=None,
                                        single=args.single, min_score=args.min_score,
                                        hearing_impaired=args.hearing_impaired)

    # output result
    if not subtitles:
        if not args.quiet:
            sys.stderr.write('No subtitles downloaded\n')
        exit(1)
    if not args.quiet:
        subtitles_count = sum([len(s) for s in subtitles.values()])
        if subtitles_count == 1:
            print('%d subtitle downloaded' % subtitles_count)
        else:
            print('%d subtitles downloaded' % subtitles_count)
Example #6
0
def find_subs(filename, movie_dir):
    video = Video.fromname(filename)
    subtitles = download_best_subtitles([video], {Language("eng")})

    if len(subtitles[video]) == 0:
        print("No subs found")
        return

    best_sub = subtitles[video][0]
    save_subtitles(video, [best_sub], directory=movie_dir)
    return get_sub_path(movie_dir)
Example #7
0
def search_for_subtitle(nome_arquivo, languages):
    BASE_DIR = os.path.dirname(os.path.dirname(__file__))
    BASE_DIR = os.path.join("..", BASE_DIR)
    BASE_DIR = os.path.join(BASE_DIR, 'cli.dbm')
    try:
        languages = babelfish.Language.fromietf(languages)
    except babelfish.Error:
        pass

    video = Video.fromguess(nome_arquivo, guessit.guess_file_info(nome_arquivo))

    subtitle_downloaded = get_video_urls({video}, {languages} )
    infos = save_subtitles(subtitle_downloaded)
    return infos
Example #8
0
 def _refine_file(video_file) -> List[SeriesEpisodeInfo]:
     log.debug("Refining file %s", video_file)
     try:
         video = Video.fromname(video_file)
     except ValueError:
         log.error("Cannot guess video file type from: %s", video_file)
         return []
     refiner = sorted(refiner_manager.names())
     refine(video, episode_refiners=refiner, movie_refiners=refiner)
     log.debug("refine result: %r", video)
     if isinstance(video, Episode):
         log.debug("series: %s", video.series)
         log.debug("season: %s", video.season)
         if not video.season:
             log.error("No season defined !")
             return []
         if isinstance(video.season, list):
             video.season = video.season[0]
             log.error("Multi season found, only using first one: %s",
                       video.season)
         log.debug("episode: %s", video.episode)
         log.debug("title: %s", video.title)
         log.debug("series_tvdb_id: %s", video.series_tvdb_id)
         r = []
         # Support for double episode
         if not isinstance(video.episode, list):
             video.episode = [video.episode]
         for video_episode in video.episode:
             r.append(
                 SeriesEpisodeInfo(
                     series_episode_uid=SeriesEpisodeUid(
                         tv_db_id=video.series_tvdb_id,
                         season_number=video.season,
                         episode_number=video_episode,
                     ),
                     series_title=video.series,
                     episode_title=video.title,
                     quality=None,
                     video_languages=None,
                     subtitles_languages=None,
                     media_filename=video_file,
                     dirty=True,
                 ))
         return r
     elif isinstance(video, Movie):
         log.debug("movie: %s", video.title)
     return []
Example #9
0
def downloadSub(myFile, lang, path, verbose):
    cli = False
    print "--- Trying to download..."
    origWD = os.getcwd()  # current working directory
    os.chdir(path)  # change working directory to where the videos are
    if cli == True:
        # old subliminal:
        #if call(["subliminal", "-q", "-l", lang, "--", myFile]):  # try to download the subtitles
        # new subliminal
        if call(["subliminal", "download", "-l", lang, "--", myFile]):  # try to download the subtitles
            print "*** Could not find %s subtitles" % langName(lang).lower()
            subDownloads = foundLang("%s - not found" % lang)
        else:
            print "--- Downloaded %s subtitles" % langName(lang).lower()
            subDownloads = foundLang(lang)  # sending language code to be added
            # subName = "%s.%s.%s" % (os.path.splitext(myFile)[0], lang, "srt")
    else:
        video = Video.fromname(myFile)
        if verbose:
            print "--- Checking subtititles for \n    %s" % video
        # configure the cache
        #region.configure('dogpile.cache.dbm', arguments={'filename': 'cachefile.dbm'})
        my_region = region.configure('dogpile.cache.memory', arguments={'filename': 'cachefile.dbm'}, replace_existing_backend=True)
        if verbose:
            print "--- Searching for best subtitle..."
        #best_subtitles = download_best_subtitles([video], {lang}, providers=['podnapisi'])
        best_subtitles = download_best_subtitles([video], {lang}, providers=['podnapisi', 'opensubtitles', 'addic7ed'])
        #best_subtitles = download_best_subtitles([video], {lang})
        try:
            best_subtitle = best_subtitles[video][0]
        except:
            print "*** Could not find %s subtitles" % langName(lang).lower()
            subDownloads = foundLang("%s - not found" % lang)
        else:
            print "--- Downloaded %s subtitles" % langName(lang).lower()
            #if verbose:
            #    print "--- Score for this subtitle is %s" % compute_score(best_subtitle, video)
            subDownloads = foundLang(lang)  # sending language code to be added
            if verbose:
                print "--- Saving subtitles..."
            save_subtitles(video, [best_subtitle])
    os.chdir(origWD)  # change working directory back
    return subDownloads
Example #10
0
def scanme(paths, config):
    logging.info('scanme: %s' % paths)
    # configure cache
    region.configure('dogpile.cache.dbm', expiration_time=timedelta(days=30),  # @UndefinedVariable
                           arguments={'filename': cachefile_file, 'lock_factory': MutexLock})

    # scan videos
    #videos = scan_videos([p for p in paths if os.path.exists(p)],# subtitles=True,
    #                     embedded_subtitles=True, age=timedelta(days=config.get('Task').as_int('age')))
    videos = scan_videos(paths, age=timedelta(days=config.get('Task').as_int('age')))

    logging.info(videos)
    # guess videos
    videos.extend([Video.fromname(p) for p in paths  if not os.path.exists(p)])
    logging.info(videos)

    # download best subtitles
    languageset=set(Language(language) for language in config['General']['languages'])
    single=True
    if not config.get('General').as_bool('single') or len(languageset) > 1:
        single=False
    hearing_impaired=False
    if config.get('General').as_bool('hearing_impaired'):
        hearing_impaired=True
    providers = config['General']['providers']
    rv = {}
    for provider in providers:
        sec = config.get(provider)
        if sec != None:
            rv[provider] = {k: v for k, v in config.get(provider).items()}
    
    subtitles = download_best_subtitles(videos, languageset, min_score=config.get('General').as_int('min_score'),
                                        providers=providers, provider_configs=rv,
                                        hearing_impaired=hearing_impaired, only_one=single)

    # save them to disk, next to the video
    for v in videos:
        save_subtitles(v, subtitles[v])

    logging.debug(subtitles)
    logging.info('Scan Done!')  
    return subtitles
Example #11
0
def get_subtitles(video_path, ov_subtitles):
    """ # get subtitles and convert them to web vtt
        Args:
        video_path: absolute path to videos
        ov_subtitles: boolean (True if input has subtitles, False if not)
        return: empty string if no subtitles was found. Otherwise return dict of subtitle absolute location with str(Language) as key
    """
    languages_to_retrieve = {
        'eng',
        'fra',
    }
    webvtt_fullpath = {}
    webvtt_ov_fullpath = ''

    if ov_subtitles:
        try:
            webvtt_ov_fullpath = os.path.splitext(video_path)[0] + '_ov.vtt'
            extract_subtitle(video_path, webvtt_ov_fullpath)
        except:
            webvtt_ov_fullpath = ''

    try:
        video = Video.fromname(video_path)
    except ValueError:
        #This usually happens when there is not enough data for subliminal to guess
        webvtt_fullpath['ov'] = webvtt_ov_fullpath
        for lang in languages_to_retrieve:
            webvtt_fullpath[lang] = ''
        return webvtt_fullpath

    try:
        webvtt_fullpath = handle_subliminal_download(video, video_path,
                                                     languages_to_retrieve)
    except:
        webvtt_fullpath = {}

    webvtt_fullpath['ov'] = webvtt_ov_fullpath
    for lang in languages_to_retrieve:
        if lang not in webvtt_fullpath:
            webvtt_fullpath[lang] = ''
    return (webvtt_fullpath)
def main():
    """
    Main function

    """

    file_path, download_subs, show_omdb_info = get_args()
    video_file = Video.fromname(file_path)

    # Display the short info
    short_info = short_details(video_file)
    print(short_info)

    # If -i flag is set show the info from the omdb api
    if show_omdb_info is True:
        spinner = Spinner()
        spinner.start()
        omdb_details(video_file.title, video_file.year)
        spinner.stop()

    # If -d flag is set download the best matching subtitles
    if download_subs is True:
        spinner = Spinner()
        spinner.start()
        # Set the cache
        region.configure('dogpile.cache.dbm', arguments={'filename': 'cachefile.dbm'})
        # Download subtitles in serbian and english
        best_subtitles = download_best_subtitles([video_file], {Language('eng'),\
                        Language('srp')}, providers=None)
        spinner.stop()
        print(best_subtitles[video_file])
        best_subtitle_sr = best_subtitles[video_file][0]
        best_subtitle_en = best_subtitles[video_file][1]
        # Save the 2 subtitle files
        save_subtitles(video_file, [best_subtitle_sr])
        save_subtitles(video_file, [best_subtitle_en])
Example #13
0
def manual_search(path, language, hi, providers, providers_auth, sceneName, media_type):
    if hi == "True":
        hi = True
    else:
        hi = False
    language_set = set()
    for lang in ast.literal_eval(language):
        lang = alpha3_from_alpha2(lang)
        if lang == 'pob':
            language_set.add(Language('por', 'BR'))
        else:
            language_set.add(Language(lang))

    use_scenename = get_general_settings()[9]
    use_postprocessing = get_general_settings()[10]
    postprocessing_cmd = get_general_settings()[11]

    try:
        if sceneName == "None" or use_scenename is False:
            used_sceneName = False
            video = scan_video(path)
        else:
            used_sceneName = True
            video = Video.fromname(sceneName)
    except:
        logging.error("Error trying to get video information.")
    else:
        if media_type == "movie":
            max_score = 120.0
        elif media_type == "series":
            max_score = 360.0

        try:
            with AsyncProviderPool(max_workers=None, providers=providers, provider_configs=providers_auth) as p:
                subtitles = p.list_subtitles(video, language_set)
        except Exception as e:
            logging.exception("Error trying to get subtitle list from provider")
        else:
            subtitles_list = []
            for s in subtitles:
                {s: compute_score(s, video, hearing_impaired=hi)}
                if media_type == "movie":
                    matched = set(s.get_matches(video))
                    if hi == s.hearing_impaired:
                        matched.add('hearing_impaired')
                    not_matched = set(score.movie_scores.keys()) - matched
                    required = set(['title'])
                    if any(elem in required for elem in not_matched):
                        continue
                    if used_sceneName:
                        not_matched.remove('hash')
                elif media_type == "series":
                    matched = set(s.get_matches(video))
                    if hi == s.hearing_impaired:
                        matched.add('hearing_impaired')
                    not_matched = set(score.episode_scores.keys()) - matched
                    required = set(['series', 'season', 'episode'])
                    if any(elem in required for elem in not_matched):
                        continue
                    if used_sceneName:
                        not_matched.remove('hash')
                subtitles_list.append(dict(score=round((compute_score(s, video, hearing_impaired=hi) / max_score * 100), 2), language=alpha2_from_alpha3(s.language.alpha3), hearing_impaired=str(s.hearing_impaired), provider=s.provider_name, subtitle=codecs.encode(pickle.dumps(s), "base64").decode(), url=s.page_link, matches=list(matched), dont_matches=list(not_matched)))
            subtitles_dict = {}
            subtitles_dict = sorted(subtitles_list, key=lambda x: x['score'], reverse=True)
            return(subtitles_dict)
Example #14
0
def manual_search(path, language, hi, providers, providers_auth, sceneName, media_type):
    logging.debug('BAZARR Manually searching subtitles for this file: ' + path)

    subtitles_dict = {}

    if hi == "True":
        hi = True
    else:
        hi = False
    language_set = set()
    for lang in ast.literal_eval(language):
        lang = alpha3_from_alpha2(lang)
        if lang == 'pob':
            language_set.add(Language('por', 'BR'))
        else:
            language_set.add(Language(lang))

    use_scenename = settings.general.getboolean('use_scenename')
    use_postprocessing = settings.general.getboolean('use_postprocessing')
    postprocessing_cmd = settings.general.postprocessing_cmd

    try:
        if sceneName == "None" or use_scenename is False:
            used_sceneName = False
            video = scan_video(path)
        else:
            used_sceneName = True
            video = Video.fromname(sceneName)
    except:
        logging.exception("BAZARR Error trying to get video information for this file: " + path)
    else:
        if media_type == "movie":
            max_score = 120.0
        elif media_type == "series":
            max_score = 360.0

        try:
            with AsyncProviderPool(max_workers=None, providers=providers, provider_configs=providers_auth) as p:
                subtitles = p.list_subtitles(video, language_set)
        except Exception as e:
            logging.exception("BAZARR Error trying to get subtitle list from provider for this file: " + path)
        else:
            subtitles_list = []
            for s in subtitles:
                {s: compute_score(s, video, hearing_impaired=hi)}
                if media_type == "movie":
                    matched = set(s.get_matches(video))
                    if hi == s.hearing_impaired:
                        matched.add('hearing_impaired')
                    not_matched = set(score.movie_scores.keys()) - matched
                    required = set(['title'])
                    if any(elem in required for elem in not_matched):
                        continue
                    if used_sceneName:
                        not_matched.remove('hash')
                    if type(s) is LegendasTVSubtitle:
                        # The pickle doesn't work very well with RAR (rarfile.RarFile) or ZIP (zipfile.ZipFile)
                        s.archive.content = None
                elif media_type == "series":
                    matched = set(s.get_matches(video))
                    if hi == s.hearing_impaired:
                        matched.add('hearing_impaired')
                    not_matched = set(score.episode_scores.keys()) - matched
                    required = set(['series', 'season', 'episode'])
                    if any(elem in required for elem in not_matched):
                        continue
                    if used_sceneName:
                        not_matched.remove('hash')
                    if type(s) is LegendasTVSubtitle:
                        # The pickle doesn't work very well with RAR (rarfile.RarFile) or ZIP (zipfile.ZipFile)
                        s.archive.content = None
                subtitles_list.append(dict(score=round((compute_score(s, video, hearing_impaired=hi) / max_score * 100), 2), language=alpha2_from_alpha3(s.language.alpha3), hearing_impaired=str(s.hearing_impaired), provider=s.provider_name, subtitle=codecs.encode(pickle.dumps(s), "base64").decode(), url=s.page_link, matches=list(matched), dont_matches=list(not_matched)))
            subtitles_dict = sorted(subtitles_list, key=lambda x: x['score'], reverse=True)
            logging.debug('BAZARR ' + str(len(subtitles_dict)) + " subtitles have been found for this file: " + path)
            logging.debug('BAZARR Ended searching subtitles for this file: ' + path)
        return(subtitles_dict)
Example #15
0
def manual_download_subtitle(path, language, hi, subtitle, provider, providers_auth, sceneName, media_type):
    logging.debug('BAZARR Manually downloading subtitles for this file: ' + path)
    if hi == "True":
        hi = True
    else:
        hi = False
    subtitle = pickle.loads(codecs.decode(subtitle.encode(), "base64"))
    if media_type == 'series':
        type_of_score = 360
    elif media_type == 'movie':
        type_of_score = 120
    use_scenename = settings.general.getboolean('use_scenename')
    use_postprocessing = settings.general.getboolean('use_postprocessing')
    postprocessing_cmd = settings.general.postprocessing_cmd

    language = alpha3_from_alpha2(language)
    if language == 'pob':
        lang_obj = Language('por', 'BR')
    else:
        lang_obj = Language(language)

    try:
        if sceneName is None or use_scenename is False:
            used_sceneName = False
            video = scan_video(path)
        else:
            used_sceneName = True
            video = Video.fromname(sceneName)
    except Exception as e:
        logging.exception("BAZARR Error trying to get video information for this file: " + path)
        pass
    else:
        try:
            download_subtitles([subtitle], providers=provider, provider_configs=providers_auth)
            logging.debug('BAZARR Subtitles file downloaded for this file:' + path)
        except Exception as e:
            logging.exception('BAZARR Error downloading subtitles for this file ' + path)
            return None
        else:
            single = settings.general.getboolean('single_language')
            try:
                score = round(float(compute_score(subtitle, video, hearing_impaired=hi)) / type_of_score * 100, 2)
                if used_sceneName == True:
                    video = scan_video(path)
                if single is True:
                    result = save_subtitles(video, [subtitle], single=True, encoding='utf-8')
                else:
                    result = save_subtitles(video, [subtitle], encoding='utf-8')
            except Exception as e:
                logging.exception('BAZARR Error saving subtitles file to disk for this file:' + path)
                return None
            else:
                if len(result) > 0:
                    downloaded_provider = result[0].provider_name
                    downloaded_language = language_from_alpha3(result[0].language.alpha3)
                    downloaded_language_code2 = alpha2_from_alpha3(result[0].language.alpha3)
                    downloaded_language_code3 = result[0].language.alpha3
                    downloaded_path = get_subtitle_path(path, downloaded_language_code2)
                    logging.debug('BAZARR Subtitles file saved to disk: ' + downloaded_path)
                    message = downloaded_language + " subtitles downloaded from " + downloaded_provider + " with a score of " + unicode(score) + "% using manual search."

                    if use_postprocessing is True:
                        command = pp_replace(postprocessing_cmd, path, downloaded_path, downloaded_language, downloaded_language_code2, downloaded_language_code3)
                        try:
                            if os.name == 'nt':
                                codepage = subprocess.Popen("chcp", shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
                                # wait for the process to terminate
                                out_codepage, err_codepage = codepage.communicate()
                                encoding = out_codepage.split(':')[-1].strip()

                            process = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
                            # wait for the process to terminate
                            out, err = process.communicate()

                            if os.name == 'nt':
                                out = out.decode(encoding)

                        except:
                            if out == "":
                                logging.error('BAZARR Post-processing result for file ' + path + ' : Nothing returned from command execution')
                            else:
                                logging.error('BAZARR Post-processing result for file ' + path + ' : ' + out)
                        else:
                            if out == "":
                                logging.info('BAZARR Post-processing result for file ' + path + ' : Nothing returned from command execution')
                            else:
                                logging.info('BAZARR Post-processing result for file ' + path + ' : ' + out)

                    return message
                else:
                    logging.error("BAZARR Tried to manually download a subtitles for file: " + path + " but we weren't able to do (probably throttled by " + str(subtitle.provider_name) + ". Please retry later or select a subtitles from another provider.")
                    return None
    logging.debug('BAZARR Ended manually downloading subtitles for file: ' + path)
Example #16
0
def download(directory, language='eng', country=None, verbose=False):
    """
    Takes in a directory path, walks through the file tree, and downloads subtitles for any video files found.
    Renames the subtitle file to match the video's name (in order to make it compatible with Roku Media Player.)

    :param (str) directory: Directory where video files or folders are located.
    :param (str) language : [optional] Desired language for subtitles, expressed as a 3-letter ISO-639-3 code.
                            Visit https://bit.ly/29fjNpm for a list of language codes.
    :param (str) country : [optional] Country code (needed in addition to language code for certain languages).
    :param (bool) verbose : [optional] Prints more output to the console.

    Examples:
    1. download_subtitles('/Users/Laura/Movies')
    2. download_subtitles(directory='./Users/Tim/TV Shows', language='spa', verbose=True)
    """
    successful = 0
    videos = []
    incompatible = []

    # Walk the file path, identifying video files that do not have a matching .srt (subtitle) file in the same folder.
    # Then collect the file and directory names within list 'videos' that we will iterate over later.
    directory = os.path.abspath(directory)
    if not os.path.isdir(directory):
        print(
            f'>>> Error: "{directory}" is not a valid directory. Please try again.'
        )
        return False
    print('>>> Walking the file tree...')
    for subdir, dirs, files in os.walk(directory):
        if verbose:
            print(subdir)
        for file in files:
            if file.endswith((".mp4", ".avi", ".mkv",
                              ".part")) and not file.startswith('.'):
                movie_title = re.split('.mp4|.avi|.mkv', file)[0]
                if file.endswith('.avi'):
                    incompatible.append(movie_title)
                if os.path.isfile(
                        str(os.path.join(subdir, movie_title) + '.srt')):
                    continue
                else:
                    videos.append([movie_title, file, subdir])

    # check to see if video files found
    if not videos:
        print('No movie files without subtitles found in folder.')
        return False

    # iterate over 'videos' and download subtitles
    with click.progressbar(videos, label='Searching for subtitles') as bar:
        for movie_title, file, subdir in bar:

            try:
                video = Video.fromname(file)

            except ValueError:
                if verbose:
                    print(f'Could not find a match for file: {file}')
                continue

            try:
                if country is not None:
                    lang = Language(language, country)
                else:
                    lang = Language(language)
                os.chdir(subdir)
                best_subtitles = download_best_subtitles(
                    [video], {Language(language)},
                    providers=['opensubtitles', 'thesubdb', 'tvsubtitles'])
                best_subtitle = best_subtitles[video][0]
                save_subtitles(video, [best_subtitle])
                if verbose:
                    print(f'Successfully downloaded subtitle for: {file}')

            except IndexError:
                if verbose:
                    print(f'Subtitles not found online for: {file}')
                continue

            successful += 1

            if language == 'eng':
                try:
                    old_name = str(os.path.join(subdir,
                                                movie_title)) + '.en.srt'
                    new_name = str(os.path.join(subdir, movie_title)) + '.srt'
                    if verbose:
                        print(f'Old name: {old_name}')
                        print(f'New name: {new_name}')
                        print(
                            f'Path    : {str(os.path.join(subdir, movie_title))}'
                        )
                    os.rename(old_name, new_name)

                except FileNotFoundError:
                    if verbose:
                        print(
                            f"Couldn't rename subtitle file for: {movie_title}."
                        )
                    continue

    print()
    print(f'>>> Finished!')
    print(
        f'>>> Fetched {successful} / {len(videos)} subtitle files successfully.'
    )
    if verbose:
        print('Movies incompatible with Roku:')
        pprint(incompatible)
    return
Example #17
0
def download_subtitle(path, language, hi, providers, providers_auth, sceneName, media_type):
    logging.debug('BAZARR Searching subtitles for this file: ' + path)
    if hi == "True":
        hi = True
    else:
        hi = False
    language_set = set()
    if language == 'pob':
        language_set.add(Language('por', 'BR'))
    else:
        language_set.add(Language(language))

    use_scenename = settings.general.getboolean('use_scenename')
    minimum_score = settings.general.minimum_score
    minimum_score_movie = settings.general.minimum_score_movie
    use_postprocessing = settings.general.getboolean('use_postprocessing')
    postprocessing_cmd = settings.general.postprocessing_cmd

    try:
        if sceneName == "None" or use_scenename is False:
            used_sceneName = False
            video = scan_video(path)
        else:
            used_sceneName = True
            video = Video.fromname(sceneName)
    except Exception as e:
        logging.exception("BAZARR Error trying to get video information for this file: " + path)
        pass
    else:
        if media_type == "movie":
            max_score = 120.0
        elif media_type == "series":
            max_score = 360.0

        try:
            with AsyncProviderPool(max_workers=None, providers=providers, provider_configs=providers_auth) as p:
                subtitles = p.list_subtitles(video, language_set)
        except Exception as e:
            logging.exception("BAZARR Error trying to get subtitle list from provider for this file: " + path)
        else:
            subtitles_list = []
            try:
                sorted_subtitles = sorted([(s, compute_score(s, video, hearing_impaired=hi)) for s in subtitles], key=operator.itemgetter(1), reverse=True)
            except Exception as e:
                logging.exception('BAZARR Exception raised while trying to compute score for this file: ' + path)
                return None
            else:
                for s, preliminary_score in sorted_subtitles:
                    if media_type == "movie":
                        if (preliminary_score / max_score * 100) < int(minimum_score_movie):
                            continue
                        matched = set(s.get_matches(video))
                        if hi == s.hearing_impaired:
                            matched.add('hearing_impaired')
                        not_matched = set(score.movie_scores.keys()) - matched
                        required = set(['title'])
                        if any(elem in required for elem in not_matched):
                            continue
                    elif media_type == "series":
                        if (preliminary_score / max_score * 100) < int(minimum_score):
                            continue
                        matched = set(s.get_matches(video))
                        if hi == s.hearing_impaired:
                            matched.add('hearing_impaired')
                        not_matched = set(score.episode_scores.keys()) - matched
                        required = set(['series', 'season', 'episode'])
                        if any(elem in required for elem in not_matched):
                            continue
                    subtitles_list.append(s)
                logging.debug('BAZARR ' + str(len(subtitles_list)) + " subtitles have been found for this file: " + path)
                if len(subtitles_list) > 0:
                    try:
                        download_result = False
                        for subtitle in subtitles_list:
                            download_result = p.download_subtitle(subtitle)
                            if download_result:
                                logging.debug('BAZARR Subtitles file downloaded from ' + str(subtitle.provider_name) + ' for this file: ' + path)
                                break
                            else:
                                logging.warning('BAZARR Subtitles file skipped from ' + str(subtitle.provider_name) + ' for this file: ' + path + ' because no content was returned by the provider (probably throttled).')
                                continue
                        if not download_result:
                            logging.error('BAZARR Tried to download a subtitles for file: ' + path + " but we weren't able to do it this time (probably being throttled). Going to retry on next search.")
                            return None
                    except Exception as e:
                        logging.exception('BAZARR Error downloading subtitles for this file ' + path)
                        return None
                    else:
                        try:
                            calculated_score = round(float(compute_score(subtitle, video, hearing_impaired=hi)) / max_score * 100, 2)
                            if used_sceneName:
                                video = scan_video(path)
                            single = settings.general.getboolean('single_language')
                            if single is True:
                                result = save_subtitles(video, [subtitle], single=True, encoding='utf-8')
                            else:
                                result = save_subtitles(video, [subtitle], encoding='utf-8')
                        except Exception as e:
                            logging.exception('BAZARR Error saving subtitles file to disk for this file:' + path)
                            pass
                        else:
                            downloaded_provider = result[0].provider_name
                            downloaded_language = language_from_alpha3(result[0].language.alpha3)
                            downloaded_language_code2 = alpha2_from_alpha3(result[0].language.alpha3)
                            downloaded_language_code3 = result[0].language.alpha3
                            downloaded_path = get_subtitle_path(path, downloaded_language_code2)
                            logging.debug('BAZARR Subtitles file saved to disk: ' + downloaded_path)
                            if used_sceneName:
                                message = downloaded_language + " subtitles downloaded from " + downloaded_provider + " with a score of " + unicode(calculated_score) + "% using this scene name: " + sceneName
                            else:
                                message = downloaded_language + " subtitles downloaded from " + downloaded_provider + " with a score of " + unicode(calculated_score) + "% using filename guessing."

                            if use_postprocessing is True:
                                command = pp_replace(postprocessing_cmd, path, downloaded_path, downloaded_language, downloaded_language_code2, downloaded_language_code3)
                                try:
                                    if os.name == 'nt':
                                        codepage = subprocess.Popen("chcp", shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
                                        # wait for the process to terminate
                                        out_codepage, err_codepage = codepage.communicate()
                                        encoding = out_codepage.split(':')[-1].strip()

                                    process = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
                                    # wait for the process to terminate
                                    out, err = process.communicate()

                                    if os.name == 'nt':
                                        out = out.decode(encoding)

                                except:
                                    if out == "":
                                        logging.error('BAZARR Post-processing result for file ' + path + ' : Nothing returned from command execution')
                                    else:
                                        logging.error('BAZARR Post-processing result for file ' + path + ' : ' + out)
                                else:
                                    if out == "":
                                        logging.info('BAZARR Post-processing result for file ' + path + ' : Nothing returned from command execution')
                                    else:
                                        logging.info('BAZARR Post-processing result for file ' + path + ' : ' + out)

                            return message
                else:
                    logging.debug('BAZARR No subtitles were found for this file: ' + path)
                    return None
    logging.debug('BAZARR Ended searching subtitles for file: ' + path)
Example #18
0
def download(
    obj,
    provider,
    language,
    age,
    directory,
    encoding,
    single,
    force,
    hearing_impaired,
    min_score,
    max_workers,
    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, age=age
                    )
                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 AsyncProviderPool(max_workers=max_workers, providers=provider, provider_configs=obj["provider_configs"]) as p:
        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:
                scores = get_scores(v)
                subtitles = p.download_best_subtitles(
                    p.list_subtitles(v, language - v.subtitle_languages),
                    v,
                    language,
                    min_score=scores["hash"] * min_score / 100,
                    hearing_impaired=hearing_impaired,
                    only_one=single,
                )
                downloaded_subtitles[v] = subtitles

    # TODO: warn about discarded providers
    # 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)
                score = compute_score(s, v)

                # score color
                score_color = None
                scores = get_scores(v)
                if isinstance(v, Movie):
                    if score < scores["title"]:
                        score_color = "red"
                    elif score < scores["title"] + scores["year"] + scores["release_group"]:
                        score_color = "yellow"
                    else:
                        score_color = "green"
                elif isinstance(v, Episode):
                    if score < scores["series"] + scores["season"] + scores["episode"]:
                        score_color = "red"
                    elif score < scores["series"] + scores["season"] + scores["episode"] + 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 -= scores["hearing_impaired"]
                scaled_score *= 100 / 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 >= 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=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 #19
0
def download(obj, provider, refiner, language, age, directory, encoding,
             single, force, hearing_impaired, min_score, max_workers, archives,
             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
                if not force:
                    video.subtitle_languages |= set(
                        search_external_subtitles(
                            video.name, directory=directory).values())
                refine(video,
                       episode_refiners=refiner,
                       movie_refiners=refiner,
                       embedded_subtitles=not force)
                videos.append(video)
                continue

            # directories
            if os.path.isdir(p):
                try:
                    scanned_videos = scan_videos(p, age=age, archives=archives)
                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):
                        if not force:
                            video.subtitle_languages |= set(
                                search_external_subtitles(
                                    video.name, directory=directory).values())
                        refine(video,
                               episode_refiners=refiner,
                               movie_refiners=refiner,
                               embedded_subtitles=not force)
                        videos.append(video)
                    else:
                        ignored_videos.append(video)
                continue

            # other inputs
            try:
                video = scan_video(p)
            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):
                if not force:
                    video.subtitle_languages |= set(
                        search_external_subtitles(
                            video.name, directory=directory).values())
                refine(video,
                       episode_refiners=refiner,
                       movie_refiners=refiner,
                       embedded_subtitles=not force)
                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 AsyncProviderPool(max_workers=max_workers,
                           providers=provider,
                           provider_configs=obj['provider_configs']) as p:
        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:
                scores = get_scores(v)
                subtitles = p.download_best_subtitles(
                    p.list_subtitles(v, language - v.subtitle_languages),
                    v,
                    language,
                    min_score=scores['hash'] * min_score / 100,
                    hearing_impaired=hearing_impaired,
                    only_one=single)
                downloaded_subtitles[v] = subtitles

        if p.discarded_providers:
            click.secho(
                'Some providers have been discarded due to unexpected errors: %s'
                % ', '.join(p.discarded_providers),
                fg='yellow')

    # 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)
                score = compute_score(s, v)

                # score color
                score_color = None
                scores = get_scores(v)
                if isinstance(v, Movie):
                    if score < scores['title']:
                        score_color = 'red'
                    elif score < scores['title'] + scores['year'] + scores[
                            'release_group']:
                        score_color = 'yellow'
                    else:
                        score_color = 'green'
                elif isinstance(v, Episode):
                    if score < scores['series'] + scores['season'] + scores[
                            'episode']:
                        score_color = 'red'
                    elif score < scores['series'] + scores['season'] + scores[
                            'episode'] + 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 -= scores['hearing_impaired']
                scaled_score *= 100 / 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 >= 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=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 #20
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 #21
0
def subliminal():
    parser = argparse.ArgumentParser(
        prog='subliminal',
        description='Subtitles, faster than your thoughts',
        epilog='Suggestions and bug reports are greatly appreciated: '
        'https://github.com/Diaoul/subliminal/issues',
        add_help=False)

    # required arguments
    required_arguments_group = parser.add_argument_group('required arguments')
    required_arguments_group.add_argument('paths',
                                          nargs='+',
                                          metavar='PATH',
                                          help='path to video file or folder')
    required_arguments_group.add_argument(
        '-l',
        '--languages',
        nargs='+',
        required=True,
        metavar='LANGUAGE',
        help='wanted languages as IETF codes e.g. fr, pt-BR, sr-Cyrl ')

    # configuration
    configuration_group = parser.add_argument_group('configuration')
    configuration_group.add_argument(
        '-s',
        '--single',
        action='store_true',
        help=
        'download without language code in subtitle\'s filename i.e. .srt only'
    )
    configuration_group.add_argument('-c',
                                     '--cache-file',
                                     default=DEFAULT_CACHE_FILE,
                                     help='cache file (default: %(default)s)')

    # filtering
    filtering_group = parser.add_argument_group('filtering')
    filtering_group.add_argument(
        '-p',
        '--providers',
        nargs='+',
        metavar='PROVIDER',
        help='providers to use (%s)' %
        ', '.join(provider_manager.available_providers))
    filtering_group.add_argument(
        '-m',
        '--min-score',
        type=int,
        default=0,
        help='minimum score for subtitles (0-%d for episodes, 0-%d for movies)'
        % (Episode.scores['hash'], Movie.scores['hash']))
    filtering_group.add_argument(
        '-a',
        '--age',
        help='download subtitles for videos newer than AGE e.g. 12h, 1w2d')
    filtering_group.add_argument('-h',
                                 '--hearing-impaired',
                                 action='store_true',
                                 help='download hearing impaired subtitles')
    filtering_group.add_argument(
        '-f',
        '--force',
        action='store_true',
        help='force subtitle download for videos with existing subtitles')

    # addic7ed
    addic7ed_group = parser.add_argument_group('addic7ed')
    addic7ed_group.add_argument('--addic7ed-username',
                                metavar='USERNAME',
                                help='username for addic7ed provider')
    addic7ed_group.add_argument('--addic7ed-password',
                                metavar='PASSWORD',
                                help='password for addic7ed provider')

    # output
    output_group = parser.add_argument_group('output')
    output_group.add_argument(
        '-d',
        '--directory',
        help=
        'save subtitles in the given directory rather than next to the video')
    output_group.add_argument(
        '-e',
        '--encoding',
        default=None,
        help='encoding to convert the subtitle to (default: no conversion)')
    output_exclusive_group = output_group.add_mutually_exclusive_group()
    output_exclusive_group.add_argument('-q',
                                        '--quiet',
                                        action='store_true',
                                        help='disable output')
    output_exclusive_group.add_argument('-v',
                                        '--verbose',
                                        action='store_true',
                                        help='verbose output')
    output_group.add_argument('--log-file',
                              help='log into a file instead of stdout')
    output_group.add_argument(
        '--color',
        action='store_true',
        help='add color to console output (requires colorlog)')

    # troubleshooting
    troubleshooting_group = parser.add_argument_group('troubleshooting')
    troubleshooting_group.add_argument('--debug',
                                       action='store_true',
                                       help='debug output')
    troubleshooting_group.add_argument('--version',
                                       action='version',
                                       version=__version__)
    troubleshooting_group.add_argument('--help',
                                       action='help',
                                       help='show this help message and exit')

    # parse args
    args = parser.parse_args()

    # parse paths
    try:
        args.paths = [
            os.path.abspath(
                os.path.expanduser(
                    p.decode('utf-8') if isinstance(p, bytes) else p))
            for p in args.paths
        ]
    except UnicodeDecodeError:
        parser.error('argument paths: encodings is not utf-8: %r' % args.paths)

    # parse languages
    try:
        args.languages = {
            babelfish.Language.fromietf(l)
            for l in args.languages
        }
    except babelfish.Error:
        parser.error('argument -l/--languages: codes are not IETF: %r' %
                     args.languages)

    # parse age
    if args.age is not None:
        match = re.match(
            r'^(?:(?P<weeks>\d+?)w)?(?:(?P<days>\d+?)d)?(?:(?P<hours>\d+?)h)?$',
            args.age)
        if not match:
            parser.error('argument -a/--age: invalid age: %r' % args.age)
        args.age = datetime.timedelta(
            **{k: int(v)
               for k, v in match.groupdict(0).items()})

    # parse cache-file
    args.cache_file = os.path.abspath(os.path.expanduser(args.cache_file))
    if not os.path.exists(os.path.split(args.cache_file)[0]):
        parser.error(
            'argument -c/--cache-file: directory %r for cache file does not exist'
            % os.path.split(args.cache_file)[0])

    # parse provider configs
    provider_configs = {}
    if (args.addic7ed_username is not None and args.addic7ed_password is None
            or args.addic7ed_username is None
            and args.addic7ed_password is not None):
        parser.error(
            'argument --addic7ed-username/--addic7ed-password: both arguments are required or none'
        )
    if args.addic7ed_username is not None and args.addic7ed_password is not None:
        provider_configs['addic7ed'] = {
            'username': args.addic7ed_username,
            'password': args.addic7ed_password
        }

    # parse color
    if args.color and colorlog is None:
        parser.error('argument --color: colorlog required')

    # setup output
    if args.log_file is None:
        handler = logging.StreamHandler()
    else:
        handler = logging.FileHandler(args.log_file, encoding='utf-8')
    if args.debug:
        if args.color:
            if args.log_file is None:
                log_format = '%(log_color)s%(levelname)-8s%(reset)s [%(blue)s%(name)s-%(funcName)s:%(lineno)d%(reset)s] %(message)s'
            else:
                log_format = '%(purple)s%(asctime)s%(reset)s %(log_color)s%(levelname)-8s%(reset)s [%(blue)s%(name)s-%(funcName)s:%(lineno)d%(reset)s] %(message)s'
            handler.setFormatter(
                colorlog.ColoredFormatter(
                    log_format,
                    log_colors=dict(colorlog.default_log_colors.items() +
                                    [('DEBUG', 'cyan')])))
        else:
            if args.log_file is None:
                log_format = '%(levelname)-8s [%(name)s-%(funcName)s:%(lineno)d] %(message)s'
            else:
                log_format = '%(asctime)s %(levelname)-8s [%(name)s-%(funcName)s:%(lineno)d] %(message)s'
            handler.setFormatter(logging.Formatter(log_format))
        logging.getLogger().addHandler(handler)
        logging.getLogger().setLevel(logging.DEBUG)
    elif args.verbose:
        if args.color:
            if args.log_file is None:
                log_format = '%(log_color)s%(levelname)-8s%(reset)s [%(blue)s%(name)s%(reset)s] %(message)s'
            else:
                log_format = '%(purple)s%(asctime)s%(reset)s %(log_color)s%(levelname)-8s%(reset)s [%(blue)s%(name)s%(reset)s] %(message)s'
            handler.setFormatter(colorlog.ColoredFormatter(log_format))
        else:
            log_format = '%(levelname)-8s [%(name)s] %(message)s'
            if args.log_file is not None:
                log_format = '%(asctime)s ' + log_format
            handler.setFormatter(logging.Formatter(log_format))
        logging.getLogger('subliminal').addHandler(handler)
        logging.getLogger('subliminal').setLevel(logging.INFO)
    elif not args.quiet:
        if args.color:
            if args.log_file is None:
                log_format = '[%(log_color)s%(levelname)s%(reset)s] %(message)s'
            else:
                log_format = '%(purple)s%(asctime)s%(reset)s [%(log_color)s%(levelname)s%(reset)s] %(message)s'
            handler.setFormatter(colorlog.ColoredFormatter(log_format))
        else:
            if args.log_file is None:
                log_format = '%(levelname)s: %(message)s'
            else:
                log_format = '%(asctime)s %(levelname)s: %(message)s'
            handler.setFormatter(logging.Formatter(log_format))
        logging.getLogger('subliminal.api').addHandler(handler)
        logging.getLogger('subliminal.api').setLevel(logging.INFO)

    # configure cache
    cache_region.configure(
        'dogpile.cache.dbm',
        expiration_time=datetime.timedelta(days=30),  # @UndefinedVariable
        arguments={
            'filename': args.cache_file,
            'lock_factory': MutexLock
        })

    # scan videos
    videos = scan_videos([p for p in args.paths if os.path.exists(p)],
                         subtitles=not args.force,
                         embedded_subtitles=not args.force,
                         age=args.age)

    # guess videos
    videos.extend(
        [Video.fromname(p) for p in args.paths if not os.path.exists(p)])

    # download best subtitles
    subtitles = download_best_subtitles(videos,
                                        args.languages,
                                        providers=args.providers,
                                        provider_configs=provider_configs,
                                        min_score=args.min_score,
                                        hearing_impaired=args.hearing_impaired,
                                        single=args.single)

    # save subtitles
    save_subtitles(subtitles,
                   single=args.single,
                   directory=args.directory,
                   encoding=args.encoding)

    # result output
    if not subtitles:
        if not args.quiet:
            print('No subtitles downloaded', file=sys.stderr)
        exit(1)
    if not args.quiet:
        subtitles_count = sum([len(s) for s in subtitles.values()])
        if subtitles_count == 1:
            print('%d subtitle downloaded' % subtitles_count)
        else:
            print('%d subtitles downloaded' % subtitles_count)
Example #22
0
def manual_download_subtitle(path, language, hi, subtitle, provider, providers_auth, sceneName, media_type):
    if hi == "True":
        hi = True
    else:
        hi = False
    subtitle = pickle.loads(codecs.decode(subtitle.encode(), "base64"))
    if media_type == 'series':
        type_of_score = 360
    elif media_type == 'movie':
        type_of_score = 120
    use_scenename = get_general_settings()[9]
    use_postprocessing = get_general_settings()[10]
    postprocessing_cmd = get_general_settings()[11]

    language = alpha3_from_alpha2(language)
    if language == 'pob':
        lang_obj = Language('por', 'BR')
    else:
        lang_obj = Language(language)

    try:
        if sceneName is None or use_scenename is False:
            used_sceneName = False
            video = scan_video(path)
        else:
            used_sceneName = True
            video = Video.fromname(sceneName)
    except Exception as e:
        logging.exception('Error trying to extract information from this filename: ' + path)
        return None
    else:
        try:
            best_subtitle = subtitle
            download_subtitles([best_subtitle], providers=provider, provider_configs=providers_auth)
        except Exception as e:
            logging.exception('Error downloading subtitles for ' + path)
            return None
        else:
            single = get_general_settings()[7]
            try:
                score = round(float(compute_score(best_subtitle, video, hearing_impaired=hi)) / type_of_score * 100, 2)
                if used_sceneName == True:
                    video = scan_video(path)
                if single is True:
                    result = save_subtitles(video, [best_subtitle], single=True, encoding='utf-8')
                else:
                    result = save_subtitles(video, [best_subtitle], encoding='utf-8')
            except Exception as e:
                logging.exception('Error saving subtitles file to disk.')
                return None
            else:
                if len(result) > 0:
                    downloaded_provider = result[0].provider_name
                    downloaded_language = language_from_alpha3(result[0].language.alpha3)
                    downloaded_language_code2 = alpha2_from_alpha3(result[0].language.alpha3)
                    downloaded_language_code3 = result[0].language.alpha3
                    downloaded_path = get_subtitle_path(path, language=lang_obj)
                    message = downloaded_language + " subtitles downloaded from " + downloaded_provider + " with a score of " + unicode(score) + "% using manual search."

                    if use_postprocessing is True:
                        command = pp_replace(postprocessing_cmd, path, downloaded_path, downloaded_language, downloaded_language_code2, downloaded_language_code3)
                        try:
                            if os.name == 'nt':
                                codepage = subprocess.Popen("chcp", shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
                                # wait for the process to terminate
                                out_codepage, err_codepage = codepage.communicate()
                                encoding = out_codepage.split(':')[-1].strip()

                            process = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
                            # wait for the process to terminate
                            out, err = process.communicate()

                            if os.name == 'nt':
                                out = out.decode(encoding)

                        except:
                            if out == "":
                                logging.error('Post-processing result for file ' + path + ' : Nothing returned from command execution')
                            else:
                                logging.error('Post-processing result for file ' + path + ' : ' + out)
                        else:
                            if out == "":
                                logging.info('Post-processing result for file ' + path + ' : Nothing returned from command execution')
                            else:
                                logging.info('Post-processing result for file ' + path + ' : ' + out)

                    return message
                else:
                    return None
Example #23
0
def download_subtitle(path, language, hi, providers, providers_auth, sceneName, media_type):
    if hi == "True":
        hi = True
    else:
        hi = False
    language_set = set()
    if language == 'pob':
        language_set.add(Language('por', 'BR'))
    else:
        language_set.add(Language(language))

    use_scenename = get_general_settings()[9]
    minimum_score = get_general_settings()[8]
    minimum_score_movie = get_general_settings()[22]
    use_postprocessing = get_general_settings()[10]
    postprocessing_cmd = get_general_settings()[11]

    try:
        if sceneName == "None" or use_scenename is False:
            used_sceneName = False
            video = scan_video(path)
        else:
            used_sceneName = True
            video = Video.fromname(sceneName)
    except Exception as e:
        logging.exception("Error trying to get video information for this file: " + path)
    else:
        if media_type == "movie":
            max_score = 120.0
        elif media_type == "series":
            max_score = 360.0

        try:
            with AsyncProviderPool(max_workers=None, providers=providers, provider_configs=providers_auth) as p:
                subtitles = p.list_subtitles(video, language_set)
        except Exception as e:
            logging.exception("Error trying to get subtitle list from provider")
        else:
            subtitles_list = []
            sorted_subtitles = sorted([(s, compute_score(s, video, hearing_impaired=hi)) for s in subtitles], key=operator.itemgetter(1), reverse=True)
            for s, preliminary_score in sorted_subtitles:
                if media_type == "movie":
                    if (preliminary_score / max_score * 100) < int(minimum_score_movie):
                        continue
                    matched = set(s.get_matches(video))
                    if hi == s.hearing_impaired:
                        matched.add('hearing_impaired')
                    not_matched = set(score.movie_scores.keys()) - matched
                    required = set(['title'])
                    if any(elem in required for elem in not_matched):
                        continue
                elif media_type == "series":
                    if (preliminary_score / max_score * 100) < int(minimum_score):
                        continue
                    matched = set(s.get_matches(video))
                    if hi == s.hearing_impaired:
                        matched.add('hearing_impaired')
                    not_matched = set(score.episode_scores.keys()) - matched
                    required = set(['series', 'season', 'episode'])
                    if any(elem in required for elem in not_matched):
                        continue
                subtitles_list.append(s)
            if len(subtitles_list) > 0:
                best_subtitle = subtitles_list[0]
                download_subtitles([best_subtitle], providers=providers, provider_configs=providers_auth)
                try:
                    calculated_score = round(float(compute_score(best_subtitle, video, hearing_impaired=hi)) / max_score * 100, 2)
                    if used_sceneName == True:
                        video = scan_video(path)
                    single = get_general_settings()[7]
                    if single is True:
                        result = save_subtitles(video, [best_subtitle], single=True, encoding='utf-8')
                    else:
                        result = save_subtitles(video, [best_subtitle], encoding='utf-8')
                except Exception as e:
                    logging.exception('Error saving subtitles file to disk.')
                    return None
                else:
                    if len(result) > 0:
                        downloaded_provider = result[0].provider_name
                        downloaded_language = language_from_alpha3(result[0].language.alpha3)
                        downloaded_language_code2 = alpha2_from_alpha3(result[0].language.alpha3)
                        downloaded_language_code3 = result[0].language.alpha3
                        downloaded_path = get_subtitle_path(path, language=language_set)
                        if used_sceneName == True:
                            message = downloaded_language + " subtitles downloaded from " + downloaded_provider + " with a score of " + unicode(calculated_score) + "% using this scene name: " + sceneName
                        else:
                            message = downloaded_language + " subtitles downloaded from " + downloaded_provider + " with a score of " + unicode(calculated_score) + "% using filename guessing."

                        if use_postprocessing is True:
                            command = pp_replace(postprocessing_cmd, path, downloaded_path, downloaded_language, downloaded_language_code2, downloaded_language_code3)
                            try:
                                if os.name == 'nt':
                                    codepage = subprocess.Popen("chcp", shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
                                    # wait for the process to terminate
                                    out_codepage, err_codepage = codepage.communicate()
                                    encoding = out_codepage.split(':')[-1].strip()

                                process = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
                                # wait for the process to terminate
                                out, err = process.communicate()

                                if os.name == 'nt':
                                    out = out.decode(encoding)

                            except:
                                if out == "":
                                    logging.error('Post-processing result for file ' + path + ' : Nothing returned from command execution')
                                else:
                                    logging.error('Post-processing result for file ' + path + ' : ' + out)
                            else:
                                if out == "":
                                    logging.info('Post-processing result for file ' + path + ' : Nothing returned from command execution')
                                else:
                                    logging.info('Post-processing result for file ' + path + ' : ' + out)

                        return message
                    else:
                        return None
            else:
                return None
    # but with part01.rar, part02.rar cases it will try to check them all.
    files = glob.glob(videodir + '/' + dirs + '/*.rar')
    if not files:
        print videodir + '/' + dirs + ' has no rarfiles'
        continue

    for file in files:
        print 'Checking content of rar: ' + file

        try:
            rf = rarfile.RarFile(file)
            for f in rf.infolist():
                #print 'Found the following file: ' + f.filename

                if f.compress_type == 48 and f.filename.endswith(allowedextensions):
                    video = Video.fromguess(dirs  + '/' + f.filename, guessit.guess_file_info(dirs  + '/' + f.filename))
                    print 'Uncompressed store algorithme used (0x30)'
                    print 'Searching subtitles for Filename: ' + f.filename
                    print 'Filesize: ' + str(f.file_size)
                    video.size = f.file_size

                    print video
                    attrs = vars(video)
                    print ', '.join("%s: %s" % item for item in attrs.items())


                    # enzyme
                    try:
                        #global video # nodig voor variable?

                        if f.filename.endswith('.mkv'):
Example #25
0
def subliminal():
    parser = argparse.ArgumentParser(prog='subliminal', description='Subtitles, faster than your thoughts',
                                     epilog='Suggestions and bug reports are greatly appreciated: '
                                     'https://github.com/Diaoul/subliminal/issues', add_help=False)

    # required arguments
    required_arguments_group = parser.add_argument_group('required arguments')
    required_arguments_group.add_argument('paths', nargs='+', metavar='PATH', help='path to video file or folder')
    required_arguments_group.add_argument('-l', '--languages', nargs='+', required=True, metavar='LANGUAGE',
                                          help='wanted languages as IETF codes e.g. fr, pt-BR, sr-Cyrl ')

    # configuration
    configuration_group = parser.add_argument_group('configuration')
    configuration_group.add_argument('-s', '--single', action='store_true',
                                     help='download without language code in subtitle\'s filename i.e. .srt only')
    configuration_group.add_argument('-c', '--cache-file', default=DEFAULT_CACHE_FILE,
                                     help='cache file (default: %(default)s)')

    # filtering
    filtering_group = parser.add_argument_group('filtering')
    filtering_group.add_argument('-p', '--providers', nargs='+', metavar='PROVIDER',
                                 help='providers to use (%s)' % ', '.join(provider_manager.available_providers))
    filtering_group.add_argument('-m', '--min-score', type=int, default=0,
                                 help='minimum score for subtitles (0-%d for episodes, 0-%d for movies)'
                                 % (Episode.scores['hash'], Movie.scores['hash']))
    filtering_group.add_argument('-a', '--age', help='download subtitles for videos newer than AGE e.g. 12h, 1w2d')
    filtering_group.add_argument('-h', '--hearing-impaired', action='store_true',
                                 help='download hearing impaired subtitles')
    filtering_group.add_argument('-f', '--force', action='store_true',
                                 help='force subtitle download for videos with existing subtitles')

    # addic7ed
    addic7ed_group = parser.add_argument_group('addic7ed')
    addic7ed_group.add_argument('--addic7ed-username', metavar='USERNAME', help='username for addic7ed provider')
    addic7ed_group.add_argument('--addic7ed-password', metavar='PASSWORD', help='password for addic7ed provider')

    # output
    output_group = parser.add_argument_group('output')
    output_group.add_argument('-d', '--directory',
                              help='save subtitles in the given directory rather than next to the video')
    output_group.add_argument('-e', '--encoding', default='utf-8', help='subtitles encoding (default: %(default)s)')
    output_exclusive_group = output_group.add_mutually_exclusive_group()
    output_exclusive_group.add_argument('-q', '--quiet', action='store_true', help='disable output')
    output_exclusive_group.add_argument('-v', '--verbose', action='store_true', help='verbose output')
    output_group.add_argument('--log-file', help='log into a file instead of stdout')
    output_group.add_argument('--color', action='store_true', help='add color to console output (requires colorlog)')

    # troubleshooting
    troubleshooting_group = parser.add_argument_group('troubleshooting')
    troubleshooting_group.add_argument('--debug', action='store_true', help='debug output')
    troubleshooting_group.add_argument('--version', action='version', version=__version__)
    troubleshooting_group.add_argument('--help', action='help', help='show this help message and exit')

    # parse args
    args = parser.parse_args()

    # parse paths
    try:
        args.paths = [os.path.abspath(os.path.expanduser(p.decode('utf-8') if isinstance(p, bytes) else p))
                      for p in args.paths]
    except UnicodeDecodeError:
        parser.error('argument paths: encodings is not utf-8: %r' % args.paths)

    # parse languages
    try:
        args.languages = {babelfish.Language.fromietf(l) for l in args.languages}
    except babelfish.Error:
        parser.error('argument -l/--languages: codes are not IETF: %r' % args.languages)

    # parse age
    if args.age is not None:
        match = re.match(r'^(?:(?P<weeks>\d+?)w)?(?:(?P<days>\d+?)d)?(?:(?P<hours>\d+?)h)?$', args.age)
        if not match:
            parser.error('argument -a/--age: invalid age: %r' % args.age)
        args.age = datetime.timedelta(**{k: int(v) for k, v in match.groupdict(0).items()})

    # parse cache-file
    args.cache_file = os.path.abspath(os.path.expanduser(args.cache_file))
    if not os.path.exists(os.path.split(args.cache_file)[0]):
        parser.error('argument -c/--cache-file: directory %r for cache file does not exist'
                     % os.path.split(args.cache_file)[0])

    # parse provider configs
    provider_configs = {}
    if (args.addic7ed_username is not None and args.addic7ed_password is None
        or args.addic7ed_username is None and args.addic7ed_password is not None):
        parser.error('argument --addic7ed-username/--addic7ed-password: both arguments are required or none')
    if args.addic7ed_username is not None and args.addic7ed_password is not None:
        provider_configs['addic7ed'] = {'username': args.addic7ed_username, 'password': args.addic7ed_password}

    # parse color
    if args.color and colorlog is None:
        parser.error('argument --color: colorlog required')

    # setup output
    if args.log_file is None:
        handler = logging.StreamHandler()
    else:
        handler = logging.FileHandler(args.log_file, encoding='utf-8')
    if args.debug:
        if args.color:
            if args.log_file is None:
                log_format = '%(log_color)s%(levelname)-8s%(reset)s [%(blue)s%(name)s-%(funcName)s:%(lineno)d%(reset)s] %(message)s'
            else:
                log_format = '%(purple)s%(asctime)s%(reset)s %(log_color)s%(levelname)-8s%(reset)s [%(blue)s%(name)s-%(funcName)s:%(lineno)d%(reset)s] %(message)s'
            handler.setFormatter(colorlog.ColoredFormatter(log_format,
                                                           log_colors=dict(colorlog.default_log_colors.items() + [('DEBUG', 'cyan')])))
        else:
            if args.log_file is None:
                log_format = '%(levelname)-8s [%(name)s-%(funcName)s:%(lineno)d] %(message)s'
            else:
                log_format = '%(asctime)s %(levelname)-8s [%(name)s-%(funcName)s:%(lineno)d] %(message)s'
            handler.setFormatter(logging.Formatter(log_format))
        logging.getLogger().addHandler(handler)
        logging.getLogger().setLevel(logging.DEBUG)
    elif args.verbose:
        if args.color:
            if args.log_file is None:
                log_format = '%(log_color)s%(levelname)-8s%(reset)s [%(blue)s%(name)s%(reset)s] %(message)s'
            else:
                log_format = '%(purple)s%(asctime)s%(reset)s %(log_color)s%(levelname)-8s%(reset)s [%(blue)s%(name)s%(reset)s] %(message)s'
            handler.setFormatter(colorlog.ColoredFormatter(log_format))
        else:
            log_format = '%(levelname)-8s [%(name)s] %(message)s'
            if args.log_file is not None:
                log_format = '%(asctime)s ' + log_format
            handler.setFormatter(logging.Formatter(log_format))
        logging.getLogger('subliminal').addHandler(handler)
        logging.getLogger('subliminal').setLevel(logging.INFO)
    elif not args.quiet:
        if args.color:
            if args.log_file is None:
                log_format = '[%(log_color)s%(levelname)s%(reset)s] %(message)s'
            else:
                log_format = '%(purple)s%(asctime)s%(reset)s [%(log_color)s%(levelname)s%(reset)s] %(message)s'
            handler.setFormatter(colorlog.ColoredFormatter(log_format))
        else:
            if args.log_file is None:
                log_format = '%(levelname)s: %(message)s'
            else:
                log_format = '%(asctime)s %(levelname)s: %(message)s'
            handler.setFormatter(logging.Formatter(log_format))
        logging.getLogger('subliminal.api').addHandler(handler)
        logging.getLogger('subliminal.api').setLevel(logging.INFO)

    # configure cache
    cache_region.configure('dogpile.cache.dbm', expiration_time=datetime.timedelta(days=30),  # @UndefinedVariable
                           arguments={'filename': args.cache_file, 'lock_factory': MutexLock})

    # scan videos
    videos = scan_videos([p for p in args.paths if os.path.exists(p)], subtitles=not args.force,
                         embedded_subtitles=not args.force, age=args.age)

    # guess videos
    videos.extend([Video.fromname(p) for p in args.paths if not os.path.exists(p)])

    # download best subtitles
    subtitles = download_best_subtitles(videos, args.languages, providers=args.providers,
                                        provider_configs=provider_configs, min_score=args.min_score,
                                        hearing_impaired=args.hearing_impaired, single=args.single)

    # save subtitles
    save_subtitles(subtitles, single=args.single, directory=args.directory, encoding=args.encoding)

    # result output
    if not subtitles:
        if not args.quiet:
            print('No subtitles downloaded', file=sys.stderr)
        exit(1)
    if not args.quiet:
        subtitles_count = sum([len(s) for s in subtitles.values()])
        if subtitles_count == 1:
            print('%d subtitle downloaded' % subtitles_count)
        else:
            print('%d subtitles downloaded' % subtitles_count)
Example #26
0
def subliminal():
    parser = argparse.ArgumentParser(
        prog="subliminal",
        description="Subtitles, faster than your thoughts",
        epilog="Suggestions and bug reports are greatly appreciated: " "https://github.com/Diaoul/subliminal/issues",
        add_help=False,
    )

    # required arguments
    required_arguments_group = parser.add_argument_group("required arguments")
    required_arguments_group.add_argument("paths", nargs="+", metavar="PATH", help="path to video file or folder")
    required_arguments_group.add_argument(
        "-l",
        "--languages",
        action="append",
        required=True,
        metavar="LANGUAGE",
        help="wanted languages as IETF codes e.g. fr, pt-BR, sr-Cyrl ",
    )

    # configuration
    configuration_group = parser.add_argument_group("configuration")
    configuration_group.add_argument(
        "-s",
        "--single",
        action="store_true",
        help="download without language code in subtitle's filename i.e. .srt only",
    )
    configuration_group.add_argument(
        "-c", "--cache-file", default=DEFAULT_CACHE_FILE, help="cache file (default: %(default)s)"
    )
    configuration_group.add_argument("--all", action="store_true", help="download all subtitles")

    # filtering
    filtering_group = parser.add_argument_group("filtering")
    filtering_group.add_argument(
        "-p",
        "--providers",
        action="append",
        metavar="PROVIDER",
        help="providers to use (%s)" % ", ".join(provider_manager.available_providers),
    )
    filtering_group.add_argument(
        "-m",
        "--min-score",
        type=int,
        default=0,
        help="minimum score for subtitles (0-%d for episodes, 0-%d for movies)"
        % (Episode.scores["hash"], Movie.scores["hash"]),
    )
    filtering_group.add_argument("-a", "--age", help="download subtitles for videos newer than AGE e.g. 12h, 1w2d")
    filtering_group.add_argument(
        "-h", "--hearing-impaired", action="store_true", help="download hearing impaired subtitles"
    )
    filtering_group.add_argument(
        "-f", "--force", action="store_true", help="force subtitle download for videos with existing subtitles"
    )

    # addic7ed
    addic7ed_group = parser.add_argument_group("addic7ed")
    addic7ed_group.add_argument("--addic7ed-username", metavar="USERNAME", help="username for addic7ed provider")
    addic7ed_group.add_argument("--addic7ed-password", metavar="PASSWORD", help="password for addic7ed provider")

    # output
    output_group = parser.add_argument_group("output")
    output_group.add_argument(
        "-d", "--directory", help="save subtitles in the given directory rather than next to the video"
    )
    output_group.add_argument(
        "-e", "--encoding", default=None, help="encoding to convert the subtitle to (default: no conversion)"
    )
    output_exclusive_group = output_group.add_mutually_exclusive_group()
    output_exclusive_group.add_argument("-q", "--quiet", action="store_true", help="disable output")
    output_exclusive_group.add_argument("-v", "--verbose", action="store_true", help="verbose output")
    output_group.add_argument("--log-file", help="log into a file instead of stdout")
    output_group.add_argument("--color", action="store_true", help="add color to console output (requires colorlog)")

    # troubleshooting
    troubleshooting_group = parser.add_argument_group("troubleshooting")
    troubleshooting_group.add_argument("--debug", action="store_true", help="debug output")
    troubleshooting_group.add_argument("--version", action="version", version=__version__)
    troubleshooting_group.add_argument("--help", action="help", help="show this help message and exit")

    # parse args
    args = parser.parse_args()

    # parse paths
    try:
        args.paths = [
            os.path.abspath(os.path.expanduser(p.decode("utf-8") if isinstance(p, bytes) else p)) for p in args.paths
        ]
    except UnicodeDecodeError:
        parser.error("argument paths: encodings is not utf-8: %r" % args.paths)

    # parse languages
    try:
        args.languages = {babelfish.Language.fromietf(l) for l in args.languages}
    except babelfish.Error:
        parser.error("argument -l/--languages: codes are not IETF: %r" % args.languages)

    # parse age
    if args.age is not None:
        match = re.match(r"^(?:(?P<weeks>\d+?)w)?(?:(?P<days>\d+?)d)?(?:(?P<hours>\d+?)h)?$", args.age)
        if not match:
            parser.error("argument -a/--age: invalid age: %r" % args.age)
        args.age = datetime.timedelta(**{k: int(v) for k, v in match.groupdict(0).items()})

    # parse cache-file
    args.cache_file = os.path.abspath(os.path.expanduser(args.cache_file))
    if not os.path.exists(os.path.split(args.cache_file)[0]):
        parser.error(
            "argument -c/--cache-file: directory %r for cache file does not exist" % os.path.split(args.cache_file)[0]
        )

    # parse provider configs
    provider_configs = {}
    if (
        args.addic7ed_username is not None
        and args.addic7ed_password is None
        or args.addic7ed_username is None
        and args.addic7ed_password is not None
    ):
        parser.error("argument --addic7ed-username/--addic7ed-password: both arguments are required or none")
    if args.addic7ed_username is not None and args.addic7ed_password is not None:
        provider_configs["addic7ed"] = {"username": args.addic7ed_username, "password": args.addic7ed_password}

    # parse color
    if args.color and colorlog is None:
        parser.error("argument --color: colorlog required")

    # setup output
    if args.log_file is None:
        handler = logging.StreamHandler()
    else:
        handler = logging.FileHandler(args.log_file, encoding="utf-8")
    if args.debug:
        if args.color:
            if args.log_file is None:
                log_format = "%(log_color)s%(levelname)-8s%(reset)s [%(blue)s%(name)s-%(funcName)s:%(lineno)d%(reset)s] %(message)s"
            else:
                log_format = "%(purple)s%(asctime)s%(reset)s %(log_color)s%(levelname)-8s%(reset)s [%(blue)s%(name)s-%(funcName)s:%(lineno)d%(reset)s] %(message)s"
            handler.setFormatter(
                colorlog.ColoredFormatter(
                    log_format, log_colors=dict(colorlog.default_log_colors.items() + [("DEBUG", "cyan")])
                )
            )
        else:
            if args.log_file is None:
                log_format = "%(levelname)-8s [%(name)s-%(funcName)s:%(lineno)d] %(message)s"
            else:
                log_format = "%(asctime)s %(levelname)-8s [%(name)s-%(funcName)s:%(lineno)d] %(message)s"
            handler.setFormatter(logging.Formatter(log_format))
        logging.getLogger().addHandler(handler)
        logging.getLogger().setLevel(logging.DEBUG)
    elif args.verbose:
        if args.color:
            if args.log_file is None:
                log_format = "%(log_color)s%(levelname)-8s%(reset)s [%(blue)s%(name)s%(reset)s] %(message)s"
            else:
                log_format = "%(purple)s%(asctime)s%(reset)s %(log_color)s%(levelname)-8s%(reset)s [%(blue)s%(name)s%(reset)s] %(message)s"
            handler.setFormatter(colorlog.ColoredFormatter(log_format))
        else:
            log_format = "%(levelname)-8s [%(name)s] %(message)s"
            if args.log_file is not None:
                log_format = "%(asctime)s " + log_format
            handler.setFormatter(logging.Formatter(log_format))
        logging.getLogger("subliminal").addHandler(handler)
        logging.getLogger("subliminal").setLevel(logging.INFO)
    elif not args.quiet:
        if args.color:
            if args.log_file is None:
                log_format = "[%(log_color)s%(levelname)s%(reset)s] %(message)s"
            else:
                log_format = "%(purple)s%(asctime)s%(reset)s [%(log_color)s%(levelname)s%(reset)s] %(message)s"
            handler.setFormatter(colorlog.ColoredFormatter(log_format))
        else:
            if args.log_file is None:
                log_format = "%(levelname)s: %(message)s"
            else:
                log_format = "%(asctime)s %(levelname)s: %(message)s"
            handler.setFormatter(logging.Formatter(log_format))
        logging.getLogger("subliminal.api").addHandler(handler)
        logging.getLogger("subliminal.api").setLevel(logging.INFO)

    # configure cache
    cache_region.configure(
        "dogpile.cache.dbm",
        expiration_time=datetime.timedelta(days=30),  # @UndefinedVariable
        arguments={"filename": args.cache_file, "lock_factory": MutexLock},
    )

    # scan videos
    videos = scan_videos(
        [p for p in args.paths if os.path.exists(p)],
        subtitles=not args.force,
        embedded_subtitles=not args.force,
        age=args.age,
    )

    # guess videos
    videos.extend([Video.fromname(p) for p in args.paths if not os.path.exists(p)])

    if args.all:
        subtitles = collections.defaultdict(list)
        with ProviderPool(args.providers, provider_configs) as pp:
            for video in videos:
                for subtitle in pp.list_subtitles(video, args.languages):
                    if pp.download_subtitle(subtitle):
                        subtitles[video].append(subtitle)
    else:
        # download best subtitles
        subtitles = download_best_subtitles(
            videos,
            args.languages,
            providers=args.providers,
            provider_configs=provider_configs,
            min_score=args.min_score,
            hearing_impaired=args.hearing_impaired,
            single=args.single,
        )

    # save subtitles
    save_subtitles(
        subtitles, single=args.single, directory=args.directory, encoding=args.encoding, save_multiple=args.all
    )

    # result output
    if not subtitles:
        if not args.quiet:
            print("No subtitles downloaded", file=sys.stderr)
        exit(1)
    if not args.quiet:
        subtitles_count = sum([len(s) for s in subtitles.values()])
        if subtitles_count == 1:
            print("%d subtitle downloaded" % subtitles_count)
        else:
            print("%d subtitles downloaded" % subtitles_count)