コード例 #1
0
ファイル: song.py プロジェクト: krissterckx/win_audio
 def print(self, extended=False, highlight_title=False):
     for tag in self.get_tag_keys(extended):
         if highlight_title and tag == 'TITLE':
             bold('TITLE:', self.get(tag))
         else:
             stdout(tag, ':', self.get(tag))
     stdout()
コード例 #2
0
ファイル: song.py プロジェクト: krissterckx/win_audio
 def print_tags(self,
                detailed=False,
                as_json=False,
                as_pprint=False,
                to_file=None,
                extended=False,
                header=True,
                subscript=None,
                highlight_title=False):
     if header and not to_file:
         stdout()
         if subscript:
             green(self.full_path(), end='')
             cyan(' (' + subscript + ')')
         else:
             green(self.full_path())
     track = self.get('TRACKNUMBER')
     fix_track = False
     if track.startswith('T'):
         track = track[1:]
         fix_track = True
     if fix_track:
         self.set('TRACKNUMBER', track)
     if detailed:
         self.print(extended, highlight_title)
     elif as_json or as_pprint:
         self.print_json(extended, as_pprint, to_file)
     else:
         self.echo()
コード例 #3
0
ファイル: functions.py プロジェクト: krissterckx/win_audio
def add_missing_file(path, track, dryrun=True):
    missed = get_missing_file_full_path(path, track)
    if dryrun:
        stdout('(dryrun)', missed, 'created')
    else:
        new_mark_file(missed)
        yellow(missed, 'created')
コード例 #4
0
def fix_track_nbrs(root,
                   project,
                   artist,
                   album,
                   songs,
                   artist_filter=None,
                   album_filter=None,
                   title_filter=None,
                   force_overwrite_total_tracks=None,
                   mark_missing_songs=False,
                   dryrun=True,
                   verbose=False,
                   silent=False,
                   radio_silent=False,
                   debug=False):
    fixed_tracks = 0
    missed_tracks = 0
    warnings = 0
    dry = '(dryrun) ' if dryrun else ''

    songs_by_track_nbr, missed_songs, total_tracks, w, _ = get_filtered_songs(
        root + '/' + project + '/' + artist + '/' + album,
        songs,
        artist_filter,
        album_filter,
        title_filter,
        sort_per_track=True,
        post_process_songs=force_overwrite_total_tracks is None,
        print_header=not silent,
        no_warn=radio_silent,
        deep_warn=True,
        mark_missing_songs=mark_missing_songs,
        dryrun=dryrun,
        verbose=verbose,
        silent=silent,
        debug=debug)

    missed_tracks += len(missed_songs)
    warnings += w

    if total_tracks or force_overwrite_total_tracks:
        for track_nbr in sorted(songs_by_track_nbr):
            for song in songs_by_track_nbr[track_nbr]:
                title = song.get('TITLE')
                track_tag = song.get_track_nbr_as_string(default=None,
                                                         verbose=verbose)
                empty_tag = track_tag is None
                new_tag = '{}/{}'.format(
                    track_nbr, force_overwrite_total_tracks
                    if force_overwrite_total_tracks else total_tracks)
                if track_tag != new_tag:
                    stdout(
                        dry + 'Fixing', project, '/', artist, '/', album, '/',
                        title, '/', 'empty track' if empty_tag else
                        ('track ' + track_tag), 'to', new_tag)
                    song.set('TRACKNUMBER', new_tag, save=True, dryrun=dryrun)
                    fixed_tracks += 1

    return fixed_tracks, missed_tracks, warnings
コード例 #5
0
ファイル: audit_songs.py プロジェクト: krissterckx/win_audio
 def sing_it(force=False):
     global sung_it  # python 3 can do nonlocal but in py2 is readonly
     elaborated = False
     if not silent and (force or not sung_it):
         if elaborated:
             stdout(init_the_song, end='')  # sing it
         else:
             yellow('Fixing', project, '/', artist_d, '/', album_d, '/',
                    song_f)
         sung_it = True
コード例 #6
0
def main():
    program = 'fix_empty_dirs'
    description = '''
    Deletes empty dirs'''

    parser = argparse.ArgumentParser(prog=program,
                                     description=description)
    parser.add_argument('-p', '--production', help='Enable production run',
                        action='store_true')
    parser.add_argument('-v', '--verbose', help='Enable verbosity',
                        action='store_true')
    parser.add_argument('-x', '--path', type=str, help='Root path')
    args = parser.parse_args()
    dryrun = not args.production or get_env_var('DRYRUN')
    verbose = args.verbose or get_env_var('VERBOSE')
    root = args.path or get_default_root()

    assert_non_empty_dir(root)
    mark_dry_or_production_run(dryrun)
    if dryrun:
        warn('Dryrun does not check nested empty dirs!')

    cnt = 0
    done = False
    dryrun_deleted_dirs = []
    while not done:
        cnt_start = cnt
        for dir_name, sub_dirs, file_names in os.walk(root):
            if verbose:
                yellow('Checking', dir_name)
            if not sub_dirs and not file_names:
                if dryrun:
                    if dir_name in dryrun_deleted_dirs:
                        continue
                    else:
                        dryrun_deleted_dirs.append(dir_name)
                remove_dir(dir_name, dryrun=dryrun, verbose=verbose)
                cnt += 1
        done = cnt == cnt_start

    if cnt:
        stdout()
    stdout(cnt, 'dirs deleted')
