def test_create_file_from_template(self):
        self.ogsrelid = "3083"

        # construct config with only default values
        tagger_config = TaggerConfig(os.path.join(parentdir, "test/empty.conf"))

        dummy_response = TestDummyResponse(self.ogsrelid)
        discogs_album = DummyDiscogsAlbum(dummy_response)
        self.album = discogs_album.map()

        taggerutils = TaggerUtils(self.source_dir, self.target_dir, self.tagger_config, self.album)

        create_file = os.path.join(self.target_dir, "info.nfo")
        assert taggerutils.create_file_from_template("/info.txt", create_file)

        assert os.path.exists(create_file)

        assert taggerutils.create_nfo(self.target_dir)

        # copy file to source directory and rename it
        self.copy_files_single_album(17)

        taggerutils = TaggerUtils(self.source_dir, self.target_dir, self.tagger_config, self.album)

        taggerutils._get_target_list()
        assert self.album.discs[0].tracks[0].new_file == "01-yonderboi-intro.flac"
        assert taggerutils.create_m3u(self.target_dir)
Beispiel #2
0
    def test_create_file_from_template(self):
        self.ogsrelid = "3083"

        # construct config with only default values
        tagger_config = TaggerConfig(os.path.join(parentdir,
                                                  "test/empty.conf"))

        dummy_response = TestDummyResponse(self.ogsrelid)
        discogs_album = DummyDiscogsAlbum(dummy_response)
        self.album = discogs_album.map()

        taggerutils = TaggerUtils(self.source_dir, self.target_dir,
                                  self.tagger_config, self.album)

        create_file = os.path.join(self.target_dir, "info.nfo")
        assert taggerutils.create_file_from_template("/info.txt", create_file)

        assert os.path.exists(create_file)

        assert taggerutils.create_nfo(self.target_dir)

        # copy file to source directory and rename it
        self.copy_files_single_album(17)

        taggerutils = TaggerUtils(self.source_dir, self.target_dir,
                                  self.tagger_config, self.album)

        taggerutils._get_target_list()
        assert self.album.discs[0].tracks[
            0].new_file == "01-yonderboi-intro.flac"
        assert taggerutils.create_m3u(self.target_dir)
