Exemplo n.º 1
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')
Exemplo n.º 2
0
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()
Exemplo n.º 3
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.')
Exemplo n.º 4
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:]))
Exemplo n.º 5
0
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.')
Exemplo n.º 6
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.')
Exemplo n.º 7
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()
Exemplo n.º 8
0
def main():
    program = 'review_songs'
    description = '''
    Review songs based on user input
    '''

    parser = argparse.ArgumentParser(prog=program,
                                     description=description)
    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('-x', '--path', type=str, help='Sets root path')
    parser.add_argument('-r', '--review-stamps',
                        help='Create/Use review stamps', 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()
    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

    assert_non_empty_dir(root)

    project_filter = args.project_filter
    artist_filter = args.artist_filter
    album_filter = args.album_filter
    title_filter = args.title_filter
    review_stamps = args.review_stamps

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

    for dir_name, _, song_fs in os.walk(root):
        # gotcha... this doesn't work if i specify a full detailed path, up
        # to the album dir ...
        process, project, artist, album = process_songs_dir(
            root, dir_name, project_filter, artist_filter, album_filter)

        if process:
            path = root + '/' + project + '/' + artist + '/' + album
            reviewed_mark = path + '/.reviewed'
            if review_stamps and is_file(reviewed_mark):
                if debug:
                    cyan('Skipping', project, '/', artist, '/', album)
            else:
                review_songs(path, song_fs, title_filter,
                             verbose=verbose, silent=silent,
                             radio_silent=radio_silent,
                             debug=debug)
                if review_stamps:
                    new_mark_file(reviewed_mark)