Beispiel #1
0
    def delete(self):
        sonarrSeriesId = request.args.get('seriesid')
        sonarrEpisodeId = request.args.get('episodeid')
        episodeInfo = TableEpisodes.select(TableEpisodes.title,
                                           TableEpisodes.path,
                                           TableEpisodes.scene_name,
                                           TableEpisodes.audio_language)\
            .where(TableEpisodes.sonarrEpisodeId == sonarrEpisodeId)\
            .dicts()\
            .get()

        episodePath = path_mappings.path_replace(episodeInfo['path'])

        language = request.form.get('language')
        forced = request.form.get('forced')
        hi = request.form.get('hi')
        subtitlesPath = request.form.get('path')

        subtitlesPath = path_mappings.path_replace_reverse(subtitlesPath)

        delete_subtitles(media_type='series',
                         language=language,
                         forced=forced,
                         hi=hi,
                         media_path=episodePath,
                         subtitles_path=subtitlesPath,
                         sonarr_series_id=sonarrSeriesId,
                         sonarr_episode_id=sonarrEpisodeId)

        return '', 204
Beispiel #2
0
    def sync(self, video_path, srt_path, srt_lang, media_type, sonarr_series_id=None, sonarr_episode_id=None,
             radarr_id=None):
        self.reference = video_path
        self.srtin = srt_path
        self.srtout = '{}.synced.srt'.format(os.path.splitext(self.srtin)[0])
        self.args = None

        ffprobe_exe = get_binary('ffprobe')
        if not ffprobe_exe:
            logging.debug('BAZARR FFprobe not found!')
            return
        else:
            logging.debug('BAZARR FFprobe used is %s', ffprobe_exe)

        ffmpeg_exe = get_binary('ffmpeg')
        if not ffmpeg_exe:
            logging.debug('BAZARR FFmpeg not found!')
            return
        else:
            logging.debug('BAZARR FFmpeg used is %s', ffmpeg_exe)

        self.ffmpeg_path = os.path.dirname(ffmpeg_exe)
        try:
            unparsed_args = [self.reference, '-i', self.srtin, '-o', self.srtout, '--ffmpegpath', self.ffmpeg_path,
                             '--vad', self.vad, '--log-dir-path', self.log_dir_path]
            if settings.subsync.getboolean('debug'):
                unparsed_args.append('--make-test-case')
            parser = make_parser()
            self.args = parser.parse_args(args=unparsed_args)
            result = run(self.args)
        except Exception as e:
            logging.exception('BAZARR an exception occurs during the synchronization process for this subtitles: '
                              '{0}'.format(self.srtin))
        else:
            if settings.subsync.getboolean('debug'):
                return result
            if os.path.isfile(self.srtout):
                if not settings.subsync.getboolean('debug'):
                    os.remove(self.srtin)
                    os.rename(self.srtout, self.srtin)

                    offset_seconds = result['offset_seconds'] or 0
                    framerate_scale_factor = result['framerate_scale_factor'] or 0
                    message = "{0} subtitles synchronization ended with an offset of {1} seconds and a framerate " \
                              "scale factor of {2}.".format(language_from_alpha2(srt_lang), offset_seconds,
                                                            "{:.2f}".format(framerate_scale_factor))

                    if media_type == 'series':
                        history_log(action=5, sonarr_series_id=sonarr_series_id, sonarr_episode_id=sonarr_episode_id,
                                    description=message, video_path=path_mappings.path_replace_reverse(self.reference),
                                    language=srt_lang, subtitles_path=srt_path)
                    else:
                        history_log_movie(action=5, radarr_id=radarr_id, description=message,
                                          video_path=path_mappings.path_replace_reverse_movie(self.reference),
                                          language=srt_lang, subtitles_path=srt_path)
            else:
                logging.error('BAZARR unable to sync subtitles: {0}'.format(self.srtin))

            return result
Beispiel #3
0
def refine_from_ffprobe(path, video):
    if isinstance(video, Movie):
        file_id = TableMovies.select(TableMovies.movie_file_id, TableMovies.file_size)\
            .where(TableMovies.path == path_mappings.path_replace_reverse_movie(path))\
            .dicts()\
            .get_or_none()
    else:
        file_id = TableEpisodes.select(TableEpisodes.episode_file_id, TableEpisodes.file_size)\
            .where(TableEpisodes.path == path_mappings.path_replace_reverse(path))\
            .dicts()\
            .get_or_none()

    if not file_id:
        return video

    if isinstance(video, Movie):
        data = parse_video_metadata(file=path, file_size=file_id['file_size'],
                                    movie_file_id=file_id['movie_file_id'])
    else:
        data = parse_video_metadata(file=path, file_size=file_id['file_size'],
                                    episode_file_id=file_id['episode_file_id'])

    if not data['ffprobe']:
        logging.debug("No FFprobe available in cache for this file: {}".format(path))
        return video

    logging.debug('FFprobe found: %s', data['ffprobe'])

    if 'video' not in data['ffprobe']:
        logging.debug('BAZARR FFprobe was unable to find video tracks in the file!')
    else:
        if 'resolution' in data['ffprobe']['video'][0]:
            if not video.resolution:
                video.resolution = data['ffprobe']['video'][0]['resolution']
        if 'codec' in data['ffprobe']['video'][0]:
            if not video.video_codec:
                video.video_codec = data['ffprobe']['video'][0]['codec']
        if 'frame_rate' in data['ffprobe']['video'][0]:
            if not video.fps:
                if isinstance(data['ffprobe']['video'][0]['frame_rate'], float):
                    video.fps = data['ffprobe']['video'][0]['frame_rate']
                else:
                    try:
                        video.fps = data['ffprobe']['video'][0]['frame_rate'].magnitude
                    except AttributeError:
                        video.fps = data['ffprobe']['video'][0]['frame_rate']

    if 'audio' not in data['ffprobe']:
        logging.debug('BAZARR FFprobe was unable to find audio tracks in the file!')
    else:
        if 'codec' in data['ffprobe']['audio'][0]:
            if not video.audio_codec:
                video.audio_codec = data['ffprobe']['audio'][0]['codec']
        for track in data['ffprobe']['audio']:
            if 'language' in track:
                video.audio_languages.add(track['language'].alpha3)

    return video
