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()
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
def rename(to): rooted_entity_path_root = root + '/' + unrooted_entity_path_root if is_file: green('Renaming', unrooted_entity_path_root.replace('/', ' / '), '/', entity_d + file_extension, 'to', to + file_extension) rename_file(rooted_entity_path_root, entity_d + file_extension, to + file_extension, safe_rename=True, add_suffix_if_exists=True, dryrun=dryrun, verbose=verbose, silent=silent, debug=debug) elif (path_exists(rooted_entity_path_root + '/' + to) and not (is_windows() and entity_d.lower() == to.lower())): green('Merging', unrooted_entity_path_root, '/', entity_d, 'into', to) merge_dir(rooted_entity_path_root + '/' + entity_d, rooted_entity_path_root + '/' + to, safe_merge=True, add_suffix_if_exists=True, merge_subdirs=True, dryrun=dryrun, verbose=verbose, silent=silent, debug=debug) else: green('Renaming', unrooted_entity_path_root.replace('/', ' / '), '/', entity_d, 'to', to) rename_dir(rooted_entity_path_root, entity_d, to, safe_rename=False, dryrun=dryrun, verbose=verbose, silent=silent, debug=debug)
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)
def retag(to): green('Retagging', unrooted_entity_path_root.replace('/', ' / '), '/', entity, 'to', to) # TODO(do we need to save here?) song.set(entity_tag, to, save=True, dryrun=dryrun)
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
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')
dryrun=dryrun, verbose=verbose, silent=silent) remove_file('.', 'test3.txt', safe_remove=safe_remove, dryrun=dryrun, verbose=verbose, silent=silent) remove_file('.', 'test3 (1).txt', safe_remove=safe_remove, dryrun=dryrun, verbose=verbose, silent=silent) cyan('test_file_manipulation_2 OK') if __name__ == "__main__": test_colours() test_windows() test_error() test_to_camel_case() test_file_extension() test_file_manipulation_1() test_file_manipulation_2() green('ALL TESTS PASS. Happy day :)') cyan('Final test is a fatal error:') fatal_error('The world exploded') error('SHOULD NOT HAVE COME HERE!')