コード例 #7
0
ファイル: song.py プロジェクト: krissterckx/win_audio
 def diff(self,
          other,
          my_name=None,
          other_name=None,
          extended=False,
          print_on_diff=True,
          print_on_diff_f=None):
     diff = False
     tags = self.get_tag_keys(extended)
     my_name = my_name or self.name()
     other_name = other_name or other.name()
     for tag in tags:
         if self.get(tag) != other.get(tag):
             if not diff and print_on_diff:
                 if print_on_diff_f:
                     stdout(print_on_diff_f)
                 else:
                     cyan(tag, 'diff:',
                          self.get(tag), '(' + my_name + ') !=',
                          other.get(tag), '(' + other_name + ')')
             diff = True
             break
     return diff
コード例 #8
0
ファイル: audit_songs.py プロジェクト: krissterckx/win_audio
    def finish_it():
        global errors_fixed

        debug_out('finish_it')

        artist = song.get('ALBUMARTIST')
        contributing_artists = song.get('ARTIST')
        album = song.get('ALBUM')
        title = song.get('TITLE')

        if sung_it:
            report('OK')
        if did_it():
            if silent:
                green('Retagged', project, '/', artist,
                      '(' + contributing_artists + ') /', album, '/', title)
            else:
                stdout('WAS:')
                print_it(keep)
                stdout('BECAME:')
                print_it()
            save_it()  # this is the moment where we save!
            errors_fixed += 1
コード例 #9
0
ファイル: review_songs.py プロジェクト: krissterckx/win_audio
def edit_song(song, debug=False):
    FILL_UP_TO = 15

    done = False
    while not done:
        start_cyan()
        option(0, 'None')
        option(1, 'SONG FILE'.ljust(FILL_UP_TO) + song.name())
        idx = 2
        tag_qualifiers = Song.get_tag_keys()
        for tag in tag_qualifiers:
            option(idx, tag.ljust(FILL_UP_TO) + song.get(tag))
            idx += 1
        end_color()
        stdout()

        while True:
            t = numerical_input('Edit file/tag', 0, idx - 1)
            if t == 0:  # exit
                done = True
                break
            elif t == 1:  # new song file
                f = string_input('New SONG FILE', prefill=song.name())
                yellow('Updating SONG FILE to', f)
                rename_file(song.path(), song.name(), f,
                            dryrun=False, silent=True, debug=debug)
                song = Song(path=song.path(), song_f=f, debug=debug)
                stdout()
            else:
                t = tag_qualifiers[t - 2]
                f = string_input('New ' + t, prefill=song.get(t))
                yellow('Updating', t, 'to', f)
                song.set(t, f, save=True, dryrun=False)  # modify for real!
                stdout()

    return song