Beispiel #4
0
def delete_subtitles(media_type, language, forced, hi, media_path, subtitles_path, sonarr_series_id=None,
                     sonarr_episode_id=None, radarr_id=None):
    if not subtitles_path.endswith('.srt'):
        logging.error('BAZARR can only delete .srt files.')
        return False

    language_log = language
    language_string = language_from_alpha2(language)
    if hi in [True, 'true', 'True']:
        language_log += ':hi'
        language_string += ' HI'
    elif forced in [True, 'true', 'True']:
        language_log += ':forced'
        language_string += ' forced'
        
    result = language_string + " subtitles deleted from disk."

    if media_type == 'series':
        try:
            os.remove(path_mappings.path_replace(subtitles_path))
        except OSError:
            logging.exception('BAZARR cannot delete subtitles file: ' + subtitles_path)
            store_subtitles(path_mappings.path_replace_reverse(media_path), media_path)
            return False
        else:
            history_log(0, sonarr_series_id, sonarr_episode_id, result, language=language_log,
                        video_path=path_mappings.path_replace_reverse(media_path),
                        subtitles_path=path_mappings.path_replace_reverse(subtitles_path))
            store_subtitles(path_mappings.path_replace_reverse(media_path), media_path)
            notify_sonarr(sonarr_series_id)
    else:
        try:
            os.remove(path_mappings.path_replace_movie(subtitles_path))
        except OSError:
            logging.exception('BAZARR cannot delete subtitles file: ' + subtitles_path)
            store_subtitles_movie(path_mappings.path_replace_reverse_movie(media_path), media_path)
            return False
        else:
            history_log_movie(0, radarr_id, result, language=language_log,
                              video_path=path_mappings.path_replace_reverse_movie(media_path),
                              subtitles_path=path_mappings.path_replace_reverse_movie(subtitles_path))
            store_subtitles_movie(path_mappings.path_replace_reverse_movie(media_path), media_path)
            notify_radarr(radarr_id)
            return True
Beispiel #5
0
def process_subtitle(subtitle,
                     media_type,
                     audio_language,
                     path,
                     max_score,
                     is_upgrade=False,
                     is_manual=False):
    use_postprocessing = settings.general.getboolean('use_postprocessing')
    postprocessing_cmd = settings.general.postprocessing_cmd

    downloaded_provider = subtitle.provider_name
    downloaded_language_code3 = _get_download_code3(subtitle)

    downloaded_language = language_from_alpha3(downloaded_language_code3)
    downloaded_language_code2 = alpha2_from_alpha3(downloaded_language_code3)
    audio_language_code2 = alpha2_from_language(audio_language)
    audio_language_code3 = alpha3_from_language(audio_language)
    downloaded_path = subtitle.storage_path
    subtitle_id = subtitle.id
    if subtitle.language.hi:
        modifier_string = " HI"
    elif subtitle.language.forced:
        modifier_string = " forced"
    else:
        modifier_string = ""
    logging.debug('BAZARR Subtitles file saved to disk: ' + downloaded_path)
    if is_upgrade:
        action = "upgraded"
    elif is_manual:
        action = "manually downloaded"
    else:
        action = "downloaded"

    percent_score = round(subtitle.score * 100 / max_score, 2)
    message = downloaded_language + modifier_string + " subtitles " + action + " from " + \
        downloaded_provider + " with a score of " + str(percent_score) + "%."

    if media_type == 'series':
        episode_metadata = TableEpisodes.select(TableEpisodes.sonarrSeriesId,
                                                TableEpisodes.sonarrEpisodeId) \
            .where(TableEpisodes.path == path_mappings.path_replace_reverse(path)) \
            .dicts() \
            .get_or_none()
        if not episode_metadata:
            return
        series_id = episode_metadata['sonarrSeriesId']
        episode_id = episode_metadata['sonarrEpisodeId']
        sync_subtitles(video_path=path,
                       srt_path=downloaded_path,
                       forced=subtitle.language.forced,
                       srt_lang=downloaded_language_code2,
                       media_type=media_type,
                       percent_score=percent_score,
                       sonarr_series_id=episode_metadata['sonarrSeriesId'],
                       sonarr_episode_id=episode_metadata['sonarrEpisodeId'])
    else:
        movie_metadata = TableMovies.select(TableMovies.radarrId) \
            .where(TableMovies.path == path_mappings.path_replace_reverse_movie(path)) \
            .dicts() \
            .get_or_none()
        if not movie_metadata:
            return
        series_id = ""
        episode_id = movie_metadata['radarrId']
        sync_subtitles(video_path=path,
                       srt_path=downloaded_path,
                       forced=subtitle.language.forced,
                       srt_lang=downloaded_language_code2,
                       media_type=media_type,
                       percent_score=percent_score,
                       radarr_id=movie_metadata['radarrId'])

    if use_postprocessing is True:
        command = pp_replace(postprocessing_cmd, path, downloaded_path,
                             downloaded_language, downloaded_language_code2,
                             downloaded_language_code3, audio_language,
                             audio_language_code2, audio_language_code3,
                             subtitle.language.forced, percent_score,
                             subtitle_id, downloaded_provider, series_id,
                             episode_id, subtitle.language.hi)

        if media_type == 'series':
            use_pp_threshold = settings.general.getboolean(
                'use_postprocessing_threshold')
            pp_threshold = int(settings.general.postprocessing_threshold)
        else:
            use_pp_threshold = settings.general.getboolean(
                'use_postprocessing_threshold_movie')
            pp_threshold = int(settings.general.postprocessing_threshold_movie)

        if not use_pp_threshold or (use_pp_threshold
                                    and percent_score < pp_threshold):
            logging.debug(
                "BAZARR Using post-processing command: {}".format(command))
            postprocessing(command, path)
        else:
            logging.debug(
                "BAZARR post-processing skipped because subtitles score isn't below this "
                "threshold value: " + str(pp_threshold) + "%")

    if media_type == 'series':
        reversed_path = path_mappings.path_replace_reverse(path)
        reversed_subtitles_path = path_mappings.path_replace_reverse(
            downloaded_path)
        notify_sonarr(episode_metadata['sonarrSeriesId'])
        event_stream(type='series',
                     action='update',
                     payload=episode_metadata['sonarrSeriesId'])
        event_stream(type='episode-wanted',
                     action='delete',
                     payload=episode_metadata['sonarrEpisodeId'])

    else:
        reversed_path = path_mappings.path_replace_reverse_movie(path)
        reversed_subtitles_path = path_mappings.path_replace_reverse_movie(
            downloaded_path)
        notify_radarr(movie_metadata['radarrId'])
        event_stream(type='movie-wanted',
                     action='delete',
                     payload=movie_metadata['radarrId'])

    track_event(category=downloaded_provider,
                action=action,
                label=downloaded_language)

    return message, reversed_path, downloaded_language_code2, downloaded_provider, subtitle.score, \
        subtitle.language.forced, subtitle.id, reversed_subtitles_path, subtitle.language.hi
