def get_best_subtitle(self):
		# Get a subtitle for a given video file
		self.status_bar.pop(self.context_id)
		self.status_bar.push(self.context_id, "Downloading Subtitle")
		self.timeout = GObject.timeout_add( 100, self.progress_pulse )
		self.subtitle = download_best_subtitles(
		[self.video],
		{ Language( self.language_combo.get_active_text() ) },
		providers=[self.provider_combo.get_active_text()] )
		
		try:
			self.subtitle = self.subtitle[self.video][0]
			self.status_bar.pop(self.context_id)
			self.status_bar.push(self.context_id, "Subtitle Downloaded Successfully")
		
		except IndexError:
			self.status_bar.pop(self.context_id)
			self.status_bar.push(self.context_id, "No Subtitle Found")
			GObject.source_remove(self.timeout)
			self.progress_bar.set_fraction(0)
			return False
		
			
		save_subtitles(self.video, [self.subtitle])
		GObject.source_remove(self.timeout)
		self.progress_bar.set_fraction(1)
Beispiel #2
0
def test_save_subtitles(movies, tmpdir, monkeypatch):
    monkeypatch.chdir(str(tmpdir))
    tmpdir.ensure(movies['man_of_steel'].name)
    subtitle_no_content = Subtitle(Language('eng'))
    subtitle = Subtitle(Language('fra'))
    subtitle.content = b'Some content'
    subtitle_other = Subtitle(Language('fra'))
    subtitle_other.content = b'Some other content'
    subtitle_pt_br = Subtitle(Language('por', 'BR'))
    subtitle_pt_br.content = b'Some brazilian content'
    subtitles = [subtitle_no_content, subtitle, subtitle_other, subtitle_pt_br]

    save_subtitles(movies['man_of_steel'], subtitles)

    # subtitle without content is skipped
    path = os.path.join(str(tmpdir), os.path.splitext(movies['man_of_steel'].name)[0] + '.en.srt')
    assert not os.path.exists(path)

    # first subtitle with language is saved
    path = os.path.join(str(tmpdir), os.path.splitext(movies['man_of_steel'].name)[0] + '.fr.srt')
    assert os.path.exists(path)
    assert io.open(path, 'rb').read() == b'Some content'

    # ietf language in path
    path = os.path.join(str(tmpdir), os.path.splitext(movies['man_of_steel'].name)[0] + '.pt-BR.srt')
    assert os.path.exists(path)
    assert io.open(path, 'rb').read() == b'Some brazilian content'
    def test_save_subtitles(self):
        videos = [EPISODES[0], EPISODES[1]]
        for video in videos:
            video.name = os.path.join(TEST_DIR, os.path.split(video.name)[1])
        languages = {Language('eng'), Language('fra')}
        subtitles = list_subtitles(videos, languages)

        # make a list of subtitles to download (one per language per video)
        subtitles_to_download = []
        for video, video_subtitles in subtitles.items():
            video_subtitle_languages = set()
            for video_subtitle in video_subtitles:
                if video_subtitle.language in video_subtitle_languages:
                    continue
                subtitles_to_download.append(video_subtitle)
                video_subtitle_languages.add(video_subtitle.language)
                if video_subtitle_languages == languages:
                    break
        self.assertEqual(len(subtitles_to_download), 4)

        # download
        download_subtitles(subtitles_to_download)
        save_subtitles(subtitles)
        for video in videos:
            self.assertTrue(os.path.exists(os.path.splitext(video.name)[0] + '.en.srt'))
            self.assertTrue(os.path.exists(os.path.splitext(video.name)[0] + '.fr.srt'))
Beispiel #4
0
def download_subs(videos, languages):
    """
    Will scan for videos newer than one week and try to download
    subtitles in English and Spanish for them.

    Parameters
    ----------
    videos: list of

    languages: list of babelfish.language

    """
    nu_vids = []
    for vid in videos:
        if len(vid.subtitle_languages) == 0:
            nu_vids.append(vid)

    # download
    try:
        subs = subliminal.download_best_subtitles(nu_vids, languages)
    except:
        raise

    log.info('Subs found:')
    log.info(subs)

    # save
    log.debug('Saving subtitle files.')
    subliminal.save_subtitles(subs, single=False)
Beispiel #5
0
    def subtitle(self, episodes):

        # Parse babelfish languages
        bb_lang = {Language.fromietf(l) for l in self.languages}

        # Create subliminal episode set
        sub_episodes = set()
        for episode in episodes:

            ep_path = os.path.join(episode['dir'], episode['filename'])
            sub_episode = Episode.fromguess(ep_path, episode)

            # Look for external subtitles (not done automatically, apparently)
            sub_episode.subtitle_languages |= set(search_external_subtitles(sub_episode.name).values())

            sub_episodes.add(sub_episode)

        # download subtitles in the specified language
        subl_subtitles = download_best_subtitles(sub_episodes, bb_lang, providers=self.providers)

        for video, subtitles in subl_subtitles.items():

            save_subtitles(video, subtitles)

            # save subtitle languages in episode dict
Beispiel #6
0
 def download_sub(self, language):
     l = Language(language)
     v = scan_video(self.path)
     sub_path = get_subtitle_path(v.name, l)
     if not os.path.isfile(sub_path):
         sub = download_best_subtitles((v,), {l})
         # TODO Save in tmp folder if regular is not available
         save_subtitles(sub)
     return sub_path
Beispiel #7
0
def downloadSubtitles(subtitles_info):
    existing_subtitles = subtitles_info['subtitles']
    # First of all, check if we need subtitles
    languages = getNeededLanguages(existing_subtitles)
    if not languages:
        logger.log(u'%s: No missing subtitles for S%02dE%02d' % (subtitles_info['show.indexerid'], subtitles_info['season'], subtitles_info['episode']), logger.DEBUG)
        return (existing_subtitles, None)

    subtitles_path = getSubtitlesPath(subtitles_info['location']).encode(sickbeard.SYS_ENCODING)
    video_path = subtitles_info['location'].encode(sickbeard.SYS_ENCODING)
    providers = getEnabledServiceList()

    try:
        video = subliminal.scan_video(video_path, subtitles=False, embedded_subtitles=False)
    except Exception:
        logger.log(u'%s: Exception caught in subliminal.scan_video for S%02dE%02d' %
        (subtitles_info['show.indexerid'], subtitles_info['season'], subtitles_info['episode']), logger.DEBUG)
        return (existing_subtitles, None)

    try:
        # TODO: Add gui option for hearing_impaired parameter ?
        found_subtitles = subliminal.download_best_subtitles([video], languages=languages, hearing_impaired=False, only_one=not sickbeard.SUBTITLES_MULTI, providers=providers)
        if not found_subtitles:
            logger.log(u'%s: No subtitles found for S%02dE%02d on any provider' % (subtitles_info['show.indexerid'], subtitles_info['season'], subtitles_info['episode']), logger.DEBUG)
            return (existing_subtitles, None)

        for index, subtitle in enumerate(found_subtitles[video]):
            encoding = subliminal.subtitle.Subtitle.guess_encoding(subtitle)
            found_subtitles[video][index].encoding = encoding

        subliminal.save_subtitles(video, found_subtitles[video], directory=subtitles_path, single=not sickbeard.SUBTITLES_MULTI)

        for video, subtitles in found_subtitles.iteritems():
            for subtitle in subtitles:
                new_video_path = subtitles_path + "/" + video.name.rsplit("/", 1)[-1]
                new_subtitles_path = subliminal.subtitle.get_subtitle_path(new_video_path, subtitle.language if sickbeard.SUBTITLES_MULTI else None)
                sickbeard.helpers.chmodAsParent(new_subtitles_path)
                sickbeard.helpers.fixSetGroupID(new_subtitles_path)

        if not sickbeard.EMBEDDED_SUBTITLES_ALL and sickbeard.SUBTITLES_EXTRA_SCRIPTS and video_path.endswith(('.mkv','.mp4')):
            run_subs_extra_scripts(subtitles_info, found_subtitles)

        current_subtitles = subtitlesLanguages(video_path)[0]
        new_subtitles = frozenset(current_subtitles).difference(existing_subtitles)

    except Exception as e:
                logger.log("Error occurred when downloading subtitles for: %s" % video_path)
                logger.log(traceback.format_exc(), logger.ERROR)
                return (existing_subtitles, None)

    if sickbeard.SUBTITLES_HISTORY:
        for video, subtitles in found_subtitles.iteritems():
            for subtitle in subtitles:
                logger.log(u'history.logSubtitle %s, %s' % (subtitle.provider_name, subtitle.language.opensubtitles), logger.DEBUG)
                history.logSubtitle(subtitles_info['show.indexerid'], subtitles_info['season'], subtitles_info['episode'], subtitles_info['status'], subtitle)

    return (current_subtitles, new_subtitles)
 def test_save_subtitles_single(self):
     videos = [EPISODES[0], EPISODES[1]]
     for video in videos:
         video.name = os.path.join(TEST_DIR, os.path.split(video.name)[1])
     languages = {Language('eng'), Language('fra')}
     subtitles = download_best_subtitles(videos, languages)
     save_subtitles(subtitles, single=True)
     for video in videos:
         self.assertIn(video, subtitles)
         self.assertEqual(len(subtitles[video]), 2)
         self.assertTrue(os.path.exists(os.path.splitext(video.name)[0] + '.srt'))