コード例 #10
0
ファイル: audit_songs.py プロジェクト: krissterckx/win_audio
def main():
    if is_py2():
        warn('Running as python 3 is advised')
        stdout()

    program = 'audit_songs'
    description = '''
    Audits songs or list of songs with its directory structure
    '''

    parser = argparse.ArgumentParser(prog=program, description=description)
    parser.add_argument('-p',
                        '--production',
                        help='Enable production run',
                        action='store_true')
    parser.add_argument('-j',
                        '--project-filter',
                        type=str,
                        help='Set project filter')
    parser.add_argument('-a',
                        '--artist-filter',
                        type=str,
                        help='Set artist filter')
    parser.add_argument('-b',
                        '--album-filter',
                        type=str,
                        help='Set album filter')
    parser.add_argument('-c',
                        '-t',
                        '--title-filter',
                        type=str,
                        help='Set title filter')
    parser.add_argument('--dir-structure-as-ref',
                        help=('Set the dir structure as the reference, '
                              'opposed to the default\'s song tags'),
                        action='store_true')
    parser.add_argument('--set-artist',
                        type=str,
                        help='Set (overrules) artists. Always use with '
                        '--artist-filter')
    parser.add_argument('--set-album',
                        type=str,
                        help='Set (overrules) album. Always use with '
                        '--album-filter')
    parser.add_argument('--set-song',
                        type=str,
                        help='Set (overrules) song title, Always use with '
                        '--title-filter')
    parser.add_argument('--provide-report',
                        help='Provide a report of modified songs',
                        action='store_true')
    parser.add_argument('-x', '--path', type=str, help='Sets root path')
    parser.add_argument('-n',
                        '--limit-changes',
                        type=int,
                        help='Set a limit to amount of changes')
    parser.add_argument('-v',
                        '--verbose',
                        help='Enable verbosity',
                        action='store_true')
    parser.add_argument('-s',
                        '--silent',
                        help='Enable silence',
                        action='store_true')
    parser.add_argument('-d',
                        '--debug',
                        help='Enable debug',
                        action='store_true')
    parser.add_argument('--force-write',
                        help='Force-Write',
                        action='store_true')

    args = parser.parse_args()
    root = args.path or get_default_root()
    dryrun = not args.production or get_env_var('DRYRUN')
    silent = args.silent or get_env_var('SILENT')
    debug = args.debug or get_env_var('DEBUG')
    verbose = args.verbose or get_env_var('VERBOSE') or debug
    provide_report = args.provide_report
    project_filter = args.project_filter
    artist_filter = args.artist_filter
    album_filter = args.album_filter
    title_filter = args.title_filter
    dir_structure_as_ref = args.dir_structure_as_ref
    set_artist = args.set_artist
    set_album = args.set_album
    set_song = args.set_song
    limit_changes = args.limit_changes or 9999999999

    if set_artist and not artist_filter:
        fatal_error('Must set artist filter when setting artist')
    if set_album and not album_filter:
        fatal_error('Must set album filter when setting album')
    if set_song and not title_filter:
        fatal_error('Must set title filter when setting song title')

    if title_filter and title_filter.lower().endswith(SONG_FILE_EXT):
        title_filter = title_filter[:-len(SONG_FILE_EXT)]
    if set_song and set_song.lower().endswith(SONG_FILE_EXT):
        set_song = set_song[:-len(SONG_FILE_EXT)]

    assert_non_empty_dir(root)
    mark_dry_or_production_run(dryrun)

    for dir_name, _, filenames in os.walk(root):
        process, project, artist, album = process_songs_dir(
            root, dir_name, project_filter, artist_filter, album_filter)
        if not process:
            continue

        if not title_filter and verbose:
            yellow('Processing', project, artist, album)

        for song in filenames:
            if not song.lower().endswith(SONG_FILE_EXT):
                continue
            if title_filter:
                if title_filter.lower() != song[:-len(SONG_FILE_EXT)].lower():
                    continue
                elif verbose:
                    yellow('Processing', project, artist, album, song)
            elif debug:
                yellow('Processing', project, artist, album, song)

            reset_artist = [None]
            reset_album = [None]

            if audit_song(
                    root,
                    project,
                    artist,
                    album,
                    song,
                    reset_artist,
                    reset_album,
                    dir_structure_as_ref=dir_structure_as_ref,
                    # Once a first song in album fixes the artist, same artist
                    # is dictated to rest of songs. This avoids ping-pong'ing.
                    set_artist=set_artist if set_artist else None,
                    # Once a first song in album fixes the album, same album is
                    # dictated to rest of songs. This avoids ping-pong'ing.
                    set_album=set_album if set_album else None,
                    # User specified song
                    set_song=set_song,
                    force_write=args.force_write,
                    dryrun=dryrun,
                    verbose=verbose,
                    silent=silent,
                    debug=debug):
                if debug:
                    stdout(errors_fixed, 'errors fixed')
                if reset_artist[0]:
                    if (artist_filter
                            and artist.lower() == artist_filter.lower()):
                        artist_filter = reset_artist[0]
                    artist = reset_artist[0]  # Make sure next songs in album
                    #                           will load correctly
                if reset_album[0]:
                    if (album_filter
                            and album.lower() == album_filter.lower()):
                        album_filter = reset_album[0]
                    album = reset_album[0]  # Make sure next songs in album
                    #                         will load correctly
                if not silent:
                    stdout()

            if errors_fixed >= limit_changes:
                break

    if not silent and errors_fixed >= limit_changes:
        stdout()
    stdout(errors_fixed, 'errors were fixed;', errors_unresolved,
           'remaining errors found')

    if provide_report and fixed_songs:
        stdout('Generating reports', ConsoleColors.ALERT)

        print_paths(fixed_songs, write_to_file=FIXED_SONGS_REPORT + '.cyg')
        print_paths(fixed_songs,
                    dos_format=True,
                    write_to_file=FIXED_SONGS_REPORT + '.dos')

        stdout(ConsoleColors.ENDC + 'Check the report:')
        stdout('   ', 'cat', FIXED_SONGS_REPORT + '.cyg')
        stdout('   ', 'cat', FIXED_SONGS_REPORT + '.dos')
        stdout()
        stdout('Feed into foobar2000 as:')
        stdout('    for i in $(cat ' + FIXED_SONGS_REPORT +
               '.dos); do songs="$songs $i"; done; foobar2000.exe /add $songs')
        stdout()
        stdout('Or do a little test:')
        stdout('    for i in $(cat ' + FIXED_SONGS_REPORT +
               '.dos); do echo "$i"; done')
        stdout()