Beispiel #6
0
def manual_upload_subtitle(path, language, forced, hi, title, scene_name, media_type, subtitle, audio_language):
    logging.debug('BAZARR Manually uploading subtitles for this file: ' + path)

    single = settings.general.getboolean('single_language')

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

    chmod = int(settings.general.chmod, 8) if not sys.platform.startswith(
        'win') and settings.general.getboolean('chmod_enabled') else None

    language = alpha3_from_alpha2(language)

    custom = CustomLanguage.from_value(language, "alpha3")
    if custom is None:
        lang_obj = Language(language)
    else:
        lang_obj = custom.subzero_language()

    if forced:
        lang_obj = Language.rebuild(lang_obj, forced=True)

    sub = Subtitle(
        lang_obj,
        mods=get_array_from(settings.general.subzero_mods)
    )

    sub.content = subtitle.read()
    if not sub.is_valid():
        logging.exception('BAZARR Invalid subtitle file: ' + subtitle.filename)
        sub.mods = None

    if settings.general.getboolean('utf8_encode'):
        sub.set_encoding("utf-8")

    saved_subtitles = []
    try:
        saved_subtitles = save_subtitles(path,
                                         [sub],
                                         single=single,
                                         tags=None,  # fixme
                                         directory=get_target_folder(path),
                                         chmod=chmod,
                                         # formats=("srt", "vtt")
                                         path_decoder=force_unicode)
    except Exception:
        logging.exception('BAZARR Error saving Subtitles file to disk for this file:' + path)
        return

    if len(saved_subtitles) < 1:
        logging.exception('BAZARR Error saving Subtitles file to disk for this file:' + path)
        return

    subtitle_path = saved_subtitles[0].storage_path

    if hi:
        modifier_string = " HI"
    elif forced:
        modifier_string = " forced"
    else:
        modifier_string = ""
    message = language_from_alpha3(language) + modifier_string + " Subtitles manually uploaded."

    if hi:
        modifier_code = ":hi"
    elif forced:
        modifier_code = ":forced"
    else:
        modifier_code = ""
    uploaded_language_code3 = language + modifier_code
    uploaded_language = language_from_alpha3(language) + modifier_string
    uploaded_language_code2 = alpha2_from_alpha3(language) + modifier_code
    audio_language_code2 = alpha2_from_language(audio_language)
    audio_language_code3 = alpha3_from_language(audio_language)

    if media_type == 'series':
        episode_metadata = TableEpisodes.select(TableEpisodes.sonarrSeriesId, TableEpisodes.sonarrEpisodeId) \
            .where(TableEpisodes.path == path_mappings.path_replace_reverse(path)) \
            .dicts() \
            .get_or_none()
        if not episode_metadata:
            return
        series_id = episode_metadata['sonarrSeriesId']
        episode_id = episode_metadata['sonarrEpisodeId']
        sync_subtitles(video_path=path, srt_path=subtitle_path, srt_lang=uploaded_language_code2, media_type=media_type,
                       percent_score=100, sonarr_series_id=episode_metadata['sonarrSeriesId'], forced=forced,
                       sonarr_episode_id=episode_metadata['sonarrEpisodeId'])
    else:
        movie_metadata = TableMovies.select(TableMovies.radarrId) \
            .where(TableMovies.path == path_mappings.path_replace_reverse_movie(path)) \
            .dicts() \
            .get_or_none()
        if not movie_metadata:
            return
        series_id = ""
        episode_id = movie_metadata['radarrId']
        sync_subtitles(video_path=path, srt_path=subtitle_path, srt_lang=uploaded_language_code2, media_type=media_type,
                       percent_score=100, radarr_id=movie_metadata['radarrId'], forced=forced)

    if use_postprocessing:
        command = pp_replace(postprocessing_cmd, path, subtitle_path, uploaded_language,
                             uploaded_language_code2, uploaded_language_code3, audio_language,
                             audio_language_code2, audio_language_code3, forced, 100, "1", "manual", series_id,
                             episode_id, hi=hi)
        postprocessing(command, path)

    if media_type == 'series':
        reversed_path = path_mappings.path_replace_reverse(path)
        reversed_subtitles_path = path_mappings.path_replace_reverse(subtitle_path)
        notify_sonarr(episode_metadata['sonarrSeriesId'])
        event_stream(type='series', action='update', payload=episode_metadata['sonarrSeriesId'])
        event_stream(type='episode-wanted', action='delete', payload=episode_metadata['sonarrEpisodeId'])
    else:
        reversed_path = path_mappings.path_replace_reverse_movie(path)
        reversed_subtitles_path = path_mappings.path_replace_reverse_movie(subtitle_path)
        notify_radarr(movie_metadata['radarrId'])
        event_stream(type='movie', action='update', payload=movie_metadata['radarrId'])
        event_stream(type='movie-wanted', action='delete', payload=movie_metadata['radarrId'])

    return message, reversed_path, reversed_subtitles_path
