Example #1
0
def search_video_files(rootdir, max_age=7, embedded_subs=False):
    '''Return a list of video files in rootdir which does not have any subtitle.

    Parameters
    ----------
    rootdir: str
        Root folder path from where to start the search.

    # this has been deprecated
    age: datetime.timedelta
        Maximum age of the video files in days to be included in the result.

    embedded_subs: bool
        If True will also take into account the subtitles embedded in the video file.

    Returns
    -------
    list of subliminal.video
    '''
    dirpath = op.abspath(op.expanduser(rootdir))

    # data path
    if not op.exists(dirpath):
        raise IOError('Folder {} not found.'.format(dirpath))

    # configure the cache
    # subliminal.cache_region.configure('dogpile.cache.dbm', arguments={'filename': data_dir.joinpath('cachefile.dbm')})

    # scan for videos in the folder and their subtitles
    videos = subliminal.scan_videos(dirpath, subtitles=True, embedded_subtitles=embedded_subs)
                                    #age=timedelta(days=max_age))

    return videos
Example #2
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)
def com_meta_fetch_subtitle_batch(dir_name, sub_lang='eng'):
    """
    # batch fetch subtitles
    """
    # configure the cache
    subliminal.cache_region.configure('dogpile.cache.dbm', arguments={'filename':
                                                                          '/mediakraken/cache/cachefile.dbm'})
    # scan for videos in the folder and their subtitles
    videos = subliminal.scan_videos(dir_name, subtitles=True, embedded_subtitles=True)
    # download
    subliminal.download_best_subtitles(videos, Language(sub_lang))
Example #4
0
def scan(paths, config):
    subliminal.cache_region.configure('dogpile.cache.dbm', arguments={'filename': '/usr/local/subliminal/cache/cachefile.dbm'})
    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=None
    if config.get('General').as_bool('hearing_impaired'):
        hearing_impaired=True
    videos = subliminal.scan_videos(paths, subtitles=True, embedded_subtitles=True, age=timedelta(days=config.get('Task').as_int('age')))
    subtitles = subliminal.api.download_best_subtitles(videos, languages=languageset, providers=config['General']['providers'], provider_configs=None, 
                                                       single=single, min_score=config.get('General').as_int('min_score'), 
                                                       hearing_impaired=hearing_impaired)
    return subtitles
    def download_callback(self, menuitem, files):
        # scan videos
        videos = []
        for f in files:
            # ignore non-writable locations
            if not f.can_write():
                continue

            # directories
            if f.is_directory():
                try:
                    scanned_videos = scan_videos(f.get_location().get_path())
                except:
                    continue
                for video in scanned_videos:
                    if check_video(video, languages=self.config.languages, age=self.config.age,
                                   undefined=self.config.single):
                        video.subtitle_languages |= set(search_external_subtitles(video.name).values())
                        refine(video, episode_refiners=self.config.refiners, movie_refiners=self.config.refiners,
                               embedded_subtitles=self.config.embedded_subtitles)
                        videos.append(video)
                continue

            # other inputs
            try:
                video = scan_video(f.get_location().get_path())
            except:
                continue
            if check_video(video, languages=self.config.languages, undefined=self.config.single):
                video.subtitle_languages |= set(search_external_subtitles(video.name).values())
                refine(video, episode_refiners=self.config.refiners, movie_refiners=self.config.refiners,
                       embedded_subtitles=self.config.embedded_subtitles)
                videos.append(video)

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

        # save subtitles
        for v, subtitles in downloaded_subtitles.items():
            save_subtitles(v, subtitles, single=self.config.single)