コード例 #11
0
ファイル: review_songs.py プロジェクト: krissterckx/win_audio
def review_songs(path, song_files, title_filter,
                 detailed=True, sort=True,
                 verbose=False, silent=False, radio_silent=False, debug=False):
    songs = []

    filtered_songs, missed_songs, _, _, _ = get_filtered_songs(
        path, song_files, title_filter=title_filter,
        sort_per_track=sort, post_process_songs=sort,
        print_header=not silent,
        verbose=verbose, silent=silent, no_warn=radio_silent, debug=debug)

    if not filtered_songs:
        return

    for track_nbr in sorted(filtered_songs):
        for song in filtered_songs[track_nbr]:
            songs.append(song)

    PAGE_SIZE = 20
    done = False
    idx = 1

    def option_title(title_idx):
        s = songs[title_idx - 1]
        # noinspection PyTypeChecker
        title = s.get('TITLE')
        if detailed:
            # noinspection PyTypeChecker
            track_nr = s.get('TRACKNUMBER')
            title += (' (' + track_nr + ')')
        option(title_idx, title)

    while not done:
        if idx > len(songs):
            break

        default = idx - 1
        stdout()
        option(default, 'None')

        for _ in range(PAGE_SIZE):
            if idx > len(songs):
                done = True
                break
            option_title(idx)
            idx += 1

        def add_options(_idx):
            _add_tags = None

            def _add_option(_s, _i):
                option(_i, _s)
                return _i, _i + 1

            if missed_songs:
                _add_tags, _idx = _add_option('-- ADD .missing TAGS --', _idx)
            _reload, _idx = _add_option('-- RELOAD --', _idx)
            _exit_the_game, _idx = _add_option('-- EXIT --', _idx)

            return _add_tags, _reload, _exit_the_game

        add_tags, reload, exit_the_game = add_options(idx)
        stdout()

        while True:
            c = numerical_input('Song to edit', default, exit_the_game)
            if missed_songs and c == add_tags:
                stdout()
                for missed in missed_songs:
                    add_missing_file(missed[0], missed[1], dryrun=False)
                stdout()
                c = None

            elif c == reload:
                stdout()
                option(default, 'None')
                for i in range(default + 2, idx):
                    option_title(i)
                add_options(idx)
                cyan('(mind, not re-sorted)')
                cyan()
                c = None

            elif c == exit_the_game:
                cyan('Bye.')
                end()

            elif c == default:
                break

            if c is not None:
                stdout()
                song_idx = c - 1
                songs[song_idx] = edit_song(songs[song_idx], debug=debug)
コード例 #12
0
ファイル: audit_songs.py プロジェクト: krissterckx/win_audio
 def print_it(p_tags=None, offset=4):
     p_tags = p_tags or song.get_tags()
     for _tag in Song.get_tag_keys():
         if _tag == 'TRACKNUMBER':
             continue  # skip
         stdout(' ' * offset + _tag + ': \'' + p_tags[_tag] + '\'')
コード例 #13
0
 def retag(song, new_title):
     if not silent:
         stdout('Retagging to', new_title)
     song.set('TITLE', new_title)
     song.save(dryrun)
コード例 #14
0
def main():
    program = 'fix_indexed_songs'
    description = '''
    Fixes indexed songs'''

    parser = argparse.ArgumentParser(prog=program, description=description)
    parser.add_argument('-x', '--path', type=str, help='Root path')
    parser.add_argument('-v',
                        '--verbose',
                        help='Enable verbosity',
                        action='store_true')
    parser.add_argument('-s',
                        '--silent',
                        help='Enable silence',
                        action='store_true')
    parser.add_argument('-d',
                        '--debug',
                        help='Enable debug',
                        action='store_true')
    parser.add_argument('-p',
                        '--production',
                        help='Enable production run',
                        action='store_true')
    parser.add_argument(
        '--safe-delete',  # create .deleted files always
        # Mind - for remixes can be good idea to set
        help='Safely delete files',
        action='store_true')

    args = parser.parse_args()
    root = args.path or get_default_root()
    dryrun = not args.production or get_env_var('DRYRUN')
    silent = args.silent or get_env_var('SILENT')
    debug = args.debug or get_env_var('DEBUG')
    verbose = args.verbose or get_env_var('VERBOSE') or debug
    safe_delete = args.safe_delete

    root = assure_not_endswith(root, '/')
    assert_non_empty_dir(root)
    mark_dry_or_production_run(dryrun)
    cnt = 0

    if dryrun:
        warn('DRYRUN results are not representative!')
    if not safe_delete:
        warn('Redundant files WILL be deleted (to modify, give --safe-delete)')
        stdout('      '
               '(While only redundant files are deleted, '
               'in case of remix songs, it can be dangerous. ')
        stdout('      '
               ' In general, make sure diff songs have diff '
               'track numbers within a given dir.)')
        stdout()

    def report(*report_args, **report_kwargs):
        if not silent:
            cyan(*report_args, **report_kwargs)

    report('Reindexing files')
    while True:
        curr_cnt = cnt

        #
        # WARN : NOT MOST EFFICIENT IMPLEMENTATION! ... but it works :)
        #

        for dir_name, _, file_names in os.walk(root):
            if dir_name == root:
                continue
            else:
                unrooted = dir_name.replace(root + '/', '')

            cnt += fix_indexed_songs(root + '/' + unrooted, file_names, dryrun,
                                     safe_delete, verbose, silent, debug)

        changed_made = cnt - curr_cnt

        # keep looping if changes made in production run
        if dryrun or not changed_made:
            break

    # now check that we didn't create gaps, if so, fill them up
    report('Filling up holes')
    for dir_name, _, file_names in os.walk(root):
        unrooted = dir_name.replace(root + '/', '')
        fill_up_holes(root + '/' + unrooted, file_names, dryrun, verbose,
                      silent)

    if cnt:
        stdout()
    stdout(cnt, 'files were renamed.')