Beispiel #7
0
    def sync(self, video_path, srt_path, srt_lang, media_type, sonarr_series_id=None, sonarr_episode_id=None,
             radarr_id=None):
        self.reference = video_path
        self.srtin = srt_path
        self.srtout = None

        ffprobe_exe = get_binary('ffprobe')
        if not ffprobe_exe:
            logging.debug('BAZARR FFprobe not found!')
            return
        else:
            logging.debug('BAZARR FFprobe used is %s', ffprobe_exe)

        api.initialize({'provider': 'ffmpeg', 'ffmpeg': ffprobe_exe})
        data = api.know(self.reference)

        using_what = None

        if 'subtitle' in data:
            for i, embedded_subs in enumerate(data['subtitle']):
                if 'language' in embedded_subs:
                    language = embedded_subs['language'].alpha3
                    if language == "eng":
                        using_what = "English embedded subtitle track"
                        self.reference_stream = "s:{}".format(i)
                        break
            if not self.reference_stream:
                using_what = "{0} embedded subtitle track".format(
                    language_from_alpha3(embedded_subs['language'].alpha3) or 'unknown language embedded subtitles '
                                                                              'track')
                self.reference_stream = "s:0"
        elif 'audio' in data:
            audio_tracks = data['audio']
            for i, audio_track in enumerate(audio_tracks):
                if 'language' in audio_track:
                    language = audio_track['language'].alpha3
                    if language == srt_lang:
                        using_what = "{0} audio track".format(language_from_alpha3(audio_track['language'].alpha3) or
                                                              'unknown language audio track')
                        self.reference_stream = "a:{}".format(i)
                        break
            if not self.reference_stream:
                audio_tracks = data['audio']
                for i, audio_track in enumerate(audio_tracks):
                    if 'language' in audio_track:
                        language = audio_track['language'].alpha3
                        if language == "eng":
                            using_what = "English audio track"
                            self.reference_stream = "a:{}".format(i)
                            break
                if not self.reference_stream:
                    using_what = "first audio track"
                    self.reference_stream = "a:0"
        else:
            raise NoAudioTrack

        ffmpeg_exe = get_binary('ffmpeg')
        if not ffmpeg_exe:
            logging.debug('BAZARR FFmpeg not found!')
            return
        else:
            logging.debug('BAZARR FFmpeg used is %s', ffmpeg_exe)

        self.ffmpeg_path = os.path.dirname(ffmpeg_exe)
        try:
            result = run(self)
        except Exception as e:
            logging.error('BAZARR an exception occurs during the synchronization process for this subtitles: ' +
                          self.srtin)
        else:
            if result['sync_was_successful']:
                message = "{0} subtitles synchronization ended with an offset of {1} seconds and a framerate scale " \
                          "factor of {2} using {3} (0:{4}).".format(language_from_alpha3(srt_lang),
                                                                    result['offset_seconds'],
                                                                    result['framerate_scale_factor'],
                                                                    using_what,
                                                                    self.reference_stream)

                if media_type == 'series':
                    history_log(action=5, sonarr_series_id=sonarr_series_id, sonarr_episode_id=sonarr_episode_id,
                                description=message, video_path=path_mappings.path_replace_reverse(self.reference),
                                language=alpha2_from_alpha3(srt_lang), subtitles_path=srt_path)
                else:
                    history_log_movie(action=5, radarr_id=radarr_id, description=message,
                                      video_path=path_mappings.path_replace_reverse_movie(self.reference),
                                      language=alpha2_from_alpha3(srt_lang), subtitles_path=srt_path)
            else:
                logging.error('BAZARR unable to sync subtitles using {0}({1}): {2}'.format(using_what,
                                                                                           self.reference_stream,
                                                                                           self.srtin))

            return result
Beispiel #8
0
def store_subtitles(original_path, reversed_path):
    logging.debug('BAZARR started subtitles indexing for this file: ' +
                  reversed_path)
    actual_subtitles = []
    if os.path.exists(reversed_path):
        if settings.general.getboolean('use_embedded_subs'):
            logging.debug("BAZARR is trying to index embedded subtitles.")
            try:
                subtitle_languages = embedded_subs_reader.list_languages(
                    reversed_path)
                for subtitle_language, subtitle_forced, subtitle_hi, subtitle_codec in subtitle_languages:
                    try:
                        if (settings.general.getboolean("ignore_pgs_subs") and subtitle_codec.lower() == "pgs") or \
                                (settings.general.getboolean("ignore_vobsub_subs") and subtitle_codec.lower() ==
                                 "vobsub"):
                            logging.debug(
                                "BAZARR skipping %s sub for language: %s" %
                                (subtitle_codec,
                                 alpha2_from_alpha3(subtitle_language)))
                            continue

                        if alpha2_from_alpha3(subtitle_language) is not None:
                            lang = str(alpha2_from_alpha3(subtitle_language))
                            if subtitle_forced:
                                lang = lang + ":forced"
                            if subtitle_hi:
                                lang = lang + ":hi"
                            logging.debug(
                                "BAZARR embedded subtitles detected: " + lang)
                            actual_subtitles.append([lang, None])
                    except:
                        logging.debug(
                            "BAZARR unable to index this unrecognized language: "
                            + subtitle_language)
                        pass
            except Exception as e:
                logging.exception(
                    "BAZARR error when trying to analyze this %s file: %s" %
                    (os.path.splitext(reversed_path)[1], reversed_path))
                pass

        brazilian_portuguese = [".pt-br", ".pob", "pb"]
        brazilian_portuguese_forced = [
            ".pt-br.forced", ".pob.forced", "pb.forced"
        ]
        try:
            dest_folder = get_subtitle_destination_folder()
            core.CUSTOM_PATHS = [dest_folder] if dest_folder else []
            subtitles = search_external_subtitles(
                reversed_path,
                languages=get_language_set(),
                only_one=settings.general.getboolean('single_language'))
            full_dest_folder_path = os.path.dirname(reversed_path)
            if dest_folder:
                if settings.general.subfolder == "absolute":
                    full_dest_folder_path = dest_folder
                elif settings.general.subfolder == "relative":
                    full_dest_folder_path = os.path.join(
                        os.path.dirname(reversed_path), dest_folder)
            subtitles = guess_external_subtitles(full_dest_folder_path,
                                                 subtitles)
        except Exception as e:
            logging.exception("BAZARR unable to index external subtitles.")
            pass
        else:
            for subtitle, language in subtitles.items():
                subtitle_path = get_external_subtitles_path(
                    reversed_path, subtitle)
                if str(os.path.splitext(subtitle)[0]).lower().endswith(
                        tuple(brazilian_portuguese)):
                    logging.debug("BAZARR external subtitles detected: " +
                                  "pb")
                    actual_subtitles.append([
                        str("pb"),
                        path_mappings.path_replace_reverse(subtitle_path)
                    ])
                elif str(os.path.splitext(subtitle)[0]).lower().endswith(
                        tuple(brazilian_portuguese_forced)):
                    logging.debug("BAZARR external subtitles detected: " +
                                  "pb:forced")
                    actual_subtitles.append([
                        str("pb:forced"),
                        path_mappings.path_replace_reverse(subtitle_path)
                    ])
                elif not language:
                    continue
                elif str(language.basename) != 'und':
                    logging.debug("BAZARR external subtitles detected: " +
                                  str(language.basename))
                    actual_subtitles.append([
                        str(language.basename +
                            (':hi' if language.hi else '')),
                        path_mappings.path_replace_reverse(subtitle_path)
                    ])

        database.execute("UPDATE table_episodes SET subtitles=? WHERE path=?",
                         (str(actual_subtitles), original_path))
        matching_episodes = database.execute(
            "SELECT sonarrEpisodeId, sonarrSeriesId FROM table_episodes WHERE path=?",
            (original_path, ))

        for episode in matching_episodes:
            if episode:
                logging.debug("BAZARR storing those languages to DB: " +
                              str(actual_subtitles))
                list_missing_subtitles(epno=episode['sonarrEpisodeId'])
            else:
                logging.debug(
                    "BAZARR haven't been able to update existing subtitles to DB : "
                    + str(actual_subtitles))
    else:
        logging.debug(
            "BAZARR this file doesn't seems to exist or isn't accessible.")

    logging.debug('BAZARR ended subtitles indexing for this file: ' +
                  reversed_path)

    return actual_subtitles
