Exemplo n.º 1
0
def is_valid_mkv(path):
    with open(path, 'rb') as f:
        try:
            enzyme.MKV(f)
            return True
        except enzyme.exceptions.MalformedMKVError:
            return False
Exemplo n.º 2
0
def check_mkv(path):
    mkv = None
    if not os.path.isfile(path):
        return None
    try:
        with open(path, "rb") as f:
            mkv = enzyme.MKV(f)
    except (IOError, OverflowError, enzyme.exceptions.MalformedMKVError, AttributeError) as e:
        print os.path.basename(path), str(e)
    if mkv is None:
        return None
    newname = fix_makemkv_name(os.path.basename(path))
    audio_info = []
    for track in mkv.audio_tracks:
        audio_info.append('%s %s' % (track.language, track.name))
    subtitle_info = []
    for track in mkv.subtitle_tracks:
        subtitle_info.append('%s %s%s%s' % (track.language,
                                            "E" if track.enabled else "",
                                            "D" if track.default else "",
                                            "F" if track.forced else ""))
    track = mkv.video_tracks[0]
    print "%s - %s - %ux%u%s %s - %s - %s" % (
        newname, mkv.info.duration,
        track.width, track.height, 'i' if track.interlaced else '', track.codec_id,
        ', '.join(audio_info), ", ".join(subtitle_info))
    return mkv
Exemplo n.º 3
0
    def list_languages(self, file):
        subtitles_list = []

        if self.ffprobe:
            parser = VideoFileParser(ffprobe=self.ffprobe,
                                     includeMissing=True,
                                     rawMode=False)
            data = parser.parseFfprobe(file)

            for detected_language in data['subtitles']:
                subtitles_list.append([
                    detected_language['language'], detected_language['forced'],
                    detected_language["codec"]
                ])
        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
Exemplo n.º 4
0
    def list_languages(self, file):
        subtitles_list = []

        if os.path.splitext(file)[1] == '.mkv':
            with open(file, 'rb') as f:
                mkv = enzyme.MKV(f)
            for subtitle_track in mkv.subtitle_tracks:
                subtitles_list.append(
                    [subtitle_track.language, subtitle_track.forced])
        else:
            if self.ffprobe:
                detected_languages = []
                try:
                    detected_languages = subprocess.check_output(
                        [
                            self.ffprobe, "-loglevel", "error",
                            "-select_streams", "s", "-show_entries",
                            "stream_tags=language", "-of", "csv=p=0",
                            file.encode(locale.getpreferredencoding())
                        ],
                        universal_newlines=True,
                        stderr=subprocess.STDOUT).strip().split("\n")
                except subprocess.CalledProcessError as e:
                    raise FFprobeError(e.output)
                else:
                    for detected_language in detected_languages:
                        subtitles_list.append([detected_language, False])
                        # I can't get the forced flag from ffprobe so I always assume it isn't forced

        return subtitles_list
Exemplo n.º 5
0
    def describe(self, video_path, context):
        """Return video metadata."""
        try:
            with open(video_path, 'rb') as f:
                data = defaultdict(dict)
                ff = todict(enzyme.MKV(f))
                data.update(ff)
                if 'info' in data and data['info'] is None:
                    return {}

                data['info']['complete_name'] = video_path
                data['info']['file_size'] = os.path.getsize(video_path)
        except enzyme.MalformedMKVError:  # pragma: no cover
            logger.warning('Invalid file %r', video_path)
            if context.get('fail_on_error'):
                raise MalformedFileError
            return {}

        if context.get('raw'):
            return data

        result = self._describe_tracks(data.get('info'),
                                       data.get('video_tracks'),
                                       data.get('audio_tracks'),
                                       data.get('subtitle_tracks'), context)

        result['provider'] = 'Enzyme {0}'.format(enzyme.__version__)
        return result
Exemplo n.º 6
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
Exemplo n.º 7
0
    def list_languages(self, file):
        subtitles_list = []

        if self.ffprobe:
            parser = VideoFileParser(ffprobe=self.ffprobe,
                                     includeMissing=True,
                                     rawMode=False)
            data = parser.parseFfprobe(file)

            for detected_language in data['subtitles']:
                subtitles_list.append([
                    detected_language['language'], detected_language['forced'],
                    detected_language["codec"]
                ])
        else:
            if os.path.splitext(file)[1] == '.mkv':
                with open(file, 'rb') as f:
                    mkv = enzyme.MKV(f)
                for subtitle_track in mkv.subtitle_tracks:
                    subtitles_list.append([
                        subtitle_track.language, subtitle_track.forced,
                        subtitle_track.codec_id
                    ])

        return subtitles_list