Beispiel #3
0
def tagger(conf, destination, releaseid, source):

    _log = init_logging(conf)

    if not destination:
        destination = source

    cfg = TaggerConfig(source, destination, conf)

    if cfg.id_tag in cfg.release_tags:
        releaseid = cfg.release_tags[cfg.id_tag].strip()

    if releaseid:
        release_id = releaseid

    if not releaseid:
        click.echo('Please specify the discogs.com releaseid ("-r")')
        sys.exit(1)

    _log.info('Attempting to tag files from target destination={0}'.format(destination))

    discogs_release = DiscogsAlbum(DiscogsWrapper().discogs, release_id, cfg.split_artists, cfg.split_genres_and_styles)
    release = TaggerUtils(discogs_release, cfg)

    # ensure we were able to map the release appropriately.
    if not release.tag_map:
        _log.fatal("Unable to map available audio files to the number of tracks in the Discogs release '{0}'. Exiting".format(
                   release_id))
        sys.exit(1)

    artist = cfg.split_artists.join(release.album.artists)
    artist = release.album.clean_name(artist)

    _log.info("Tagging album '{0} - {1}'".format(artist, release.album.title))

    dest_dir_name = release.dest_dir_name

    if os.path.exists(dest_dir_name):
        _log.fatal('Destination directory already exists. directory={0}. Aborting operation'.format(dest_dir_name))
        sys.exit(1)
    else:
        _log.info("Creating destination directory '{0}'".format(dest_dir_name))
        mkdir_p(dest_dir_name)

    _log.info("Downloading and storing images")
    release.album.get_images(dest_dir_name, cfg.images_format, cfg.first_image_name)

    disc_names = dict()
    folder_names = dict()
    if release.album.disctotal > 1 and cfg.split_discs_folder:
        _log.debug("Creating disc structure")
        for i in range(1, release.album.disctotal + 1):
            folder_name = "%s%.d" % (release.album_folder_name, i)
            disc_dir_name = os.path.join(dest_dir_name, folder_name)
            mkdir_p(disc_dir_name)
    # This is duplicate, remove one of the following statements
            disc_names[i] = disc_dir_name
            folder_names[i] = folder_name
    else:
        folder_names[1] = ""

    for track in release.tag_map:
        # copy old file into new location
        if release.album.disctotal > 1 and cfg.split_discs_folder:
            target_folder = disc_names[int(track['discnumber'])]
        else:
            target_folder = dest_dir_name

        _log.debug("Source file {0}".format(os.path.join(source, track['orig_file'])))
        _log.info("Writing file {0}".format(os.path.join(target_folder, track['new_file'])))
        _log.debug("metadata -> {0:2d} {1} - {2}".format(track['tracknumber'], track['artist'], track['title']))
        _log.debug("----------> {0}".format(track['new_file']))

        shutil.copyfile(track['orig_file'], os.path.join(target_folder, track['new_file']))

        # load metadata information
        metadata = MediaFile(os.path.join(target_folder, track['new_file']))

        # read already existing (and still wanted) properties
        keep_tags = {}
        if cfg.keep_tags:
            for name in cfg.keep_tags.split(","):
                try:
                    getattr(metadata, name)
                except AttributeError:
                    _log.warn('Unable to keep_tag. tag={0}'.format(name))
                    continue
                keep_tags[name] = getattr(metadata, name)

        # remove current metadata
        metadata.delete()

        # set album metadata
        metadata.album = release.album.title

        if cfg.split_discs_folder and release.album.disctotal > 1:
            # the fileext should be stored on the album/track as well
            fileext = os.path.splitext(track['orig_file'])[1]
            disc_title_extension = release._value_from_tag_format(cfg.split_discs_extension,
                                                                  track['tracknumber'],
                                                                  track['position'] - 1, fileext)
            metadata.album = "{0}{1}".format(metadata.album, disc_title_extension)

        metadata.composer = artist
        metadata.albumartist = artist
        metadata.albumartist_sort = release.album.sort_artist
        metadata.label = release.album.label
        metadata.year = release.album.year
        metadata.country = release.album.country
        metadata.url = release.album.url
        # add styles to the grouping tag (right now, we can just use one)
        metadata.grouping = release.album.styles

        # adding two as there is no standard. discogstagger pre v1
        # used (TXXX desc="Catalog #")
        # mediafile uses TXXX desc="CATALOGNUMBER"
        metadata.catalognum = release.album.catno
        metadata.catalognumber = release.album.catno

        # use the correct genre field, on config use the first style
        genre = release.album.genres
        if cfg.use_style:
            genre = release.album.style

        metadata.genre = genre
        metadata.discogs_id = release_id

        if release.album.disctotal and release.album.disctotal > 1 and track['discnumber']:
            _log.debug("writing disctotal and discnumber")
            metadata.disc = track['discnumber']
            metadata.disctotal = release.album.disctotal

        if release.album.is_compilation:
            metadata.comp = True

        metadata.comments = release.album.note

        # encoder
        if cfg.encoder_tag is not None:
            metadata.encoder = cfg.encoder_tag

        #    if track.discsubtotal:
        #        metadata.discsubtotal = track.discsubtotal

        # set track metadata
        metadata.title = track['title']
        metadata.artist = track['artist']
        metadata.artist_sort = track['sortartist']
        metadata.track = track['tracknumber']

        # the following value will be wrong, if the disc has a name or is a multi
        # disc release --> fix it
        metadata.tracktotal = release.album.tracktotal_on_disc(track['discnumber'])

        # it does not make sense to store this in the "common" configuration, but only in the
        # id.txt. we use a special naming convention --> most probably we should reuse the
        # configuration parser for this one as well, no?
        for name, value in list(cfg.release_tags.items()):
            if name.startswith("tag:"):
                name = name.split(":")
                name = name[1]
                setattr(metadata, name, value)

        first_image_name = cfg.first_image_name
        # this should be done in a cleaner way to avoid multiple images in different
        # folders (use the dest_dir again....)
        if cfg.embed_coverart and os.path.exists(os.path.join(dest_dir_name,
                                                 first_image_name)):
            imgdata = open(os.path.join(dest_dir_name,
                           first_image_name), 'rb').read()
            imgtype = imghdr.what(None, imgdata)

            if imgtype in ("jpeg", "png"):
                _log.debug("Embedding album art.")
                metadata.art = imgdata

        if keep_tags is not None:
            for name in keep_tags:
                setattr(metadata, name, keep_tags[name])

        metadata.save()

    # start supplementary actions

    if cfg.write_nfo:
        _log.info("Generating .nfo file")
        release.create_nfo()

    # adopt for multi disc support
    if cfg.write_m3u:
        _log.info("Generating .m3u file")
        release.create_m3u(folder_names)

    # copy "other files" on request
    if cfg.copy_other_files and len(release.copy_files) > 0:
        _log.info("copying files from source directory")
        copy_files = release.copy_files
        dir_list = os.listdir(source)
        _log.debug("start_dir: {0}".format(source))
        _log.debug("dir list: {0}".format(dir_list))
        file_list = [os.path.join(source, x) for x in dir_list if not x.lower().endswith(TaggerUtils.FILE_TYPE) and
                     os.path.isfile(os.path.join(source, x))]
        copy_files.extend(file_list)

        for fname in copy_files:
            if not fname.endswith(".m3u"):
                _log.debug("source: {0}".format(fname))
                _log.debug("target: {0}".format(os.path.join(dest_dir_name, os.path.basename(fname))))
                shutil.copyfile(fname, os.path.join(dest_dir_name, os.path.basename(fname)))

    # remove source directory, if configured as such.
    if not cfg.keep_original:
        _log.info("Deleting source directory '{0}'".format(source))
        shutil.rmtree(source)

    _log.info("Tagging complete.")
        fileHandler.get_images(connector)

        logger.debug("Embedding Albumart")
        fileHandler.embed_coverart_album()

        if options.replaygain:
            logger.debug("Add ReplayGain tags (if necessary)")
            fileHandler.add_replay_gain_tags()

    # !TODO make this more generic to use different templates and files,
    # furthermore adopt to reflect multi-disc-albums
        logger.debug("Generate m3u")
        taggerUtils.create_m3u(album.target_dir)

        logger.debug("Generate nfo")
        taggerUtils.create_nfo(album.target_dir)

        fileHandler.create_done_file()
    except Exception as ex:
        if releaseid:
            msg = "Error during tagging ({0}), {1}: {2}".format(releaseid, source_dir, ex)
        else:
            msg = "Error during tagging (no relid) {0}: {1}".format(source_dir, ex)
        logger.error(msg)
        discs_with_errors.append(msg)
        continue

    # !TODO - make this a check during the taggerutils run
    # ensure we were able to map the release appropriately.
    #if not release.tag_map:
    #    logger.error("Unable to match file list to discogs release '%s'" %
        fileHandler.get_images(connector)

        logger.debug("Embedding Albumart")
        fileHandler.embed_coverart_album()

        if options.replaygain:
            logger.debug("Add ReplayGain tags (if necessary)")
            fileHandler.add_replay_gain_tags()

    # !TODO make this more generic to use different templates and files,
    # furthermore adopt to reflect multi-disc-albums
        logger.debug("Generate m3u")
        taggerUtils.create_m3u(album.target_dir)

        logger.debug("Generate nfo")
        taggerUtils.create_nfo(album.target_dir)

        fileHandler.create_done_file()
    except Exception as ex:
        if releaseid:
            msg = "Error during tagging ({0}), {1}: {2}".format(
                releaseid, source_dir, ex)
        else:
            msg = "Error during tagging (no relid) {0}: {1}".format(
                source_dir, ex)
        logger.error(msg)
        discs_with_errors.append(msg)
        continue

    # !TODO - make this a check during the taggerutils run
    # ensure we were able to map the release appropriately.
