Exemple #1
0
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
Exemple #2
0
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)
Exemple #3
0
    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)
Exemple #4
0
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()
Exemple #5
0
    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
Exemple #6
0
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
Exemple #7
0
    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
Exemple #8
0
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
Exemple #9
0
    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
Exemple #10
0
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