Exemplo n.º 8
0
def __is_uhd_mkv(target):
    with open(target, 'rb') as mkv_f:
        import enzyme
        mkv = enzyme.MKV(mkv_f)
        if len(mkv.video_tracks) > 0:
            uhd_track = next((v for v in mkv.video_tracks if v.display_width > 1920), None)
            return uhd_track is not None
    return False
Exemplo n.º 9
0
def mkv_for_filenames(**kwargs):
    for fname in cli_filenames(**kwargs):
        with open(fname, 'rb') as f:
            try:
                mkv = enzyme.MKV(f)
            except enzyme.exceptions.MalformedMKVError as ex:
                print('Error parsing %s: %s' % (fname, ex))
                continue

            yield (fname, mkv)
def rename_files(movie_dir, kind="movie"):
    print("Renaming files in: {}".format(movie_dir))
    files = sorted(
        [x for x in os.listdir(movie_dir) if os.path.isfile(os.path.join(movie_dir, x)) and x != "MANUALLY_NAMED"],
        key=functools.cmp_to_key(logical_sort))
    prefix, imdb_id = create_file_name_prefix(os.path.basename(movie_dir), kind, files)
    runtime = int(get_imdb_runtime(imdb_id))
    main_file_found = 0
    filename_maps = []
    for old_file in files:
        old_name, extension = os.path.splitext(old_file)
        new_name = prefix
        is_main_file = False
        movie = None
        if extension == ".mkv":
            if len(files) == 1:
                new_name += " - Main file"
            else:
                with open(os.path.join(movie_dir, old_file), "rb") as fi:
                    try:
                        movie = enzyme.MKV(fi)
                    except:
                        movie = None
                if movie and (movie.info.duration.seconds - (movie.info.duration.seconds % 60)) / 60 in [runtime - 1,
                                                                                                         runtime,
                                                                                                         runtime + 1]:
                    if not main_file_found:
                        new_name += " - Main file"
                    else:
                        new_name += " - Main file ({})".format(main_file_found)
                    print("\tFound main file")
                    main_file_found += 1
                    is_main_file = True
        part = get_file_part_name(old_name)
        if part and not is_main_file:
            new_name += " - pt{}".format(part[-1])
        new_name += extension
        filename_maps.append((old_file, new_name, is_main_file, get_aspect_ratio(movie, new_name)))
    aspect_ratios_found = list(set([x[3] for x in filename_maps if x[2]]))
    for name_map in filename_maps:
        old_file = name_map[0]
        new_name = name_map[1]
        is_main_file = name_map[2]
        if is_main_file and main_file_found == 2 and len(aspect_ratios_found) == 2:
            name, extension = os.path.splitext(new_name)
            new_name = name.replace(" (1)", "") + " - " + name_map[3] + extension
        if not is_main_file and main_file_found:
            if not os.path.isdir(os.path.join(movie_dir, "Other")):
                os.mkdir(os.path.join(movie_dir, "Other"))
            os.rename(os.path.join(movie_dir, old_file), os.path.join(movie_dir, "Other", new_name))
        elif old_file != new_name:
            try:
                os.rename(os.path.join(movie_dir, old_file), os.path.join(movie_dir, new_name))
            except:
                pdb.set_trace()
Exemplo n.º 11
0
def getMatroska(vfile):
    """
    Get metadata and track information from Matroska containers
    """
    try:
        with open(vfile) as f:
            mkv = enzyme.MKV(f)
    except enzyme.MalformedMKVError as e:
        logexc(e, "Not a Matroska container or segment is corrupt")
        return False
    return mkv.to_dict()