Example #6
0
	def downloadsubtitles(self_) :
		LOGGER.info('*** START DOWNLOADING SUBTITLES ***')
		
		if SIMULATE_MODE :
			 return
		
		# scan for videos in the folder and their subtitles
		videos = subliminal.scan_videos(self_.scanPath, subtitles=True, embedded_subtitles=True)
	
		# download
		subs = subliminal.download_best_subtitles(videos, {babelfish.Language('eng')})
		
		# save
		for video, sub in subs.items():
			subliminal.save_subtitles(video, sub)
    def run(self):
        """
        The main thread. this will run:
        - download torrent using utorrent
        - check utorent for status until finish downloading
        - move file to new location
        :return:
        """
        # start downloading and get hash
        self.state = DownloadTorrentThread.STATE_DOWNLOADING
        before_list = utorrentUtils.get_all_torrents()
        if not utorrentUtils.download_file(self.magnet_link):
            # TODO: run utorrent
            raise RuntimeError('Utorrent not working!')
        time.sleep(1)
        after_list = utorrentUtils.get_all_torrents()
        self.hash, torrent_data = self._get_new_downloaded_hash(before_list, after_list)

        if not self.hash:
            print 'file already existing in utorrent'
            return
        # print self.hash
        # print torrent_data

        torrent_name = self._wait_to_finish_downloading()

        # get all video files and move them to the correct location
        self.state = DownloadTorrentThread.STATE_MOVING
        files = utorrentUtils.get_torrent_files(self.hash)
        video_files_data = utorrentUtils.get_data_for_video_files(files, torrent_name=torrent_name)
        if video_files_data:
            self.video_files_data = video_files_data
            self._copy_files()

            # download subtitles
            for data in video_files_data:
                src_file = data['full_file_path']
                dst_dir = os.path.join(LocalFilesUtil.get_series_path(data['series_name']), 'Season ' + str(data['season']))
                dst_file = os.path.join(dst_dir, os.path.split(src_file)[1])
                videos = subliminal.scan_videos([dst_file])
                subtitles = subliminal.download_best_subtitles(videos, {Language('heb'), Language('eng')})
                subliminal.save_subtitles(subtitles)

        self.state = DownloadTorrentThread.STATE_FINISHED

        pass
Example #8
0
def updateSeriesDB(dbFilePath_, seriesPath_) :
	"""Update the database for a given path
	
	:param String dbFilePath_
	:param String seriesPath_
	"""
	conn = sqlite3.connect(dbFilePath_)
	c = conn.cursor()
	
	LOGGER.info('*** START UPDATING DATABASE ***')
	videos = subliminal.scan_videos(seriesPath_, True, True)
	
	for video in videos :
		subEn = babelfish.Language('eng') in video.subtitle_languages
		subFr = babelfish.Language('fra') in video.subtitle_languages
		updateEpisode(c, video, subEn, subFr, True)
		
	conn.commit()
	conn.close()
Example #9
0
def downloadSubtitles(path_) :
	"""Download all subtitles in the given path

	:param String path_
	"""
	
	LOGGER.info('*** START DOWNLOADING SUBTITLES ***')

	if SIMULATE_MODE :
		return
	
	# configure the cache
	if (not os.path.isdir(_cachePath)) :
		os.makedirs(_cachePath)
	subliminal.cache_region.configure('dogpile.cache.dbm', arguments={'filename': _cachePath + 'cachefile.dbm'})
	
	# scan for videos in the folder and their subtitles
	upath = unicode(path_)
	videos = subliminal.scan_videos(upath, subtitles=True, embedded_subtitles=True)
	
	# download
	subs = subliminal.download_best_subtitles(videos, {babelfish.Language('eng')})
Example #10
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 #11
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 #12
0
def main(folder_dir):
    print(folder_dir)
    videos = scan_videos(folder_dir)
    subs = download_best_subtitles(videos, {Language('heb')})
    print(videos, subs)
    save_and_merge(subs)
Example #13
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)
from babelfish import Language
from subliminal import download_best_subtitles, region, save_subtitles, scan_videos
import os

region.configure('dogpile.cache.dbm', arguments={'filename': 'cachefile.dbm'})
videos = scan_videos(os.getcwd())
subtitles = download_best_subtitles(videos, {Language('eng'), Language('fas')})
for v in videos:
    print(v)
    save_subtitles(v, subtitles[v])

Example #15
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)
Example #16
0
 def fetch_subtitles(self, media_dict):
     vids = media_dict.keys() if isinstance(media_dict, dict) else media_dict
     subs = scan_videos(vids, subtitles=True, embedded_subtitles=False)
     single = True if len(BABELFISH_LANG) == 1 else False
     subliminal.download_best_subtitles(subs, BABELFISH_LANG, single=single)
Example #17
0
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    }
}

# Internationalization
# https://docs.djangoproject.com/en/1.6/topics/i18n/

LANGUAGE_CODE = 'en-us'

TIME_ZONE = 'UTC'

USE_I18N = True

USE_L10N = True

USE_TZ = True


# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/1.6/howto/static-files/

STATIC_URL = '/static/'

# Subliminal stuff
SUBLIMINAL_CACHE = subliminal.cache_region.configure('dogpile.cache.dbm', arguments={'filename': '/tmp/cachefile.dbm'})
print "SUBLIMINAL_CACHE => %s" % SUBLIMINAL_CACHE

videos = subliminal.scan_videos(['/Users/crsantos/Movies'], subtitles=True, embedded_subtitles=True, age=timedelta(weeks=1))
print videos
Example #18
0
from datetime import timedelta