コード例 #15
0
def main():
    program = 'diff_songs'
    description = '''
    Diffs songs'''

    parser = argparse.ArgumentParser(prog=program, description=description)
    parser.add_argument('-p',
                        '--production',
                        help='Enable production run',
                        action='store_true')
    parser.add_argument('-x1',
                        '--path1',
                        type=str,
                        help='Path to music file 1 or dir 1 of music files')
    parser.add_argument('-x2',
                        '--path2',
                        type=str,
                        help='Path to music file 2 or dir 2 of music files')
    parser.add_argument('-n1',
                        '--name1',
                        type=str,
                        help='A name for music file 1 or dir 1 of music files')
    parser.add_argument('-n2',
                        '--name2',
                        type=str,
                        help='A name for music file 2 or dir 2 of music files')
    parser.add_argument('-r',
                        '--recursive',
                        help='Treat paths recursively',
                        action='store_true')
    parser.add_argument('-e',
                        '--extended',
                        help='Comparing also the song tags',
                        action='store_true')
    parser.add_argument('-v',
                        '--verbose',
                        help='Enable verbosity',
                        action='store_true')
    parser.add_argument('-d',
                        '--debug',
                        help='Enable debug',
                        action='store_true')
    parser.add_argument('-m',
                        '--minimal_verbose',
                        help='Enable minimal verbosity',
                        action='store_true')
    parser.add_argument('-s',
                        '--synchronize',
                        help='Synchronize differences',
                        action='store_true')
    parser.add_argument('--ignore-not-existing',
                        help='Ignore not-existing files',
                        action='store_true')
    parser.add_argument('--ignore-file-differences',
                        help='Ignore file differences',
                        action='store_true')
    parser.add_argument('--ignore-files-only-dirs',
                        help='Ignore files; only focuses on dirs',
                        action='store_true')
    parser.add_argument('--delete-orphan-files',
                        help='Delete orphan path2 files. '
                        'CAUTION is to be applied!',
                        action='store_true')

    args = parser.parse_args()
    dryrun = not args.production or get_env_var('DRYRUN')
    debug = args.debug or get_env_var('DEBUG')
    verbose = args.verbose or get_env_var('VERBOSE') or debug
    minimal_verbose = args.minimal_verbose or get_env_var('MINIMAL_VERBOSE')
    if args.production and not args.synchronize:
        fatal_error('Pointless production run while not synchronizing. '
                    'Give -s -p instead.')

    mark_dry_or_production_run(dryrun)

    root1 = args.path1
    root2 = args.path2

    if not root1 or not root2:
        parser.print_help()
        return

    name1 = args.name1 or '1'
    name2 = args.name2 or '2'

    if args.recursive:
        if root1.endswith('/'):
            root1 = root1[:-1]  # needed for checks below
        if root2.endswith('/'):
            root2 = root2[:-1]  # needed for checks below

        if args.synchronize:
            stdout('=== Diff\'ing and Syncing music files ===\n')
        else:
            stdout('=== Diff\'ing music files ===\n')

        stdout('SOURCE:', root1)
        stdout('TARGET:', root2)
        stdout()

        cnt = diff_files(root1,
                         root2,
                         name1,
                         name2,
                         args.ignore_files_only_dirs,
                         args.ignore_not_existing,
                         args.ignore_file_differences,
                         args.extended,
                         args.synchronize,
                         dryrun=dryrun,
                         verbose=verbose,
                         minimal_verbose=minimal_verbose,
                         debug=debug)
        if minimal_verbose:
            stdout('\bCOMPLETE\n')
        elif cnt:
            stdout()
        diff_cnt = cnt

        if not args.ignore_not_existing and args.delete_orphan_files:
            stdout('CHECKING TARGET FOR ORPHANS (MIND!)')
            stdout()
            cnt = diff_files(
                root2,
                root1,
                name2,
                name1,  # mind, swapped
                args.ignore_files_only_dirs,
                synchronize=args.synchronize,
                delete_root1_files_only=True,  # in reality root2
                dryrun=dryrun,
                verbose=verbose,
                minimal_verbose=minimal_verbose,
                debug=debug)
            if minimal_verbose:
                stdout('\bCOMPLETE\n')
            elif cnt:
                stdout()
            diff_cnt += cnt

        if diff_cnt:
            if args.synchronize:
                stdout(diff_cnt, 'diffs corrected')
            else:
                stdout(diff_cnt, 'diffs observed')
        else:
            stdout('No diff observed')

    elif diff_tags(root1, root2, name1, name2):
        red('Different')
    else:
        green('Equal')
コード例 #16
0
ファイル: song.py プロジェクト: krissterckx/win_audio
 def echo(self):
     stdout('[' + self.get('TRACKNUMBER'), self.get('ALBUM') + ']', end=' ')
     bold(self.get('TITLE'), end=' ')
     stdout('[' + self.get('ALBUMARTIST') + ']')