Exemplo n.º 12
0
def store_subtitles(file):
    languages = []
    actual_subtitles = []
    if os.path.exists(file):
        if os.path.splitext(file)[1] == '.mkv':
            try:
                with open(file, 'rb') as f:
                    mkv = enzyme.MKV(f)
                
                for subtitle_track in mkv.subtitle_tracks:
                    try:
                        if alpha2_from_alpha3(subtitle_track.language) != None:
                            actual_subtitles.append([str(alpha2_from_alpha3(subtitle_track.language)),None])
                    except:
                        pass
            except:
                pass


        brazilian_portuguese = [".pt-br", ".pob", "pb"]
        try:
            subtitles = core.search_external_subtitles(file)
        except:
            pass
        else:
            for subtitle, language in subtitles.iteritems():
                if str(os.path.splitext(subtitle)[0]).lower().endswith(tuple(brazilian_portuguese)) is True:
                    actual_subtitles.append([str("pb"), path_replace_reverse(os.path.join(os.path.dirname(file), subtitle))])
                elif str(language) != 'und':
                    actual_subtitles.append([str(language), path_replace_reverse(os.path.join(os.path.dirname(file), subtitle))])
                else:
                    with open(path_replace(os.path.join(os.path.dirname(file), subtitle)), 'r') as f:
                        text = list(islice(f, 100))
                        text = ' '.join(text)
                        encoding = UnicodeDammit(text)
                        try:
                            text = text.decode(encoding.original_encoding)
                        except Exception as e:
                            logging.exception('Error trying to detect character encoding for this subtitles file: ' + path_replace(os.path.join(os.path.dirname(file), subtitle)) + ' You should try to delete this subtitles file manually and ask Bazarr to download it again.')
                        else:
                            detected_language = langdetect.detect(text)
                            if len(detected_language) > 0:
                                actual_subtitles.append([str(detected_language), path_replace_reverse(os.path.join(os.path.dirname(file), subtitle))])

            conn_db = sqlite3.connect(os.path.join(os.path.dirname(__file__), 'data/db/bazarr.db'), timeout=30)
            c_db = conn_db.cursor()

            c_db.execute("UPDATE table_episodes SET subtitles = ? WHERE path = ?", (str(actual_subtitles), path_replace_reverse(file)))
            conn_db.commit()

            c_db.close()

    return actual_subtitles
Exemplo n.º 13
0
def main(args):
    parser = argparse.ArgumentParser()
    parser.add_argument("--select",
                        "-s",
                        action="store_true",
                        help="Use zenity to select witch tracks to export")
    parser.add_argument(
        "--notify",
        action="store_true",
        help="Use notify-send to notify when each jobe is done")
    parser.add_argument("--dry-run",
                        "-n",
                        action="store_true",
                        help="Don't run the mkvextract command")
    parser.add_argument("--progress",
                        action="store_true",
                        help="Use zenity to draw a progress bar")
    parser.add_argument("filename", nargs="+")
    args = parser.parse_args()

    for filename in args.filename:
        with open(filename, 'rb') as f:
            mkv = enzyme.MKV(f)

        subtitle_tracks = mkv.subtitle_tracks
        if args.select:
            cmd = construct_zenity_cmd(subtitle_tracks)
            print(cmd)
            selected_numbers = [
                int(x) for x in subprocess.check_output(
                    cmd, shell=True).decode().strip().split("|")
            ]
            print(selected_numbers)
            subtitle_tracks = subtitle_track_by_number(subtitle_tracks,
                                                       selected_numbers)
        if not subtitle_tracks:
            print(f"No subtitle tracks found in {filename}", file=sys.stderr)
            continue
        print(
            f"Will run mkvextract with the following tracks:\n{subtitle_tracks}\n"
        )
        cmd = construct_mkvextract_cmd(filename, subtitle_tracks)
        if args.progress:
            cmd += " | " + ZENITY_PROGRESS_CMD.format(filename=filename)
        print("Command to be executed:\n" + cmd)
        if not args.dry_run:
            result = subprocess.call(cmd, shell=True)
            result = "Done" if result == 0 else "Failed"
        if args.notify:
            subprocess.call(
                f"notify-send 'Subtitle Extraction {result}' '{result} with {filename}'",
                shell=True)
    return 0
def read_mkv_file(source_file):
    """Retrieve MKV file information"""
    import sys
    import enzyme
    from enzyme.exceptions import MalformedMKVError
    with open(source_file, "rb") as mkv_source:
        try:
            mkv_file = enzyme.MKV(mkv_source)
        except MalformedMKVError:
            return SABResult(False,
                             error="[ERROR] {0}".format(sys.exc_info()[0]))

    return SABResult(True, data=mkv_file)