Beispiel #6
0
def processSourceDirs(source_dirs, tagger_config):
    # initialize connection (could be a problem if using multiple sources...)
    discogs_connector = DiscogsConnector(tagger_config)
    local_discogs_connector = LocalDiscogsConnector(discogs_connector)
    # try to re-use search, may be useful if working with several releases by the same artist
    discogsSearch = DiscogsSearch(tagger_config)

    logger.info("start tagging")
    discs_with_errors = []

    converted_discs = 0

    for source_dir in source_dirs:
        releaseid = None
        release = None
        connector = None

        try:
            done_file = tagger_config.get("details", "done_file")
            done_file_path = os.path.join(source_dir, done_file)

            if os.path.exists(done_file_path) and not options.forceUpdate:
                logger.warn(
                    'Do not read {}, because {} exists and forceUpdate is false'
                    .format(source_dir, done_file))
                continue

            # reread config to make sure, that the album specific options are reset for each
            # album
            tagger_config = TaggerConfig(options.conffile)

            if options.releaseid is not None:
                releaseid = options.releaseid
            else:
                releaseid = file_utils.read_id_file(source_dir, id_file,
                                                    options)

            if not releaseid:
                searchParams = discogsSearch.getSearchParams(source_dir)
                # release = discogsSearch.search_discogs(searchParams)
                release = discogsSearch.search_discogs()
                # reuse the Discogs Release class, it saves re-fetching later
                if release is not None and type(release).__name__ in (
                        'Release', 'Version'):
                    releaseid = release.id
                    connector = discogs_connector

            if not releaseid:
                logger.warn('No releaseid for {}'.format(source_dir))
                continue

            # if not releaseid:
            #     p.error("Please specify the discogs.com releaseid ('-r')")

            logger.info('Found release ID: {} for source dir: {}'.format(
                releaseid, source_dir))

            # read destination directory
            # !TODO if both are the same, we are not copying anything,
            # this should be "configurable"
            if not options.destdir:
                destdir = source_dir
            else:
                destdir = options.destdir
                logger.debug('destdir set to {}'.format(options.destdir))

            logger.info('Using destination directory: {}'.format(destdir))
            logger.debug("starting tagging...")

            if releaseid is not None and release is None:
                #! TODO this is dirty, refactor it to be able to reuse it for later enhancements
                if tagger_config.get("source", "name") == "local":
                    release = local_discogs_connector.fetch_release(
                        releaseid, source_dir)
                    connector = local_discogs_connector
                else:
                    release = discogs_connector.fetch_release(releaseid)
                    connector = discogs_connector

            discogs_album = DiscogsAlbum(release)

            try:
                album = discogs_album.map()
            except AlbumError as ae:
                msg = "Error during mapping ({0}), {1}: {2}".format(
                    releaseid, source_dir, ae)
                logger.error(msg)
                discs_with_errors.append(msg)
                continue

            logger.info('Tagging album "{} - {}"'.format(
                album.artist, album.title))

            tagHandler = TagHandler(album, tagger_config)

            taggerUtils = TaggerUtils(source_dir, destdir, tagger_config,
                                      album)

            fileHandler = FileHandler(album, tagger_config)

            try:
                taggerUtils._get_target_list()
            except TaggerError as te:
                msg = "Error during Tagging ({0}), {1}: {2}".format(
                    releaseid, source_dir, te)
                logger.error(msg)
                discs_with_errors.append(msg)
                continue

            tagHandler.tag_album()
            taggerUtils.gather_addional_properties()
            # reset the target directory now that we have discogs metadata and
            #  filedata - otherwise this is declared too early in the process
            album.target_dir = taggerUtils.dest_dir_name

            fileHandler.copy_files()

            logger.debug("Tagging files")

            # Do replaygain analysis before copying other files, the directory
            #  contents are cleaner, less prone to mistakes
            if options.replaygain:
                logger.debug("Add ReplayGain tags (if requested)")
                fileHandler.add_replay_gain_tags()

            logger.debug("Copy other interesting files (on request)")
            fileHandler.copy_other_files()

            logger.debug("Downloading and storing images")
            fileHandler.get_images(connector)

            logger.debug("Embedding Albumart")
            fileHandler.embed_coverart_album()

            # !TODO make this more generic to use different templates and files,
            # furthermore adopt to reflect multi-disc-albums
            logger.debug("Generate m3u")
            taggerUtils.create_m3u(album.target_dir)

            logger.debug("Generate nfo")
            taggerUtils.create_nfo(album.target_dir)

            fileHandler.create_done_file()
        except Exception as ex:
            if releaseid:
                msg = "Error during tagging ({0}), {1}: {2}".format(
                    releaseid, source_dir, ex)
            else:
                msg = "Error during tagging (no relid) {0}: {1}".format(
                    source_dir, ex)
            logger.error(msg)
            discs_with_errors.append(msg)
            continue

        # !TODO - make this a check during the taggerutils run
        # ensure we were able to map the release appropriately.
        #if not release.tag_map:
        #    logger.error("Unable to match file list to discogs release '%s'" %
        #                  releaseid)
        #    sys.exit()
        converted_discs = converted_discs + 1
        logger.info("Converted %d/%d" % (converted_discs, len(source_dirs)))

    logger.info("Tagging complete.")
    logger.info("converted successful: %d" % converted_discs)
    logger.info("converted with Errors %d" % len(discs_with_errors))
    logger.info("releases touched: %s" % len(source_dirs))

    if discs_with_errors:
        logger.error("The following discs could not get converted.")
        for msg in discs_with_errors:
            logger.error(msg)