Beispiel #9
0
def test_save_subtitles_single_directory_encoding(movies, tmpdir):
    subtitle = Subtitle(Language('jpn'))
    subtitle.content = u'ハローワールド'.encode('shift-jis')
    subtitle_pt_br = Subtitle(Language('por', 'BR'))
    subtitle_pt_br.content = b'Some brazilian content'
    subtitles = [subtitle, subtitle_pt_br]

    save_subtitles(movies['man_of_steel'], subtitles, single=True, directory=str(tmpdir), encoding='utf-8')

    # first subtitle only and correctly encoded
    path = os.path.join(str(tmpdir), os.path.splitext(os.path.split(movies['man_of_steel'].name)[1])[0] + '.srt')
    assert os.path.exists(path)
    assert io.open(path, encoding='utf-8').read() == u'ハローワールド'
        def _download_subtitle():
            # download the subtitle
            with ProviderPool(providers=self.config.providers, provider_configs=self.config.provider_configs) as pool:
                pool.download_subtitle(subtitle)

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

            # mark the subtitle as downloaded
            model.set_value(iter, 6, True)

            # stop the spinner
            self.spinner.stop()
    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)
Beispiel #12
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)
Beispiel #13
0
def download_subs(file):
    print("    Analyzing video file...")
    try:
        video = scan_video(file['full_path'])
    except ValueError as ex:
        print("    Failed to analyze video. ", ex)
        return None
    print("    Choosing subtitle from online providers...")
    best_subtitles = download_best_subtitles({video}, {Language('eng')}, only_one=True)
    if best_subtitles[video]:
        sub = best_subtitles[video][0]
        print("    Choosen subtitle: {f}".format(f=sub))
        print("    Downloading...")
        save_subtitles(video, [sub], single=True)
    else:
        print("    ERROR: No subtitles found online.")
    def save(self):
        """
        Save the subtitle without further handling
        """

        log.info("Saving subtitle")

        # Check download_item
        if 'video' in self._keys and 'subtitles' in self._keys and 'single' in self._keys:
            # Save the subtitle
            video = self._download_item['video']
            subliminal.save_subtitles(video, self._download_item['subtitles'][video], self._download_item['single'])
            return True
        else:
            log.error("Download item is not complete, skipping")
            return False
Beispiel #15
0
def import_subs(filename):
    if not core.GETSUBS:
        return
    try:
        subliminal.cache_region.configure('dogpile.cache.memory')
    except:
        pass   

    languages = set()
    for item in core.SLANGUAGES:
        try:
            languages.add(Language(item))
        except:
            pass
    if not languages:
        return

    logger.debug("Attempting to download subtitles for %s" %(filename), 'SUBTITLES')
    try:
        # subliminal.logger = subliminal.logging.getLogger('subliminal')
        # subliminal.logger.setLevel(subliminal.logging.DEBUG)
        # ch = subliminal.logging.StreamHandler()
        # ch.setLevel(subliminal.logging.DEBUG)
        # formatter = subliminal.logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
        # ch.setFormatter(formatter)
        # subliminal.logger.addHandler(ch)

        video = subliminal.scan_video(filename, subtitles=True, embedded_subtitles=True)
        subtitles = subliminal.download_best_subtitles([video], languages, hearing_impaired=False)
        saved_subtitles = subliminal.save_subtitles(video, subtitles[video])
        logger.debug("Saved subtitles:%s" %(saved_subtitles), 'SUBTITLES')
    except Exception as e:
        logger.error("Failed to download subtitles for %s due to: %s" %(filename, e), 'SUBTITLES') 
    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
    def save(self):
        """
        Save the subtitle
        """

        log.debug('Saving subtitle')

        # Check download_item (check for not None on boolean variables!)
        if self._download_item.video and self._download_item.subtitles and self._download_item.single is not None:
            # Save the subtitle
            video = self._download_item.video
            encoding = 'utf-8' if autosubliminal.SUBTITLEUTF8ENCODING else None
            subliminal.save_subtitles(video, self._download_item.subtitles, single=self._download_item.single,
                                      encoding=encoding)
            return True
        else:
            log.error('Download item is not complete, skipping')
            return False
Beispiel #18
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
Beispiel #19
0
    def on_subtitles_treeview_row_activated(self, treeview, path, view_column):
        model = treeview.get_model()
        iter = model.get_iter(path)

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

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

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

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

        # mark the subtitle as downloaded
        model.set_value(iter, 6, True)
    def run(self):
        """
        Save the subtitle with further handling
        """

        log.info("Running sub downloader")

        # Check download_item
        if 'video' in self._keys and 'subtitles' in self._keys and 'single' in self._keys:

            # Save the subtitle
            video = self._download_item['video']
            subliminal.save_subtitles(video, self._download_item['subtitles'][video], self._download_item['single'])

            # Add download_item to last downloads
            self._download_item['timestamp'] = time.strftime('%Y-%m-%d %H:%M:%S')
            LastDownloads().set_last_downloads(self._download_item)

            # Notify
            if autosubliminal.NOTIFY:
                Notifier(self._download_item).notify_download()

            # Post processing
            if autosubliminal.POSTPROCESS:
                PostProcessor(self._download_item).run()

            # Show success message
            language = self._download_item['downlang']
            name = utils.display_name(self._download_item)
            provider = self._download_item['provider']
            utils.add_notification_message(
                "Downloaded '" + language + "' subtitle for '" + name + "' from '" + provider + "'", 'success')

            return True
        else:
            log.error("Download item is not complete, skipping")
            return False
def import_subs(filename):
    if not nzbtomedia.GETSUBS:
        return
    try:
        subliminal.cache_region.configure('dogpile.cache.memory')
    except:
        pass   

    languages = set()
    for item in nzbtomedia.SLANGUAGES:
        try:
            languages.add(Language(item))
        except:
            pass
    if not languages:
        return

    logger.debug("Attempting to download subtitles for %s" %(filename), 'SUBTITLES')
    try:
        video = subliminal.scan_video(filename, subtitles=True, embedded_subtitles=True)
        subtitles = subliminal.download_best_subtitles([video], languages, hearing_impaired=False)
        subliminal.save_subtitles(subtitles)
    except:
        logger.error("Failed to download subtitles for %s" %(filename), 'SUBTITLES') 
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])
Beispiel #23
0
def import_subs(filename):
    if not core.GETSUBS:
        return
    try:
        subliminal.region.configure('dogpile.cache.dbm', arguments={'filename': 'cachefile.dbm'})
    except:
        pass

    languages = set()
    for item in core.SLANGUAGES:
        try:
            languages.add(Language(item))
        except:
            pass
    if not languages:
        return

    logger.info("Attempting to download subtitles for {0}".format(filename), 'SUBTITLES')
    try:
        video = subliminal.scan_video(filename)
        subtitles = subliminal.download_best_subtitles({video}, languages)
        subliminal.save_subtitles(video, subtitles[video])
    except Exception as e:
        logger.error("Failed to download subtitles for {0} due to: {1}".format(filename, e), 'SUBTITLES')