Exemplo n.º 15
0
 def get_vid_duraiton(file_name):
     """
     use enzyme library to extract video duration object
     param: file_name
     """
     try:
         with open(file_name, "rb") as f:
             meta = enzyme.MKV(f)
             t_delta = meta.info.duration
     except OSError:
         f.close()
         return None
     f.close()
     return t_delta
Exemplo n.º 16
0
def read_mkv_file(source_file):
    """Retrieve MKV file information"""
    import sys
    import collections
    import enzyme
    from enzyme.exceptions import MalformedMKVError
    result = collections.namedtuple('Result', 'mkv_file error')
    with open(source_file, 'rb') as mkv_source:
        try:
            mkv_file = enzyme.MKV(mkv_source)
        except MalformedMKVError:
            return result(None, '[ERROR] %s' % sys.exc_info()[0])

    return result(mkv_file, None)
Exemplo n.º 17
0
def mkv_metadata(file):
    """retrieve info from MKV's metadata file"""
    with open(file, 'rb') as f:
        mkv = enzyme.MKV(f)

    resolution = str(mkv.video_tracks[0].width) + 'x' + str(
        mkv.video_tracks[0].height)
    audio_channels = mkv.audio_tracks[0].channels
    runtime = str(mkv.info.duration).split('.', 1)[0]

    return {
        'resolution': resolution,
        'audio_channels': audio_channels,
        'runtime': runtime
    }
Exemplo n.º 18
0
def store_subtitles_movie(file):
    languages = []
    actual_subtitles = []
    if os.path.exists(file):
        if os.path.splitext(file)[1] == '.mkv':
            try:
                with open(file, 'rb') as f:
                    mkv = enzyme.MKV(f)

                for subtitle_track in mkv.subtitle_tracks:
                    try:
                        actual_subtitles.append([str(pycountry.languages.lookup(subtitle_track.language).alpha_2), None])
                    except:
                        pass
            except:
                pass

        subtitles = core.search_external_subtitles(file)

        for subtitle, language in subtitles.iteritems():
            if str(language) != 'und':
                actual_subtitles.append([str(language), path_replace_reverse_movie(os.path.join(os.path.dirname(file), subtitle))])
            else:
                if os.path.splitext(subtitle)[1] != ".sub":
                    with open(path_replace_movie(os.path.join(os.path.dirname(file), subtitle)), 'r') as f:
                        text = list(islice(f, 100))
                        text = ' '.join(text)
                        encoding = UnicodeDammit(text)
                        try:
                            text = text.decode(encoding.original_encoding)
                        except Exception as e:
                            logging.exception('Error trying to detect character encoding for this subtitles file: ' + path_replace_movie(os.path.join(os.path.dirname(file), subtitle)) + ' You should try to delete this subtitles file manually and ask Bazarr to download it again.')
                        else:
                            detected_language = langdetect.detect(text)
                            if len(detected_language) > 0:
                                actual_subtitles.append([str(detected_language), path_replace_reverse_movie(os.path.join(os.path.dirname(file), subtitle))])

        conn_db = sqlite3.connect(os.path.join(os.path.dirname(__file__), 'data/db/bazarr.db'), timeout=30)
        c_db = conn_db.cursor()

        c_db.execute("UPDATE table_movies SET subtitles = ? WHERE path = ?", (str(actual_subtitles), path_replace_reverse_movie(file)))
        conn_db.commit()

        c_db.close()

    return actual_subtitles
