예제 #1
0
def dismount_iso_on_windows(iso):
    '''
    Dismounts the ISO.
    :param iso: the iso.
    '''
    iso_to_dismount = os.path.abspath(iso)
    command = f"PowerShell Dismount-DiskImage {iso_to_dismount}"
    main_logger.debug(f"Triggering : {command}")
    result = subprocess.run(command, capture_output=True)
    if result is not None and result.returncode == 0:
        main_logger.info(f"Dismounted {iso_to_dismount}")
    else:
        main_logger.error(
            f"Unable to dismount {iso_to_dismount} , stdout: {result.stdout.decode('utf-8')}, stderr: {result.stderr.decode('utf-8')}"
        )
예제 #2
0
def mount_iso_on_windows(iso):
    '''
    Mounts ISO and returns the mounted drive path.
    :param iso: the iso.
    :return: the mounted path.
    '''
    iso_to_mount = os.path.abspath(iso)
    command = f"PowerShell ((Mount-DiskImage {iso_to_mount} -PassThru) | Get-Volume).DriveLetter"
    main_logger.debug(f"Triggering : {command}")
    result = subprocess.run(command, capture_output=True)
    if result is not None and result.returncode == 0:
        target = f"{result.stdout.decode('utf-8').rstrip()}:{os.path.sep}"
        main_logger.info(f"Mounted {iso_to_mount} on {target}")
    else:
        main_logger.error(
            f"Unable to mount {iso_to_mount} , stdout: {result.stdout.decode('utf-8')}, stderr: {result.stderr.decode('utf-8')}"
        )
        target = None
    return target
예제 #3
0
def __read_playlists_from_disc_inf(bd, bd_folder_path):
    candidate_titles = {}
    if os.path.exists(os.path.join(bd_folder_path, 'disc.inf')):
        obfuscated_playlists = None
        with open(os.path.join(bd_folder_path, 'disc.inf'), mode='r') as f:
            for line in f:
                if line.startswith('playlists='):
                    obfuscated_playlists = [f"{int(x.strip()):05}.mpls" for x in line[10:].split(',')]
                    break
        if obfuscated_playlists is not None:
            main_logger.debug(f"disc.inf found with obfuscated playlists {obfuscated_playlists}")
            for x in range(bd.NumberOfTitles):
                t = bd.GetTitle(x)
                if t.Playlist in obfuscated_playlists:
                    candidate_titles[x] = t
        else:
            main_logger.debug('No playlists found in disc.inf')
    else:
        main_logger.debug('No disc.inf found')
    return candidate_titles
예제 #4
0
def process_measurements(bd, bd_folder_path, args):
    '''
    Creates measurement files by measuring or copying as necessary for the requested titles.
    :param bd: the libbluray Bluray wrapper.
    :param bd_folder_path: the physical path to the bd folder.
    :param args: the cli args
    '''
    from madmeasurer.loggers import main_logger
    main_titles = get_main_titles(bd, bd_folder_path, args)
    if args.measure is True:
        for title_number in range(bd.NumberOfTitles):
            measure_it = False
            title = bd.GetTitle(title_number)
            if is_any_title_uhd(bd.Path, main_titles.values()):
                if title_number in main_titles.keys():
                    measure_it = True
                    main_logger.debug(f"Measurement candidate {bd.Path} - {title.Playlist} : main title")
                elif args.measure_all_playlists is True:
                    from bluread.objects import TicksToTuple
                    title_duration = TicksToTuple(title.Length)
                    title_duration_mins = (title_duration[0] * 60) + title_duration[1]
                    if title_duration_mins >= args.min_duration:
                        if args.max_duration is None or title_duration_mins <= args.max_duration:
                            main_logger.info(f"Measurement candidate {bd.Path} - {title.Playlist} : length is {title.LengthFancy}")
                            measure_it = True
                if measure_it is True:
                    playlist_file = os.path.join(bd_folder_path, 'BDMV', 'PLAYLIST', title.Playlist)
                    do_measure_if_necessary(playlist_file, args)
                else:
                    main_logger.debug(f"No measurement required for {bd.Path} - {title.Playlist}")
            else:
                main_logger.debug(f"Ignoring non uhd title {bd.Path} - {title.Playlist}")

    if args.copy is True:
        for t in main_titles.values():
            copy_measurements(bd.Path, t.Playlist, args)