def parse_video_metadata(file,
                         file_size,
                         episode_file_id=None,
                         movie_file_id=None,
                         use_cache=True):
    # Define default data keys value
    data = {
        "ffprobe": {},
        "enzyme": {},
        "file_id": episode_file_id or movie_file_id,
        "file_size": file_size,
    }

    if use_cache:
        # Get the actual cache value form database
        if episode_file_id:
            cache_key = TableEpisodes.select(TableEpisodes.ffprobe_cache)\
                .where(TableEpisodes.path == path_mappings.path_replace_reverse(file))\
                .dicts()\
                .get()
        elif movie_file_id:
            cache_key = TableMovies.select(TableMovies.ffprobe_cache)\
                .where(TableMovies.path == path_mappings.path_replace_reverse_movie(file))\
                .dicts()\
                .get()
        else:
            cache_key = None

        # check if we have a value for that cache key
        try:
            # Unpickle ffprobe cache
            cached_value = pickle.loads(cache_key['ffprobe_cache'])
        except:
            pass
        else:
            # Check if file size and file id matches and if so, we return the cached value
            if cached_value['file_size'] == file_size and cached_value[
                    'file_id'] in [episode_file_id, movie_file_id]:
                return cached_value

    # if not, we retrieve the metadata from the file
    from utils import get_binary

    ffprobe_path = get_binary("ffprobe")

    # if we have ffprobe available
    if ffprobe_path:
        api.initialize({"provider": "ffmpeg", "ffmpeg": ffprobe_path})
        data["ffprobe"] = api.know(file)
    # if not, we use enzyme for mkv files
    else:
        if os.path.splitext(file)[1] == ".mkv":
            with open(file, "rb") as f:
                try:
                    mkv = enzyme.MKV(f)
                except MalformedMKVError:
                    logger.error(
                        "BAZARR cannot analyze this MKV with our built-in MKV parser, you should install "
                        "ffmpeg/ffprobe: " + file)
                else:
                    data["enzyme"] = mkv

    # we write to db the result and return the newly cached ffprobe dict
    if episode_file_id:
        TableEpisodes.update({TableEpisodes.ffprobe_cache: pickle.dumps(data, pickle.HIGHEST_PROTOCOL)})\
            .where(TableEpisodes.path == path_mappings.path_replace_reverse(file))\
            .execute()
    elif movie_file_id:
        TableMovies.update({TableEpisodes.ffprobe_cache: pickle.dumps(data, pickle.HIGHEST_PROTOCOL)})\
            .where(TableMovies.path == path_mappings.path_replace_reverse_movie(file))\
            .execute()
    return data
Beispiel #10
0
    def patch(self):
        action = request.args.get('action')

        language = request.form.get('language')
        subtitles_path = request.form.get('path')
        media_type = request.form.get('type')
        id = request.form.get('id')

        if media_type == 'episode':
            subtitles_path = path_mappings.path_replace(subtitles_path)
            metadata = TableEpisodes.select(TableEpisodes.path, TableEpisodes.sonarrSeriesId)\
                .where(TableEpisodes.sonarrEpisodeId == id)\
                .dicts()\
                .get_or_none()

            if not metadata:
                return 'Episode not found', 500

            video_path = path_mappings.path_replace(metadata['path'])
        else:
            subtitles_path = path_mappings.path_replace_movie(subtitles_path)
            metadata = TableMovies.select(TableMovies.path).where(
                TableMovies.radarrId == id).dicts().get_or_none()

            if not metadata:
                return 'Movie not found', 500

            video_path = path_mappings.path_replace_movie(metadata['path'])

        if action == 'sync':
            subsync = SubSyncer()
            if media_type == 'episode':
                subsync.sync(video_path=video_path,
                             srt_path=subtitles_path,
                             srt_lang=language,
                             media_type='series',
                             sonarr_series_id=metadata['sonarrSeriesId'],
                             sonarr_episode_id=int(id))
            else:
                subsync.sync(video_path=video_path,
                             srt_path=subtitles_path,
                             srt_lang=language,
                             media_type='movies',
                             radarr_id=id)
            del subsync
            gc.collect()
        elif action == 'translate':
            dest_language = language
            forced = True if request.form.get('forced') == 'true' else False
            hi = True if request.form.get('hi') == 'true' else False
            result = translate_subtitles_file(video_path=video_path,
                                              source_srt_file=subtitles_path,
                                              to_lang=dest_language,
                                              forced=forced,
                                              hi=hi)
            if result:
                if media_type == 'episode':
                    store_subtitles(
                        path_mappings.path_replace_reverse(video_path),
                        video_path)
                else:
                    store_subtitles_movie(
                        path_mappings.path_replace_reverse_movie(video_path),
                        video_path)
                return '', 200
            else:
                return '', 404
        else:
            subtitles_apply_mods(language, subtitles_path, [action])

        # apply chmod if required
        chmod = int(settings.general.chmod, 8) if not sys.platform.startswith(
            'win') and settings.general.getboolean('chmod_enabled') else None
        if chmod:
            os.chmod(subtitles_path, chmod)

        return '', 204