Beispiel #7
0
def tagger(conf, destination, releaseid, source):

    _log = init_logging(conf)

    if not destination:
        destination = source

    cfg = TaggerConfig(source, destination, conf)

    if cfg.id_tag in cfg.release_tags:
        releaseid = cfg.release_tags[cfg.id_tag].strip()

    if releaseid:
        release_id = releaseid

    if not releaseid:
        click.echo('Please specify the discogs.com releaseid ("-r")')
        sys.exit(1)

    _log.info('Attempting to tag files from target destination={0}'.format(
        destination))

    discogs_release = DiscogsAlbum(DiscogsWrapper().discogs, release_id,
                                   cfg.split_artists,
                                   cfg.split_genres_and_styles)
    release = TaggerUtils(discogs_release, cfg)

    # ensure we were able to map the release appropriately.
    if not release.tag_map:
        _log.fatal(
            "Unable to map available audio files to the number of tracks in the Discogs release '{0}'. Exiting"
            .format(release_id))
        sys.exit(1)

    artist = cfg.split_artists.join(release.album.artists)
    artist = release.album.clean_name(artist)

    _log.info("Tagging album '{0} - {1}'".format(artist, release.album.title))

    dest_dir_name = release.dest_dir_name

    if os.path.exists(dest_dir_name):
        _log.fatal(
            'Destination directory already exists. directory={0}. Aborting operation'
            .format(dest_dir_name))
        sys.exit(1)
    else:
        _log.info("Creating destination directory '{0}'".format(dest_dir_name))
        mkdir_p(dest_dir_name)

    _log.info("Downloading and storing images")
    release.album.get_images(dest_dir_name, cfg.images_format,
                             cfg.first_image_name)

    disc_names = dict()
    folder_names = dict()
    if release.album.disctotal > 1 and cfg.split_discs_folder:
        _log.debug("Creating disc structure")
        for i in range(1, release.album.disctotal + 1):
            folder_name = "%s%.d" % (release.album_folder_name, i)
            disc_dir_name = os.path.join(dest_dir_name, folder_name)
            mkdir_p(disc_dir_name)
            # This is duplicate, remove one of the following statements
            disc_names[i] = disc_dir_name
            folder_names[i] = folder_name
    else:
        folder_names[1] = ""

    for track in release.tag_map:
        # copy old file into new location
        if release.album.disctotal > 1 and cfg.split_discs_folder:
            target_folder = disc_names[int(track['discnumber'])]
        else:
            target_folder = dest_dir_name

        _log.debug("Source file {0}".format(
            os.path.join(source, track['orig_file'])))
        _log.info("Writing file {0}".format(
            os.path.join(target_folder, track['new_file'])))
        _log.debug("metadata -> {0:2d} {1} - {2}".format(
            track['tracknumber'], track['artist'], track['title']))
        _log.debug("----------> {0}".format(track['new_file']))

        shutil.copyfile(track['orig_file'],
                        os.path.join(target_folder, track['new_file']))

        # load metadata information
        metadata = MediaFile(os.path.join(target_folder, track['new_file']))

        # read already existing (and still wanted) properties
        keep_tags = {}
        if cfg.keep_tags:
            for name in cfg.keep_tags.split(","):
                try:
                    getattr(metadata, name)
                except AttributeError:
                    _log.warn('Unable to keep_tag. tag={0}'.format(name))
                    continue
                keep_tags[name] = getattr(metadata, name)

        # remove current metadata
        metadata.delete()

        # set album metadata
        metadata.album = release.album.title

        if cfg.split_discs_folder and release.album.disctotal > 1:
            # the fileext should be stored on the album/track as well
            fileext = os.path.splitext(track['orig_file'])[1]
            disc_title_extension = release._value_from_tag_format(
                cfg.split_discs_extension, track['tracknumber'],
                track['position'] - 1, fileext)
            metadata.album = "{0}{1}".format(metadata.album,
                                             disc_title_extension)

        metadata.composer = artist
        metadata.albumartist = artist
        metadata.albumartist_sort = release.album.sort_artist
        metadata.label = release.album.label
        metadata.year = release.album.year
        metadata.country = release.album.country
        metadata.url = release.album.url
        # add styles to the grouping tag (right now, we can just use one)
        metadata.grouping = release.album.styles

        # adding two as there is no standard. discogstagger pre v1
        # used (TXXX desc="Catalog #")
        # mediafile uses TXXX desc="CATALOGNUMBER"
        metadata.catalognum = release.album.catno
        metadata.catalognumber = release.album.catno

        # use the correct genre field, on config use the first style
        genre = release.album.genres
        if cfg.use_style:
            genre = release.album.style

        metadata.genre = genre
        metadata.discogs_id = release_id

        if release.album.disctotal and release.album.disctotal > 1 and track[
                'discnumber']:
            _log.debug("writing disctotal and discnumber")
            metadata.disc = track['discnumber']
            metadata.disctotal = release.album.disctotal

        if release.album.is_compilation:
            metadata.comp = True

        metadata.comments = release.album.note

        # encoder
        if cfg.encoder_tag is not None:
            metadata.encoder = cfg.encoder_tag

        #    if track.discsubtotal:
        #        metadata.discsubtotal = track.discsubtotal

        # set track metadata
        metadata.title = track['title']
        metadata.artist = track['artist']
        metadata.artist_sort = track['sortartist']
        metadata.track = track['tracknumber']

        # the following value will be wrong, if the disc has a name or is a multi
        # disc release --> fix it
        metadata.tracktotal = release.album.tracktotal_on_disc(
            track['discnumber'])

        # it does not make sense to store this in the "common" configuration, but only in the
        # id.txt. we use a special naming convention --> most probably we should reuse the
        # configuration parser for this one as well, no?
        for name, value in list(cfg.release_tags.items()):
            if name.startswith("tag:"):
                name = name.split(":")
                name = name[1]
                setattr(metadata, name, value)

        first_image_name = cfg.first_image_name
        # this should be done in a cleaner way to avoid multiple images in different
        # folders (use the dest_dir again....)
        if cfg.embed_coverart and os.path.exists(
                os.path.join(dest_dir_name, first_image_name)):
            imgdata = open(os.path.join(dest_dir_name, first_image_name),
                           'rb').read()
            imgtype = imghdr.what(None, imgdata)

            if imgtype in ("jpeg", "png"):
                _log.debug("Embedding album art.")
                metadata.art = imgdata

        if keep_tags is not None:
            for name in keep_tags:
                setattr(metadata, name, keep_tags[name])

        metadata.save()

    # start supplementary actions

    if cfg.write_nfo:
        _log.info("Generating .nfo file")
        release.create_nfo()

    # adopt for multi disc support
    if cfg.write_m3u:
        _log.info("Generating .m3u file")
        release.create_m3u(folder_names)

    # copy "other files" on request
    if cfg.copy_other_files and len(release.copy_files) > 0:
        _log.info("copying files from source directory")
        copy_files = release.copy_files
        dir_list = os.listdir(source)
        _log.debug("start_dir: {0}".format(source))
        _log.debug("dir list: {0}".format(dir_list))
        file_list = [
            os.path.join(source, x) for x in dir_list
            if not x.lower().endswith(TaggerUtils.FILE_TYPE)
            and os.path.isfile(os.path.join(source, x))
        ]
        copy_files.extend(file_list)

        for fname in copy_files:
            if not fname.endswith(".m3u"):
                _log.debug("source: {0}".format(fname))
                _log.debug("target: {0}".format(
                    os.path.join(dest_dir_name, os.path.basename(fname))))
                shutil.copyfile(
                    fname, os.path.join(dest_dir_name,
                                        os.path.basename(fname)))

    # remove source directory, if configured as such.
    if not cfg.keep_original:
        _log.info("Deleting source directory '{0}'".format(source))
        shutil.rmtree(source)

    _log.info("Tagging complete.")