Beispiel #24
0
def save_subs(tv_episode, video, found_subtitles, video_path=None):
    """Save subtitles.

    :param tv_episode: the episode to download subtitles
    :type tv_episode: sickbeard.tv.Episode
    :param video:
    :type video: subliminal.Video
    :param found_subtitles:
    :type found_subtitles: list of subliminal.Subtitle
    :param video_path: the video path. If none, the episode location will be used
    :type video_path: str
    :return: a sorted list of the opensubtitles codes for the downloaded subtitles
    :rtype: list of str
    """
    video_path = video_path or tv_episode.location
    show_name = tv_episode.series.name
    season = tv_episode.season
    episode = tv_episode.episode
    episode_name = tv_episode.name
    show_indexerid = tv_episode.series.indexerid
    subtitles_dir = get_subtitles_dir(video_path)
    saved_subtitles = save_subtitles(video, found_subtitles, directory=subtitles_dir,
                                     single=not app.SUBTITLES_MULTI, encoding='utf-8')

    for subtitle in saved_subtitles:
        logger.info(u'Found subtitle for %s in %s provider with language %s', os.path.basename(video_path),
                    subtitle.provider_name, subtitle.language.opensubtitles)
        subtitle_path = compute_subtitle_path(subtitle, video_path, subtitles_dir)
        helpers.chmod_as_parent(subtitle_path)
        helpers.fix_set_group_id(subtitle_path)

        if app.SUBTITLES_EXTRA_SCRIPTS and is_media_file(video_path):
            subtitle_path = compute_subtitle_path(subtitle, video_path, subtitles_dir)
            run_subs_extra_scripts(video_path=video_path, subtitle_path=subtitle_path,
                                   subtitle_language=subtitle.language, show_name=show_name, season=season,
                                   episode=episode, episode_name=episode_name, show_indexerid=show_indexerid)

        if app.SUBTITLES_HISTORY:
            logger.debug(u'Logging to history downloaded subtitle from provider %s and language %s',
                         subtitle.provider_name, subtitle.language.opensubtitles)
            history.log_subtitle(tv_episode, subtitle)

    # Refresh the subtitles property
    if tv_episode.location:
        tv_episode.refresh_subtitles()

    return sorted({subtitle.language.opensubtitles for subtitle in saved_subtitles})
    def generateOptions(self, inputfile, original=None):    
        #Get path information from the input file
        input_dir, filename, input_extension = self.parseFile(inputfile)

        info = Converter(self.FFMPEG_PATH, self.FFPROBE_PATH).probe(inputfile)
       
        #Video stream
        print "Video codec detected: " + info.video.codec
        vcodec = 'copy' if info.video.codec in self.video_codec else self.video_codec[0]

        #Audio streams
        audio_settings = {}
        l = 0
        for a in info.audio:
            print "Audio stream detected: " + a.codec + " " + a.language + " [Stream " + str(a.index) + "]"
            # Set undefined language to default language if specified
            if self.adl is not None and a.language == 'und':
                print "Undefined language detected, defaulting to " + self.adl
                a.language = self.adl
            # Proceed if no whitelist is set, or if the language is in the whitelist
            if self.awl is None or a.language in self.awl:
                # Create iOS friendly audio stream if the default audio stream has too many channels (iOS only likes AAC stereo)
                if self.iOS:
                    if a.audio_channels > 2:
                        print "Creating dual audio channels for iOS compatability for this stream"
                        audio_settings.update({l: {
                            'map': a.index,
                            'codec': self.iOS,
                            'channels': 2,
                            'bitrate': 256,
                            'language': a.language,
                        }})
                        l += 1
                # If the iOS audio option is enabled and the source audio channel is only stereo, the additional iOS channel will be skipped and a single AAC 2.0 channel will be made regardless of codec preference to avoid multiple stereo channels
                if self.iOS and a.audio_channels == 2:
                    acodec = 'copy' if a.codec == 'aac' else self.iOS
                else:
                    # If desired codec is the same as the source codec, copy to avoid quality loss
                    acodec = 'copy' if a.codec in self.audio_codec else self.audio_codec[0]

                # Bitrate calculations/overrides
                if self.audio_bitrate is None or self.audio_bitrate > (a.audio_channels * 256):
                    abitrate = 256 * a.audio_channels
                else:
                    abitrate = self.audio_bitrate

                audio_settings.update({l: {
                    'map': a.index,
                    'codec': acodec,
                    'channels': a.audio_channels,
                    'bitrate': abitrate,
                    'language': a.language,
                }})
                l = l + 1

        # Subtitle streams
        subtitle_settings = {}
        l = 0
        for s in info.subtitle:
            print "Subtitle stream detected: " + s.codec + " " + s.language + " [Stream " + str(s.index) + "]"

            # Set undefined language to default language if specified
            if self.sdl is not None and s.language == 'und':
                s.language = self.sdl
            # Make sure its not an image based codec
            if s.codec not in bad_subtitle_codecs and self.embedsubs:
                
                # Proceed if no whitelist is set, or if the language is in the whitelist
                if self.swl is None or s.language in self.swl:
                    subtitle_settings.update({l: {
                        'map': s.index,
                        'codec': 'mov_text',
                        'language': s.language
                        #'forced': s.sub_forced,
                        #'default': s.sub_default
                    }})
                    l = l + 1
            else:
                if self.swl is None or s.language in self.swl:
                    ripsub = {1: {
                        'map': s.index,
                        'codec': 'srt',
                        'language': s.language
                    }}
                    options = {
                        'format': 'srt',
                        'subtitle': ripsub,
                    }
                    input_dir, filename, input_extension = self.parseFile(inputfile)
                    output_dir = input_dir if self.output_dir is None else self.output_dir
                    outputfile = os.path.join(output_dir, filename + "." + s.language + ".srt")
                    
                    i = 2
                    while os.path.isfile(outputfile):
                        outputfile = os.path.join(output_dir, filename + "." + s.language + "." + str(i) + ".srt")
                        i += i
                    print "Ripping " + s.language + " subtitle from file"
                    conv = Converter(self.FFMPEG_PATH, self.FFPROBE_PATH).convert(inputfile, outputfile, options, timeout=None)
                    for timecode in conv:
                            pass

                    try:
                        print outputfile + " created"
                    except:
                        print "File created"

        # External subtitle import

        # Attempt to download subtitles if they are missing using subliminal
        languages = set()
        if self.swl:
            for alpha3 in self.swl:
                languages.add(Language(alpha3))
        elif self.sdl:
            languages.add(Language(self.sdl))
        else:
            self.downloadsubs = False

        if self.downloadsubs:
            import subliminal
            print "Attempting to download subtitles, please wait"

            try:
                subliminal.cache_region.configure('dogpile.cache.memory')
            except:
                pass

            try:
                video = subliminal.scan_video(os.path.abspath(inputfile), subtitles=True, embedded_subtitles=True, original=original)
                subtitles = subliminal.download_best_subtitles([video], languages, hearing_impaired=False, providers=self.subproviders)
                subliminal.save_subtitles(subtitles)
            except Exception as e:
                print e
                print "Unable to download subtitle"

        src = 1  # FFMPEG input source number
        for dirName, subdirList, fileList in os.walk(input_dir):
            for fname in fileList:
                subname, subextension = os.path.splitext(fname)
                # Watch for appropriate file extension
                if subextension[1:] in valid_subtitle_extensions:
                    x, lang = os.path.splitext(subname)
                    lang = lang[1:]
                    # Using bablefish to convert a 2 language code to a 3 language code
                    if len(lang) is 2:
                        try:
                            babel = Language.fromalpha2(lang)
                            lang = babel.alpha3
                        except:
                            pass
                    # If subtitle file name and input video name are the same, proceed
                    if x == filename and self.embedsubs:
                        print "External subtitle file detected, language " + lang
                        if self.swl is None or lang in self.swl:
                            print "Importing %s subtitle stream" % (fname)
                            subtitle_settings.update({l: {
                                'path': os.path.join(dirName, fname),
                                'source': src,
                                'map': 0,
                                'codec': 'mov_text',
                                'language': lang,
                                }})
                            l = l + 1
                            src = src + 1
                            self.deletesubs.add(os.path.join(dirName, fname))
                        else:
                            print "Ignoring %s external subtitle stream due to language: %s" % (fname, lang)

        # Collect all options
        options = {
            'format': self.output_format,
            'video': {
                'codec': vcodec,
                'map': info.video.index,
                'bitrate': info.format.bitrate
            },
            'audio': audio_settings,
            'subtitle': subtitle_settings,
        }
        self.options = options
        return options
Beispiel #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)
Beispiel #27
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 "")
        )
Beispiel #28
0
def download_subtitles(filepath):
    video = scan_video(filepath)
    subtitles = download_best_subtitles([video], {Language('eng')})

    save_subtitles(video, subtitles[video], single=True)
