def rename(config, data, reverse=False): renamer = Renamer(data=data, config=config) rename_map, _ = renamer.map() if reverse: rename_map = {v:k for k,v in rename_map.items()} if len(rename_map) < 1: logging.debug(f"Found no files to rename. (all tracks filename match dirs/renamed/audios)") return True if config.get('options/confirm/rename-tracks'): if config.get('options/contract-rename-map'): rename_map_disp = dict() for k, v in rename_map.items(): commonprefix = os.path.commonprefix((k, v)) k = '(...)' + os.path.sep + k.replace(commonprefix, '', 1) v = '(...)' + os.path.sep + v.replace(commonprefix, '', 1) rename_map_disp[k] = v else: rename_map_disp = rename_map print(ui.pprint_dict(rename_map_disp, sep='--> ')) if not ui.ask('Rename ?', choices='yn', default='y'): return False renamer.rename() return True
def wizard(configfile=None, write=False, no_auto_json=False): configdir = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'config') # If the given filename does not have a file extension: if configfile: if not os.path.splitext(configfile)[1] and not no_auto_json: configfile += '.json' if configfile not in os.listdir(configdir): if configfile is None: if ui.ask("No config file has been supplied. Wanna create a new one?",choices='yn'): configfile = input("config/") with open(config_path(configfile), 'w') as f: f.write('{}') write = True else: configfile = 'config.json' else: logging.fatal(f'Config file "{configfile}" does not exist! Create one in "{configdir}"') sys.exit() def ask(key): # print(f"Oops! The setting '{key}' is not properly configured.") value = input(f"{key} = ") if value in internalconf.CFGWIZ_TRUES: return True elif value in internalconf.CFGWIZ_FALSES: return False elif internalconf.CFGWIZ_LISTS.match(value): return internalconf.CFGWIZ_LISTS.findall(value) else: return value return Config(configfile, fix_values=ask, fix_missing=ask, write=write)
def get_kind(tracks): if len(tracks) >= 4: kind = 'Album' elif len(tracks) >= 1: kind = 'EP' else: kind = 'Single' return ui.ask(value='kind', choices=('Single', 'EP', 'Album'), default=kind)
def metadata(config, data): metadatator = Metadata(config, data) if config.get('options/confirm/apply-metadata'): preview = metadatator.preview() logging.info("The following metadata will be applied:") ui.pprint_dict(preview) if not ui.ask('Apply ?', choices='yn', default='y'): return False metadatator.apply()
def get_artist(tracks): deduped_artists = list(set([e['artist'] for e in tracks])) if len(deduped_artists) >= 1: artist = deduped_artists[0] if len(deduped_artists) < int(config.get('various-artists/threshold')): artist = config.get('various-artists/separator').join(deduped_artists) else: artist = config.get('various-artists/default-name') if config.get('various-artists/ask'): artist = ui.ask("Collection artist", default=artist) return artist
def _extract(file): # Extract zip file (if fails prompt for password) label("Extracting archive...") from zipfile import ZipFile archive = ZipFile(file) password = "" while True: try: output = temp + file[file.rfind('/') + 1:file.rfind('.')] archive.extractall(output, pwd=bytes(password, 'utf-8')) break except: password = ask("Password", "The file is encrypted and needs a password:"******"Password is needed to extract archive!") pass
def get_tracks(title): any_remixes = ui.ask(value='at least one remix', choices='yn', default='no') tracks = list() # whatever filename, since we only do this to get the dirname directory = os.path.dirname(schemes.apply('paths/files/audios', title=title, slug=slug, filename='whatever')) dirlist = list() for file in utils.listdir(directory): patt = config.get('paths/files/audios').replace('<filename>','(.+)') fname_patt = re.compile(os.path.split(patt)[1]) patt = re.compile(patt) if patt.match(os.path.join(directory, file)): dirlist.append(file) else: logging.debug(f'Pattern "{fname_patt.pattern}" not matched for file "{file}"') if len(dirlist): logging.info(f"Found {len(dirlist)} valid {shared.plural('file', len(dirlist))}") else: logging.fatal("No tracks where found.") logging.info(f"Make sure that your file names matches the following pattern: {os.path.split(config.get('paths/files/audios'))[1]}") if config.get('options/automatic/open-dirs'): logging.info(f"Opening directory {directory}") webbrowser.open(directory) sys.exit(1) if config.get('options/show-audiofiles-dirlist'): if len(dirlist) > 1: files = str() for file in dirlist: files += '\n'+(' '*(8+3) + str(os.path.split(file)[1])) logging.info(f"Files in directory {directory}:{files}") for filename in dirlist: if not re.match(r'.+\.mp3$', filename): logging.debug(f'Skipping file "{filename}": is not a .mp3 file') continue logging.info(f'Audio file "{filename}"...') if not config.get('options/all-audios-are-final-versions'): if not ui.ask('Is this file the latest version ?', choices='yn'): continue # turns into an absolute path filename = os.path.join(directory, filename) # determinate if it's a remix or not if any_remixes: is_remix = ui.ask(value='remix', choices='yn', default='no') else: is_remix = False if is_remix: artist = ui.ask(value='Original artist') else: artist = config.get('defaults/artist') # ask for basic track info trackinfo = dict() if len(dirlist) > 1: trackinfo['tracknum'] = int(ui.ask(value='Track no. ', choices=list(range(2,len(dirlist))))) else: trackinfo['tracknum'] = 1 trackinfo['track_title'] = ui.ask(value='Track title', default=patt.search(filename).group(1)) # set basic track info trackinfo['filename'] = filename trackinfo['artist'] = artist trackinfo['title'] = title tracknum = trackinfo['tracknum'] # set video if file exists videopath = schemes.apply('paths/files/videos', **trackinfo) videopath2 = schemes.apply('paths/renamed/videos', **trackinfo) if os.path.isfile(videopath): trackinfo['video'] = videopath elif os.path.isfile(videopath2): trackinfo['video'] = videopath2 else: trackinfo['video'] = False # add to tracks data list tracks.append(trackinfo) return tracks
def get(config, utils): def get_description(**data): langs = config.get('description-languages') descs = dict() for lang in langs: file = schemes.apply('paths/files/descriptions', lang=lang, **data) file = os.path.realpath(os.path.normpath(file)) logging.info(f'Searching for file {file}') if os.path.isfile(file): logging.debug(f'Found a description file for language {lang}') with open(file, 'r') as f: descs[lang] = f.read() else: logging.warning(f'Description file not found for language {lang}') descs[lang] = ui.text(f'description({lang})') if config.get('options/save-descriptions'): logging.info(f'Saving description to file "{file}"...') with open(file, 'w', encoding='utf8') as f: f.write(descs[lang]) return descs def get_kind(tracks): if len(tracks) >= 4: kind = 'Album' elif len(tracks) >= 1: kind = 'EP' else: kind = 'Single' return ui.ask(value='kind', choices=('Single', 'EP', 'Album'), default=kind) def get_artist(tracks): deduped_artists = list(set([e['artist'] for e in tracks])) if len(deduped_artists) >= 1: artist = deduped_artists[0] if len(deduped_artists) < int(config.get('various-artists/threshold')): artist = config.get('various-artists/separator').join(deduped_artists) else: artist = config.get('various-artists/default-name') if config.get('various-artists/ask'): artist = ui.ask("Collection artist", default=artist) return artist def get_tracks(title): any_remixes = ui.ask(value='at least one remix', choices='yn', default='no') tracks = list() # whatever filename, since we only do this to get the dirname directory = os.path.dirname(schemes.apply('paths/files/audios', title=title, slug=slug, filename='whatever')) dirlist = list() for file in utils.listdir(directory): patt = config.get('paths/files/audios').replace('<filename>','(.+)') fname_patt = re.compile(os.path.split(patt)[1]) patt = re.compile(patt) if patt.match(os.path.join(directory, file)): dirlist.append(file) else: logging.debug(f'Pattern "{fname_patt.pattern}" not matched for file "{file}"') if len(dirlist): logging.info(f"Found {len(dirlist)} valid {shared.plural('file', len(dirlist))}") else: logging.fatal("No tracks where found.") logging.info(f"Make sure that your file names matches the following pattern: {os.path.split(config.get('paths/files/audios'))[1]}") if config.get('options/automatic/open-dirs'): logging.info(f"Opening directory {directory}") webbrowser.open(directory) sys.exit(1) if config.get('options/show-audiofiles-dirlist'): if len(dirlist) > 1: files = str() for file in dirlist: files += '\n'+(' '*(8+3) + str(os.path.split(file)[1])) logging.info(f"Files in directory {directory}:{files}") for filename in dirlist: if not re.match(r'.+\.mp3$', filename): logging.debug(f'Skipping file "{filename}": is not a .mp3 file') continue logging.info(f'Audio file "{filename}"...') if not config.get('options/all-audios-are-final-versions'): if not ui.ask('Is this file the latest version ?', choices='yn'): continue # turns into an absolute path filename = os.path.join(directory, filename) # determinate if it's a remix or not if any_remixes: is_remix = ui.ask(value='remix', choices='yn', default='no') else: is_remix = False if is_remix: artist = ui.ask(value='Original artist') else: artist = config.get('defaults/artist') # ask for basic track info trackinfo = dict() if len(dirlist) > 1: trackinfo['tracknum'] = int(ui.ask(value='Track no. ', choices=list(range(2,len(dirlist))))) else: trackinfo['tracknum'] = 1 trackinfo['track_title'] = ui.ask(value='Track title', default=patt.search(filename).group(1)) # set basic track info trackinfo['filename'] = filename trackinfo['artist'] = artist trackinfo['title'] = title tracknum = trackinfo['tracknum'] # set video if file exists videopath = schemes.apply('paths/files/videos', **trackinfo) videopath2 = schemes.apply('paths/renamed/videos', **trackinfo) if os.path.isfile(videopath): trackinfo['video'] = videopath elif os.path.isfile(videopath2): trackinfo['video'] = videopath2 else: trackinfo['video'] = False # add to tracks data list tracks.append(trackinfo) return tracks def get_coverarts(**data): cover_arts = dict() for format in COVER_ART_FORMATS: cover_arts[format] = dict() fulldata = dict(**data, format=format) fres_path = schemes.apply('paths/files/covers', **fulldata) lres_path = schemes.apply('paths/files/covers-lowres', **fulldata) if os.path.isfile(fres_path): logging.info(f'Found {format} cover art: {os.path.split(fres_path)[1]}') cover_arts[format]['full_res'] = fres_path else: cover_arts[format]['full_res'] = False if format == 'wide': logging.fatal(f'You need at least a wide, full resolution cover art: {fres_path}') if os.path.isfile(lres_path): logging.info(f'Found low resolution {format} cover art: {os.path.split(lres_path)[1]}') cover_arts[format]['low_res'] = lres_path else: cover_arts[format]['low_res'] = False return cover_arts if os.path.isfile(config.get('paths/misc/track_data_file')): if not config.get('options/automatic/recover'): recover = False if ui.ask('Recover song data from latest run ?', choices='yn'): recover = True else: recover = True else: recover = False if recover: with open(config.get('paths/misc/track_data_file'), 'r') as f: json_raw = f.read() data = json.loads(json_raw) else: schemes = shared.Schemer(config, None) title = ui.ask(value='Title') slug = ui.ask(value='Title slug', default=shared.slugify(title)) tracks = get_tracks(title) kind = get_kind(tracks) artist = get_artist(tracks) descriptions = get_description(title=title, kind=kind, slug=slug) cover_arts = get_coverarts(title=title, kind=kind, slug=slug) # data dict data = { "title" : title, "slug" : slug, "tracks" : tracks, "kind" : kind, "descriptions" : descriptions, "cover_arts" : cover_arts, "collection_artist": artist } with open(config.get('paths/misc/track_data_file'), 'w') as f: json_raw = json.dumps(data, indent=4) f.write(json_raw) return data
def get_tracks(title): any_remixes = ui.ask('at least one remix', choices='yn', default='no') tracks = list() # whatever tracknum, since we only do this to get the dirname dir = os.path.dirname( schemes.apply('paths/files/audios', title=title, slug=slug, tracknum=0)) dirlist = [ e for e in utils.listdir(dir) if schemes.scheme_match('paths/files/audios', os.path.join(dir, e)) ] if len(dirlist): logging.info( f"Found {len(dirlist)} {shared.plural('track', len(dirlist))}") else: logging.fatal("No tracks where found.") logging.info( f"Make sure that your file names matches the following pattern: {os.path.split(config.get('paths/files/audios'))[1]}" ) for filename in dirlist: if not re.match(r'.+\.mp3$', filename): logging.debug(f'Skipping file "{filename}"') continue logging.info(f'Audio file "{filename}"...') # turns into an absolute path filename = os.path.join(dir, filename) # determinate if it's a remix or not if any_remixes: is_remix = ui.ask('remix', choices='yn', default='no') else: is_remix = False if is_remix: artist = ui.ask('Original artist') else: artist = config.get('defaults/artist') # extract track info try: trackinfo = schemes.extract('paths/files/audios', filename)[0] except ValueError: try: trackinfo = schemes.extract('paths/renamed/audios', filename)[0] except ValueError: logging.fatal( f'The audio file "{filename}" does not match any scheme (neither paths/files/audios nor paths/renamed/audios)' ) trackinfo['filename'] = filename trackinfo['artist'] = artist tracknum = trackinfo['tracknum'] # set track title title = schemes.apply( 'titles/' + ('remix' if is_remix else 'track'), **trackinfo) if config.get('options/confirm/track-title'): title = ui.ask('Track name', default=title) trackinfo['track_title'] = title # set track number if config.get('options/confirm/track-number'): tracknum = ui.ask('Track #', default=tracknum) trackinfo['tracknum'] = tracknum # set video if file exists videopath = schemes.apply('paths/files/videos', **trackinfo) videopath2 = schemes.apply('paths/renamed/videos', **trackinfo) if os.path.isfile(videopath): trackinfo['video'] = videopath elif os.path.isfile(videopath2): trackinfo['video'] = videopath2 else: trackinfo['video'] = False # add to tracks data list tracks.append(trackinfo) return tracks
def get(config, utils): def get_description(**data): langs = config.get('description-languages') descs = dict() for lang in langs: file = schemes.apply('paths/files/descriptions', lang=lang, **data) file = os.path.realpath(os.path.normpath(file)) logging.info(f'Searching for file {file}') if os.path.isfile(file): logging.debug(f'Found a description file for language {lang}') with open(file, 'r') as f: descs[lang] = f.read() else: logging.warning( f'Description file not found for language {lang}') descs[lang] = ui.text(f'description({lang})') return descs def get_kind(tracks): if len(tracks) >= 4: kind = 'Album' elif len(tracks) >= 1: kind = 'EP' else: kind = 'Single' return ui.ask('kind', choices=('Single', 'EP', 'Album'), default=kind) def get_artist(tracks): deduped_artists = list(set([e['artist'] for e in tracks])) if len(deduped_artists) >= 1: artist = deduped_artists[0] if len(deduped_artists) < int(config.get('various-artists/threshold')): artist = config.get('various-artists/separator').join( deduped_artists) else: artist = config.get('various-artists/default-name') if config.get('various-artists/ask'): artist = ui.ask("Collection artist", default=artist) return artist def get_tracks(title): any_remixes = ui.ask('at least one remix', choices='yn', default='no') tracks = list() # whatever tracknum, since we only do this to get the dirname dir = os.path.dirname( schemes.apply('paths/files/audios', title=title, slug=slug, tracknum=0)) dirlist = [ e for e in utils.listdir(dir) if schemes.scheme_match('paths/files/audios', os.path.join(dir, e)) ] if len(dirlist): logging.info( f"Found {len(dirlist)} {shared.plural('track', len(dirlist))}") else: logging.fatal("No tracks where found.") logging.info( f"Make sure that your file names matches the following pattern: {os.path.split(config.get('paths/files/audios'))[1]}" ) for filename in dirlist: if not re.match(r'.+\.mp3$', filename): logging.debug(f'Skipping file "{filename}"') continue logging.info(f'Audio file "{filename}"...') # turns into an absolute path filename = os.path.join(dir, filename) # determinate if it's a remix or not if any_remixes: is_remix = ui.ask('remix', choices='yn', default='no') else: is_remix = False if is_remix: artist = ui.ask('Original artist') else: artist = config.get('defaults/artist') # extract track info try: trackinfo = schemes.extract('paths/files/audios', filename)[0] except ValueError: try: trackinfo = schemes.extract('paths/renamed/audios', filename)[0] except ValueError: logging.fatal( f'The audio file "{filename}" does not match any scheme (neither paths/files/audios nor paths/renamed/audios)' ) trackinfo['filename'] = filename trackinfo['artist'] = artist tracknum = trackinfo['tracknum'] # set track title title = schemes.apply( 'titles/' + ('remix' if is_remix else 'track'), **trackinfo) if config.get('options/confirm/track-title'): title = ui.ask('Track name', default=title) trackinfo['track_title'] = title # set track number if config.get('options/confirm/track-number'): tracknum = ui.ask('Track #', default=tracknum) trackinfo['tracknum'] = tracknum # set video if file exists videopath = schemes.apply('paths/files/videos', **trackinfo) videopath2 = schemes.apply('paths/renamed/videos', **trackinfo) if os.path.isfile(videopath): trackinfo['video'] = videopath elif os.path.isfile(videopath2): trackinfo['video'] = videopath2 else: trackinfo['video'] = False # add to tracks data list tracks.append(trackinfo) return tracks def get_coverarts(**data): cover_arts = dict() for format in COVER_ART_FORMATS: cover_arts[format] = dict() fulldata = dict(**data, format=format) fres_path = schemes.apply('paths/files/covers', **fulldata) lres_path = schemes.apply('paths/files/covers-lowres', **fulldata) if os.path.isfile(fres_path): logging.info( f'Found {format} cover art: {os.path.split(fres_path)[1]}') cover_arts[format]['full_res'] = fres_path else: cover_arts[format]['full_res'] = False if format == 'wide': logging.fatal( f'You need at least a wide, full resolution cover art: {fres_path}' ) if os.path.isfile(lres_path): logging.info( f'Found low resolution {format} cover art: {os.path.split(lres_path)[1]}' ) cover_arts[format]['low_res'] = lres_path else: cover_arts[format]['low_res'] = False return cover_arts if os.path.isfile(config.get('paths/misc/track_data_file')): if not config.get('options/automatic/recover'): recover = False if ui.ask('Recover song data from latest run ?', choices='yn'): recover = True else: recover = True else: recover = False if recover: with open(config.get('paths/misc/track_data_file'), 'r') as f: json_raw = f.read() data = json.loads(json_raw) else: schemes = shared.Schemer(config, None) title = ui.ask('Title') slug = ui.ask('Title slug', default=shared.slugify(title)) tracks = get_tracks(title) kind = get_kind(tracks) artist = get_artist(tracks) descriptions = get_description(title=title, kind=kind, slug=slug) cover_arts = get_coverarts(title=title, kind=kind, slug=slug) # data dict data = { "title": title, "slug": slug, "tracks": tracks, "kind": kind, "descriptions": descriptions, "cover_arts": cover_arts, "collection_artist": artist } with open(config.get('paths/misc/track_data_file'), 'w') as f: json_raw = json.dumps(data, indent=4) f.write(json_raw) return data