Example #1
0
    def list_languages(self, file):
        subtitles_list = []

        if self.ffprobe:
            api.initialize({'provider': 'ffmpeg', 'ffmpeg': self.ffprobe})
            data = api.know(file)

            if 'subtitle' in data:
                for detected_language in data['subtitle']:
                    if 'language' in detected_language:
                        language = detected_language['language'].alpha3
                        forced = detected_language[
                            'forced'] if 'forced' in detected_language else None
                        codec = detected_language[
                            'format'] if 'format' in detected_language else None
                        subtitles_list.append([language, forced, codec])
                    else:
                        continue
        else:
            if os.path.splitext(file)[1] == '.mkv':
                with open(file, 'rb') as f:
                    try:
                        mkv = enzyme.MKV(f)
                    except MalformedMKVError:
                        logging.error(
                            'BAZARR cannot analyze this MKV with our built-in MKV parser, you should install ffmpeg: '
                            + file)
                    else:
                        for subtitle_track in mkv.subtitle_tracks:
                            subtitles_list.append([
                                subtitle_track.language, subtitle_track.forced,
                                subtitle_track.codec_id
                            ])

        return subtitles_list
Example #2
0
def knowit(
    video_path: typing.Union[str, os.PathLike],
    options: argparse.Namespace,
    context: typing.MutableMapping,
) -> typing.Mapping:
    """Extract video metadata."""
    context['path'] = video_path
    if not options.report:
        console.info('For: %s', video_path)
    else:
        console.info('Parsing: %s', video_path)
    info = api.know(video_path, context)
    if not options.report:
        console.info('Knowit %s found: ', __version__)
        console.info(dumps(info, options, context))
    return info
Example #3
0
    def list_languages(self, file):
        from utils import get_binary
        self.ffprobe = get_binary("ffprobe")

        subtitles_list = []
        if self.ffprobe:
            api.initialize({'provider': 'ffmpeg', 'ffmpeg': self.ffprobe})
            data = api.know(file)

            traditional_chinese = ["cht", "tc", "traditional", "zht", "hant", "big5", u"繁", u"雙語"]
            brazilian_portuguese = ["pt-br", "pob", "pb", "brazilian", "brasil", "brazil"]

            if 'subtitle' in data:
                for detected_language in data['subtitle']:
                    if 'language' in detected_language:
                        language = detected_language['language'].alpha3
                        if language == 'zho' and 'name' in detected_language:
                            if any (ext in (detected_language['name'].lower()) for ext in traditional_chinese):
                                language = 'zht'
                        if language == 'por' and 'name' in detected_language:
                            if any (ext in (detected_language['name'].lower()) for ext in brazilian_portuguese):
                                language = 'pob'
                        forced = detected_language['forced'] if 'forced' in detected_language else False
                        hearing_impaired = detected_language['hearing_impaired'] if 'hearing_impaired' in \
                                                                                    detected_language else False
                        codec = detected_language['format'] if 'format' in detected_language else None
                        subtitles_list.append([language, forced, hearing_impaired, codec])
                    else:
                        continue
        else:
            if os.path.splitext(file)[1] == '.mkv':
                with open(file, 'rb') as f:
                    try:
                        mkv = enzyme.MKV(f)
                    except MalformedMKVError:
                        logging.error('BAZARR cannot analyze this MKV with our built-in MKV parser, you should install ffmpeg: ' + file)
                    else:
                        for subtitle_track in mkv.subtitle_tracks:
                            hearing_impaired = False
                            if subtitle_track.name:
                                if 'sdh' in subtitle_track.name.lower():
                                    hearing_impaired = True
                            subtitles_list.append([subtitle_track.language, subtitle_track.forced, hearing_impaired,
                                                   subtitle_track.codec_id])

        return subtitles_list
Example #4
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
Example #5
0
def parse_video_metadata(file,
                         file_size,
                         episode_file_id=None,
                         movie_file_id=None):
    # Define default data keys value
    data = {
        'ffprobe': {},
        'enzyme': {},
        'file_id': episode_file_id if episode_file_id else movie_file_id,
        'file_size': file_size
    }

    # Get the actual cache value form database
    if episode_file_id:
        cache_key = database.execute(
            'SELECT ffprobe_cache FROM table_episodes WHERE episode_file_id=? AND file_size=?',
            (episode_file_id, file_size),
            only_one=True)
    elif movie_file_id:
        cache_key = database.execute(
            'SELECT ffprobe_cache FROM table_movies WHERE movie_file_id=? AND file_size=?',
            (movie_file_id, file_size),
            only_one=True)
    else:
        cache_key = None

    # check if we have a value for that cache key
    if not isinstance(cache_key, dict):
        return data
    else:
        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 nto, 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:
                    logging.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:
        database.execute(
            'UPDATE table_episodes SET ffprobe_cache=? WHERE episode_file_id=?',
            (pickle.dumps(data, pickle.HIGHEST_PROTOCOL), episode_file_id))
    elif movie_file_id:
        database.execute(
            'UPDATE table_movies SET ffprobe_cache=? WHERE movie_file_id=?',
            (pickle.dumps(data, pickle.HIGHEST_PROTOCOL), movie_file_id))
    return data
Example #6
0
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