コード例 #17
0
ファイル: list_songs.py プロジェクト: krissterckx/win_audio
def main():
    program = 'list_songs'
    description = '''
    Lists a set of songs'''

    parser = argparse.ArgumentParser(prog=program, description=description)
    parser.add_argument('-x', '--path', type=str, help='Set root path')
    parser.add_argument('-a',
                        '--artist-filter',
                        type=str,
                        help='Set artist filter')
    parser.add_argument('-b',
                        '--album-filter',
                        type=str,
                        help='Set album filter')
    parser.add_argument('-c',
                        '-t',
                        '--title-filter',
                        type=str,
                        help='Set title filter')
    parser.add_argument('-np',
                        '--no-paths',
                        help='Don\'t print paths',
                        action='store_true')
    parser.add_argument('-po',
                        '--paths-only',
                        help='Print paths only',
                        action='store_true')
    parser.add_argument('--dos',
                        help='Use DOS path format',
                        action='store_true')
    parser.add_argument('--windows',
                        help='Use Windows path format',
                        action='store_true')
    parser.add_argument('--detailed',
                        help='Enable detailed output',
                        action='store_true')
    parser.add_argument('-e',
                        '--extended',
                        help='get extended tags (only matters when detailed',
                        action='store_true')
    parser.add_argument('-v',
                        '--verbose',
                        help='Enable verbose',
                        action='store_true')
    parser.add_argument('-s',
                        '--silent',
                        help='Enable silence',
                        action='store_true')
    parser.add_argument('-d',
                        '--debug',
                        help='Enable debug',
                        action='store_true')

    args = parser.parse_args()
    root = args.path or get_default_root()
    detailed = args.detailed
    extended = args.extended
    silent = args.silent or get_env_var('SILENT')
    debug = args.debug or get_env_var('DEBUG')
    verbose = args.verbose or get_env_var('VERBOSE') or debug

    root = assure_not_endswith(root, '/')
    assert_non_empty_dir(root)
    listed = 0

    for dir_name, _, filenames in os.walk(root):
        c, _ = print_songs(dir_name,
                           filenames,
                           artist_filter=args.artist_filter,
                           album_filter=args.album_filter,
                           title_filter=args.title_filter,
                           detailed=detailed,
                           extended=extended,
                           sort_per_track=True,
                           warn_for_inconsistencies=not silent,
                           print_paths=verbose and not args.no_paths,
                           path_only=args.paths_only,
                           dos_format=args.dos,
                           windows_format=args.windows,
                           verbose=verbose,
                           silent=silent,
                           debug=debug)

        if c and not verbose:
            stdout()
            listed += c

    stdout(listed, 'songs listed.')
コード例 #18
0
ファイル: review_songs.py プロジェクト: krissterckx/win_audio
def option(n, s):
    if 0 <= n <= 9:
        stdout(' [' + str(n) + ']', s)
    else:
        stdout('[' + str(n) + ']', s)
コード例 #19
0
def main():
    program = 'fix_track_nbrs'
    description = '''
    Fixes song track numbers'''

    parser = argparse.ArgumentParser(prog=program, description=description)
    parser.add_argument('-x', '--path', type=str, help='Set root path')
    parser.add_argument('-j',
                        '--project-filter',
                        type=str,
                        help='Set project filter')
    parser.add_argument('-a',
                        '--artist-filter',
                        type=str,
                        help='Set artist filter')
    parser.add_argument('-b',
                        '--album-filter',
                        type=str,
                        help='Set album filter')
    parser.add_argument('-c',
                        '-t',
                        '--title-filter',
                        type=str,
                        help='Set title filter')
    parser.add_argument('-m',
                        '--missing-songs-stamps',
                        help='Create missing songs stamps',
                        action='store_true')
    parser.add_argument('--force-overwrite-total-tracks',
                        type=int,
                        help='Force-overwrite tracks total')
    parser.add_argument('-p',
                        '--production',
                        help='Enable production run',
                        action='store_true')
    parser.add_argument('-v',
                        '--verbose',
                        help='Enable verbose',
                        action='store_true')
    parser.add_argument('-s',
                        '--silent',
                        help='Enable silence',
                        action='store_true')
    parser.add_argument('-rs',
                        '--radio-silent',
                        help='Enable radio silence',
                        action='store_true')
    parser.add_argument('-d',
                        '--debug',
                        help='Enable debug',
                        action='store_true')

    args = parser.parse_args()
    root = args.path or get_default_root()
    project_filter = args.project_filter
    artist_filter = args.artist_filter
    album_filter = args.album_filter
    title_filter = args.title_filter
    mark_missing_songs = args.missing_songs_stamps
    force_overwrite_total_tracks = args.force_overwrite_total_tracks
    dryrun = not args.production or get_env_var('DRYRUN')
    radio_silent = args.radio_silent or get_env_var('RADIO_SILENT')
    silent = args.silent or get_env_var('SILENT') or radio_silent
    debug = args.debug or get_env_var('DEBUG')
    verbose = args.verbose or get_env_var('VERBOSE') or debug

    root = assure_not_endswith(root, '/')  # makes dir_name / filename to be
    #                                        always correct
    assert_non_empty_dir(root)
    mark_dry_or_production_run(dryrun)

    if force_overwrite_total_tracks:
        assert artist_filter or album_filter or title_filter

    fixed = missed = warnings = 0
    for dir_name, _, filenames in os.walk(root):
        process, project, artist, album = process_songs_dir(
            root, dir_name, project_filter, artist_filter, album_filter)
        if not process:
            continue

        f, m, w = fix_track_nbrs(
            root,
            project,
            artist,
            album,
            filenames,
            title_filter=title_filter,
            mark_missing_songs=mark_missing_songs,
            force_overwrite_total_tracks=force_overwrite_total_tracks,
            dryrun=dryrun,
            verbose=verbose,
            silent=silent,
            radio_silent=radio_silent,
            debug=debug)
        fixed += f
        missed += m
        warnings += w

    if fixed or (missed and not silent) or (warnings and not radio_silent):
        stdout()
    stdout(fixed, 'tracks were fixed.')
    if missed and not silent:
        stdout(missed, 'tracks are missed.')
    if warnings and not radio_silent:
        stdout(warnings, 'warnings were raised.')