Beispiel #29
0
    def generateOptions(self, inputfile, original=None):
        # Get path information from the input file
        input_dir, filename, input_extension = self.parseFile(inputfile)

        info = Converter(self.FFMPEG_PATH, self.FFPROBE_PATH).probe(inputfile)

        # Video stream
        self.log.info("Reading video stream.")
        self.log.info("Video codec detected: %s." % info.video.codec)

        try:
            vbr = self.estimateVideoBitrate(info)
        except:
            vbr = info.format.bitrate / 1000

        if info.video.codec.lower() in self.video_codec:
            vcodec = 'copy'
        else:
            vcodec = self.video_codec[0]
        vbitrate = self.video_bitrate if self.video_bitrate else vbr

        self.log.info("Pix Fmt: %s." % info.video.pix_fmt)
        if self.pix_fmt and info.video.pix_fmt.lower() not in self.pix_fmt:
            vcodec = self.video_codec[0]

        if self.video_bitrate is not None and vbr > self.video_bitrate:
            self.log.debug("Overriding video bitrate. Codec cannot be copied because video bitrate is too high.")
            vcodec = self.video_codec[0]
            vbitrate = self.video_bitrate

        if self.video_width is not None and self.video_width < info.video.video_width:
            self.log.debug("Video width is over the max width, it will be downsampled. Video stream can no longer be copied.")
            vcodec = self.video_codec[0]
            vwidth = self.video_width
        else:
            vwidth = None

        if '264' in info.video.codec.lower() and self.h264_level and info.video.video_level and (info.video.video_level / 10 > self.h264_level):
            self.log.info("Video level %0.1f." % (info.video.video_level / 10))
            vcodec = self.video_codec[0]

        self.log.debug("Video codec: %s." % vcodec)
        self.log.debug("Video bitrate: %s." % vbitrate)

        # Audio streams
        self.log.info("Reading audio streams.")

        overrideLang = True
        for a in info.audio:
            try:
                if a.metadata['language'].strip() == "" or a.metadata['language'] is None:
                    a.metadata['language'] = 'und'
            except KeyError:
                a.metadata['language'] = 'und'
            if (a.metadata['language'] == 'und' and self.adl) or (self.awl and a.metadata['language'].lower() in self.awl):
                overrideLang = False
                break

        if overrideLang:
            self.awl = None
            self.log.info("No audio streams detected in any appropriate language, relaxing restrictions so there will be some audio stream present.")

        audio_settings = {}
        l = 0
        for a in info.audio:
            try:
                if a.metadata['language'].strip() == "" or a.metadata['language'] is None:
                    a.metadata['language'] = 'und'
            except KeyError:
                a.metadata['language'] = 'und'

            self.log.info("Audio detected for stream #%s: %s [%s]." % (a.index, a.codec, a.metadata['language']))

            # Set undefined language to default language if specified
            if self.adl is not None and a.metadata['language'] == 'und':
                self.log.debug("Undefined language detected, defaulting to [%s]." % self.adl)
                a.metadata['language'] = self.adl

            # Proceed if no whitelist is set, or if the language is in the whitelist
            iosdata = None
            if self.awl is None or a.metadata['language'].lower() in self.awl:
                # Create iOS friendly audio stream if the default audio stream has too many channels (iOS only likes AAC stereo)
                if self.iOS and a.audio_channels > 2:
                    iOSbitrate = 256 if (self.audio_bitrate * 2) > 256 else (self.audio_bitrate * 2)
                    self.log.info("Creating audio stream %s from source audio stream %s [iOS-audio]." % (str(l), a.index))
                    self.log.debug("Audio codec: %s." % self.iOS[0])
                    self.log.debug("Channels: 2.")
                    self.log.debug("Filter: %s." % self.iOS_filter)
                    self.log.debug("Bitrate: %s." % iOSbitrate)
                    self.log.debug("Language: %s." % a.metadata['language'])
                    if l == 0:
                        disposition = 'default'
                        self.log.info("Audio track is number %s setting disposition to %s" % (str(l), disposition))
                    else:
                        disposition = 'none'
                        self.log.info("Audio track is number %s setting disposition to %s" % (str(l), disposition))
                    iosdata = {
                        'map': a.index,
                        'codec': self.iOS[0],
                        'channels': 2,
                        'bitrate': iOSbitrate,
                        'filter': self.iOS_filter,
                        'language': a.metadata['language'],
                        'disposition': disposition,
                        }
                    if not self.iOSLast:
                        audio_settings.update({l: iosdata})
                        l += 1
                # If the iOS audio option is enabled and the source audio channel is only stereo, the additional iOS channel will be skipped and a single AAC 2.0 channel will be made regardless of codec preference to avoid multiple stereo channels
                self.log.info("Creating audio stream %s from source stream %s." % (str(l), a.index))
                if self.iOS and a.audio_channels <= 2:
                    self.log.debug("Overriding default channel settings because iOS audio is enabled but the source is stereo [iOS-audio].")
                    acodec = 'copy' if a.codec in self.iOS else self.iOS[0]
                    audio_channels = a.audio_channels
                    afilter = self.iOS_filter
                    abitrate = a.audio_channels * 128 if (a.audio_channels * self.audio_bitrate) > (a.audio_channels * 128) else (a.audio_channels * self.audio_bitrate)
                else:
                    # If desired codec is the same as the source codec, copy to avoid quality loss
                    acodec = 'copy' if a.codec.lower() in self.audio_codec else self.audio_codec[0]
                    # Audio channel adjustments
                    if self.maxchannels and a.audio_channels > self.maxchannels:
                        audio_channels = self.maxchannels
                        if acodec == 'copy':
                            acodec = self.audio_codec[0]
                        abitrate = self.maxchannels * self.audio_bitrate
                    else:
                        audio_channels = a.audio_channels
                        abitrate = a.audio_channels * self.audio_bitrate
                    # Bitrate calculations/overrides
                    if self.audio_bitrate is 0:
                        self.log.debug("Attempting to set bitrate based on source stream bitrate.")
                        try:
                            abitrate = a.bitrate / 1000
                        except:
                            self.log.warning("Unable to determine audio bitrate from source stream %s, defaulting to 256 per channel." % a.index)
                            abitrate = a.audio_channels * 256
                    afilter = self.audio_filter

                self.log.debug("Audio codec: %s." % acodec)
                self.log.debug("Channels: %s." % audio_channels)
                self.log.debug("Bitrate: %s." % abitrate)
                self.log.debug("Language: %s" % a.metadata['language'])
                self.log.debug("Filter: %s" % afilter)

                # If the iOSFirst option is enabled, disable the iOS option after the first audio stream is processed
                if self.iOS and self.iOSFirst:
                    self.log.debug("Not creating any additional iOS audio streams.")
                    self.iOS = False

                # Set first track as default disposition
                if l == 0:
                    disposition = 'default'
                    self.log.info("Audio Track is number %s setting disposition to %s" % (a.index, disposition))
                else:
                    disposition = 'none'
                    self.log.info("Audio Track is number %s setting disposition to %s" % (a.index, disposition))

                audio_settings.update({l: {
                    'map': a.index,
                    'codec': acodec,
                    'channels': audio_channels,
                    'bitrate': abitrate,
                    'filter': afilter,
                    'language': a.metadata['language'],
                    'disposition': disposition,
                }})

                if acodec == 'copy' and a.codec == 'aac' and self.aac_adtstoasc:
                    audio_settings[l]['bsf'] = 'aac_adtstoasc'
                l += 1

                #Add the iOS track last instead
                if self.iOSLast and iosdata:
                    iosdata['disposition'] = 'none'
                    audio_settings.update({l: iosdata})
                    l += 1

                if self.audio_copyoriginal and acodec != 'copy':
                    self.log.info("Adding copy of original audio track in format %s" % a.codec)
                    audio_settings.update({l: {
                        'map': a.index,
                        'codec': 'copy',
                        'language': a.metadata['language'],
                        'disposition': 'none',
                    }})

        # Subtitle streams
        subtitle_settings = {}
        l = 0
        self.log.info("Reading subtitle streams.")
        for s in info.subtitle:
            try:
                if s.metadata['language'].strip() == "" or s.metadata['language'] is None:
                    s.metadata['language'] = 'und'
            except KeyError:
                s.metadata['language'] = 'und'

            self.log.info("Subtitle detected for stream #%s: %s [%s]." % (s.index, s.codec, s.metadata['language']))

            # Set undefined language to default language if specified
            if self.sdl is not None and s.metadata['language'] == 'und':
                self.log.debug("Undefined language detected, defaulting to [%s]." % self.sdl)
                s.metadata['language'] = self.sdl
            # Make sure its not an image based codec
            if s.codec.lower() not in bad_subtitle_codecs and self.embedsubs:

                # Proceed if no whitelist is set, or if the language is in the whitelist
                if self.swl is None or s.metadata['language'].lower() in self.swl:
                    subtitle_settings.update({l: {
                        'map': s.index,
                        'codec': self.scodec[0],
                        'language': s.metadata['language'],
                        'encoding': self.subencoding,
                        # 'forced': s.sub_forced,
                        # 'default': s.sub_default
                    }})
                    self.log.info("Creating subtitle stream %s from source stream %s." % (l, s.index))
                    l = l + 1
            elif s.codec.lower() not in bad_subtitle_codecs and not self.embedsubs:
                if self.swl is None or s.metadata['language'].lower() in self.swl:
                    for codec in self.scodec:
                        ripsub = {0: {
                            'map': s.index,
                            'codec': codec,
                            'language': s.metadata['language']
                        }}
                        options = {
                            'format': codec,
                            'subtitle': ripsub,
                        }

                        try:
                            extension = subtitle_codec_extensions[codec]
                        except:
                            self.log.info("Wasn't able to determine subtitle file extension, defaulting to '.srt'.")
                            extension = 'srt'

                        forced = ".forced" if s.sub_forced else ""

                        input_dir, filename, input_extension = self.parseFile(inputfile)
                        output_dir = input_dir if self.output_dir is None else self.output_dir
                        outputfile = os.path.join(output_dir, filename + "." + s.metadata['language'] + forced + "." + extension)

                        i = 2
                        while os.path.isfile(outputfile):
                            self.log.debug("%s exists, appending %s to filename." % (outputfile, i))
                            outputfile = os.path.join(output_dir, filename + "." + s.metadata['language'] + forced + "." + str(i) + "." + extension)
                            i += 1
                        try:
                            self.log.info("Ripping %s subtitle from source stream %s into external file." % (s.metadata['language'], s.index))
                            conv = Converter(self.FFMPEG_PATH, self.FFPROBE_PATH).convert(inputfile, outputfile, options, timeout=None)
                            for timecode in conv:
                                    pass

                            self.log.info("%s created." % outputfile)
                        except:
                            self.log.exception("Unabled to create external subtitle file for stream %s." % (s.index))

        # Attempt to download subtitles if they are missing using subliminal
        languages = set()
        try:
            if self.swl:
                for alpha3 in self.swl:
                    languages.add(Language(alpha3))
            elif self.sdl:
                languages.add(Language(self.sdl))
            else:
                self.downloadsubs = False
                self.log.error("No valid subtitle language specified, cannot download subtitles.")
        except:
            self.log.exception("Unable to verify subtitle languages for download.")
            self.downloadsubs = False

        if self.downloadsubs:
            import subliminal
            self.log.info("Attempting to download subtitles.")

            # Attempt to set the dogpile cache
            try:
                subliminal.region.configure('dogpile.cache.memory')
            except:
                pass

            try:
                video = subliminal.scan_video(os.path.abspath(inputfile), subtitles=True, embedded_subtitles=True)
                subtitles = subliminal.download_best_subtitles([video], languages, hearing_impaired=False, providers=self.subproviders)
                try:
                    subliminal.save_subtitles(video, subtitles[video])
                except:
                    # Support for older versions of subliminal
                    subliminal.save_subtitles(subtitles)
                    self.log.info("Please update to the latest version of subliminal.")
            except Exception as e:
                self.log.info("Unable to download subtitles.", exc_info=True)
                self.log.debug("Unable to download subtitles.", exc_info=True)
        # External subtitle import
        if self.embedsubs and not self.embedonlyinternalsubs:  # Don't bother if we're not embeddeding subtitles and external subtitles
            src = 1  # FFMPEG input source number
            for dirName, subdirList, fileList in os.walk(input_dir):
                for fname in fileList:
                    subname, subextension = os.path.splitext(fname)
                    # Watch for appropriate file extension
                    if subextension[1:] in valid_subtitle_extensions:
                        x, lang = os.path.splitext(subname)
                        lang = lang[1:]
                        # Using bablefish to convert a 2 language code to a 3 language code
                        if len(lang) is 2:
                            try:
                                babel = Language.fromalpha2(lang)
                                lang = babel.alpha3
                            except:
                                pass
                        # If subtitle file name and input video name are the same, proceed
                        if x == filename:
                            self.log.info("External %s subtitle file detected." % lang)
                            if self.swl is None or lang in self.swl:

                                self.log.info("Creating subtitle stream %s by importing %s." % (l, fname))

                                subtitle_settings.update({l: {
                                    'path': os.path.join(dirName, fname),
                                    'source': src,
                                    'map': 0,
                                    'codec': 'mov_text',
                                    'language': lang}})

                                self.log.debug("Path: %s." % os.path.join(dirName, fname))
                                self.log.debug("Source: %s." % src)
                                self.log.debug("Codec: mov_text.")
                                self.log.debug("Langauge: %s." % lang)

                                l = l + 1
                                src = src + 1

                                self.deletesubs.add(os.path.join(dirName, fname))

                            else:
                                self.log.info("Ignoring %s external subtitle stream due to language %s." % (fname, lang))

        # Collect all options
        options = {
            'format': self.output_format,
            'video': {
                'codec': vcodec,
                'map': info.video.index,
                'bitrate': vbitrate,
                'level': self.h264_level
            },
            'audio': audio_settings,
            'subtitle': subtitle_settings,
            'preopts': [],
            'postopts': ['-threads', self.threads]
        }

        # If a CRF option is set, override the determine bitrate
        if self.vcrf:
            del options['video']['bitrate']
            options['video']['crf'] = self.vcrf

        if len(options['subtitle']) > 0:
            options['preopts'].append('-fix_sub_duration')

        if self.preopts:
            options['preopts'].extend(self.preopts)

        if self.postopts:
            options['postopts'].extend(self.postopts)

        # If using h264qsv, add the codec in front of the input for decoding
        if vcodec == "h264qsv" and info.video.codec.lower() == "h264" and self.qsv_decoder and (info.video.video_level / 10) < 5:
            options['preopts'].extend(['-vcodec', 'h264_qsv'])

        if self.dxva2_decoder: # DXVA2 will fallback to CPU decoding when it hits a file that it cannot handle, so we don't need to check if the file is supported.
            options['preopts'].extend(['-hwaccel', 'dxva2' ])

        # Add width option
        if vwidth:
            options['video']['width'] = vwidth

        # Add pix_fmt
        if self.pix_fmt:
            options['video']['pix_fmt'] = self.pix_fmt[0]

        self.options = options
        return options