from babelfish import Language
from subliminal import download_best_subtitles, region, save_subtitles, scan_videos

SEARCH_ROOT = '~/Downloads'

# configure the cache
region.configure('dogpile.cache.dbm', arguments={'filename': 'cachefile.dbm'})

# scan for videos newer than 2 weeks and their existing subtitles in a folder
videos = scan_videos(SEARCH_ROOT, age=timedelta(weeks=2))

# download best subtitles
subtitles = download_best_subtitles(videos, {Language('eng'), Language('fra')})

# save them to disk, next to the video
for v in videos:
    print(v)
    save_subtitles(v, subtitles[v])
    def run(self,
            scan_path,
            scan_age,
            languages,
            encoding,
            min_score,
            providers,
            provider_configs,
            max_workers,
            plex_url=None,
            plex_token=None,
            *args,
            **kwargs):
        if not os.path.isdir(scan_path):
            raise IOError('Path \'%s\' doesn\'t exist!' % scan_path)
        if not scan_age >= 1:
            raise ValueError('\'scan_age\' must by at least 1!')
        if not len(languages) >= 1:
            raise ValueError('\'languages\' list can\'t be empty!')
        if not providers:
            raise ValueError('\'providers\' argument can\'t be empty!')
        if not max_workers >= 1:
            raise ValueError('\'max_workers\' must be at least 1!')

        if not provider_configs:
            provider_configs = {}

        __tree_dict = lambda: defaultdict(__tree_dict)
        result = __tree_dict()

        encoding = codecs.lookup(encoding).name
        age = timedelta(weeks=scan_age)
        languages = set([Language(l) for l in languages])

        plex = None
        if plex_url and plex_token:
            plex = PlexServer(plex_url, plex_token)

        scan_start = datetime.now()

        videos = []
        ignored_videos = []

        if not region.is_configured:
            region.configure('dogpile.cache.dbm',
                             expiration_time=timedelta(days=30),
                             arguments={
                                 'filename': 'subliminal.dbm',
                                 'lock_factory': MutexLock
                             })

        # scan videos
        scanned_videos = scan_videos(scan_path, age=age)

        for video in scanned_videos:
            video.subtitle_languages |= set(
                search_external_subtitles(video.name).values())
            if check_video(video,
                           languages=languages,
                           age=age,
                           undefined=False):
                refine(video)
                if languages - video.subtitle_languages:
                    videos.append(video)
                else:
                    ignored_videos.append(video)
            else:
                ignored_videos.append(video)

        if videos:
            result['videos']['collected'] = [
                os.path.split(v.name)[1] for v in videos
            ]
        if ignored_videos:
            result['videos']['ignored'] = len(ignored_videos)

        if videos:
            # download best subtitles
            downloaded_subtitles = defaultdict(list)
            with AsyncProviderPool(max_workers=max_workers,
                                   providers=providers,
                                   provider_configs=provider_configs) as p:
                for video in videos:
                    scores = get_scores(video)
                    subtitles_to_download = p.list_subtitles(
                        video, languages - video.subtitle_languages)
                    downloaded_subtitles[video] = p.download_best_subtitles(
                        subtitles_to_download,
                        video,
                        languages,
                        min_score=scores['hash'] * min_score / 100)

                if p.discarded_providers:
                    result['providers']['discarded'] = list(
                        p.discarded_providers)

            # filter subtitles
            with TinyDB('subtitle_db.json') as db:
                table = db.table('downloaded')
                query = Query()
                for video, subtitles in downloaded_subtitles.items():
                    discarded_subtitles = list()
                    discarded_subtitles_info = list()

                    for s in subtitles:
                        subtitle_hash = hashlib.sha256(s.content).hexdigest()
                        subtitle_file = get_subtitle_path(
                            os.path.split(video.name)[1], s.language)
                        dbo = {'hash': subtitle_hash, 'file': subtitle_file}
                        if table.search((query.hash == subtitle_hash)
                                        & (query.file == subtitle_file)):
                            discarded_subtitles.append(s)
                            discarded_subtitles_info.append(dbo)
                        else:
                            table.insert(dbo)

                    downloaded_subtitles[video] = [
                        x for x in subtitles if x not in discarded_subtitles
                    ]
                    if discarded_subtitles_info:
                        result['subtitles'][
                            'discarded'] = result['subtitles'].get(
                                'discarded', []) + discarded_subtitles_info

            downloaded_subtitles = {
                k: v
                for k, v in downloaded_subtitles.items() if v
            }

            # save subtitles
            saved_subtitles = {}
            for video, subtitles in downloaded_subtitles.items():
                saved_subtitles[video] = save_subtitles(video,
                                                        subtitles,
                                                        directory=None,
                                                        encoding=encoding)

                for key, group in groupby(saved_subtitles[video],
                                          lambda x: x.provider_name):
                    subtitle_filenames = [
                        get_subtitle_path(
                            os.path.split(video.name)[1], s.language)
                        for s in list(group)
                    ]
                    result['subtitles'][key] = result['subtitles'].get(
                        key, []) + subtitle_filenames
            result['subtitles']['total'] = sum(
                len(v) for v in saved_subtitles.values())

            # refresh plex
            for video, subtitles in saved_subtitles.items():
                if plex and subtitles:
                    item_found = False
                    for section in plex.library.sections():
                        try:
                            if isinstance(section,
                                          MovieSection) and isinstance(
                                              video, Movie):
                                results = section.search(title=video.title,
                                                         year=video.year,
                                                         libtype='movie',
                                                         sort='addedAt:desc',
                                                         maxresults=1)

                                if not results:
                                    raise NotFound

                                plex_item = results[0]
                            elif isinstance(section,
                                            ShowSection) and isinstance(
                                                video, Episode):
                                results = section.search(title=video.series,
                                                         year=video.year,
                                                         libtype='show',
                                                         sort='addedAt:desc',
                                                         maxresults=1)

                                if not results:
                                    raise NotFound

                                plex_item = results[0].episode(
                                    season=video.season, episode=video.episode)
                            else:
                                continue
                        except NotFound:
                            continue
                        except BadRequest:
                            continue

                        if plex_item:
                            plex_item.refresh()
                            result['plex']['refreshed'] = result['plex'].get(
                                'refreshed', []) + [
                                    '%s%s' %
                                    (repr(plex_item.section()), repr(video))
                                ]
                            item_found = True

                    if not item_found:
                        result['plex']['failed'] = result['plex'].get(
                            'failed', []) + [repr(video)]

            # convert subtitles
            for video, subtitles in saved_subtitles.items():
                target_format = aeidon.formats.SUBRIP
                for s in subtitles:
                    subtitle_path = get_subtitle_path(video.name, s.language)
                    source_format = aeidon.util.detect_format(
                        subtitle_path, encoding)
                    source_file = aeidon.files.new(
                        source_format, subtitle_path,
                        aeidon.encodings.detect_bom(subtitle_path) or encoding)

                    if source_format != target_format:
                        format_info = {
                            'file':
                            get_subtitle_path(
                                os.path.split(video.name)[1], s.language),
                            'from':
                            source_format.label,
                            'to':
                            target_format.label
                        }
                        result['subtitles'][
                            'converted'] = result['subtitles'].get(
                                'converted', []) + [format_info]

                    aeidon_subtitles = source_file.read()
                    for f in [
                            aeidon.formats.SUBRIP, aeidon.formats.MICRODVD,
                            aeidon.formats.MPL2
                    ]:
                        markup = aeidon.markups.new(f)
                        for s in aeidon_subtitles:
                            s.main_text = markup.decode(s.main_text)

                    markup = aeidon.markups.new(target_format)
                    for s in aeidon_subtitles:
                        s.main_text = markup.encode(s.main_text)

                    target_file = aeidon.files.new(target_format,
                                                   subtitle_path, encoding)
                    target_file.write(aeidon_subtitles, aeidon.documents.MAIN)

        scan_end = datetime.now()
        result['meta']['start'] = scan_start.isoformat()
        result['meta']['end'] = scan_end.isoformat()
        result['meta']['duration'] = str(scan_end - scan_start)
        return result
    def download_callback(self, menuitem, files):
        # scan videos
        videos = []
        for f in files:
            # ignore non-writable locations
            if not f.can_write():
                continue

            # directories
            if f.is_directory():
                try:
                    scanned_videos = scan_videos(f.get_location().get_path())
                except:
                    continue
                for video in scanned_videos:
                    if check_video(video,
                                   languages=self.config.languages,
                                   age=self.config.age,
                                   undefined=self.config.single):
                        video.subtitle_languages |= set(
                            search_external_subtitles(video.name).values())
                        refine(
                            video,
                            episode_refiners=self.config.refiners,
                            movie_refiners=self.config.refiners,
                            embedded_subtitles=self.config.embedded_subtitles)
                        videos.append(video)
                continue

            # other inputs
            try:
                video = scan_video(f.get_location().get_path())
            except:
                continue
            if check_video(video,
                           languages=self.config.languages,
                           undefined=self.config.single):
                video.subtitle_languages |= set(
                    search_external_subtitles(video.name).values())
                refine(video,
                       episode_refiners=self.config.refiners,
                       movie_refiners=self.config.refiners,
                       embedded_subtitles=self.config.embedded_subtitles)
                videos.append(video)

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

        # save subtitles
        for v, subtitles in downloaded_subtitles.items():
            save_subtitles(v, subtitles, single=self.config.single)