Exemplo n.º 19
0
 def prepare_subtitles(self, s, offset=None, keep_on_screen=False):
     if s.is_internal and not keep_on_screen:
         full_path = os.path.join(s.directory, s.file_name)
         with open(full_path, 'rb') as fd:
             mkv = enzyme.MKV(fd)
             # TODO: check which track number instead of iterate
             for sub_track in mkv.subtitle_tracks:
                 sub_track = mkv.subtitle_tracks[0]
                 if sub_track.codec_id == 'S_TEXT/UTF8':
                     new_file = 'subtitle_{id}.srt'.format(id=s.id)
                     cmd = [
                         'mkvextract', 'tracks', full_path,
                         '{n}:{e}'.format(n=sub_track.number - 1,
                                          e=new_file)
                     ]
                     subprocess.check_output(cmd)
                     subtitle_path = new_file
                     break
     if not s.is_internal:
         subtitle_path = os.path.join(s.directory, s.file_name)
     if keep_on_screen:
         subtitle_path = '{id}_keep.srt'.format(id=s.id)
         call_command('export_subtitles', s.id, subtitle_path, True)
     res = subtitle_path
     output = subprocess.check_output(['file', subtitle_path])
     cmd = None
     extension = s.extension if s.extension != 'mkv' else 'srt'
     new_name = '{id}.utf8.{ext}'.format(id=s.id, ext=extension)
     if 'ISO-8859' in output or 'Non-ISO extended-ASCII' in output:
         cmd = 'iconv --from-code=ISO-8859-1 --to-code=UTF-8 "{s}" > "{n}"'\
             .format(s=subtitle_path, n=new_name)
     elif 'ASCII' in output:
         cmd = 'iconv --from-code=ASCII --to-code=UTF-8 "{s}" > "{n}"'\
             .format(s=subtitle_path, n=new_name)
     if cmd:
         os.system(cmd)
         res = new_name
     if offset:
         split = new_name.split('.')
         n = '.'.join(split[:-1])
         new_name = '{n}.ss.{ext}'.format(n=n, ext=split[-1])
         cmd = 'ffmpeg -i "{res}" -ss {offset} -f {ext} -y "{nn}"'.format(
             res=res, offset=offset, ext=split[-1], nn=new_name)
         os.system(cmd)
         res = new_name
     return res
Exemplo n.º 20
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
Exemplo n.º 21
0
def parse_video(file, guid):
    with open(file, 'rb') as f:
        mkv = enzyme.MKV(f)
        length = mkv.info.duration
        bitrate = mkv.audio_tracks[0].sampling_frequency
        channels = mkv.audio_tracks[0].channels
        f_format = get_extension(file)
        width = mkv.video_tracks[0].width
        height = mkv.video_tracks[0].height
        with connection.cursor() as cursor:
            cursor.execute(
                """
				INSERT INTO video_metadata (
					file_guid, file_format, length, bit_rate, mono_or_stereo, width, height
				) VALUES (
					%s, %s, %s, %s, %s, %s, %s
				)
			""", [guid, f_format, length, bitrate, channels, width, height])

    return True
Exemplo n.º 22
0
    def get_mkv_ttid_map(self):
        mkv_ttid_map = dict()
        for path in Path(self.download_dir).rglob('*.mkv'):
            try:
                with open(path, 'rb') as f:
                    mkv = enzyme.MKV(f)
                    if mkv.tags:
                        for x in mkv.tags:
                            for y in x.simpletags:
                                if y.name == 'TTID':
                                    mkv_ttid_map[y.string] = str(path)
                                    raise GetOutOfLoop
            except GetOutOfLoop:
                pass
            except enzyme.MalformedMKVError as ex:
                self.logger.warning("Exception while parsing file {}".format(str(path)))
                self.logger.warning("You may want to delete and re-download this file.")
                self.logger.warning("Exception: {}".format(ex))
                pass

        return mkv_ttid_map
Exemplo n.º 23
0
def weebify_mkv(mkv_path, noop=False):
    print('Opening {}'.format(mkv_path), file=sys.stderr)
    with open(mkv_path, 'rb') as fp:
        mkv = enzyme.MKV(fp)

    jpn_audio_track = find_jpn_audio_track(mkv)
    def_audio_track = find_default_audio_track(mkv)
    set_default_sub = should_avoid_default_sub(mkv)
    set_default_audio = jpn_audio_track and jpn_audio_track != def_audio_track
    track_changes = {track.number: [] for track in mkv.audio_tracks + mkv.subtitle_tracks}
    if set_default_audio:
        if noop:
            print('Would flag audio track {} as default'.format(jpn_audio_track.number), file=sys.stderr)
        track_changes[jpn_audio_track.number].append('flag-default=1')
        for track in mkv.audio_tracks:
            if track != jpn_audio_track and track.default:
                if noop:
                    print('Would unflag audio track {} as default'.format(track.number), file=sys.stderr)
                track_changes[track.number].append('flag-default=0')
    if set_default_sub:
        primary_eng_sub = find_eng_sub(mkv)
        if noop:
            print('Would flag subtitle track {} as default'.format(primary_eng_sub.number), file=sys.stderr)
        track_changes[primary_eng_sub.number].append('flag-default=1')
        for track in mkv.subtitle_tracks:
            if track != primary_eng_sub and track.default:
                if noop:
                    print('Would unflag subtitle track {} as default'.format(track.number), file=sys.stderr)
                track_changes[track.number].append('flag-default=0')

    args = build_args(track_changes)
    if args:
        if noop:
            return 1
        else:
            subprocess.check_call(['mkvpropedit', '-v', mkv_path, '-v'] + args)
            return 0
    else:
        print('Nothing to do', file=sys.stderr)
        return 0