Beispiel #30
0
 def on_task_output(self, task, config):
     """
     Configuration::
         subliminal:
             languages: List of languages (as IETF codes) in order of preference. At least one is required.
             alternatives: List of second-choice languages; subs will be downloaded but entries rejected.
             exact_match: Use file hash only to search for subs, otherwise Subliminal will try to guess by filename.
             providers: List of providers from where to download subtitles.
             single: Download subtitles in single mode (no language code added to subtitle filename).
     """
     if not task.accepted:
         log.debug('nothing accepted, aborting')
         return
     from babelfish import Language
     from dogpile.cache.exception import RegionAlreadyConfigured
     import subliminal
     from subliminal.cli import MutexLock
     try:
         subliminal.region.configure('dogpile.cache.dbm', 
                                           arguments={'filename': os.path.join(tempfile.gettempdir(),
                                                                               'cachefile.dbm'),
                                           'lock_factory': MutexLock})
     except RegionAlreadyConfigured:
         pass
     logging.getLogger("subliminal").setLevel(logging.CRITICAL)
     logging.getLogger("enzyme").setLevel(logging.WARNING)
     langs = set([Language.fromietf(s) for s in config.get('languages', [])])
     alts = set([Language.fromietf(s) for s in config.get('alternatives', [])])
     # keep all downloaded subtitles and save to disk when done (no need to write every time)
     downloaded_subtitles = collections.defaultdict(list)
     providers_list = config.get('providers', None)
     # test if only one language was provided, if so we will download in single mode
     # (aka no language code added to subtitle filename)
     # unless we are forced not to by configuration
     # if we pass 'yes' for single in configuration but choose more than one language
     # we ignore the configuration and add the language code to the
     # potentially downloaded files
     single_mode = config.get('single', '') and len(langs | alts) <= 1
     for entry in task.accepted:
         if 'location' not in entry:
             log.warning('Cannot act on entries that do not represent a local file.')
         elif not os.path.exists(entry['location']):
             entry.fail('file not found: %s' % entry['location'])
         elif '$RECYCLE.BIN' not in entry['location']:  # ignore deleted files in Windows shares
             try:
                 entry_langs = entry.get('subtitle_languages', [])
                 if not entry_langs:
                     entry_langs = langs
                 video = subliminal.scan_video(entry['location'])
                 if isinstance(video, subliminal.Episode):
                     title = video.series
                 else:
                     title = video.title
                 log.info('Name computed for %s was %s' % (entry['location'], title))
                 msc = video.scores['hash'] if config['exact_match'] else 0
                 if entry_langs & video.subtitle_languages:
                     entry['subtitles_missing'] = set()
                     continue  # subs for preferred lang(s) already exists
                 else:
                     subtitle = subliminal.download_best_subtitles([video], entry_langs, providers=providers_list,
                                                                   min_score=msc)
                     if subtitle and any(subtitle.values()):
                         downloaded_subtitles.update(subtitle)
                         log.info('Subtitles found for %s' % entry['location'])
                     else:
                         # TODO check performance hit -- this explicit check may be better on slower devices
                         # but subliminal already handles it for us, but it loops over all providers before stopping
                         remaining_alts = alts - video.subtitle_languages
                         if remaining_alts:
                             # only try to download for alternatives that aren't alread downloaded
                             subtitle = subliminal.download_best_subtitles([video], remaining_alts,
                                                                           providers=providers_list, min_score=msc)
                         # this potentially just checks an already checked assignment bleh
                         if subtitle and any(subtitle.values()):
                             downloaded_subtitles.update(subtitle)
                             entry.fail('subtitles found for a second-choice language.')
                         else:
                             entry.fail('cannot find any subtitles for now.')
                     downloaded_languages = set([Language.fromietf(unicode(l.language))
                                                 for l in subtitle[video]])
                     if entry_langs:
                         entry['subtitles_missing'] = entry_langs - downloaded_languages
             except Exception as err:
                 # don't want to abort the entire task for errors in a  
                 # single video file or for occasional network timeouts
                 if err.args:
                     msg = unicode(err.args[0])
                 else:
                     # Subliminal errors don't always have a message, just use the name
                     msg = 'subliminal error: %s' % err.__class__.__name__
                 log.debug(msg)
                 entry.fail(msg)
     if downloaded_subtitles:
         # save subtitles to disk
         for k, v in downloaded_subtitles.iteritems():
             if v:
                 subliminal.save_subtitles(k, v, single=single_mode)
Beispiel #31
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

    # 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 ''))
Beispiel #32
0
def download_subtitles(subtitles_info):  # pylint: disable=too-many-locals, too-many-branches, too-many-statements
    existing_subtitles = subtitles_info['subtitles']

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

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

    subtitles_path = get_subtitles_path(subtitles_info['location'])
    video_path = subtitles_info['location']

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

                                downloaded_languages.add(
                                    subtitle.language.opensubtitles)

                            # Don't run post processor unless at least one file has all of the needed subtitles
                            if not needs_subtitles(downloaded_languages):
                                run_post_process = True
                        except Exception as error:
                            logger.log(
                                u'Error occurred when downloading subtitles for: {}. Error: {}'
                                .format(os.path.join(root, video_filename),
                                        ex(error)))
            if run_post_process:
                logger.log(
                    u'Starting post-process with default settings now that we found subtitles'
                )
                processTV.processDir(sickbeard.TV_DOWNLOAD_DIR)