コード例 #20
0
def main():
    program = 'copy_album_art'
    description = '''
    Copies album art'''

    parser = argparse.ArgumentParser(prog=program, description=description)
    parser.add_argument('-p',
                        '--production',
                        help='production run',
                        action='store_true')
    parser.add_argument('-x',
                        '--path',
                        type=str,
                        help='path to music file or dir of music files')
    parser.add_argument('-a',
                        '--album_art_path',
                        type=str,
                        help='destination path for music art')
    parser.add_argument('-r',
                        '--recursive',
                        help='treat paths recursively',
                        action='store_true')
    parser.add_argument('-v',
                        '--verbose',
                        help='enables verbosity',
                        action='store_true')
    parser.add_argument('-s',
                        '--silent',
                        help='enables silence',
                        action='store_true')

    args = parser.parse_args()
    dryrun = not args.production or get_env_var('DRYRUN')
    verbose = args.verbose or get_env_var('VERBOSE')
    silent = args.silent or get_env_var('SILENT')

    root = args.path or get_default_root()
    assert_non_empty_dir(root)
    mark_dry_or_production_run(dryrun)

    dest = args.album_art_path or get_default_album_art_root(dryrun=dryrun,
                                                             verbose=verbose)
    assert_non_empty_dir(dest)

    if root and dest:
        if args.recursive:
            if root.endswith('/'):
                root = root[:-1]  # needed for checks below
            if dest.endswith('/'):
                dest = dest[:-1]  # needed for checks below

            stdout('SOURCE:', root)
            stdout('TARGET:', dest)
            stdout()

            for dir_name, _, file_names in os.walk(root):
                if dir_name == root:
                    continue
                else:
                    unrooted = dir_name.replace(root + '/', '')
                make_dir(dest,
                         unrooted,
                         conditionally=True,
                         dryrun=dryrun,
                         verbose=verbose,
                         silent=silent)
                for f in file_names:
                    for album_art_ext in ALBUM_ART_EXT:
                        if f.endswith(album_art_ext):
                            copy_file(root + '/' + unrooted + '/' + f,
                                      dest + '/' + unrooted + '/' + f,
                                      dryrun=dryrun,
                                      verbose=verbose,
                                      silent=silent)
        else:
            stdout('Non-recursive not implemented yet')

    else:
        parser.print_help()