Exemplo n.º 24
0
    def has_subtitle(self, language):
        """ Returns true if the video has already
        a subtitle for a specific language. """
        has_subtitle = False

        # Look for embedded subtitle in mkv video
        if Video.is_mkv(self.signature):
            with open(self.filename, 'rb') as file_handler:
                mkv_video = enzyme.MKV(file_handler)

            for sub in mkv_video.subtitle_tracks:
                try:
                    if sub.language and \
                            Language.fromalpha3b(sub.language) == language:
                        has_subtitle = True
                        break
                    elif sub.name and \
                            Language.fromname(sub.name) == language:
                        has_subtitle = True
                        break
                except BabelfishError:
                    LOG.error("Embedded subtitle track"
                              "language {} is not a valid language".format(
                                  sub.language))

        # Look for external subtitle
        dir_name = os.path.dirname(self.filename)
        base_name, _ = os.path.splitext(os.path.basename(self.filename))

        search_subtitle = os.path.join(
            dir_name, "{}.{}.*".format(base_name, language.alpha2))
        existing_subtitles = [
            sub_file for sub_file in glob.glob(search_subtitle)
            if os.path.splitext(sub_file)[1] in Subtitle.EXTENSIONS
        ]

        if existing_subtitles:
            has_subtitle = True

        return has_subtitle
Exemplo n.º 25
0
 def list_languages(self, file):
     if self.ffprobe:
         try:
             if not settings.general.getboolean('ignore_pgs_subs'):
                 subtitle_languages = subprocess.check_output([self.ffprobe, "-loglevel", "error", "-select_streams", "s", "-show_entries", "stream_tags=language", "-of", "csv=p=0", file.encode(locale.getpreferredencoding())], universal_newlines=True, stderr=subprocess.STDOUT).strip()
                 if not subtitle_languages:
                     return []
                 return subtitle_languages.split('\n')
             subtitle_tracks = subprocess.check_output([self.ffprobe, "-loglevel", "error", "-select_streams", "s", "-show_entries", "stream=codec_name:stream_tags=language", "-of", "csv=p=0", file.encode(locale.getpreferredencoding())], universal_newlines=True, stderr=subprocess.STDOUT).strip()
             if not subtitle_tracks:
                 return []
             subtitle_tracks = subtitle_tracks.split('\n')
             return [lang for (sub_type, lang) in map(lambda subtitle_track: subtitle_track.split(','), subtitle_tracks) if sub_type != 'hdmv_pgs_subtitle']
         except subprocess.CalledProcessError as e:
             raise FFprobeError(e.output)
     if os.path.splitext(file)[1] != '.mkv':
         raise NotMKVAndNoFFprobe()
     with open(file, 'rb') as f:
         mkv = enzyme.MKV(f)
     if not settings.general.getboolean('ignore_pgs_subs'):
         return [subtitle_track.language for subtitle_track in mkv.subtitle_tracks]
     return [subtitle_track.language for subtitle_track in mkv.subtitle_tracks if subtitle_track.codec_id != "S_HDMV/PGS"]
Exemplo n.º 26
0
 def collect_mkv(self, directory, file_name):
     full_path = os.path.join(directory, file_name)
     with open(full_path, 'rb') as fd:
         try:
             mkv = enzyme.MKV(fd)
         except Exception as e:
             print(full_path)
             print(e)
             return
         if mkv.subtitle_tracks:
             # TODO: collect all subtitles
             s = mkv.subtitle_tracks[0]
             # TODO: collect S_TEXT/ASS too
             if s.codec_id == 'S_TEXT/UTF8':
                 temp_file = 'temp_subtitle.srt'
                 cmd = [
                     'mkvextract', 'tracks', full_path,
                     '{n}:{e}'.format(n=s.number - 1, e=temp_file)
                 ]
                 subprocess.check_output(cmd)
                 # TODO: guess the language
                 lang = 'simple'
                 rel_mediafile = MediaFile.objects.filter(
                     directory=directory, file_name=file_name).first()
                 subtitle_file = SubtitlesFile.objects.create(
                     file_name=file_name,
                     directory=directory,
                     extension='mkv',
                     mediafile=rel_mediafile,
                     language=lang)
                 self.collect_subtitles_lines(subtitle_file, temp_file)
                 os.remove(temp_file)
                 return subtitle_file
             else:
                 print 'Found other codec id {id} in {f}'.format(
                     id=s.codec_id, f=full_path)
