Exemplo n.º 1
0
 def get_track_nbr_as_string(self, default='1', verbose=False):
     t = self.get('TRACKNUMBER')
     if not t and default is not None:
         if verbose:
             warn(self.get('TITLE'), 'has no track number, '
                  'assuming track #1')
         t = default
     return t
Exemplo n.º 2
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.º 3
0
def get_filtered_songs(path, song_fs,
                       artist_filter=None, album_filter=None,
                       title_filter=None,
                       sort_per_track=False, post_process_songs=False,
                       print_header=True,
                       no_warn=False, deep_warn=False,
                       mark_missing_songs=False, dryrun=True,
                       verbose=False, silent=False, debug=False):
    printed_header = False
    filtered_songs = {}
    missed_songs = []
    warnings = 0
    max_track_len = 0
    total_album_tracks = None  # unknown or inconsistent
    track_info_per_song = {}

    for song in song_fs:
        if is_song_file(song):
            s = Song(path=path, song_f=song, debug=debug)
            if ((not artist_filter or
                 artist_filter.lower() in s.get('ALBUMARTIST').lower()) and
                    ((not album_filter or
                      album_filter.lower() in s.get('ALBUM').lower()) and
                     (not title_filter or
                      title_filter.lower() in s.get('TITLE').lower()))):
                if print_header and not printed_header:
                    green()
                    green('Listing', path)
                    printed_header = True
                if sort_per_track:
                    track_tag = s.get_track_nbr_as_string(verbose=verbose)
                    track_nbr, total = s.parse_track_nbr(track_tag)
                    track_info_per_song[s.name()] = (track_nbr, total)

                    # build up a list, in case of mixes directory, there would
                    # be track number overlaps
                    f_songs = filtered_songs.get(track_nbr)
                    if f_songs:
                        f_songs.append(s)
                    else:
                        filtered_songs[track_nbr] = [s]

                else:
                    track_tag = s.get_track_nbr_as_string(verbose=verbose)
                    filtered_songs[len(filtered_songs)] = [s]

                max_track_len = max(max_track_len, len(track_tag))

    if filtered_songs and sort_per_track and post_process_songs:
        prev_track_nbr = 0
        song_that_gave_total_tracks = None
        total_tracks_is_inconsistent = False
        for track_nbr in sorted(filtered_songs):
            first_song = True
            for song in filtered_songs[track_nbr]:
                song_f = song.name()
                song_base = song_f[:-len(SONG_FILE_EXT)]
                track_nbr, total = track_info_per_song[song_f]
                if missing_file_exists(path, track_nbr):
                    error('.missing file exists for', song_f, end='\n')
                    error('You must delete it:',
                          get_missing_file_full_path(path, track_nbr),
                          end='\n')
                if first_song:
                    if track_nbr != prev_track_nbr + 1:
                        # TODO(if last song is missing, we don't report)
                        for i in range(prev_track_nbr + 1, track_nbr):
                            if not missing_file_exists(path, i):
                                if mark_missing_songs:
                                    add_missing_file(path, i, dryrun)
                                else:
                                    missed_songs.append((path, i))

                    prev_track_nbr = track_nbr
                    first_song = False

                if total and not total_tracks_is_inconsistent:
                    if total_album_tracks is None:
                        total_album_tracks = total
                        song_that_gave_total_tracks = song_base
                    elif total_album_tracks != total:
                        total_tracks_is_inconsistent = True
                        total_album_tracks = None

                        if not no_warn:
                            warn('Within', path, 'album,')
                            yellow('     ', song_base,
                                   'has inconsistent total tracks with',
                                   song_that_gave_total_tracks)
                            if deep_warn:
                                print_songs(path, song_fs,
                                            artist_filter, album_filter,
                                            title_filter, sort_per_track=True,
                                            verbose=verbose, silent=silent,
                                            debug=debug)
                            warnings += 1

        if not silent:
            for song in missed_songs:
                warn(song[0], '[Track', song[1], '\b] is missing')
                warnings += 1

    return (filtered_songs, missed_songs, total_album_tracks, warnings,
            max_track_len)
Exemplo n.º 4
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.º 5
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.º 6
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
Exemplo n.º 7
0
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import time, os, sys

BATCHPATH = os.path.dirname(
    os.path.dirname(os.path.abspath(os.path.realpath(__file__))))
sys.path.insert(0, BATCHPATH)

from lib.base import gettime, info, warn, error

if __name__ == '__main__':
    tt = (1, 2, (30, 40))
    info("hash(tt): {0}".format(hash(tt)))

    tl = (1, 2, [30, 40])
    try:
        info("hash(tl): {0}".format(hash(tl)))
    except Exception as err:
        warn("throw: {0}".format(err))

    tf = (1, 2, frozenset([30, 40]))
    info("hash(tf): {0}".format(hash(tf)))