Example #21
0
import glob, os
from shutil import copyfile, move
from subliminal import download_best_subtitles, save_subtitles, scan_videos
from babelfish import Language

#Vuse Torrent Default: userProf + "/Documents/Vuze Downloads"
#BiglyBT Torrent Default: userProf + "/Documents/BiglyBT Downloads"

__author__ = "TooSlepy"
__PyVer__ = "3.6"
userProf = os.getenv("userprofile")
videoSaveLoc = userProf + "/Documents/Vuze Downloads"
saveLoc = "D:/Moviex/"
lang = "eng"

os.chdir(videoSaveLoc)
for x in ("*.avi", "*.mkv", "*.mp4", "*.mpg"):
    for file in glob.glob(x):
        fileDir = file.rsplit('.', 1)[0]
        if not os.path.exists(fileDir):
            os.mkdir(fileDir)
        move(file, fileDir + "/" + file)
        # scan for videos in a folder
        videos = scan_videos(fileDir)
        # download best subtitles
        subtitles = download_best_subtitles(videos, {Language(lang)})
        # save them to disk, next to the video
        for v in videos:
            save_subtitles(v, subtitles[v])
        move(fileDir, saveLoc + "/" + fileDir)
        print(file + " has been moved and subtitled.")
Example #22
0
if not config['OPENSUBTITLE']['password']:
    logger.info('Problem in configuration')