Beispiel #11
0
def store_subtitles(original_path, reversed_path):
    logging.debug('BAZARR started subtitles indexing for this file: ' +
                  reversed_path)
    actual_subtitles = []
    if os.path.exists(reversed_path):
        if settings.general.getboolean('use_embedded_subs'):
            logging.debug("BAZARR is trying to index embedded subtitles.")
            try:
                item = database.execute(
                    'SELECT file_size, episode_file_id FROM table_episodes '
                    'WHERE path = ?', (original_path, ),
                    only_one=True)
                subtitle_languages = embedded_subs_reader(
                    reversed_path,
                    file_size=item['file_size'],
                    episode_file_id=item['episode_file_id'])
                for subtitle_language, subtitle_forced, subtitle_hi, subtitle_codec in subtitle_languages:
                    try:
                        if (settings.general.getboolean("ignore_pgs_subs") and subtitle_codec.lower() == "pgs") or \
                                (settings.general.getboolean("ignore_vobsub_subs") and subtitle_codec.lower() ==
                                 "vobsub") or \
                                (settings.general.getboolean("ignore_ass_subs") and subtitle_codec.lower() ==
                                 "ass"):
                            logging.debug(
                                "BAZARR skipping %s sub for language: %s" %
                                (subtitle_codec,
                                 alpha2_from_alpha3(subtitle_language)))
                            continue

                        if alpha2_from_alpha3(subtitle_language) is not None:
                            lang = str(alpha2_from_alpha3(subtitle_language))
                            if subtitle_forced:
                                lang = lang + ":forced"
                            if subtitle_hi:
                                lang = lang + ":hi"
                            logging.debug(
                                "BAZARR embedded subtitles detected: " + lang)
                            actual_subtitles.append([lang, None])
                    except:
                        logging.debug(
                            "BAZARR unable to index this unrecognized language: "
                            + subtitle_language)
                        pass
            except Exception as e:
                logging.exception(
                    "BAZARR error when trying to analyze this %s file: %s" %
                    (os.path.splitext(reversed_path)[1], reversed_path))
                pass

        brazilian_portuguese = [".pt-br", ".pob", "pb"]
        brazilian_portuguese_forced = [
            ".pt-br.forced", ".pob.forced", "pb.forced"
        ]
        simplified_chinese_fuzzy = [u"简", u"双语"]
        simplified_chinese = [
            ".chs", ".sc", ".zhs", ".zh-hans", ".hans", ".zh_hans", ".zhhans",
            ".gb", ".simplified"
        ]
        simplified_chinese_forced = [
            ".chs.forced", ".sc.forced", ".zhs.forced", "hans.forced",
            ".gb.forced", u"简体中文.forced", u"双语.forced"
        ]
        traditional_chinese_fuzzy = [u"繁", u"雙語"]
        traditional_chinese = [
            ".cht", ".tc", ".zh-tw", ".zht", ".zh-hant", ".zhhant", ".zh_hant",
            ".hant", ".big5", ".traditional"
        ]
        traditional_chinese_forced = [
            ".cht.forced", ".tc.forced", ".zht.forced", "hant.forced",
            ".big5.forced", u"繁體中文.forced", u"雙語.forced", "zh-tw.forced"
        ]

        try:
            dest_folder = get_subtitle_destination_folder()
            core.CUSTOM_PATHS = [dest_folder] if dest_folder else []
            subtitles = search_external_subtitles(
                reversed_path,
                languages=get_language_set(),
                only_one=settings.general.getboolean('single_language'))
            full_dest_folder_path = os.path.dirname(reversed_path)
            if dest_folder:
                if settings.general.subfolder == "absolute":
                    full_dest_folder_path = dest_folder
                elif settings.general.subfolder == "relative":
                    full_dest_folder_path = os.path.join(
                        os.path.dirname(reversed_path), dest_folder)
            subtitles = guess_external_subtitles(full_dest_folder_path,
                                                 subtitles)
        except Exception as e:
            logging.exception("BAZARR unable to index external subtitles.")
            pass
        else:
            for subtitle, language in subtitles.items():
                subtitle_path = get_external_subtitles_path(
                    reversed_path, subtitle)
                if str(os.path.splitext(subtitle)[0]).lower().endswith(
                        tuple(brazilian_portuguese)):
                    logging.debug("BAZARR external subtitles detected: " +
                                  "pb")
                    actual_subtitles.append([
                        str("pb"),
                        path_mappings.path_replace_reverse(subtitle_path)
                    ])
                elif str(os.path.splitext(subtitle)[0]).lower().endswith(
                        tuple(brazilian_portuguese_forced)):
                    logging.debug("BAZARR external subtitles detected: " +
                                  "pb:forced")
                    actual_subtitles.append([
                        str("pb:forced"),
                        path_mappings.path_replace_reverse(subtitle_path)
                    ])
                elif str(os.path.splitext(subtitle)[0]).lower().endswith(
                        tuple(simplified_chinese)) or (
                            str(subtitle_path).lower()
                        )[:-5] in simplified_chinese_fuzzy:
                    logging.debug("BAZARR external subtitles detected: " +
                                  "zh")
                    actual_subtitles.append([
                        str("zh"),
                        path_mappings.path_replace_reverse(subtitle_path)
                    ])
                elif any(ext in (
                        str(os.path.splitext(subtitle)[0]).lower())[-12:]
                         for ext in simplified_chinese_forced):
                    logging.debug("BAZARR external subtitles detected: " +
                                  "zh:forced")
                    actual_subtitles.append([
                        str("zh:forced"),
                        path_mappings.path_replace_reverse(subtitle_path)
                    ])
                elif str(os.path.splitext(subtitle)[0]).lower().endswith(
                        tuple(traditional_chinese)) or (
                            str(subtitle_path).lower()
                        )[:-5] in traditional_chinese_fuzzy:
                    logging.debug("BAZARR external subtitles detected: " +
                                  "zt")
                    actual_subtitles.append([
                        str("zt"),
                        path_mappings.path_replace_reverse(subtitle_path)
                    ])
                elif any(ext in (
                        str(os.path.splitext(subtitle)[0]).lower())[-12:]
                         for ext in traditional_chinese_forced):
                    logging.debug("BAZARR external subtitles detected: " +
                                  "zt:forced")
                    actual_subtitles.append([
                        str("zt:forced"),
                        path_mappings.path_replace_reverse(subtitle_path)
                    ])
                elif not language:
                    continue
                elif str(language) != 'und':
                    if language.forced:
                        language_str = str(language)
                    elif language.hi:
                        language_str = str(language) + ':hi'
                    else:
                        language_str = str(language)
                    logging.debug("BAZARR external subtitles detected: " +
                                  language_str)
                    actual_subtitles.append([
                        language_str,
                        path_mappings.path_replace_reverse(subtitle_path)
                    ])

        database.execute("UPDATE table_episodes SET subtitles=? WHERE path=?",
                         (str(actual_subtitles), original_path))
        matching_episodes = database.execute(
            "SELECT sonarrEpisodeId, sonarrSeriesId FROM table_episodes WHERE path=?",
            (original_path, ))

        for episode in matching_episodes:
            if episode:
                logging.debug("BAZARR storing those languages to DB: " +
                              str(actual_subtitles))
                list_missing_subtitles(epno=episode['sonarrEpisodeId'])
            else:
                logging.debug(
                    "BAZARR haven't been able to update existing subtitles to DB : "
                    + str(actual_subtitles))
    else:
        logging.debug(
            "BAZARR this file doesn't seems to exist or isn't accessible.")

    logging.debug('BAZARR ended subtitles indexing for this file: ' +
                  reversed_path)

    return actual_subtitles