コード例 #21
0
def diff_files(root1,
               root2,
               name1,
               name2,
               ignore_files_only_dirs=False,
               ignore_not_existing=False,
               ignore_file_differences=True,
               extended=False,
               synchronize=False,
               delete_root1_files_only=False,
               dryrun=True,
               verbose=False,
               minimal_verbose=False,
               debug=False):
    diff_cnt = 0

    # minimal verbose: start
    index_c = '('  # always diff
    minimal_verbose_diff_cnt = -1
    # minimal verbose: end

    for dir_name, _, file_names in os.walk(root1):
        if dir_name == root1:
            continue
        else:
            unrooted = dir_name.replace(root1 + '/', '')
        target_dir_name = dir_name.replace(root1, root2)

        if minimal_verbose:
            if '/' not in unrooted:
                cur_index_c = unrooted[0:1].upper()
                if cur_index_c != index_c:
                    if minimal_verbose_diff_cnt != diff_cnt:
                        stdout(PROCESSING, end='')
                        minimal_verbose_diff_cnt = diff_cnt
                    stdout('\b' + cur_index_c, end='')
                    index_c = cur_index_c

        if not os.path.exists(target_dir_name) and not ignore_not_existing:
            if synchronize:
                if delete_root1_files_only:
                    remove_dir(root1, unrooted, dryrun=dryrun, verbose=True)
                else:
                    make_dir(root2, unrooted, dryrun=dryrun, verbose=True)
            else:
                if minimal_verbose:
                    stdout('\b' * len(PROCESSING), end='')
                red(target_dir_name, 'does not exist')

        if ignore_files_only_dirs:
            continue

        for file_name in file_names:

            if is_supported_file_ext(file_name, include_shadow_files=False):
                base_file = dir_name + '/' + file_name
                target_file = target_dir_name + '/' + file_name
                if os.path.exists(target_file):
                    if ignore_file_differences:
                        continue

                    action = (ConsoleColors.WARNING +
                              'DIFF .../{}/{}'.format(unrooted, file_name) +
                              ConsoleColors.ENDC)
                    if (extended and file_name.endswith(SONG_FILE_EXT) and
                            diff_tags(base_file,
                                      target_file,
                                      name1,
                                      name2,
                                      print_on_diff_f=(
                                          ('\n' if minimal_verbose else '') +
                                          action + ConsoleColors.ALERT +
                                          ' DIFF' + ConsoleColors.ENDC)
                                      if not synchronize else None,
                                      debug=debug)):

                        diff_cnt += 1

                        if synchronize:
                            copy_file(root1 + '/' + unrooted + '/' + file_name,
                                      root2 + '/' + unrooted + '/' + file_name,
                                      safe_copy=False,
                                      dryrun=dryrun,
                                      verbose=True,
                                      debug=debug)

                    elif verbose:
                        stdout(action, end='')
                        green(' OK')

                elif not ignore_not_existing:
                    if synchronize:
                        if delete_root1_files_only:
                            remove_file(root1 + '/' + unrooted,
                                        file_name,
                                        safe_remove=False,
                                        dryrun=dryrun,
                                        verbose=verbose,
                                        debug=debug)
                        else:
                            copy_file(root1 + '/' + unrooted + '/' + file_name,
                                      root2 + '/' + unrooted + '/' + file_name,
                                      safe_copy=False,
                                      dryrun=dryrun,
                                      verbose=True,
                                      debug=debug)
                    else:
                        if minimal_verbose:
                            stdout('\b' * len(PROCESSING), end='')
                        red(target_file, 'does not exist')

                    diff_cnt += 1

            elif verbose:
                warn(file_name, 'is ignored in diff!')

    return diff_cnt
コード例 #22
0
ファイル: audit_songs.py プロジェクト: krissterckx/win_audio
 def debug_out(*args, **kwargs):
     if debug:
         stdout(ConsoleColors.ENDC, end='')
         stdout(*args, **kwargs)
コード例 #23
0
ファイル: test_base.py プロジェクト: krissterckx/win_audio
def test_colours():
    stdout('USA is ', end='')
    red('stars ', end='')
    stdout('and ', end='')
    blue('stripes')
    cyan('test_colours OK')
コード例 #24
0
def main():
    program = 'fix_non_flac'
    description = '''
    Fix non-FLAC songs'''

    parser = argparse.ArgumentParser(prog=program, description=description)
    parser.add_argument('-x', '--path', type=str, help='Root path')
    parser.add_argument('-p', '--production', help='Enable production run',
                        action='store_true')
    parser.add_argument('-ir', '--include-reviewed-files',
                        help='Include .reviewed files',
                        action='store_true')
    parser.add_argument('-f', '--full',
                        help='Full clean, including tolerated extensions',
                        action='store_true')
    parser.add_argument('-fa', '--full-including-album-art',
                        help='Full clean, including album art and '
                             'tolerated extensions',
                        action='store_true')
    parser.add_argument('-v', '--verbose', help='Enable verbosity',
                        action='store_true')
    parser.add_argument('-s', '--silent', help='Enable silence',
                        action='store_true')
    parser.add_argument('-d', '--debug', help='Enable debug',
                        action='store_true')
    args = parser.parse_args()
    root = args.path or get_default_root()
    dryrun = not args.production or get_env_var('DRYRUN')
    silent = args.silent or get_env_var('SILENT')
    debug = args.debug or get_env_var('DEBUG')
    verbose = args.verbose or get_env_var('VERBOSE') or debug

    assert_non_empty_dir(root)
    mark_dry_or_production_run(dryrun)
    cnt = 0

    if args.full_including_album_art:
        protected_extensions = []
    elif args.full:
        protected_extensions = ALBUM_ART_EXT
    elif args.include_reviewed_files:
        protected_extensions = MISSING_EXTENSIONS + ALBUM_ART_EXT
    else:
        protected_extensions = TOLERATED_FILE_EXTENSIONS + ALBUM_ART_EXT

    def protected():
        for extension in protected_extensions:
            if file_name.lower().endswith(extension):
                return True
        return False

    for dir_name, _, file_names in os.walk(root):
        for file_name in file_names:
            if not is_song_file(file_name):
                if not protected():
                    yellow('Deleting', dir_name + '/' + file_name)
                    remove_file(dir_name, file_name, False,
                                dryrun=dryrun, verbose=verbose, silent=silent,
                                debug=debug)
                    cnt += 1
    if cnt:
        stdout()
    stdout(cnt, 'non-{} files deleted.'.format(SONG_FILE_EXT[1:]))