Exemplo n.º 27
0
def scan_video(path, subtitles=True, embedded_subtitles=True, original=None):
    """Scan a video and its subtitle languages from a video `path`

    :param string path: absolute path to the video
    :param bool subtitles: scan for subtitles with the same name
    :param bool embedded_subtitles: scan for embedded subtitles
    :return: the scanned video
    :rtype: :class:`Video`
    :raise: ValueError if cannot guess enough information from the path

    """
    if not original:
        original = path

    dirpath, filename = os.path.split(path)
    logger.info('Scanning video %r in %r', filename, dirpath)
    video = Video.fromguess(path,
                            guessit.guess_file_info(original, 'autodetect'))
    video.size = os.path.getsize(path)
    if video.size > 10485760:
        logger.debug('Size is %d', video.size)
        video.hashes['opensubtitles'] = hash_opensubtitles(path)
        video.hashes['thesubdb'] = hash_thesubdb(path)
        logger.debug('Computed hashes %r', video.hashes)
    else:
        logger.warning('Size is lower than 10MB: hashes not computed')
    if subtitles:
        video.subtitle_languages |= scan_subtitle_languages(path)
    # enzyme
    try:
        if filename.endswith('.mkv'):
            with open(path, 'rb') as f:
                mkv = enzyme.MKV(f)
            if mkv.video_tracks:
                video_track = mkv.video_tracks[0]
                # resolution
                if video_track.height in (480, 720, 1080):
                    if video_track.interlaced:
                        video.resolution = '%di' % video_track.height
                        logger.debug('Found resolution %s with enzyme',
                                     video.resolution)
                    else:
                        video.resolution = '%dp' % video_track.height
                        logger.debug('Found resolution %s with enzyme',
                                     video.resolution)
                # video codec
                if video_track.codec_id == 'V_MPEG4/ISO/AVC':
                    video.video_codec = 'h264'
                    logger.debug('Found video_codec %s with enzyme',
                                 video.video_codec)
                elif video_track.codec_id == 'V_MPEG4/ISO/SP':
                    video.video_codec = 'DivX'
                    logger.debug('Found video_codec %s with enzyme',
                                 video.video_codec)
                elif video_track.codec_id == 'V_MPEG4/ISO/ASP':
                    video.video_codec = 'XviD'
                    logger.debug('Found video_codec %s with enzyme',
                                 video.video_codec)
            else:
                logger.warning('MKV has no video track')
            if mkv.audio_tracks:
                audio_track = mkv.audio_tracks[0]
                # audio codec
                if audio_track.codec_id == 'A_AC3':
                    video.audio_codec = 'AC3'
                    logger.debug('Found audio_codec %s with enzyme',
                                 video.audio_codec)
                elif audio_track.codec_id == 'A_DTS':
                    video.audio_codec = 'DTS'
                    logger.debug('Found audio_codec %s with enzyme',
                                 video.audio_codec)
                elif audio_track.codec_id == 'A_AAC':
                    video.audio_codec = 'AAC'
                    logger.debug('Found audio_codec %s with enzyme',
                                 video.audio_codec)
            else:
                logger.warning('MKV has no audio track')
            if mkv.subtitle_tracks:
                # embedded subtitles
                if embedded_subtitles:
                    embedded_subtitle_languages = set()
                    for st in mkv.subtitle_tracks:
                        if st.language:
                            try:
                                embedded_subtitle_languages.add(
                                    babelfish.Language.fromalpha3b(
                                        st.language))
                            except babelfish.Error:
                                logger.error(
                                    'Embedded subtitle track language %r is not a valid language',
                                    st.language)
                                embedded_subtitle_languages.add(
                                    babelfish.Language('und'))
                        elif st.name:
                            try:
                                embedded_subtitle_languages.add(
                                    babelfish.Language.fromname(st.name))
                            except babelfish.Error:
                                logger.debug(
                                    'Embedded subtitle track name %r is not a valid language',
                                    st.name)
                                embedded_subtitle_languages.add(
                                    babelfish.Language('und'))
                        else:
                            embedded_subtitle_languages.add(
                                babelfish.Language('und'))
                    logger.debug('Found embedded subtitle %r with enzyme',
                                 embedded_subtitle_languages)
                    video.subtitle_languages |= embedded_subtitle_languages
            else:
                logger.debug('MKV has no subtitle track')
    except enzyme.Error:
        logger.exception('Parsing video metadata with enzyme failed')
    return video