예제 #5
0
def get_main_title_by_jriver(bd, bd_folder_path, resolution='seconds'):
    '''
    Locates the main title using JRiver's algorithm which compares entries one by one by duration, audio stream count
    and then playlist name albeit allowing a slightly (within 10%) shorter track with more audio streams to still win.
    :param bd: the pybluread BD.
    :param bd_folder_path: the folder path.
    :param resolution: the resolution to use when comparison durations.
    :return: the main title.
    '''
    candidate_titles = __read_playlists_from_disc_inf(bd, bd_folder_path)
    if len(candidate_titles) == 0:
        candidate_titles = {x: bd.GetTitle(x) for x in range(bd.NumberOfTitles)}

    max_audio_titles = 0
    main_title = None
    main_title_num = 0

    for title_num, title in candidate_titles.items():
        new_main = False
        reason = ''
        if main_title is None:
            new_main = True
        else:
            audio_titles = __get_max_audio(title)
            cmp = 0
            if title.Length >= (main_title.Length*0.9):
                cmp = audio_titles - max_audio_titles

            if cmp == 0:
                this_len = TicksToTuple(title.Length)
                main_len = TicksToTuple(main_title.Length)
                if resolution == 'minutes':
                    cmp = ((this_len[0] * 60) + this_len[1]) - ((main_len[0] * 60) + main_len[1])
                elif resolution == 'seconds':
                    cmp = ((this_len[0] * 60 * 60) + (this_len[1] * 60) + this_len[2]) \
                          - ((main_len[0] * 60 * 60) + (main_len[1] * 60) + main_len[2])
                else:
                    cmp = title.Length - main_title.Length
                if cmp == 0:
                    cmp = audio_titles - max_audio_titles
                    if cmp == 0:
                        if title.Playlist < main_title.Playlist:
                            cmp = 1
                            reason = 'playlist name order'
                    else:
                        reason = 'audio stream count'
                else:
                    reason = 'duration'
            elif cmp > 0:
                reason = 'audio stream count, duration within 10%'

            if cmp > 0:
                new_main = True

        if new_main is True:
            if main_title is not None:
                main_logger.debug(f"New main title found {title.Playlist} vs {main_title.Playlist} : {reason}")
            else:
                main_logger.debug(f"Initialising main title search with {title.Playlist}")
            main_title = title
            main_title_num = title_num
            max_audio_titles = __get_max_audio(title)
        else:
            main_logger.debug(f"Main title remains {main_title.Playlist}, discarding {title.Playlist}")

    if main_title is None:
        main_logger.error(f"No main title found in {bd.Path}")

    return main_title_num
예제 #6
0
def describe_bd(bd, bd_folder_path, force=False, verbose=False):
    '''
    Outputs a yaml file into the bd folder describing the BD.
    :param bd: the libbluray BD.
    :param bd_folder_path: the BD folder path.
    :param force: overwrite the file if it exists.
    :param verbose: if true, dump the output to the screen
    '''
    output_file = os.path.join(bd_folder_path, 'disc.yaml')
    if not os.path.exists(output_file) or force is True:
        details = {'name': bd.Path, 'title_count': bd.NumberOfTitles,
                   'main_titles': main_title_by_algo(bd, bd_folder_path)}
        titles = []
        for title_number in range(bd.NumberOfTitles):
            t = bd.GetTitle(title_number)
            title = {'idx': title_number, 'playlist': t.Playlist, 'duration_raw': t.Length, 'duration': t.LengthFancy,
                     'angle_count': t.NumberOfAngles, 'chapter_count': t.NumberOfChapters}

            chapters = []
            for chapter_number in range(1, t.NumberOfChapters + 1):
                c = t.GetChapter(chapter_number)
                chapter = {'idx': chapter_number, 'start_raw': c.Start, 'start': c.StartFancy, 'end_raw': c.End,
                           'end': c.EndFancy, 'duration_raw': c.Length, 'duration': c.LengthFancy}
                chapters.append(chapter)
            title['chapters'] = chapters

            title['clip_count'] = t.NumberOfClips
            clips = []
            for clip_number in range(t.NumberOfClips):
                c = t.GetClip(clip_number)
                clip = {'idx': clip_number, 'video_primary_count': c.NumberOfVideosPrimary,
                        'video_secondary_count': c.NumberOfVideosSecondary}
                videos = []
                for video_number in range(c.NumberOfVideosPrimary):
                    v = c.GetVideo(video_number)
                    video = {'idx': video_number, 'language': v.Language, 'coding_type': v.CodingType,
                             'format': v.Format, 'rate': v.Rate, 'aspect': v.Aspect}
                    videos.append(video)
                clip['video_primary'] = videos

                clip['audio_primary_count'] = c.NumberOfAudiosPrimary
                clip['audio_secondary_count'] = c.NumberOfAudiosSecondary
                audios = []
                for audio_number in range(c.NumberOfAudiosPrimary):
                    a = c.GetAudio(audio_number)
                    audio = {'idx': audio_number, 'language': a.Language, 'coding_type': a.CodingType,
                             'format': a.Format, 'rate': a.Rate}
                    audios.append(audio)
                clip['audio_primary'] = audios

                clip['subtitle_count'] = c.NumberOfSubtitles
                subtitles = []
                for subtitle_number in range(c.NumberOfSubtitles):
                    s = c.GetSubtitle(subtitle_number)
                    subtitle = {'idx': subtitle_number, 'language': s.Language}
                    subtitles.append(subtitle)
                clip['subtitles'] = subtitles
                clips.append(clip)

            title['clips'] = clips
            titles.append(title)

        details['titles'] = titles
        with open(output_file, 'w+') as f:
            yaml.dump(details, f)
            if verbose is True:
                main_logger.debug(yaml.dump(details))