Beispiel #12
0
    def sync(self,
             video_path,
             srt_path,
             srt_lang,
             media_type,
             sonarr_series_id=None,
             sonarr_episode_id=None,
             radarr_id=None):
        self.reference = video_path
        self.srtin = srt_path
        self.srtout = None
        self.args = None

        ffprobe_exe = get_binary('ffprobe')
        if not ffprobe_exe:
            logging.debug('BAZARR FFprobe not found!')
            return
        else:
            logging.debug('BAZARR FFprobe used is %s', ffprobe_exe)

        ffmpeg_exe = get_binary('ffmpeg')
        if not ffmpeg_exe:
            logging.debug('BAZARR FFmpeg not found!')
            return
        else:
            logging.debug('BAZARR FFmpeg used is %s', ffmpeg_exe)

        self.ffmpeg_path = os.path.dirname(ffmpeg_exe)
        try:
            unparsed_args = [
                self.reference, '-i', self.srtin, '--overwrite-input',
                '--ffmpegpath', self.ffmpeg_path, '--vad', self.vad
            ]
            parser = make_parser()
            self.args = parser.parse_args(args=unparsed_args)
            result = run(self.args)
        except Exception as e:
            logging.exception(
                'BAZARR an exception occurs during the synchronization process for this subtitles: '
                '{0}'.format(self.srtin))
        else:
            if result['sync_was_successful']:
                message = "{0} subtitles synchronization ended with an offset of {1} seconds and a framerate scale " \
                          "factor of {2}.".format(language_from_alpha3(srt_lang), result['offset_seconds'],
                                                  "{:.2f}".format(result['framerate_scale_factor']))

                if media_type == 'series':
                    history_log(action=5,
                                sonarr_series_id=sonarr_series_id,
                                sonarr_episode_id=sonarr_episode_id,
                                description=message,
                                video_path=path_mappings.path_replace_reverse(
                                    self.reference),
                                language=alpha2_from_alpha3(srt_lang),
                                subtitles_path=srt_path)
                else:
                    history_log_movie(
                        action=5,
                        radarr_id=radarr_id,
                        description=message,
                        video_path=path_mappings.path_replace_reverse_movie(
                            self.reference),
                        language=alpha2_from_alpha3(srt_lang),
                        subtitles_path=srt_path)
            else:
                logging.error('BAZARR unable to sync subtitles: {0}'.format(
                    self.srtin))

            return result
Beispiel #13
0
def refine_from_db(path, video):
    if isinstance(video, Episode):
        data = TableEpisodes.select(TableShows.title.alias('seriesTitle'),
                                    TableEpisodes.season,
                                    TableEpisodes.episode,
                                    TableEpisodes.title.alias('episodeTitle'),
                                    TableShows.year,
                                    TableShows.tvdbId,
                                    TableShows.alternateTitles,
                                    TableEpisodes.format,
                                    TableEpisodes.resolution,
                                    TableEpisodes.video_codec,
                                    TableEpisodes.audio_codec,
                                    TableEpisodes.path,
                                    TableShows.imdbId)\
            .join(TableShows, on=(TableEpisodes.sonarrSeriesId == TableShows.sonarrSeriesId))\
            .where((TableEpisodes.path == path_mappings.path_replace_reverse(path)))\
            .dicts()

        if len(data):
            data = data[0]
            video.series = re.sub(r'\s(\(\d\d\d\d\))', '', data['seriesTitle'])
            video.season = int(data['season'])
            video.episode = int(data['episode'])
            video.title = data['episodeTitle']
            # Commented out because Sonarr provided so much bad year
            # if data['year']:
            #     if int(data['year']) > 0: video.year = int(data['year'])
            video.series_tvdb_id = int(data['tvdbId'])
            video.alternative_series = ast.literal_eval(
                data['alternateTitles'])
            if data['imdbId'] and not video.series_imdb_id:
                video.series_imdb_id = data['imdbId']
            if not video.source:
                video.source = convert_to_guessit('source',
                                                  str(data['format']))
            if not video.resolution:
                video.resolution = str(data['resolution'])
            if not video.video_codec:
                if data['video_codec']:
                    video.video_codec = convert_to_guessit(
                        'video_codec', data['video_codec'])
            if not video.audio_codec:
                if data['audio_codec']:
                    video.audio_codec = convert_to_guessit(
                        'audio_codec', data['audio_codec'])
    elif isinstance(video, Movie):
        data = TableMovies.select(TableMovies.title,
                                  TableMovies.year,
                                  TableMovies.alternativeTitles,
                                  TableMovies.format,
                                  TableMovies.resolution,
                                  TableMovies.video_codec,
                                  TableMovies.audio_codec,
                                  TableMovies.imdbId)\
            .where(TableMovies.path == path_mappings.path_replace_reverse_movie(path))\
            .dicts()

        if len(data):
            data = data[0]
            video.title = re.sub(r'\s(\(\d\d\d\d\))', '', data['title'])
            # Commented out because Radarr provided so much bad year
            # if data['year']:
            #     if int(data['year']) > 0: video.year = int(data['year'])
            if data['imdbId'] and not video.imdb_id:
                video.imdb_id = data['imdbId']
            video.alternative_titles = ast.literal_eval(
                data['alternativeTitles'])
            if not video.source:
                if data['format']:
                    video.source = convert_to_guessit('source', data['format'])
            if not video.resolution:
                if data['resolution']:
                    video.resolution = data['resolution']
            if not video.video_codec:
                if data['video_codec']:
                    video.video_codec = convert_to_guessit(
                        'video_codec', data['video_codec'])
            if not video.audio_codec:
                if data['audio_codec']:
                    video.audio_codec = convert_to_guessit(
                        'audio_codec', data['audio_codec'])

    return video