Exemplo n.º 28
0
def guess_video_metadata(filename):
    """Gets the video metadata properties out of a given file. The file needs to
    exist on the filesystem to be able to be analyzed. An empty guess is
    returned otherwise.

    You need to have the Enzyme python package installed for this to work."""
    result = Guess()

    def found(prop, value):
        result[prop] = value
        log.debug('Found with enzyme %s: %s' % (prop, value))

    # first get the size of the file, in bytes
    try:
        size = os.stat(filename).st_size
        found('fileSize', size)

    except Exception as e:
        log.error('Cannot get video file size: %s' % e)
        # file probably does not exist, we might as well return now
        return result

    # then get additional metadata from the file using enzyme, if available
    try:
        import enzyme

        with open(filename) as f:
            mkv = enzyme.MKV(f)

            found('duration', mkv.info.duration.total_seconds())

            if mkv.video_tracks:
                video_track = mkv.video_tracks[0]

                # resolution
                if video_track.height in (480, 720, 1080):
                    if video_track.interlaced:
                        found('screenSize', '%di' % video_track.height)
                    else:
                        found('screenSize', '%dp' % video_track.height)
                else:
                    # TODO: do we want this?
                    #found('screenSize', '%dx%d' % (video_track.width, video_track.height))
                    pass

                # video codec
                if video_track.codec_id == 'V_MPEG4/ISO/AVC':
                    found('videoCodec', 'h264')
                elif video_track.codec_id == 'V_MPEG4/ISO/SP':
                    found('videoCodec', 'DivX')
                elif video_track.codec_id == 'V_MPEG4/ISO/ASP':
                    found('videoCodec', 'XviD')

            else:
                log.warning('MKV has no video track')

            if mkv.audio_tracks:
                audio_track = mkv.audio_tracks[0]
                # audio codec
                if audio_track.codec_id == 'A_AC3':
                    found('audioCodec', 'AC3')
                elif audio_track.codec_id == 'A_DTS':
                    found('audioCodec', 'DTS')
                elif audio_track.codec_id == 'A_AAC':
                    found('audioCodec', 'AAC')
            else:
                log.warning('MKV has no audio track')

            if mkv.subtitle_tracks:
                embedded_subtitle_languages = set()
                for st in mkv.subtitle_tracks:
                    try:
                        if st.language:
                            lang = babelfish.Language.fromalpha3b(st.language)
                        elif st.name:
                            lang = babelfish.Language.fromname(st.name)
                        else:
                            lang = babelfish.Language('und')

                    except babelfish.Error:
                        lang = babelfish.Language('und')

                    embedded_subtitle_languages.add(lang)

                found('subtitleLanguage', embedded_subtitle_languages)
            else:
                log.debug('MKV has no subtitle track')

        return result

    except ImportError:
        log.error('Cannot get video file metadata, missing dependency: enzyme')
        log.error(
            'Please install it from PyPI, by doing eg: pip install enzyme')
        return result

    except IOError as e:
        log.error('Could not open file: %s' % filename)
        log.error(
            'Make sure it exists and is available for reading on the filesystem'
        )
        log.error('Error: %s' % e)
        return result

    except enzyme.Error as e:
        log.error('Cannot guess video file metadata')
        log.error('enzyme.Error while reading file: %s' % filename)
        log.error('Error: %s' % e)
        return result
Exemplo n.º 29
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
Exemplo n.º 30
0
 def extract_info(cls, video_path):
     """Extract info from the video."""
     with open(video_path, 'rb') as f:
         return to_dict(enzyme.MKV(f))