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
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
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
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
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
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