Beispiel #34
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 = 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(
            "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 == True:
                                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 download_result == False:
                            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 == True:
                                video = scan_video(path)
                            single = get_general_settings()[7]
                            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 == 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(
                                            '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)
Beispiel #35
0
def download_subtitles(episode, force_lang=None):
    existing_subtitles = episode.subtitles

    if not needs_subtitles(existing_subtitles, force_lang):
        logger.debug(
            "Episode already has all needed subtitles, skipping {0} {1}".format(
                episode.show.name, episode_num(episode.season, episode.episode) or episode_num(episode.season, episode.episode, numbering="absolute")
            )
        )
        return existing_subtitles, None

    if not force_lang:
        languages = get_needed_languages(existing_subtitles)
    else:
        languages = {from_code(force_lang)}

    if not languages:
        logger.debug(
            "No subtitles needed for {0} {1}".format(
                episode.show.name, episode_num(episode.season, episode.episode) or episode_num(episode.season, episode.episode, numbering="absolute")
            )
        )
        return existing_subtitles, None

    subtitles_path = get_subtitles_path(episode.location)
    video_path = episode.location

    # Perfect match = hash score - hearing impaired score - resolution score
    # (subtitle for 720p is the same as for 1080p)
    # Perfect match = 215 - 1 - 1 = 213
    # Non-perfect match = series + year + season + episode
    # Non-perfect match = 108 + 54 + 18 + 18 = 198
    # From latest subliminal code:
    # episode_scores = {'hash': 215, 'series': 108, 'year': 54, 'season': 18, 'episode': 18, 'release_group': 9,
    #                   'source': 4, 'audio_codec': 2, 'resolution': 1, 'hearing_impaired': 1, 'video_codec': 1}
    user_score = 213 if settings.SUBTITLES_PERFECT_MATCH else 198

    video = get_video(video_path, subtitles_path=subtitles_path, episode=episode)
    if not video:
        logger.debug(
            "Exception caught in subliminal.scan_video for {0} {1}".format(
                episode.show.name, episode_num(episode.season, episode.episode) or episode_num(episode.season, episode.episode, numbering="absolute")
            )
        )
        return existing_subtitles, None

    providers = enabled_service_list()
    pool = SubtitleProviderPool()

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

        for provider in providers:
            if provider in pool.discarded_providers:
                logger.debug("Could not search in {0} provider. Discarding for now".format(provider))

        if not subtitles_list:
            logger.debug(
                "No subtitles found for {0} {1}".format(
                    episode.show.name, episode_num(episode.season, episode.episode) or episode_num(episode.season, episode.episode, numbering="absolute")
                )
            )
            return existing_subtitles, None

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

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

        subliminal.save_subtitles(video, found_subtitles, directory=subtitles_path, single=not settings.SUBTITLES_MULTI, encoding="utf8")
    except IOError as error:
        if "No space left on device" in str(error):
            logger.warning("Not enough space on the drive to save subtitles")
        else:
            logger.warning(traceback.format_exc())
        return existing_subtitles, None
    except Exception:
        logger.info("Error occurred when downloading subtitles for: {0}".format(video_path))
        logger.exception(traceback.format_exc())
        return existing_subtitles, None

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

        sickchill.oldbeard.helpers.chmodAsParent(subtitle_path)
        sickchill.oldbeard.helpers.fixSetGroupID(subtitle_path)

        if settings.SUBTITLES_HISTORY:
            logger.debug("history.logSubtitle {0}, {1}".format(subtitle.provider_name, subtitle.language.opensubtitles))

            history.logSubtitle(episode.show.indexerid, episode.season, episode.episode, episode.status, subtitle)

        if settings.SUBTITLES_EXTRA_SCRIPTS and is_media_file(video_path) and not settings.EMBEDDED_SUBTITLES_ALL:

            run_subs_extra_scripts(episode, subtitle, video, single=not settings.SUBTITLES_MULTI)

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

    return current_subtitles, new_subtitles
    def on_task_output(self, task, config):
        """
        Configuration::
            subliminal:
                languages: List of languages (as IETF codes) in order of preference. At least one is required.
                alternatives: List of second-choice languages; subs will be downloaded but entries rejected.
                exact_match: Use file hash only to search for subs, otherwise Subliminal will try to guess by filename.
                providers: List of providers from where to download subtitles.
                single: Download subtitles in single mode (no language code added to subtitle filename).
        """
        if not task.accepted:
            log.debug('nothing accepted, aborting')
            return
        from babelfish import Language
        from dogpile.cache.exception import RegionAlreadyConfigured
        import subliminal
        from subliminal.cli import MutexLock
        from subliminal.score import episode_scores, movie_scores
        try:
            subliminal.region.configure('dogpile.cache.dbm',
                                        arguments={
                                            'filename': os.path.join(tempfile.gettempdir(), 'cachefile.dbm'),
                                            'lock_factory': MutexLock,
                                        })
        except RegionAlreadyConfigured:
            pass
        logging.getLogger("subliminal").setLevel(logging.CRITICAL)
        logging.getLogger("enzyme").setLevel(logging.WARNING)
        languages = set([Language.fromietf(s) for s in config.get('languages', [])])
        alternative_languages = set([Language.fromietf(s) for s in config.get('alternatives', [])])
        # keep all downloaded subtitles and save to disk when done (no need to write every time)
        downloaded_subtitles = collections.defaultdict(list)
        providers_list = config.get('providers', None)
        # test if only one language was provided, if so we will download in single mode
        # (aka no language code added to subtitle filename)
        # unless we are forced not to by configuration
        # if we pass 'yes' for single in configuration but choose more than one language
        # we ignore the configuration and add the language code to the
        # potentially downloaded files
        single_mode = config.get('single', '') and len(languages | alternative_languages) <= 1
        for entry in task.accepted:
            if 'location' not in entry:
                log.warning('Cannot act on entries that do not represent a local file.')
            elif not os.path.exists(entry['location']):
                entry.fail('file not found: %s' % entry['location'])
            elif '$RECYCLE.BIN' not in entry['location']:  # ignore deleted files in Windows shares
                try:
                    entry_languages = entry.get('subtitle_languages') or languages

                    video = subliminal.scan_video(entry['location'])
                    existing_subtitles = set(subliminal.core.search_external_subtitles(entry['location']).values())
                    video.subtitle_languages = existing_subtitles
                    if isinstance(video, subliminal.Episode):
                        title = video.series
                        hash_scores = episode_scores['hash']
                    else:
                        title = video.title
                        hash_scores = movie_scores['hash']
                    log.info('Name computed for %s was %s', entry['location'], title)
                    msc = hash_scores if config['exact_match'] else 0
                    if entry_languages & existing_subtitles:
                        log.debug('All preferred languages already exist for "%s"', entry['title'])
                        entry['subtitles_missing'] = set()
                        continue  # subs for preferred lang(s) already exists
                    else:
                        subtitle = subliminal.download_best_subtitles([video], entry_languages,
                                                                      providers=providers_list, min_score=msc)
                        if subtitle and any(subtitle.values()):
                            downloaded_subtitles.update(subtitle)
                            log.info('Subtitles found for %s', entry['location'])
                        else:
                            # only try to download for alternatives that aren't alread downloaded
                            subtitle = subliminal.download_best_subtitles([video], alternative_languages,
                                                                          providers=providers_list, min_score=msc)

                            if subtitle and any(subtitle.values()):
                                downloaded_subtitles.update(subtitle)
                                entry.fail('subtitles found for a second-choice language.')
                            else:
                                entry.fail('cannot find any subtitles for now.')
                        downloaded_languages = set([Language.fromietf(str(l.language))
                                                    for l in subtitle[video]])
                        if entry_languages:
                            entry['subtitles_missing'] = entry_languages - downloaded_languages
                except ValueError as e:
                    log.error('subliminal error: %s', e)
                    entry.fail()

        if downloaded_subtitles:
            # save subtitles to disk
            for video, subtitle in downloaded_subtitles.items():
                if subtitle:
                    subliminal.save_subtitles(video, subtitle, single=single_mode)
Beispiel #37
0
    def on_task_output(self, task, config):
        """
        Configuration::
            subliminal:
                languages: List of languages (as IETF codes) in order of preference. At least one is required.
                alternatives: List of second-choice languages; subs will be downloaded but entries rejected.
                exact_match: Use file hash only to search for subs, otherwise Subliminal will try to guess by filename.
                providers: List of providers from where to download subtitles.
                single: Download subtitles in single mode (no language code added to subtitle filename).
                directory: Path to directory where to save the subtitles, default is next to the video.
                hearing_impaired: Prefer subtitles for the hearing impaired when available
                authentication: >
                  Dictionary of configuration options for different providers.
                  Keys correspond to provider names, and values are dictionaries, usually specifying `username` and
                  `password`.
        """
        if not task.accepted:
            log.debug('nothing accepted, aborting')
            return
        from babelfish import Language
        from dogpile.cache.exception import RegionAlreadyConfigured
        import subliminal
        from subliminal import scan_video, save_subtitles
        from subliminal.cli import MutexLock
        from subliminal.core import ARCHIVE_EXTENSIONS, scan_archive, refine, search_external_subtitles
        from subliminal.score import episode_scores, movie_scores
        from subliminal.video import VIDEO_EXTENSIONS
        try:
            subliminal.region.configure('dogpile.cache.dbm',
                                        arguments={
                                            'filename': os.path.join(tempfile.gettempdir(), 'cachefile.dbm'),
                                            'lock_factory': MutexLock,
                                        })
        except RegionAlreadyConfigured:
            pass

        # Let subliminal be more verbose if our logger is set to DEBUG
        if log.isEnabledFor(logging.DEBUG):
            logging.getLogger("subliminal").setLevel(logging.INFO)
        else:
            logging.getLogger("subliminal").setLevel(logging.CRITICAL)

        logging.getLogger("dogpile").setLevel(logging.CRITICAL)
        logging.getLogger("enzyme").setLevel(logging.WARNING)
        try:
            languages = set([Language.fromietf(s) for s in config.get('languages', [])])
            alternative_languages = set([Language.fromietf(s) for s in config.get('alternatives', [])])
        except ValueError as e:
            raise plugin.PluginError(e)
        # keep all downloaded subtitles and save to disk when done (no need to write every time)
        downloaded_subtitles = collections.defaultdict(list)
        providers_list = config.get('providers', None)
        provider_configs = config.get('authentication', None)
        # test if only one language was provided, if so we will download in single mode
        # (aka no language code added to subtitle filename)
        # unless we are forced not to by configuration
        # if we pass 'yes' for single in configuration but choose more than one language
        # we ignore the configuration and add the language code to the
        # potentially downloaded files
        single_mode = config.get('single', '') and len(languages | alternative_languages) <= 1
        hearing_impaired = config.get('hearing_impaired', False)

        with subliminal.core.ProviderPool(providers=providers_list, provider_configs=provider_configs) as provider_pool:
            for entry in task.accepted:
                if 'location' not in entry:
                    log.warning('Cannot act on entries that do not represent a local file.')
                    continue
                if not os.path.exists(entry['location']):
                    entry.fail('file not found: %s' % entry['location'])
                    continue
                if '$RECYCLE.BIN' in entry['location']:  # ignore deleted files in Windows shares
                    continue

                try:
                    entry_languages = set(entry.get('subtitle_languages', [])) or languages

                    if entry['location'].endswith(VIDEO_EXTENSIONS):
                        video = scan_video(entry['location'])
                    elif entry['location'].endswith(ARCHIVE_EXTENSIONS):
                        video = scan_archive(entry['location'])
                    else:
                        entry.reject('File extension is not a supported video or archive extension')
                        continue
                    # use metadata refiner to get mkv metadata
                    refiner = ('metadata',)
                    refine(video, episode_refiners=refiner, movie_refiners=refiner)
                    existing_subtitles = set(search_external_subtitles(entry['location']).values())
                    video.subtitle_languages |= existing_subtitles
                    if isinstance(video, subliminal.Episode):
                        title = video.series
                        hash_scores = episode_scores['hash']
                    else:
                        title = video.title
                        hash_scores = movie_scores['hash']
                    log.info('Name computed for %s was %s', entry['location'], title)
                    msc = hash_scores if config['exact_match'] else 0
                    if entry_languages.issubset(video.subtitle_languages):
                        log.debug('All preferred languages already exist for "%s"', entry['title'])
                        entry['subtitles_missing'] = set()
                        continue  # subs for preferred lang(s) already exists
                    else:
                        # Gather the subtitles for the alternative languages too, to avoid needing to search the sites
                        # again. They'll just be ignored if the main languages are found.
                        all_subtitles = provider_pool.list_subtitles(video, entry_languages | alternative_languages)
                        try:
                            subtitles = provider_pool.download_best_subtitles(all_subtitles, video, entry_languages,
                                                                              min_score=msc,
                                                                              hearing_impaired=hearing_impaired)
                        except TypeError as e:
                            log.error('Downloading subtitles failed due to a bug in subliminal. Please see'
                                      'https://github.com/Diaoul/subliminal/issues/921. Error: %s', e)
                            subtitles = []
                        if subtitles:
                            downloaded_subtitles[video].extend(subtitles)
                            log.info('Subtitles found for %s', entry['location'])
                        else:
                            # only try to download for alternatives that aren't already downloaded
                            subtitles = provider_pool.download_best_subtitles(all_subtitles, video,
                                                                              alternative_languages, min_score=msc,
                                                                              hearing_impaired=hearing_impaired)

                            if subtitles:
                                downloaded_subtitles[video].extend(subtitles)
                                entry.reject('subtitles found for a second-choice language.')
                            else:
                                entry.reject('cannot find any subtitles for now.')

                        downloaded_languages = set([Language.fromietf(str(l.language))
                                                    for l in subtitles])
                        if entry_languages:
                            entry['subtitles_missing'] = entry_languages - downloaded_languages
                            if len(entry['subtitles_missing']) > 0:
                                entry.reject('Subtitles for all primary languages not found')
                except ValueError as e:
                    log.error('subliminal error: %s', e)
                    entry.fail()

        if downloaded_subtitles:
            if task.options.test:
                log.verbose('Test mode. Found subtitles:')
            # save subtitles to disk
            for video, subtitle in downloaded_subtitles.items():
                if subtitle:
                    _directory = config.get('directory')
                    if _directory:
                        _directory = os.path.expanduser(_directory)
                    if task.options.test:
                        log.verbose('     FOUND LANGUAGES %s for %s', [str(l.language) for l in subtitle], video.name)
                        continue
                    save_subtitles(video, subtitle, single=single_mode, directory=_directory)
    def generateOptions(self, inputfile, original=None):
        # Get path information from the input file
        input_dir, filename, input_extension = self.parseFile(inputfile)

        info = Converter(self.FFMPEG_PATH, self.FFPROBE_PATH).probe(inputfile)

        # Video stream
        self.log.info("Reading video stream.")
        self.log.info("Video codec detected: %s." % info.video.codec)

        try:
            vbr = self.estimateVideoBitrate(info)
        except:
            vbr = info.format.bitrate / 1000

        if info.video.codec.lower() in self.video_codec:
            vcodec = "copy"
        else:
            vcodec = self.video_codec[0]
        vbitrate = self.video_bitrate if self.video_bitrate else vbr

        self.log.info("Pix Fmt: %s." % info.video.pix_fmt)
        if self.pix_fmt and info.video.pix_fmt.lower() not in self.pix_fmt:
            vcodec = self.video_codec[0]

        if self.video_bitrate is not None and vbr > self.video_bitrate:
            self.log.debug("Overriding video bitrate. Codec cannot be copied because video bitrate is too high.")
            vcodec = self.video_codec[0]
            vbitrate = self.video_bitrate

        if self.video_width is not None and self.video_width < info.video.video_width:
            self.log.debug(
                "Video width is over the max width, it will be downsampled. Video stream can no longer be copied."
            )
            vcodec = self.video_codec[0]
            vwidth = self.video_width
        else:
            vwidth = None

        if self.h264_level and info.video.video_level and (info.video.video_level / 10 > self.h264_level):
            self.log.info("Video level %0.1f." % (info.video.video_level / 10))
            vcodec = self.video_codec[0]

        self.log.debug("Video codec: %s." % vcodec)
        self.log.debug("Video bitrate: %s." % vbitrate)

        # Audio streams
        self.log.info("Reading audio streams.")

        overrideLang = True
        for a in info.audio:
            try:
                if a.metadata["language"].strip() == "" or a.metadata["language"] is None:
                    a.metadata["language"] = "und"
            except KeyError:
                a.metadata["language"] = "und"
            if (a.metadata["language"] == "und" and self.adl) or (
                self.awl and a.metadata["language"].lower() in self.awl
            ):
                overrideLang = False
                break

        if overrideLang:
            self.awl = None
            self.log.info(
                "No audio streams detected in any appropriate language, relaxing restrictions so there will be some audio stream present."
            )

        audio_settings = {}
        l = 0
        for a in info.audio:
            try:
                if a.metadata["language"].strip() == "" or a.metadata["language"] is None:
                    a.metadata["language"] = "und"
            except KeyError:
                a.metadata["language"] = "und"

            self.log.info("Audio detected for stream #%s: %s [%s]." % (a.index, a.codec, a.metadata["language"]))

            # Set undefined language to default language if specified
            if self.adl is not None and a.metadata["language"] == "und":
                self.log.debug("Undefined language detected, defaulting to [%s]." % self.adl)
                a.metadata["language"] = self.adl

            # Proceed if no whitelist is set, or if the language is in the whitelist
            if self.awl is None or a.metadata["language"].lower() in self.awl:
                # Create iOS friendly audio stream if the default audio stream has too many channels (iOS only likes AAC stereo)
                if self.iOS:
                    if a.audio_channels > 2:
                        iOSbitrate = 256 if (self.audio_bitrate * 2) > 256 else (self.audio_bitrate * 2)
                        self.log.info(
                            "Creating audio stream %s from source audio stream %s [iOS-audio]." % (str(l), a.index)
                        )
                        self.log.debug("Audio codec: %s." % self.iOS)
                        self.log.debug("Channels: 2.")
                        self.log.debug("Bitrate: %s." % iOSbitrate)
                        self.log.debug("Language: %s." % a.metadata["language"])
                        audio_settings.update(
                            {
                                l: {
                                    "map": a.index,
                                    "codec": self.iOS,
                                    "channels": 2,
                                    "bitrate": iOSbitrate,
                                    "language": a.metadata["language"],
                                }
                            }
                        )
                        l += 1
                # If the iOS audio option is enabled and the source audio channel is only stereo, the additional iOS channel will be skipped and a single AAC 2.0 channel will be made regardless of codec preference to avoid multiple stereo channels
                self.log.info("Creating audio stream %s from source stream %s." % (str(l), a.index))
                if self.iOS and a.audio_channels <= 2:
                    self.log.debug(
                        "Overriding default channel settings because iOS audio is enabled but the source is stereo [iOS-audio]."
                    )
                    acodec = "copy" if a.codec == self.iOS else self.iOS
                    audio_channels = a.audio_channels
                    abitrate = (
                        a.audio_channels * 128
                        if (a.audio_channels * self.audio_bitrate) > (a.audio_channels * 128)
                        else (a.audio_channels * self.audio_bitrate)
                    )
                else:
                    # If desired codec is the same as the source codec, copy to avoid quality loss
                    acodec = "copy" if a.codec.lower() in self.audio_codec else self.audio_codec[0]
                    # Audio channel adjustments
                    if self.maxchannels and a.audio_channels > self.maxchannels:
                        audio_channels = self.maxchannels
                        if acodec == "copy":
                            acodec = self.audio_codec[0]
                        abitrate = self.maxchannels * self.audio_bitrate
                    else:
                        audio_channels = a.audio_channels
                        abitrate = a.audio_channels * self.audio_bitrate
                    # Bitrate calculations/overrides
                    if self.audio_bitrate is 0:
                        self.log.debug("Attempting to set bitrate based on source stream bitrate.")
                        try:
                            abitrate = a.bitrate / 1000
                        except:
                            self.log.warning(
                                "Unable to determine audio bitrate from source stream %s, defaulting to 256 per channel."
                                % a.index
                            )
                            abitrate = a.audio_channels * 256

                self.log.debug("Audio codec: %s." % acodec)
                self.log.debug("Channels: %s." % audio_channels)
                self.log.debug("Bitrate: %s." % abitrate)
                self.log.debug("Language: %s" % a.metadata["language"])

                # If the iOSFirst option is enabled, disable the iOS option after the first audio stream is processed
                if self.iOS and self.iOSFirst:
                    self.log.debug("Not creating any additional iOS audio streams.")
                    self.iOS = False

                audio_settings.update(
                    {
                        l: {
                            "map": a.index,
                            "codec": acodec,
                            "channels": audio_channels,
                            "bitrate": abitrate,
                            "language": a.metadata["language"],
                        }
                    }
                )

                if acodec == "copy" and a.codec == "aac":
                    audio_settings[l]["bsf"] = "aac_adtstoasc"
                l = l + 1

        # Subtitle streams
        subtitle_settings = {}
        l = 0
        self.log.info("Reading subtitle streams.")
        for s in info.subtitle:
            try:
                if s.metadata["language"].strip() == "" or s.metadata["language"] is None:
                    s.metadata["language"] = "und"
            except KeyError:
                s.metadata["language"] = "und"

            self.log.info("Subtitle detected for stream #%s: %s [%s]." % (s.index, s.codec, s.metadata["language"]))

            # Set undefined language to default language if specified
            if self.sdl is not None and s.metadata["language"] == "und":
                self.log.debug("Undefined language detected, defaulting to [%s]." % self.sdl)
                s.metadata["language"] = self.sdl
            # Make sure its not an image based codec
            if s.codec.lower() not in bad_subtitle_codecs and self.embedsubs:

                # Proceed if no whitelist is set, or if the language is in the whitelist
                if self.swl is None or s.metadata["language"].lower() in self.swl:
                    subtitle_settings.update(
                        {
                            l: {
                                "map": s.index,
                                "codec": self.scodec[0],
                                "language": s.metadata["language"],
                                "encoding": self.subencoding,
                                # 'forced': s.sub_forced,
                                # 'default': s.sub_default
                            }
                        }
                    )
                    self.log.info("Creating subtitle stream %s from source stream %s." % (l, s.index))
                    l = l + 1
            elif s.codec.lower() not in bad_subtitle_codecs and not self.embedsubs:
                if self.swl is None or s.metadata["language"].lower() in self.swl:
                    for codec in self.scodec:
                        ripsub = {0: {"map": s.index, "codec": codec, "language": s.metadata["language"]}}
                        options = {"format": codec, "subtitle": ripsub}

                        try:
                            extension = subtitle_codec_extensions[codec]
                        except:
                            self.log.info("Wasn't able to determine subtitle file extension, defaulting to '.srt'.")
                            extension = "srt"

                        forced = ".forced" if s.sub_forced else ""

                        input_dir, filename, input_extension = self.parseFile(inputfile)
                        output_dir = input_dir if self.output_dir is None else self.output_dir
                        outputfile = os.path.join(
                            output_dir, filename + "." + s.metadata["language"] + forced + "." + extension
                        )

                        i = 2
                        while os.path.isfile(outputfile):
                            self.log.debug("%s exists, appending %s to filename." % (outputfile, i))
                            outputfile = os.path.join(
                                output_dir,
                                filename + "." + s.metadata["language"] + forced + "." + str(i) + "." + extension,
                            )
                            i += 1
                        try:
                            self.log.info(
                                "Ripping %s subtitle from source stream %s into external file."
                                % (s.metadata["language"], s.index)
                            )
                            conv = Converter(self.FFMPEG_PATH, self.FFPROBE_PATH).convert(
                                inputfile, outputfile, options, timeout=None
                            )
                            for timecode in conv:
                                pass

                            self.log.info("%s created." % outputfile)
                        except:
                            self.log.exception("Unabled to create external subtitle file for stream %s." % (s.index))

        # Attempt to download subtitles if they are missing using subliminal
        languages = set()
        try:
            if self.swl:
                for alpha3 in self.swl:
                    languages.add(Language(alpha3))
            elif self.sdl:
                languages.add(Language(self.sdl))
            else:
                self.downloadsubs = False
                self.log.error("No valid subtitle language specified, cannot download subtitles.")
        except:
            self.log.exception("Unable to verify subtitle languages for download.")
            self.downloadsubs = False

        if self.downloadsubs:
            import subliminal

            self.log.info("Attempting to download subtitles.")

            # Attempt to set the dogpile cache
            try:
                subliminal.region.configure("dogpile.cache.memory")
            except:
                pass

            try:
                video = subliminal.scan_video(os.path.abspath(inputfile), subtitles=True, embedded_subtitles=True)
                subtitles = subliminal.download_best_subtitles(
                    [video], languages, hearing_impaired=False, providers=self.subproviders
                )
                try:
                    subliminal.save_subtitles(video, subtitles[video])
                except:
                    # Support for older versions of subliminal
                    subliminal.save_subtitles(subtitles)
                    self.log.info("Please update to the latest version of subliminal.")
            except Exception as e:
                self.log.info("Unable to download subtitles.", exc_info=True)
                self.log.debug("Unable to download subtitles.", exc_info=True)
        # External subtitle import
        if self.embedsubs:  # Don't bother if we're not embeddeding any subtitles
            src = 1  # FFMPEG input source number
            for dirName, subdirList, fileList in os.walk(input_dir):
                for fname in fileList:
                    subname, subextension = os.path.splitext(fname)
                    # Watch for appropriate file extension
                    if subextension[1:] in valid_subtitle_extensions:
                        x, lang = os.path.splitext(subname)
                        lang = lang[1:]
                        # Using bablefish to convert a 2 language code to a 3 language code
                        if len(lang) is 2:
                            try:
                                babel = Language.fromalpha2(lang)
                                lang = babel.alpha3
                            except:
                                pass
                        # If subtitle file name and input video name are the same, proceed
                        if x == filename:
                            self.log.info("External %s subtitle file detected." % lang)
                            if self.swl is None or lang in self.swl:

                                self.log.info("Creating subtitle stream %s by importing %s." % (l, fname))

                                subtitle_settings.update(
                                    {
                                        l: {
                                            "path": os.path.join(dirName, fname),
                                            "source": src,
                                            "map": 0,
                                            "codec": "mov_text",
                                            "language": lang,
                                        }
                                    }
                                )

                                self.log.debug("Path: %s." % os.path.join(dirName, fname))
                                self.log.debug("Source: %s." % src)
                                self.log.debug("Codec: mov_text.")
                                self.log.debug("Langauge: %s." % lang)

                                l = l + 1
                                src = src + 1

                                self.deletesubs.add(os.path.join(dirName, fname))

                            else:
                                self.log.info(
                                    "Ignoring %s external subtitle stream due to language %s." % (fname, lang)
                                )

        # Collect all options
        options = {
            "format": self.output_format,
            "video": {"codec": vcodec, "map": info.video.index, "bitrate": vbitrate, "level": self.h264_level},
            "audio": audio_settings,
            "subtitle": subtitle_settings,
            "preopts": ["-fix_sub_duration"],
            "postopts": ["-threads", self.threads],
        }

        # If using h264qsv, add the codec in front of the input for decoding
        if (
            vcodec == "h264qsv"
            and info.video.codec.lower() == "h264"
            and self.qsv_decoder
            and (info.video.video_level / 10) < 5
        ):
            options["preopts"].extend(["-vcodec", "h264_qsv"])

        # Add width option
        if vwidth:
            options["video"]["width"] = vwidth

        # Add pix_fmt
        if self.pix_fmt:
            options["video"]["pix_fmt"] = self.pix_fmt[0]

        self.options = options
        return options
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])

Beispiel #40
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 = 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(
            "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 = get_general_settings()[7]
            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)
Beispiel #41
0
    def subtitles_download_in_pp():  # pylint: disable=too-many-locals, too-many-branches, too-many-statements
        logger.log(u'Checking for needed subtitles in Post-Process folder',
                   logger.INFO)

        providers = enabled_service_list()
        pool = SubtitleProviderPool()

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

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

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

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

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

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

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

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

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

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

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

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

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

                                downloaded_languages.add(
                                    subtitle.language.opensubtitles)

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