# configure providers with config
providerOpenSubtitles = OpenSubtitlesProvider(
    username=config['OPENSUBTITLE']['username'],
    password=config['OPENSUBTITLE']['password'])

# configure the cache
region.configure('dogpile.cache.dbm', arguments={'filename': 'cachefile.dbm'})

# configure the path to scan
pathToScan = config['DEFAULT']['pathToScan']

# scan for videos newer than 2 weeks and their existing subtitles in a folder
videos = scan_videos(pathToScan, age=timedelta(days=30))
logger.info('Analyse video  % s ' % (videos))

# Download all shooters
shooter_providers = ['shooter']
shooter_subtitles = list_subtitles(videos, {Language('zho')},
                                   providers=shooter_providers)

for movie, subtitles in shooter_subtitles.items():
    try:
        download_subtitles(subtitles)
        for subtitle in subtitles:
            if subtitle.content is None:
                logger.error('Skipping subtitle %r: no content' % subtitle)
                continue
Example #23
0
#!/usr/bin/python

from __future__ import unicode_literals  # python 2 only
from babelfish import Language
from datetime import timedelta
import subliminal

# configure the cache
subliminal.cache_region.configure('dogpile.cache.dbm', arguments={'filename': '/path/to/cachefile.dbm'})

# scan for videos in the folder and their subtitles
videos = subliminal.scan_videos(['/path/to/video/folder'], subtitles=True, embedded_subtitles=True, age=timedelta(weeks=1))

# download best subtitles
subtitles = subliminal.download_best_subtitles(videos, {Language('eng'), Language('fra')}, age=timedelta(weeks=1))

# save them to disk, next to the video
subliminal.save_subtitles(subtitles)
Example #24
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 #25
0
def download_subtitles_subliminal(subs_dirs):
    subliminal.cache_region.configure('dogpile.cache.dbm', arguments={'filename': 'cachefile.dbm'})
    videos = subliminal.scan_videos(subs_dirs, subtitles=True)
    result = subliminal.download_best_subtitles(videos, {Language('eng')})
    return result
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', 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 #27
0
from datetime import timedelta

from babelfish import Language
from subliminal import download_best_subtitles, region, save_subtitles, scan_videos

# configure the cache
region.configure('dogpile.cache.dbm', arguments={'filename': 'cachefile.dbm'})

# scan for videos newer than 2 weeks and their existing subtitles in a folder
videos = scan_videos(
    'D:\TV Series\Westworld\[TorrentCouch.com].Westworld.S02.Complete.720p.WEB-DL.x264.[MP4].[5.3GB].[Season.2.Full]'
)

# download best subtitles
subtitles = download_best_subtitles(videos, {Language('eng')})

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