Beispiel #14
0
def store_subtitles(original_path, reversed_path, use_cache=True):
    logging.debug('BAZARR started subtitles indexing for this file: ' + reversed_path)
    actual_subtitles = []
    if os.path.exists(reversed_path):
        if settings.general.getboolean('use_embedded_subs'):
            logging.debug("BAZARR is trying to index embedded subtitles.")
            item = TableEpisodes.select(TableEpisodes.episode_file_id, TableEpisodes.file_size)\
                .where(TableEpisodes.path == original_path)\
                .dicts()\
                .get_or_none()
            if not item:
                logging.exception(f"BAZARR error when trying to select this episode from database: {reversed_path}")
            else:
                try:
                    subtitle_languages = embedded_subs_reader(reversed_path,
                                                              file_size=item['file_size'],
                                                              episode_file_id=item['episode_file_id'],
                                                              use_cache=use_cache)
                    for subtitle_language, subtitle_forced, subtitle_hi, subtitle_codec in subtitle_languages:
                        try:
                            if (settings.general.getboolean("ignore_pgs_subs") and subtitle_codec.lower() == "pgs") or \
                                    (settings.general.getboolean("ignore_vobsub_subs") and subtitle_codec.lower() ==
                                     "vobsub") or \
                                    (settings.general.getboolean("ignore_ass_subs") and subtitle_codec.lower() ==
                                     "ass"):
                                logging.debug("BAZARR skipping %s sub for language: %s" % (subtitle_codec, alpha2_from_alpha3(subtitle_language)))
                                continue

                            if alpha2_from_alpha3(subtitle_language) is not None:
                                lang = str(alpha2_from_alpha3(subtitle_language))
                                if subtitle_forced:
                                    lang = lang + ":forced"
                                if subtitle_hi:
                                    lang = lang + ":hi"
                                logging.debug("BAZARR embedded subtitles detected: " + lang)
                                actual_subtitles.append([lang, None])
                        except Exception as error:
                            logging.debug("BAZARR unable to index this unrecognized language: %s (%s)", subtitle_language, error)
                except Exception:
                    logging.exception(
                        "BAZARR error when trying to analyze this %s file: %s" % (os.path.splitext(reversed_path)[1],
                                                                                  reversed_path))
                    pass
        try:
            dest_folder = get_subtitle_destination_folder()
            core.CUSTOM_PATHS = [dest_folder] if dest_folder else []
            subtitles = search_external_subtitles(reversed_path, languages=get_language_set(),
                                                  only_one=settings.general.getboolean('single_language'))
            full_dest_folder_path = os.path.dirname(reversed_path)
            if dest_folder:
                if settings.general.subfolder == "absolute":
                    full_dest_folder_path = dest_folder
                elif settings.general.subfolder == "relative":
                    full_dest_folder_path = os.path.join(os.path.dirname(reversed_path), dest_folder)
            subtitles = guess_external_subtitles(full_dest_folder_path, subtitles)
        except Exception:
            logging.exception("BAZARR unable to index external subtitles.")
        else:
            for subtitle, language in subtitles.items():
                valid_language = False
                if language:
                    if hasattr(language, 'alpha3'):
                        valid_language = alpha2_from_alpha3(language.alpha3)
                else:
                    logging.debug(f"Skipping subtitles because we are unable to define language: {subtitle}")
                    continue

                if not valid_language:
                    logging.debug(f'{language.alpha3} is an unsupported language code.')
                    continue

                subtitle_path = get_external_subtitles_path(reversed_path, subtitle)

                custom = CustomLanguage.found_external(subtitle, subtitle_path)
                if custom is not None:
                    actual_subtitles.append([custom, path_mappings.path_replace_reverse(subtitle_path)])

                elif str(language) != 'und':
                    if language.forced:
                        language_str = str(language)
                    elif language.hi:
                        language_str = str(language) + ':hi'
                    else:
                        language_str = str(language)
                    logging.debug("BAZARR external subtitles detected: " + language_str)
                    actual_subtitles.append([language_str, path_mappings.path_replace_reverse(subtitle_path)])

        TableEpisodes.update({TableEpisodes.subtitles: str(actual_subtitles)})\
            .where(TableEpisodes.path == original_path)\
            .execute()
        matching_episodes = TableEpisodes.select(TableEpisodes.sonarrEpisodeId, TableEpisodes.sonarrSeriesId)\
            .where(TableEpisodes.path == original_path)\
            .dicts()

        for episode in matching_episodes:
            if episode:
                logging.debug("BAZARR storing those languages to DB: " + str(actual_subtitles))
                list_missing_subtitles(epno=episode['sonarrEpisodeId'])
            else:
                logging.debug("BAZARR haven't been able to update existing subtitles to DB : " + str(actual_subtitles))
    else:
        logging.debug("BAZARR this file doesn't seems to exist or isn't accessible.")

    logging.debug('BAZARR ended subtitles indexing for this file: ' + reversed_path)

    return actual_subtitles