Example #1
0
    def handleDone(self):
        if self._num_loaded == 0:
            super(StatisticsPlugin, self).handleDone()
            return

        print()
        for stat in self._stats + [self._rules_stat]:
            stat.report()
            print()

        # Detailed rule violations
        if self.args.verbose:
            for path in self._rules_log:
                printMsg(path)  # does the right thing for unicode
                for score, text in self._rules_log[path]:
                    print("\t%s%s%s (%s)" %
                          (Fore.RED, str(score).center(3), Fore.RESET, text))

        def prettyScore():
            score = float(self._score_sum) / float(self._score_count)
            if score > 80:
                color = Fore.GREEN
            elif score > 70:
                color = Fore.YELLOW
            else:
                color = Fore.RED
            return (score, color)

        score, color = prettyScore()
        print("%sScore%s = %s%d%%%s" %
              (Style.BRIGHT, Style.RESET_BRIGHT, color, score, Fore.RESET))
        if not self.args.verbose:
            print("Run with --verbose to see files and their rule violations")
        print()
Example #2
0
    def handleDone(self):
        if self._num_loaded == 0:
            super(StatisticsPlugin, self).handleDone()
            return

        print()
        for stat in self._stats + [self._rules_stat]:
            stat.report()
            print()

        # Detailed rule violations
        if self.args.verbose:
            for path in self._rules_log:
                printMsg(path)  # does the right thing for unicode
                for score, text in self._rules_log[path]:
                    print(f"\t{Fore.RED}{str(score).center(3)}{Fore.RESET} ({text})")

        def prettyScore():
            s = float(self._score_sum) / float(self._score_count)
            if s > 80:
                c = Fore.GREEN
            elif s > 70:
                c = Fore.YELLOW
            else:
                c = Fore.RED
            return s, c

        score, color = prettyScore()
        print(f"{Style.BRIGHT}Score{Style.RESET_BRIGHT} = {color}{score}%%{Fore.RESET}")
        if not self.args.verbose:
            print("Run with --verbose to see files and their rule violations")
        print()
Example #3
0
 def printHeader(self, file_path):
     from stat import ST_SIZE
     file_size = os.stat(file_path)[ST_SIZE]
     size_str = utils.formatSize(file_size)
     printMsg("%s\t%s[ %s ]%s" %
              (boldText(os.path.basename(file_path), c=HEADER_COLOR()),
               HEADER_COLOR(), size_str, Fore.RESET))
Example #4
0
    def _getOne(self,
                key,
                values,
                default=None,
                Type=UnicodeType,
                required=True):
        values = set(values)
        if None in values:
            values.remove(None)

        if len(values) != 1:
            printMsg(u"Detected %s %s names%s" % (
                "0" if len(values) == 0 else "multiple",
                key,
                "." if not values else
                (":\n\t%s" % "\n\t".join([compat.unicode(v) for v in values])),
            ))

            value = prompt(u"Enter %s" % key.title(),
                           default=default,
                           type_=Type,
                           required=required)
        else:
            value = values.pop()

        return value
Example #5
0
    def handleDone(self):
        if self._num_loaded == 0:
            super(StatisticsPlugin, self).handleDone()
            return

        print()
        for stat in self._stats + [self._rules_stat]:
            stat.report()
            print()

        # Detailed rule violations
        if self.args.verbose:
            for path in self._rules_log:
                printMsg(path)  # does the right thing for unicode
                for score, text in self._rules_log[path]:
                    print("\t%s%s%s (%s)" % (Fore.RED, str(score).center(3), Fore.RESET, text))

        def prettyScore():
            score = float(self._score_sum) / float(self._score_count)
            if score > 80:
                color = Fore.GREEN
            elif score > 70:
                color = Fore.YELLOW
            else:
                color = Fore.RED
            return (score, color)

        score, color = prettyScore()
        print("%sScore%s = %s%d%%%s" % (Style.BRIGHT, Style.RESET_BRIGHT, color, score, Fore.RESET))
        if not self.args.verbose:
            print("Run with --verbose to see files and their rule violations")
        print()
Example #6
0
def printAudioInfo(info):
    if isinstance(info, classic.mp3.Mp3AudioInfo):
        printMsg(
            classic.boldText('  Time: ') +
            '%s\tMPEG%d, Layer %s\t[ %s @ %s Hz - %s ]' %
            (classic.utils.formatTime(info.time_secs), info.mp3_header.version,
             'I' * info.mp3_header.layer, info.bit_rate_str,
             info.mp3_header.sample_freq, info.mp3_header.mode))
        printMsg('-' * DummyPlugin.terminal_width)
def test_printMsg():
    eyed3.utils.console.USE_ANSI = False
    with RedirectStdStreams() as out:
        printMsg("EYEHATEGOD")
    assert (out.stdout.read() == "EYEHATEGOD\n")

    eyed3.utils.console.USE_ANSI = True
    with RedirectStdStreams() as out:
        printMsg("EYEHATEGOD")
    assert (out.stdout.read() == "EYEHATEGOD\n")
Example #8
0
 def printAudioInfo(self, info):
     if isinstance(info, mp3.Mp3AudioInfo):
         printMsg(boldText("Time: ") +
                  "%s\tMPEG%d, Layer %s\t[ %s @ %s Hz - %s ]" %
                  (utils.formatTime(info.time_secs),
                   info.mp3_header.version,
                   "I" * info.mp3_header.layer,
                   info.bit_rate_str,
                   info.mp3_header.sample_freq, info.mp3_header.mode))
         printMsg("-" * 79)
Example #9
0
def test_printMsg():
    eyed3.utils.console.USE_ANSI = False
    with RedirectStdStreams() as out:
        printMsg("EYEHATEGOD")
    assert_equal(out.stdout.read(), "EYEHATEGOD\n")

    eyed3.utils.console.USE_ANSI = True
    with RedirectStdStreams() as out:
        printMsg("EYEHATEGOD")
    assert_equal(out.stdout.read(), "EYEHATEGOD\n")
Example #10
0
    def handleFile(self, f):
        parse_version = self.args.tag_version

        super(ClassicPlugin, self).handleFile(f, tag_version=parse_version)

        if not self.audio_file:
            return

        self.printHeader(f)
        printMsg("-" * 79)

        new_tag = False
        if (not self.audio_file.tag or
                self.handleRemoves(self.audio_file.tag)):
            self.audio_file.initTag(version=parse_version)
            new_tag = True

        save_tag = (self.handleEdits(self.audio_file.tag) or
                    self.args.force_update or self.args.convert_version)

        self.printAudioInfo(self.audio_file.info)

        if not save_tag and new_tag:
            printError("No ID3 %s tag found!" %
                       id3.versionToString(self.args.tag_version))
            return

        self.printTag(self.audio_file.tag)

        if save_tag:
            # Use current tag version unless a convert was supplied
            version = (self.args.convert_version or
                       self.audio_file.tag.version)
            printWarning("Writing ID3 version %s" %
                         id3.versionToString(version))

            self.audio_file.tag.save(
                    version=version, encoding=self.args.text_encoding,
                    backup=self.args.backup,
                    preserve_file_time=self.args.preserve_file_time)

        if self.args.rename_pattern:
            # Handle file renaming.
            from eyed3.id3.tag import TagTemplate
            template = TagTemplate(self.args.rename_pattern)
            name = template.substitute(self.audio_file.tag, zeropad=True)
            orig = self.audio_file.path
            try:
                self.audio_file.rename(name)
                printWarning("Renamed '%s' to '%s'" %
                             (orig, self.audio_file.path))
            except IOError as ex:
                printError(ex.message)

        printMsg("-" * 79)
Example #11
0
def printHeader(file_path, new_name=None):
    file_len = len(file_path)
    from stat import ST_SIZE
    file_size = os.stat(file_path)[ST_SIZE]
    size_str = classic.utils.formatSize(file_size)
    size_len = len(size_str) + 5
    if file_len + size_len >= DummyPlugin.terminal_width:
        file_path = '...' + file_path[-(75 - size_len):]
        file_len = len(file_path)
    pat_len = DummyPlugin.terminal_width - file_len - size_len
    printMsg(
        '%s%s%s[ %s ]%s' %
        (classic.boldText(file_path, c=classic.HEADER_COLOR()),
         classic.HEADER_COLOR(), ' ' * pat_len, size_str, classic.Fore.RESET))
Example #12
0
    def tagFile(self, filename, track_num, artist, title):
        # TODO extract GENRE
        # if GENRE:
            # validate GENRE

        # force removal of existing tag
        if self.args.force is True and self.audio_file.tag is not None:
            id3.Tag.remove(self.audio_file.path, id3.ID3_ANY_VERSION)
            printMsg("Tag removed from '{}'".format(filename))

        # initialize 
        if self.audio_file.tag is None:
            self.audio_file.initTag(id3.ID3_V2_4)

        # set the remainder of the tags
        self.audio_file.tag.track_num = track_num
        self.audio_file.tag.title = title
        self.audio_file.tag.artist = artist
        self.audio_file.tag.album_artist = self.meta['album_artist']
        self.audio_file.tag.album = self.meta['album']
        self.audio_file.tag.track_num = (track_num, self.meta['total_num_tracks'])
        self.audio_file.tag.recording_date = core.Date(self.meta['year'])
        self.audio_file.tag.tagging_date = '{:%Y-%m-%d}'.format(datetime.datetime.now())

        # set a tag to say this was ripped with EAC
        if self.args.eac is True:
            self.audio_file.tag.user_text_frames.set('EAC', 'Ripping Tool')

        # write a cover art image
        if self.meta['image'] is not None:
            self.audio_file.tag.images.set(
                type_=id3.frames.ImageFrame.FRONT_COVER,
                img_data=self.meta['image'],
                mime_type='image/jpeg',
            )

        # save the tag
        self.audio_file.tag.save(
            version=id3.ID3_V2_4,
            encoding='utf8',
            preserve_file_time=True,
        )

        # use classic plugin to print nice output
        self.classic.terminal_width = getTtySize()[1]
        self.classic.printHeader(self.audio_file.path)
        printMsg("-" * self.classic.terminal_width)
        self.classic.printAudioInfo(self.audio_file.info)
        self.classic.printTag(self.audio_file.tag)
Example #13
0
    def _getOne(self, key, values, default=None, Type=unicode, required=True):
        values = set(values)
        if None in values:
            values.remove(None)

        if len(values) != 1:
            printMsg(
                u"Detected %s %s names%s" %
                ("0" if len(values) == 0 else "multiple",
                 key,
                 "." if not values
                     else (":\n\t%s" % "\n\t".join([compat.unicode(v)
                                                      for v in values])),
                ))

            value = prompt(u"Enter %s" % key.title(), default=default,
                           type_=Type, required=required)
        else:
            value = values.pop()

        return value
Example #14
0
    def handleDirectory(self, d, _):
        global md5_file_cache
        md5_file_cache.clear()

        try:
            if not self._file_cache:
                print("%s: nothing to do." % d)
                return

            printMsg("\nProcessing %s" % d)

            # File images
            dir_art = []
            for img_file in self._dir_images:
                img_base = os.path.basename(img_file)
                art_file = ArtFile(img_file)
                try:
                    pil_img = pilImage(img_file)
                except IOError as ex:
                    printWarning(compat.unicode(ex))
                    continue

                if art_file.art_type:
                    printMsg("file %s: %s\n\t%s" % (img_base, art_file.art_type,
                                                    pilImageDetails(pil_img)))
                    dir_art.append(art_file)
                else:
                    printMsg("file %s: unknown (ignored)" % img_base)

            if not dir_art:
                print("No art files found.")
                self._retval += 1

            # Tag images
            all_tags = sorted([f.tag for f in self._file_cache],
                              key=lambda x: x.file_info.name)
            for tag in all_tags:
                file_base = os.path.basename(tag.file_info.name)
                for img in tag.images:
                    try:
                        pil_img = pilImage(img)
                    except IOError as ex:
                        printWarning(compat.unicode(ex))
                        continue

                    if img.picture_type in art.FROM_ID3_ART_TYPES:
                        img_type = art.FROM_ID3_ART_TYPES[img.picture_type]
                        printMsg("tag %s: %s (Description: %s)\n\t%s" %
                                 (file_base, img_type, img.description,
                                  pilImageDetails(pil_img)))
                        if self.args.update_files:
                            assert(not self.args.update_tags)
                            path = os.path.dirname(tag.file_info.name)
                            if img.description.startswith(DESCR_FNAME_PREFIX):
                                # Use filename from Image description
                                fname = img.description[
                                          len(DESCR_FNAME_PREFIX):].strip()
                                fname = os.path.splitext(fname)[0]
                            else:
                                fname = art.FILENAMES[img_type][0].strip("*")
                            fname = img.makeFileName(name=fname)

                            if (md5File(os.path.join(path, fname)) ==
                                    md5Data(img.image_data)):
                                printMsg("Skipping writing of %s, file "
                                         "exists and is exactly the same." %
                                         img_file)
                            else:
                                img_file = makeUniqueFileName(
                                    os.path.join(path, fname),
                                    uniq=img.description)
                                printWarning("Writing %s..." % img_file)
                                with open(img_file, "wb") as fp:
                                    fp.write(img.image_data)
                    else:
                        printMsg("tag %s: unhandled image type %d (ignored)" %
                                 (file_base, img.picture_type))

            # Copy file art to tags.
            if self.args.update_tags:
                assert(not self.args.update_files)
                for tag in all_tags:
                    for art_file in dir_art:
                        descr = "filename: %s" % \
                                os.path.splitext(
                                      os.path.basename(art_file.file_path))[0]
                        tag.images.set(art_file.id3_art_type,
                                       art_file.image_data, art_file.mime_type,
                                       description=descr)
                    tag.save()

        finally:
            # Cleans up...
            super(ArtPlugin, self).handleDirectory(d, _)
Example #15
0
    def handleFile(self, f):
        super(Xep118Plugin, self).handleFile(f)

        if self.audio_file and self.audio_file.tag:
            xml = self.getXML(self.audio_file)
            printMsg(xml)
Example #16
0
    def handleDirectory(self, directory, _):
        if not self._file_cache:
            return

        directory = os.path.abspath(directory)
        print("\n" + Style.BRIGHT + Fore.GREY +
              "Scanning directory%s %s" % (Style.RESET_ALL, directory))

        def _path(af):
            return af.path

        self._handled_one = True

        # Make sure all of the audio files has a tag.
        for f in self._file_cache:
            if f.tag is None:
                f.initTag()

        audio_files = sorted(list(self._file_cache), key=_path)

        self._file_cache = []
        edited_files = set()

        # Check for corrections to LP, EP, COMP
        if (self.args.dir_type in (LP_TYPE, COMP_TYPE) and
                len(audio_files) < EP_MAX_HINT):
            # Do you want EP?
            if prompt("Only %d audio files, process directory as an EP" %
                      len(audio_files),
                      default=True):
                self.args.dir_type = EP_TYPE
        elif (self.args.dir_type in (EP_TYPE, DEMO_TYPE) and
                len(audio_files) > EP_MAX_HINT):
            # Do you want LP?
            if prompt("%d audio files is large for type %s, process "
                      "directory as an LP" % (len(audio_files),
                                              self.args.dir_type),
                      default=True):
                self.args.dir_type = LP_TYPE

        last = defaultdict(lambda: None)

        album_artist = None
        artists = set()
        album = None

        if self.args.dir_type != SINGLE_TYPE:
            album_artist, artists = self._resolveArtistInfo(audio_files)
            print(Fore.BLUE + u"Album artist: " + Style.RESET_ALL +
                  (album_artist or u""))
            print(Fore.BLUE + "Artist" + ("s" if len(artists) > 1 else "") +
                  ": " + Style.RESET_ALL + u", ".join(artists))

            album = self._getAlbum(audio_files)
            print(Fore.BLUE + "Album: " + Style.RESET_ALL + album)

            rel_date, orel_date, rec_date = self._getDates(audio_files)
            for what, d in [("Release", rel_date),
                            ("Original", orel_date),
                            ("Recording", rec_date)]:
                print(Fore.BLUE + ("%s date: " % what) + Style.RESET_ALL +
                        str(d))

            num_audio_files = len(audio_files)
            track_nums = set([f.tag.track_num[0] for f in audio_files])
            fix_track_nums = set(range(1, num_audio_files + 1)) != track_nums
            new_track_nums = []

        dir_type = self.args.dir_type
        for f in sorted(audio_files, key=_path):
            print(Style.BRIGHT + Fore.GREEN + u"Checking" + Fore.RESET +
                  Fore.GREY + (" %s" % os.path.basename(f.path)) +
                  Style.RESET_ALL)

            if not f.tag:
                print("\tAdding new tag")
                f.initTag()
                edited_files.add(f)
            tag = f.tag

            if tag.version != ID3_V2_4:
                print("\tConverting to ID3 v2.4")
                tag.version = ID3_V2_4
                edited_files.add(f)

            if (dir_type != SINGLE_TYPE and album_artist != tag.album_artist):
                print(u"\tSetting album artist: %s" % album_artist)
                tag.album_artist = album_artist
                edited_files.add(f)

            if not tag.artist and dir_type in (VARIOUS_TYPE, SINGLE_TYPE):
                # Prompt artist
                tag.artist = self.prompt("Artist name", default=last["artist"])
                last["artist"] = tag.artist
            elif len(artists) == 1 and tag.artist != artists[0]:
                assert(dir_type != SINGLE_TYPE)
                print(u"\tSetting artist: %s" % artists[0])
                tag.artist = artists[0]
                edited_files.add(f)

            if tag.album != album and dir_type != SINGLE_TYPE:
                print(u"\tSetting album: %s" % album)
                tag.album = album
                edited_files.add(f)

            orig_title = tag.title
            if not tag.title:
                tag.title = prompt("Track title")
            tag.title = tag.title.strip()
            if self.args.fix_case:
                tag.title = _fixCase(tag.title)
            if orig_title != tag.title:
                print(u"\tSetting title: %s" % tag.title)
                edited_files.add(f)

            if dir_type != SINGLE_TYPE:
                # Track numbers
                tnum, ttot = tag.track_num
                update = False
                if ttot != num_audio_files:
                    update = True
                    ttot = num_audio_files

                if fix_track_nums or not (1 <= tnum <= num_audio_files):
                    tnum = None
                    while tnum is None:
                        tnum = int(prompt("Track #", type_=int))
                        if not (1 <= tnum <= num_audio_files):
                            print(Fore.RED + "Out of range: " + Fore.RESET +
                                  "1 <= %d <= %d" % (tnum, num_audio_files))
                            tnum = None
                        elif tnum in new_track_nums:
                            print(Fore.RED + "Duplicate value: " + Fore.RESET +
                                    str(tnum))
                            tnum = None
                        else:
                            update = True
                            new_track_nums.append(tnum)

                if update:
                    tag.track_num = (tnum, ttot)
                    print("\tSetting track numbers: %s" % str(tag.track_num))
                    edited_files.add(f)
            else:
                # Singles
                if tag.track_num != (None, None):
                    tag.track_num = (None, None)
                    edited_files.add(f)

            if dir_type != SINGLE_TYPE:
                # Dates
                if tag.recording_date != rec_date:
                    print("\tSetting %s date (%s)" %
                            ("recording", str(rec_date)))
                    tag.recording_date = rec_date
                    edited_files.add(f)
                if tag.release_date != rel_date:
                    print("\tSetting %s date (%s)" % ("release", str(rel_date)))
                    tag.release_date = rel_date
                    edited_files.add(f)
                if tag.original_release_date != orel_date:
                    print("\tSetting %s date (%s)" % ("original release",
                                                      str(orel_date)))
                    tag.original_release_date = orel_date
                    edited_files.add(f)

            for fid in ("USER", "PRIV"):
                n = len(tag.frame_set[fid] or [])
                if n:
                    print("\tRemoving %d %s frames..." % (n, fid))
                    del tag.frame_set[fid]
                    edited_files.add(f)

            # Add TLEN
            tlen = tag.getTextFrame("TLEN")
            real_tlen = f.info.time_secs * 1000
            if tlen is None or int(tlen) != real_tlen:
                print("\tSetting TLEN (%d)" % real_tlen)
                tag.setTextFrame("TLEN", unicode(real_tlen))
                edited_files.add(f)

            # Add custom album type if special and otherwise not able to be
            # determined.
            curr_type = tag.album_type
            if curr_type != dir_type:
                if dir_type in (LP_TYPE, VARIOUS_TYPE):
                    if curr_type is not None:
                        print("\tClearing %s = %s" % (TXXX_ALBUM_TYPE,
                                                      curr_type))
                        tag.album_type = None
                        edited_files.add(f)
                    # We don't set lp because it is the default, and various
                    # can be determined.
                else:
                    print("\tSetting %s = %s" % (TXXX_ALBUM_TYPE,
                                                 dir_type))
                    tag.album_type = dir_type
                    edited_files.add(f)

        if not self._checkCoverArt(directory, audio_files):
            if not prompt("Proceed without valid cover file", default=True):
                return

        # Determine other changes, like file and/or directory renames
        # so they can be reported before save confirmation.

        # File renaming
        file_renames = []
        if self.args.file_rename_pattern:
            format_str = self.args.file_rename_pattern
        else:
            if dir_type == SINGLE_TYPE:
                format_str = SINGLE_FNAME_FORMAT
            elif dir_type == VARIOUS_TYPE:
                format_str = VARIOUS_FNAME_FORMAT
            else:
                format_str = NORMAL_FNAME_FORMAT

        for f in audio_files:
            orig_name, orig_ext = os.path.splitext(os.path.basename(f.path))
            new_name = TagTemplate(format_str).substitute(f.tag, zeropad=True)
            if orig_name != new_name:
                printMsg(u"Rename file to %s%s" % (new_name, orig_ext))
                file_renames.append((f, new_name, orig_ext))

        # Directory renaming
        dir_rename = None
        if dir_type != SINGLE_TYPE:
            if self.args.dir_rename_pattern:
                dir_format = self.args.dir_rename_pattern
            else:
                if dir_type == LIVE_TYPE:
                    dir_format = LIVE_DNAME_FORMAT
                else:
                    dir_format = NORMAL_DNAME_FORMAT
            template = TagTemplate(dir_format,
                                   dotted_dates=self.args.dotted_dates)

            pref_dir = template.substitute(audio_files[0].tag, zeropad=True)
            if os.path.basename(directory) != pref_dir:
                new_dir = os.path.join(os.path.dirname(directory), pref_dir)
                printMsg("Rename directory to %s" % new_dir)
                dir_rename = (directory, new_dir)

        if not self.args.dry_run:
            confirmed = False

            if (edited_files or file_renames or dir_rename):
                confirmed = prompt("\nSave changes", default=True)

            if confirmed:
                for f in edited_files:
                    print(u"Saving %s" % os.path.basename(f.path))
                    f.tag.save(version=ID3_V2_4, preserve_file_time=True)

                for f, new_name, orig_ext in file_renames:
                    printMsg(u"Renaming file to %s%s" % (new_name, orig_ext))
                    f.rename(new_name, preserve_file_time=True)

                if dir_rename:
                    printMsg("Renaming directory to %s" % dir_rename[1])
                    s = os.stat(dir_rename[0])
                    os.rename(dir_rename[0], dir_rename[1])
                    # With a rename use the origianl access time
                    os.utime(dir_rename[1], (s.st_atime, s.st_atime))
        else:
            printMsg("\nNo changes made (run without -n/--dry-run)")
Example #17
0
 def _verbose(self, s):
     if self.args.verbose:
         printMsg(s)
Example #18
0
    def handleDirectory(self, d, _):
        global md5_file_cache
        md5_file_cache.clear()

        try:
            if not self._file_cache:
                print("%s: nothing to do." % d)
                return

            printMsg("\nProcessing %s" % d)

            # File images
            dir_art = []
            for img_file in self._dir_images:
                img_base = os.path.basename(img_file)
                art_file = ArtFile(img_file)
                try:
                    pil_img = pilImage(img_file)
                except IOError as ex:
                    printWarning(unicode(ex))
                    continue

                if art_file.art_type:
                    printMsg("file %s: %s\n\t%s" % (img_base, art_file.art_type,
                                                    pilImageDetails(pil_img)))
                    dir_art.append(art_file)
                else:
                    printMsg("file %s: unknown (ignored)" % img_base)

            if not dir_art:
                print("No art files found.")
                self._retval += 1

            # Tag images
            all_tags = sorted([f.tag for f in self._file_cache],
                              key=lambda x: x.file_info.name)
            for tag in all_tags:
                file_base = os.path.basename(tag.file_info.name)
                for img in tag.images:
                    try:
                        pil_img = pilImage(img)
                    except IOError as ex:
                        printWarning(unicode(ex))
                        continue

                    if img.picture_type in art.FROM_ID3_ART_TYPES:
                        img_type = art.FROM_ID3_ART_TYPES[img.picture_type]
                        printMsg("tag %s: %s (Description: %s)\n\t%s" %
                                 (file_base, img_type, img.description,
                                  pilImageDetails(pil_img)))
                        if self.args.update_files:
                            assert(not self.args.update_tags)
                            path = os.path.dirname(tag.file_info.name)
                            if img.description.startswith(DESCR_FNAME_PREFIX):
                                # Use filename from Image description
                                fname = img.description[
                                          len(DESCR_FNAME_PREFIX):].strip()
                                fname = os.path.splitext(fname)[0]
                            else:
                                fname = art.FILENAMES[img_type][0].strip("*")
                            fname = img.makeFileName(name=fname)

                            if (md5File(os.path.join(path, fname)) ==
                                    md5Data(img.image_data)):
                                printMsg("Skipping writing of %s, file "
                                         "exists and is exactly the same." %
                                         img_file)
                            else:
                                img_file = makeUniqueFileName(
                                    os.path.join(path, fname),
                                    uniq=img.description)
                                printWarning("Writing %s..." % img_file)
                                with open(img_file, "wb") as fp:
                                    fp.write(img.image_data)
                    else:
                        printMsg("tag %s: unhandled image type %d (ignored)" %
                                 (file_base, img.picture_type))

            # Copy file art to tags.
            if self.args.update_tags:
                assert(not self.args.update_files)
                for tag in all_tags:
                    for art_file in dir_art:
                        descr = "filename: %s" % \
                                os.path.splitext(
                                      os.path.basename(art_file.file_path))[0]
                        tag.images.set(art_file.id3_art_type,
                                       art_file.image_data, art_file.mime_type,
                                       description=descr)
                    tag.save()

        finally:
            # Cleans up...
            super(ArtPlugin, self).handleDirectory(d, _)
Example #19
0
 def printHeader(self, file_path):
     w = getTtySize()[1]
     printMsg(self._getFileHeader(file_path, w))
     printMsg(self._getHardRule(w))
Example #20
0
    def handleDone(self):
        if not self.albums:
            printMsg(u"No albums found.")
            return

        for album in self.albums:
            audio_files = self.albums[album]
            if not audio_files:
                continue
            audio_files.sort(key=lambda af: af.tag.track_num)

            max_title_len = 0
            avg_bitrate = 0
            encoder_info = ''
            for audio_file in audio_files:
                tag = audio_file.tag
                # Compute maximum title length
                title_len = len(tag.title)
                if title_len > max_title_len:
                    max_title_len = title_len
                # Compute average bitrate
                avg_bitrate += audio_file.info.bit_rate[1]
                # Grab the last lame version in case not all files have one
                if "encoder_version" in audio_file.info.lame_tag:
                    version = audio_file.info.lame_tag['encoder_version']
                    encoder_info = (version or encoder_info)
            avg_bitrate = avg_bitrate / len(audio_files)

            printMsg("")
            printMsg("Artist   : %s" % audio_files[0].tag.artist)
            printMsg("Album    : %s" % album)
            printMsg("Released : %s" %
                     (audio_files[0].tag.original_release_date
                      or audio_files[0].tag.release_date))
            printMsg("Recorded : %s" % audio_files[0].tag.recording_date)
            genre = audio_files[0].tag.genre
            if genre:
                genre = genre.name
            else:
                genre = ""
            printMsg("Genre    : %s" % genre)

            printMsg("")
            printMsg("Source  : ")
            printMsg("Encoder : %s" % encoder_info)
            printMsg("Codec   : mp3")
            printMsg("Bitrate : ~%s K/s @ %s Hz, %s" %
                     (avg_bitrate, audio_files[0].info.sample_freq,
                      audio_files[0].info.mode))
            printMsg("Tag     : ID3 %s" %
                     versionToString(audio_files[0].tag.version))

            printMsg("")
            printMsg("Ripped By: ")

            printMsg("")
            printMsg("Track Listing")
            printMsg("-------------")
            count = 0
            total_time = 0
            total_size = 0
            for audio_file in audio_files:
                tag = audio_file.tag
                count += 1

                title = tag.title
                title_len = len(title)
                padding = " " * ((max_title_len - title_len) + 3)
                time_secs = audio_file.info.time_secs
                total_time += time_secs
                total_size += audio_file.info.size_bytes

                zero_pad = "0" * (len(str(len(audio_files))) - len(str(count)))
                printMsg(
                    " %s%d. %s%s(%s)" %
                    (zero_pad, count, title, padding, formatTime(time_secs)))

            printMsg("")
            printMsg("Total play time : %s" % formatTime(total_time))
            printMsg("Total size      : %s" % formatSize(total_size))

            printMsg("")
            printMsg("=" * 78)
            printMsg(".NFO file created with eyeD3 %s on %s" %
                     (VERSION, time.asctime()))
            printMsg("For more information about eyeD3 go to %s" %
                     "http://eyeD3.nicfit.net/")
            printMsg("=" * 78)
Example #21
0
    def tagFile(self, filename):
        # get the filesystem character encoding
        fs_encoding = sys.getfilesystemencoding()
        
        parts = os.path.splitext(filename)[0].split(' - ')

        if self.args.compilation:
            # compilations are named "01i - Artist Name - Track Name"
            track_num = parts[0]
            artist = parts[1]
            title = parts[2]
        else:
            # normal albums are named "01 - Track Name"
            track_num = parts[0]
            artist = self.meta['artist']
            title = parts[1]

        # extract GENRE
        # if GENRE:
            # validate GENRE

        # force removal of existing tag
        if self.args.force is True and self.audio_file.tag is not None:
            id3.Tag.remove(self.audio_file.path, id3.ID3_ANY_VERSION)
            printMsg("Tag removed from '{}'".format(filename))

        # initialize 
        if self.audio_file.tag is None:
            self.audio_file.initTag(id3.ID3_V2_4)

        # decode from filesystem encoding where necessary
        if type(artist) is str:
            self.audio_file.tag.artist = artist.decode(fs_encoding)
        else:
            self.audio_file.tag.artist = artist

        if type(self.meta['album_artist']) is str:
            self.audio_file.tag.album_artist = self.meta['album_artist'].decode(fs_encoding)
        else:
            self.audio_file.tag.album_artist = self.meta['album_artist']

        if type(self.meta['album']) is str:
            self.audio_file.tag.album = self.meta['album'].decode(fs_encoding)
        else:
            self.audio_file.tag.album = self.meta['album']

        # set the remainder of the tags
        self.audio_file.tag.title = title
        self.audio_file.tag.track_num = (track_num, self.meta['total_num_tracks'])
        self.audio_file.tag.recording_date = core.Date(self.meta['year'])
        self.audio_file.tag.tagging_date = '{:%Y-%m-%d}'.format(datetime.datetime.now())

        # set a tag to say this was ripped with EAC
        if self.args.eac is True:
            self.audio_file.tag.user_text_frames.set(u'EAC', u'Ripping Tool')

        # write a cover art image
        if self.meta['image'] is not None:
            self.audio_file.tag.images.set(
                type_=id3.frames.ImageFrame.FRONT_COVER,
                img_data=self.meta['image'],
                mime_type='image/jpeg',
            )

        # save the tag
        self.audio_file.tag.save(
            version=id3.ID3_V2_4,
            encoding='utf8',
            preserve_file_time=True,
        )

        # print output from the classic plugin
        self.classic.printHeader(self.audio_file.path)
        printMsg("-" * 79)
        self.classic.printAudioInfo(self.audio_file.info)
        self.classic.printTag(self.audio_file.tag)
Example #22
0
    def printTag(self, tag):
        if isinstance(tag, id3.Tag):
            if self.args.quiet:
                printMsg("ID3 %s: %d frames" %
                         (id3.versionToString(tag.version),
                          len(tag.frame_set)))
                return

            printMsg("ID3 %s:" % id3.versionToString(tag.version))
            artist = tag.artist if tag.artist else u""
            title = tag.title if tag.title else u""
            album = tag.album if tag.album else u""
            printMsg("%s: %s" % (boldText("title"), title))
            printMsg("%s: %s" % (boldText("artist"), artist))
            printMsg("%s: %s" % (boldText("album"), album))

            for date, date_label in [
                    (tag.release_date, "release date"),
                    (tag.original_release_date, "original release date"),
                    (tag.recording_date, "recording date"),
                    (tag.encoding_date, "encoding date"),
                    (tag.tagging_date, "tagging date"),
                    ]:
                if date:
                    printMsg("%s: %s" % (boldText(date_label), str(date)))

            track_str = ""
            (track_num, track_total) = tag.track_num
            if track_num is not None:
                track_str = str(track_num)
                if track_total:
                    track_str += "/%d" % track_total

            genre = tag.genre
            genre_str = "%s: %s (id %s)" % (boldText("genre"),
                                            genre.name,
                                            str(genre.id)) if genre else u""
            printMsg("%s: %s\t\t%s" % (boldText("track"), track_str, genre_str))

            disc_str = ""
            (num, total) = tag.disc_num
            if num is not None:
                disc_str = str(num)
                if total:
                    disc_str += "/%d" % total
                printMsg("%s: %s" % (boldText("disc"), disc_str))

            # PCNT
            play_count = tag.play_count
            if tag.play_count is not None:
                 printMsg("%s %d" % (boldText("Play Count:"), play_count))

            # POPM
            for popm in tag.popularities:
                printMsg("%s [email: %s] [rating: %d] [play count: %d]" %
                         (boldText("Popularity:"), popm.email, popm.rating,
                          popm.count))

            # TBPM
            bpm = tag.bpm
            if bpm is not None:
                 printMsg("%s %d" % (boldText("BPM:"), bpm))

            # TPUB
            pub = tag.publisher
            if pub is not None:
                 printMsg("%s %s" % (boldText("Publisher/label:"), pub))

            # UFID
            for ufid in tag.unique_file_ids:
                printMsg("%s [%s] : %s" % \
                        (boldText("Unique File ID:"), ufid.owner_id,
                         ufid.uniq_id.encode("string_escape")))

            # COMM
            for c in tag.comments:
                printMsg("%s: [Description: %s] [Lang: %s]\n%s" %
                         (boldText("Comment"), c.description or "",
                          c.lang or "", c.text or ""))

            # USLT
            for l in tag.lyrics:
                printMsg("%s: [Description: %s] [Lang: %s]\n%s" %
                         (boldText("Lyrics"), l.description or u"",
                          l.lang or "", l.text))

            # TXXX
            for f in tag.user_text_frames:
                printMsg("%s: [Description: %s]\n%s" %
                         (boldText("UserTextFrame"), f.description, f.text))

            # URL frames
            for desc, url in ( ("Artist URL", tag.artist_url),
                               ("Audio source URL", tag.audio_source_url),
                               ("Audio file URL", tag.audio_file_url),
                               ("Internet radio URL", tag.internet_radio_url),
                               ("Commercial URL", tag.commercial_url),
                               ("Payment URL", tag.payment_url),
                               ("Publisher URL", tag.publisher_url),
                               ("Copyright URL", tag.copyright_url),
                             ):
                if url:
                    printMsg("%s: %s" % (boldText(desc), url))


            # user url frames
            for u in tag.user_url_frames:
                printMsg("%s [Description: %s]: %s" % (u.id, u.description,
                                                       u.url))

            # APIC
            for img in tag.images:
                if img.mime_type != ImageFrame.URL_MIME_TYPE:
                    printMsg("%s: [Size: %d bytes] [Type: %s]" %
                        (boldText(img.picTypeToString(img.picture_type) +
                                  " Image"),
                        len(img.image_data),
                        img.mime_type))
                    printMsg("Description: %s" % img.description)
                    printMsg("")
                    if self.args.write_images_dir:
                        img_path = "%s%s" % (self.args.write_images_dir, os.sep)
                        if not os.path.isdir(img_path):
                            raise IOError("Directory does not exist: %s" %
                                          img_path)
                        img_file = self._getDefaultNameForImage(img)
                        count = 1
                        while os.path.exists(os.path.join(img_path, img_file)):
                            img_file = self._getDefaultNameForImage(img,
                                                                    str(count))
                            count += 1
                        printWarning("Writing %s..." % os.path.join(img_path,
                                                                    img_file))
                        with open(os.path.join(img_path, img_file), "wb") as fp:
                            fp.write(img.image_data)
                else:
                    printMsg("%s: [Type: %s] [URL: %s]" %
                        (boldText(img.picTypeToString(img.picture_type) +
                                  " Image"),
                        img.mime_type, img.image_url))
                    printMsg("Description: %s" % img.description)
                    printMsg("")

            # GOBJ
            for obj in tag.objects:
                printMsg("%s: [Size: %d bytes] [Type: %s]" %
                         (boldText("GEOB"), len(obj.object_data),
                          obj.mime_type))
                printMsg("Description: %s" % obj.description)
                printMsg("Filename: %s" % obj.filename)
                printMsg("\n")
                if self.args.write_objects_dir:
                    obj_path = "%s%s" % (self.args.write_objects_dir, os.sep)
                    if not os.path.isdir(obj_path):
                        raise IOError("Directory does not exist: %s" % obj_path)
                    obj_file = self._getDefaultNameForObject(obj)
                    count = 1
                    while os.path.exists(os.path.join(obj_path, obj_file)):
                        obj_file = self._getDefaultNameForObject(obj,
                                                                 str(count))
                        count += 1
                    printWarning("Writing %s..." % os.path.join(obj_path,
                                                                obj_file))
                    with open(os.path.join(obj_path, obj_file), "wb") as fp:
                        fp.write(obj.object_data)

            # PRIV
            for p in tag.privates:
                printMsg("%s: [Data: %d bytes]" % (boldText("PRIV"),
                                                   len(p.data)))
                printMsg("Owner Id: %s" % p.owner_id)

            # MCDI
            if tag.cd_id:
                printMsg("\n%s: [Data: %d bytes]" % (boldText("MCDI"),
                                                     len(tag.cd_id)))

            # USER
            if tag.terms_of_use:
                printMsg("\nTerms of Use (%s): %s" % (boldText("USER"),
                                                      tag.terms_of_use))

            if self.args.verbose:
                printMsg("-" * 79)
                printMsg("%d ID3 Frames:" % len(tag.frame_set))
                for fid in tag.frame_set:
                    num_frames = len(tag.frame_set[fid])
                    count = " x %d" % num_frames if num_frames > 1 else ""
                    printMsg("%s%s" % (fid, count))
        else:
            raise TypeError("Unknown tag type: " + str(type(tag)))
Example #23
0
 def handleDone(self):
     """If no audio files were loaded this simply prints 'Nothing to do'."""
     if self._num_loaded == 0:
         printMsg("Nothing to do")
Example #24
0
 def handleDone(self):
     '''If no audio files were loaded this simply prints "Nothing to do".'''
     if self._num_loaded == 0:
         printMsg("Nothing to do")
Example #25
0
    def handleDirectory(self, directory, _):
        if not self._file_cache:
            return

        directory = os.path.abspath(directory)
        print("\n" + Style.bright + Fore.grey +
              "Scanning directory%s %s" % (Style.reset_all, directory))

        def _path(af):
            return af.path
        audio_files = sorted(list(self._file_cache), key=_path)
        self._file_cache = []

        edited_files = set()

        if (len(audio_files) < EP_MAX_HINT and
                self.args.dir_type not in (EP_TYPE, DEMO_TYPE, VARIOUS_TYPE)):
            if _prompt("Only %d audio files, process directory as an EP" %
                       len(audio_files),
                       default=True):
                self.args.dir_type = EP_TYPE
        elif self.args.dir_type == EP_TYPE and len(audio_files) > EP_MAX_HINT:
            if _prompt("%d audio files is large for an EP, process directory "
                       "as an LP" % len(audio_files), default=True):
                self.args.dir_type = LP_TYPE
        elif (self.args.dir_type not in (VARIOUS_TYPE, COMP_TYPE, LIVE_TYPE) and
                len(audio_files) > LP_MAX_HINT):
            if _prompt("%d audio files is large for an LP, process directory "
                       "as a compilation" % len(audio_files), default=True):
                self.args.dir_type = COMP_TYPE

        last = defaultdict(lambda: None)

        artist = self._getArtist(audio_files)
        print(Fore.BLUE + "Artist: " + Style.RESET_ALL +
              (artist or "Various Artists"))

        album = self._getAlbum(audio_files)
        print(Fore.BLUE + "Album: " + Style.RESET_ALL + album)

        rel_date, orel_date, rec_date = self._getDates(audio_files)
        for what, d in [("Release", rel_date),
                        ("Original", orel_date),
                        ("Recording", rec_date)]:
            print(Fore.BLUE + ("%s date: " % what) + Style.RESET_ALL + str(d))

        num_audio_files = len(audio_files)
        track_nums = set([f.tag.track_num[0] for f in audio_files])
        fix_track_nums = bool(set(range(1, num_audio_files + 1)) != track_nums)
        new_track_nums = []

        for f in sorted(audio_files, key=_path):
            print(Style.bright + Fore.grey +
                  u"Checking%s %s" % (Style.reset_all,
                                      os.path.basename(f.path)))

            if not f.tag:
                print("\tAdding new tag")
                f.initTag()
                edited_files.add(f)
            tag = f.tag

            if tag.version != ID3_V2_4:
                print("\tConverting to ID3 v2.4")
                tag.version = ID3_V2_4
                edited_files.add(f)

            if self.args.dir_type == VARIOUS_TYPE:
                if not tag.artist:
                    tag.artist = self._prompt("Artist name",
                                              default=last["artist"])
                last["artist"] = tag.artist
            elif tag.artist != artist:
                print(u"\tSetting artist: %s" % artist)
                tag.artist = artist
                edited_files.add(f)

            if tag.album != album:
                print(u"\tSetting album: %s" % album)
                tag.album = album
                edited_files.add(f)

            orig_title = tag.title
            if not tag.title:
                tag.title = _prompt("Track title")
            if self.args.fix_case:
                tag.title = _fixCase(tag.title)
            if orig_title != tag.title:
                print(u"\tSetting title: %s" % tag.title)
                edited_files.add(f)

            # Track numbers
            tnum, ttot = tag.track_num
            update = False
            if ttot != num_audio_files:
                update = True
                ttot = num_audio_files

            if fix_track_nums or not (1 <= tnum <= num_audio_files):
                tnum = None
                while tnum is None:
                    tnum = int(_prompt("Track #"))
                    if not (1 <= tnum <= num_audio_files):
                        print(Fore.red + "Out of range: " + Fore.reset +
                              "1 <= %d <= %d" % (tnum, num_audio_files))
                        tnum = None
                    elif tnum in new_track_nums:
                        print(Fore.red + "Duplicate value: " + Fore.reset +
                                str(tnum))
                        tnum = None
                    else:
                        update = True
                        new_track_nums.append(tnum)

            if update:
                tag.track_num = (tnum, ttot)
                print("\tSetting track numbers: %s" % str(tag.track_num))
                edited_files.add(f)

            # Dates
            if tag.recording_date != rec_date:
                print("\tSetting %s date (%s)" % ("recording", str(rec_date)))
                tag.recording_date = rec_date
                edited_files.add(f)
            if tag.release_date != rel_date:
                print("\tSetting %s date (%s)" % ("release", str(rel_date)))
                tag.release_date = rel_date
                edited_files.add(f)
            if tag.original_release_date != orel_date:
                print("\tSetting %s date (%s)" % ("original release",
                                                  str(orel_date)))
                tag.original_release_date = orel_date
                edited_files.add(f)

            for fid in ("USER", "PRIV"):
                n = len(tag.frame_set[fid] or [])
                if n:
                    print("\tRemoving %d %s frames..." % (n, fid))
                    del tag.frame_set[fid]
                    edited_files.add(f)

            # Add TLEN
            tlen = tag.getTextFrame("TLEN")
            real_tlen = f.info.time_secs * 1000
            if tlen is None or int(tlen) != real_tlen:
                print("\tSetting TLEN (%d)" % real_tlen)
                tag.setTextFrame("TLEN", unicode(real_tlen))
                edited_files.add(f)

            # Add custom album type if special and otherwise not able to be
            # determined.
            curr_type = tag.user_text_frames.get(TXXX_ALBUM_TYPE)
            if curr_type is not None:
                curr_type = curr_type.text
            if curr_type != self.args.dir_type:
                if self.args.dir_type in (LP_TYPE, VARIOUS_TYPE):
                    if curr_type is not None:
                        print("\tClearing %s = %s" % (TXXX_ALBUM_TYPE,
                                                      curr_type))
                        tag.user_text_frames.remove(TXXX_ALBUM_TYPE)
                        edited_files.add(f)
                    # We don't set lp because it is the default, and various
                    # can be determined.
                else:
                    print("\tSetting %s = %s" % (TXXX_ALBUM_TYPE,
                                                 self.args.dir_type))
                    tag.user_text_frames.set(self.args.dir_type,
                                             TXXX_ALBUM_TYPE)
                    edited_files.add(f)

        # Determine other changes, like file and/or duirectory renames
        # so they can be reported before save confirmation.
        file_renames = []
        format_str = (NORMAL_FNAME_FORMAT
                        if self.args.dir_type != VARIOUS_TYPE
                        else VARIOUS_FNAME_FORMAT)
        for f in audio_files:
            orig_name, orig_ext = os.path.splitext(os.path.basename(f.path))
            new_name = TagTemplate(format_str).substitute(f.tag, zeropad=True)
            if orig_name != new_name:
                printMsg(u"Rename file to %s%s" % (new_name, orig_ext))
                file_renames.append((f, new_name, orig_ext))

        dir_rename = None
        if self.args.dir_type == LIVE_TYPE:
            dir_format = LIVE_DNAME_FORMAT
        else:
            dir_format = NORMAL_DNAME_FORMAT
        template = TagTemplate(dir_format, dotted_dates=self.args.dotted_dates)

        pref_dir = template.substitute(audio_files[0].tag, zeropad=True)
        if os.path.basename(directory) != pref_dir:
            new_dir = os.path.join(os.path.dirname(directory), pref_dir)
            printMsg("Rename directory to %s" % new_dir)
            dir_rename = (directory, new_dir)

        if not self.args.dry_run:
            confirmed = False

            if (edited_files or file_renames or dir_rename):
                confirmed = _prompt("\nSave changes", default=True)

            if confirmed:
                for f in edited_files:
                    print(u"Saving %s" % os.path.basename(f.path))
                    f.tag.save(version=ID3_V2_4)

                for f, new_name, orig_ext in file_renames:
                    printMsg(u"Renaming file to %s%s" % (new_name, orig_ext))
                    f.rename(new_name)

                if dir_rename:
                    printMsg("Renaming directory to %s" % dir_rename[1])
                    os.rename(dir_rename[0], dir_rename[1])
        else:
            printMsg("\nNo changes made (run without -n/--dry-run)")
Example #26
0
    def handleFile(self, f, *_, **__):
        super().handleFile(f)
        if self.audio_file is None:
            return

        self.printHeader(f)
        if (self.audio_file.info is None or not self.audio_file.info.lame_tag):
            printMsg("No LAME Tag")
            return

        lt = self.audio_file.info.lame_tag
        if "infotag_crc" not in lt:
            try:
                printMsg(f"Encoder Version: {lt['encoder_version']}")
            except KeyError:
                pass
            return

        values = [
            ("Encoder Version", lt['encoder_version']),
            ("LAME Tag Revision", lt['tag_revision']),
            ("VBR Method", lt['vbr_method']),
            ("Lowpass Filter", lt['lowpass_filter']),
        ]

        if "replaygain" in lt:
            try:
                peak = lt["replaygain"]["peak_amplitude"]
                db = 20 * math.log10(peak)
                val = "%.8f (%+.1f dB)" % (peak, db)
                values.append(("Peak Amplitude", val))
            except KeyError:
                pass
            for type_ in ["radio", "audiofile"]:
                try:
                    gain = lt["replaygain"][type_]
                    name = "%s Replay Gain" % gain['name'].capitalize()
                    val = "%s dB (%s)" % (gain['adjustment'],
                                          gain['originator'])
                    values.append((name, val))
                except KeyError:
                    pass

        values.append(("Encoding Flags", " ".join((lt["encoding_flags"]))))
        if lt["nogap"]:
            values.append(("No Gap", " and ".join(lt["nogap"])))
        values.append(("ATH Type", lt["ath_type"]))
        values.append(("Bitrate (%s)" % lt["bitrate"][1], lt["bitrate"][0]))
        values.append(("Encoder Delay", "%s samples" % lt["encoder_delay"]))
        values.append(
            ("Encoder Padding", "%s samples" % lt["encoder_padding"]))
        values.append(("Noise Shaping", lt["noise_shaping"]))
        values.append(("Stereo Mode", lt["stereo_mode"]))
        values.append(("Unwise Settings", lt["unwise_settings"]))
        values.append(("Sample Frequency", lt["sample_freq"]))
        values.append(
            ("MP3 Gain",
             "%s (%+.1f dB)" % (lt["mp3_gain"], lt["mp3_gain"] * 1.5)))
        values.append(("Preset", lt["preset"]))
        values.append(("Surround Info", lt["surround_info"]))
        values.append(("Music Length", "%s" % formatSize(lt["music_length"])))
        values.append(("Music CRC-16", "%04X" % lt["music_crc"]))
        values.append(("LAME Tag CRC-16", "%04X" % lt["infotag_crc"]))

        for v in values:
            printMsg(f"{v[0]:<20}: {v[1]}")
Example #27
0
    def handleFile(self, f):
        super(LameInfoPlugin, self).handleFile(f)

        self.printHeader(f)
        if not self.audio_file or not self.audio_file.info.lame_tag:
            printMsg('No LAME Tag')
            return

        format = '%-20s: %s'
        lt = self.audio_file.info.lame_tag
        if "infotag_crc" not in lt:
            try:
                printMsg('%s: %s' % ('Encoder Version', lt['encoder_version']))
            except KeyError:
                pass
            return

        values = []

        values.append(('Encoder Version', lt['encoder_version']))
        values.append(('LAME Tag Revision', lt['tag_revision']))
        values.append(('VBR Method', lt['vbr_method']))
        values.append(('Lowpass Filter', lt['lowpass_filter']))

        if "replaygain" in lt:
            try:
                peak = lt['replaygain']['peak_amplitude']
                db = 20 * math.log10(peak)
                val = '%.8f (%+.1f dB)' % (peak, db)
                values.append(('Peak Amplitude', val))
            except KeyError:
                pass
            for type in ['radio', 'audiofile']:
                try:
                    gain = lt['replaygain'][type]
                    name = '%s Replay Gain' % gain['name'].capitalize()
                    val = '%s dB (%s)' % (gain['adjustment'],
                                          gain['originator'])
                    values.append((name, val))
                except KeyError:
                    pass

        values.append(('Encoding Flags', ' '.join((lt['encoding_flags']))))
        if lt['nogap']:
            values.append(('No Gap', ' and '.join(lt['nogap'])))
        values.append(('ATH Type', lt['ath_type']))
        values.append(('Bitrate (%s)' % lt['bitrate'][1], lt['bitrate'][0]))
        values.append(('Encoder Delay', '%s samples' % lt['encoder_delay']))
        values.append(
            ('Encoder Padding', '%s samples' % lt['encoder_padding']))
        values.append(('Noise Shaping', lt['noise_shaping']))
        values.append(('Stereo Mode', lt['stereo_mode']))
        values.append(('Unwise Settings', lt['unwise_settings']))
        values.append(('Sample Frequency', lt['sample_freq']))
        values.append(
            ('MP3 Gain',
             '%s (%+.1f dB)' % (lt['mp3_gain'], lt['mp3_gain'] * 1.5)))
        values.append(('Preset', lt['preset']))
        values.append(('Surround Info', lt['surround_info']))
        values.append(('Music Length', '%s' % formatSize(lt['music_length'])))
        values.append(('Music CRC-16', '%04X' % lt['music_crc']))
        values.append(('LAME Tag CRC-16', '%04X' % lt['infotag_crc']))

        for v in values:
            printMsg(format % (v))
Example #28
0
    def handleDone(self):
        if not self.albums:
            printMsg(u"No albums found.")
            return

        for album in self.albums:
            audio_files = self.albums[album]
            if not audio_files:
                continue
            audio_files.sort(key=lambda af: af.tag.track_num)

            max_title_len = 0
            avg_bitrate = 0
            encoder_info = ''
            for audio_file in audio_files:
                tag = audio_file.tag
                # Compute maximum title length
                title_len = len(tag.title)
                if title_len > max_title_len:
                    max_title_len = title_len
                # Compute average bitrate
                avg_bitrate += audio_file.info.bit_rate[1]
                # Grab the last lame version in case not all files have one
                if "encoder_version" in audio_file.info.lame_tag:
                    version = audio_file.info.lame_tag['encoder_version']
                    encoder_info = (version or encoder_info)
            avg_bitrate = avg_bitrate / len(audio_files)

            printMsg("")
            printMsg("Artist   : %s" % audio_files[0].tag.artist)
            printMsg("Album    : %s" % album)
            printMsg("Released : %s" %
                     (audio_files[0].tag.original_release_date or
                      audio_files[0].tag.release_date))
            printMsg("Recorded : %s" % audio_files[0].tag.recording_date)
            genre = audio_files[0].tag.genre
            if genre:
                genre = genre.name
            else:
                genre = ""
            printMsg("Genre    : %s" % genre)

            printMsg("")
            printMsg("Source  : ")
            printMsg("Encoder : %s" % encoder_info)
            printMsg("Codec   : mp3")
            printMsg("Bitrate : ~%s K/s @ %s Hz, %s" %
                     (avg_bitrate, audio_files[0].info.sample_freq,
                      audio_files[0].info.mode))
            printMsg("Tag     : ID3 %s" %
                     versionToString(audio_files[0].tag.version))

            printMsg("")
            printMsg("Ripped By: ")

            printMsg("")
            printMsg("Track Listing")
            printMsg("-------------")
            count = 0
            total_time = 0
            total_size = 0
            for audio_file in audio_files:
                tag = audio_file.tag
                count += 1

                title = tag.title
                title_len = len(title)
                padding = " " * ((max_title_len - title_len) + 3)
                time_secs = audio_file.info.time_secs
                total_time += time_secs
                total_size += audio_file.info.size_bytes

                zero_pad = "0" * (len(str(len(audio_files))) - len(str(count)))
                printMsg(" %s%d. %s%s(%s)" %
                         (zero_pad, count, title, padding,
                          formatTime(time_secs)))

            printMsg("")
            printMsg("Total play time : %s" %
                     formatTime(total_time))
            printMsg("Total size      : %s" %
                     formatSize(total_size))

            printMsg("")
            printMsg("=" * 78)
            printMsg(".NFO file created with eyeD3 %s on %s" %
                     (VERSION, time.asctime()))
            printMsg("For more information about eyeD3 go to %s" %
                     "http://eyeD3.nicfit.net/")
            printMsg("=" * 78)
Example #29
0
    def handleFile(self, f):
        super(LameInfoPlugin, self).handleFile(f)

        self.printHeader(f)
        if not self.audio_file or not self.audio_file.info.lame_tag:
            printMsg('No LAME Tag')
            return

        format = '%-20s: %s'
        lt = self.audio_file.info.lame_tag
        if "infotag_crc" not in lt:
            try:
                printMsg('%s: %s' % ('Encoder Version', lt['encoder_version']))
            except KeyError:
                pass
            return

        values = []

        values.append(('Encoder Version', lt['encoder_version']))
        values.append(('LAME Tag Revision', lt['tag_revision']))
        values.append(('VBR Method', lt['vbr_method']))
        values.append(('Lowpass Filter', lt['lowpass_filter']))

        if "replaygain" in lt:
           try:
               peak = lt['replaygain']['peak_amplitude']
               db = 20 * math.log10(peak)
               val = '%.8f (%+.1f dB)' % (peak, db)
               values.append(('Peak Amplitude', val))
           except KeyError:
               pass
           for type in ['radio', 'audiofile']:
               try:
                   gain = lt['replaygain'][type]
                   name = '%s Replay Gain' % gain['name'].capitalize()
                   val = '%s dB (%s)' % (gain['adjustment'], gain['originator'])
                   values.append((name, val))
               except KeyError:
                   pass

        values.append(('Encoding Flags', ' '.join((lt['encoding_flags']))))
        if lt['nogap']:
            values.append(('No Gap', ' and '.join(lt['nogap'])))
        values.append(('ATH Type', lt['ath_type']))
        values.append(('Bitrate (%s)' % lt['bitrate'][1], lt['bitrate'][0]))
        values.append(('Encoder Delay', '%s samples' % lt['encoder_delay']))
        values.append(('Encoder Padding', '%s samples' % lt['encoder_padding']))
        values.append(('Noise Shaping', lt['noise_shaping']))
        values.append(('Stereo Mode', lt['stereo_mode']))
        values.append(('Unwise Settings', lt['unwise_settings']))
        values.append(('Sample Frequency', lt['sample_freq']))
        values.append(('MP3 Gain', '%s (%+.1f dB)' % (lt['mp3_gain'],
                                                      lt['mp3_gain'] * 1.5)))
        values.append(('Preset', lt['preset']))
        values.append(('Surround Info', lt['surround_info']))
        values.append(('Music Length', '%s' % formatSize(lt['music_length'])))
        values.append(('Music CRC-16', '%04X' % lt['music_crc']))
        values.append(('LAME Tag CRC-16', '%04X' % lt['infotag_crc']))

        for v in values:
            printMsg(format % (v))
Example #30
0
File: art.py Project: COMU/gramafon
 def _verbose(self, s):
     if self.args.verbose:
         printMsg(s)
Example #31
0
 def handleDone(self):
     '''If no audio files were loaded this simply prints "Nothing to do".'''
     if self._num_loaded == 0:
         printMsg("Nothing to do")
Example #32
0
File: art.py Project: COMU/gramafon
    def handleDirectory(self, d, _):
        global md5_file_cache
        md5_file_cache.clear()

        if not self._file_cache:
            log.debug("%s: nothing to do." % d)
            return

        try:
            all_tags = sorted([f.tag for f in self._file_cache if f.tag],
                              key=lambda x: x.file_info.name)

            # If not deemed an album, move on.
            if len(set([t.album for t in all_tags])) > 1:
                log.debug("Skipping directory '%s', non-album." % d)
                return

            printMsg(cformat("\nChecking: ", Fore.BLUE) + d)

            # File images
            dir_art = []
            for img_file in self._dir_images:
                img_base = os.path.basename(img_file)
                art_file = ArtFile(img_file)
                try:
                    pil_img = pilImage(img_file)
                except IOError as ex:
                    printWarning(compat.unicode(ex))
                    continue

                if art_file.art_type:
                    self._verbose("file %s: %s\n\t%s" %
                                  (img_base, art_file.art_type,
                                   pilImageDetails(pil_img)))
                    dir_art.append(art_file)
                else:
                    self._verbose("file %s: unknown (ignored)" % img_base)

            if not dir_art:
                print(cformat("NONE", Fore.RED))
                self._retval += 1
            else:
                print(cformat("OK", Fore.GREEN))

            # --download handling
            if not dir_art and self.args.download and _have_lastfm:
                tag = all_tags[0]
                artists = set([t.artist for t in all_tags])
                if len(artists) > 1:
                    artist_query = VARIOUS_ARTISTS
                else:
                    artist_query = tag.album_artist or tag.artist

                try:
                    url = getAlbumArt(artist_query, tag.album)
                    resp = requests.get(url)
                    if resp.status_code != 200:
                        raise ValueError()
                except ValueError:
                    print("Album art download not found")
                else:
                    print("Downloading album art...")
                    img = pilImage(io.BytesIO(resp.content))
                    cover = Path(d) / "cover.{}".format(img.format.lower())
                    assert not cover.exists()
                    img.save(str(cover))
                    print("Save {cover}".format(cover=cover))

            # Tag images
            for tag in all_tags:
                file_base = os.path.basename(tag.file_info.name)
                for img in tag.images:
                    try:
                        pil_img = pilImage(img)
                        pil_img_details = pilImageDetails(pil_img)
                    except (OSError, IOError) as ex:
                        printWarning(compat.unicode(ex))
                        continue

                    if img.picture_type in art.FROM_ID3_ART_TYPES:
                        img_type = art.FROM_ID3_ART_TYPES[img.picture_type]
                        self._verbose("tag %s: %s (Description: %s)\n\t%s" %
                                      (file_base, img_type, img.description,
                                       pil_img_details))
                        if self.args.update_files:
                            assert(not self.args.update_tags)
                            path = os.path.dirname(tag.file_info.name)
                            if img.description.startswith(DESCR_FNAME_PREFIX):
                                # Use filename from Image description
                                fname = img.description[
                                          len(DESCR_FNAME_PREFIX):].strip()
                                fname = os.path.splitext(fname)[0]
                            else:
                                fname = art.FILENAMES[img_type][0].strip("*")
                            fname = img.makeFileName(name=fname)

                            if (md5File(os.path.join(path, fname)) ==
                                    md5Data(img.image_data)):
                                printMsg("Skipping writing of %s, file "
                                         "exists and is exactly the same." %
                                         fname)
                            else:
                                img_file = makeUniqueFileName(
                                    os.path.join(path, fname),
                                    uniq=img.description)
                                printWarning("Writing %s..." % img_file)
                                with open(img_file, "wb") as fp:
                                    fp.write(img.image_data)
                    else:
                        self._verbose(
                            "tag %s: unhandled image type %d (ignored)" %
                            (file_base, img.picture_type)
                        )

            # Copy file art to tags.
            if self.args.update_tags:
                assert(not self.args.update_files)
                for tag in all_tags:
                    for art_file in dir_art:
                        art_path = os.path.basename(art_file.file_path)
                        printMsg("Copying %s to tag '%s' image" %
                                 (art_path, art_file.id3_art_type))

                        descr = "filename: %s" % os.path.splitext(art_path)[0]
                        tag.images.set(art_file.id3_art_type,
                                       art_file.image_data, art_file.mime_type,
                                       description=descr)
                    tag.save()

        finally:
            # Cleans up...
            super(ArtPlugin, self).handleDirectory(d, _)
Example #33
0
    def handleDirectory(self, d, _):
        global md5_file_cache
        md5_file_cache.clear()

        if not self._file_cache:
            log.debug(f"{d}: nothing to do.")
            return

        try:
            all_tags = sorted([f.tag for f in self._file_cache if f.tag],
                              key=lambda x: x.file_info.name)

            # If not deemed an album, move on.
            if len(set([t.album for t in all_tags])) > 1:
                log.debug(f"Skipping directory '{d}', non-album.")
                return

            printMsg(cformat("\nChecking: ", Fore.BLUE) + d)

            # File images
            dir_art = []
            for img_file in self._dir_images:
                img_base = os.path.basename(img_file)
                art_file = ArtFile(img_file)
                try:
                    pil_img = pilImage(img_file)
                except IOError as ex:
                    printWarning(str(ex))
                    continue

                if art_file.art_type:
                    self._verbose(
                        f"file {img_base}: {art_file.art_type}\n\t{pilImageDetails(pil_img)}")
                    dir_art.append(art_file)
                else:
                    self._verbose(f"file {img_base}: unknown (ignored)")

            if not dir_art:
                print(cformat("NONE", Fore.RED))
                self._retval += 1
            else:
                print(cformat("OK", Fore.GREEN))

            # --download handling
            if not dir_art and self.args.download:
                tag = all_tags[0]
                artists = set([t.artist for t in all_tags])
                if len(artists) > 1:
                    artist_query = VARIOUS_ARTISTS
                else:
                    artist_query = tag.album_artist or tag.artist

                try:
                    url = getAlbumArt(artist_query, tag.album)
                    print("Downloading album art...")
                    resp = requests.get(url)
                    if resp.status_code != 200:
                        raise ValueError()
                except ValueError:
                    print("Album art download not found")
                else:
                    img = pilImage(io.BytesIO(resp.content))
                    cover = Path(d) / "cover.{}".format(img.format.lower())
                    assert not cover.exists()
                    img.save(str(cover))
                    print("Save {cover}".format(cover=cover))

            # Tag images
            for tag in all_tags:
                file_base = os.path.basename(tag.file_info.name)
                for img in tag.images:
                    try:
                        pil_img = pilImage(img)
                        pil_img_details = pilImageDetails(pil_img)
                    except (OSError, IOError) as ex:
                        printWarning(str(ex))
                        continue

                    if img.picture_type in art.FROM_ID3_ART_TYPES:
                        img_type = art.FROM_ID3_ART_TYPES[img.picture_type]
                        self._verbose("tag %s: %s (Description: %s)\n\t%s" %
                                      (file_base, img_type, img.description,
                                       pil_img_details))
                        if self.args.update_files:
                            assert(not self.args.update_tags)
                            path = os.path.dirname(tag.file_info.name)
                            if img.description.startswith(DESCR_FNAME_PREFIX):
                                # Use filename from Image description
                                fname = img.description[
                                          len(DESCR_FNAME_PREFIX):].strip()
                                fname = os.path.splitext(fname)[0]
                            else:
                                fname = art.FILENAMES[img_type][0].strip("*")
                            fname = img.makeFileName(name=fname)

                            if (md5File(os.path.join(path, fname)) ==
                                    md5Data(img.image_data)):
                                printMsg("Skipping writing of %s, file "
                                         "exists and is exactly the same." %
                                         fname)
                            else:
                                img_file = makeUniqueFileName(
                                    os.path.join(path, fname),
                                    uniq=img.description)
                                printWarning("Writing %s..." % img_file)
                                with open(img_file, "wb") as fp:
                                    fp.write(img.image_data)
                    else:
                        self._verbose(
                            "tag %s: unhandled image type %d (ignored)" %
                            (file_base, img.picture_type)
                        )

            # Copy file art to tags.
            if self.args.update_tags:
                assert(not self.args.update_files)
                for tag in all_tags:
                    for art_file in dir_art:
                        art_path = os.path.basename(art_file.file_path)
                        printMsg("Copying %s to tag '%s' image" %
                                 (art_path, art_file.id3_art_type))

                        descr = "filename: %s" % os.path.splitext(art_path)[0]
                        tag.images.set(art_file.id3_art_type,
                                       art_file.image_data, art_file.mime_type,
                                       description=descr)
                    tag.save()

        finally:
            # Cleans up...
            super(ArtPlugin, self).handleDirectory(d, _)
 def handleDone(self):
     """If no audio files were loaded this simply prints 'Nothing to do'."""
     if self._num_loaded == 0:
         printMsg("Nothing to do")
Example #35
0
 def handleDone(self):
     if not self._handled_one:
         printMsg("Nothing to do")
Example #36
0
    def handleDirectory(self, directory, _):
        if not self._file_cache:
            return

        directory = os.path.abspath(directory)
        print("\n" + Style.BRIGHT + Fore.GREY +
              "Scanning directory%s %s" % (Style.RESET_ALL, directory))

        def _path(af):
            return af.path

        self._handled_one = True

        # Make sure all of the audio files has a tag.
        for f in self._file_cache:
            if f.tag is None:
                f.initTag()

        audio_files = sorted(list(self._file_cache), key=_path)

        self._file_cache = []
        edited_files = set()
        self._curr_dir_type = self.args.dir_type
        if self._curr_dir_type is None:
            types = set([a.tag.album_type for a in audio_files])
            if len(types) == 1:
                self._curr_dir_type = types.pop()

        # Check for corrections to LP, EP, COMP
        if (self._curr_dir_type is None and
                    len(audio_files) < EP_MAX_SIZE_HINT):
            # Do you want EP?
            if False in [a.tag.album_type == EP_TYPE for a in audio_files]:
                if prompt("Only %d audio files, process directory as an EP" %
                          len(audio_files),
                          default=True):
                    self._curr_dir_type = EP_TYPE
            else:
                self._curr_dir_type = EP_TYPE
        elif (self._curr_dir_type in (EP_TYPE, DEMO_TYPE) and
                len(audio_files) > EP_MAX_SIZE_HINT):
            # Do you want LP?
            if prompt("%d audio files is large for type %s, process "
                      "directory as an LP" % (len(audio_files),
                                              self._curr_dir_type),
                      default=True):
                self._curr_dir_type = LP_TYPE

        last = defaultdict(lambda: None)

        album_artist = None
        artists = set()
        album = None

        if self._curr_dir_type != SINGLE_TYPE:
            album_artist, artists = self._resolveArtistInfo(audio_files)
            print(Fore.BLUE + u"Album artist: " + Style.RESET_ALL +
                  (album_artist or u""))
            print(Fore.BLUE + "Artist" + ("s" if len(artists) > 1 else "") +
                  ": " + Style.RESET_ALL + u", ".join(artists))

            album = self._getAlbum(audio_files)
            print(Fore.BLUE + "Album: " + Style.RESET_ALL + album)

            rel_date, orel_date, rec_date = self._getDates(audio_files)
            for what, d in [("Release", rel_date),
                            ("Original", orel_date),
                            ("Recording", rec_date)]:
                print(Fore.BLUE + ("%s date: " % what) + Style.RESET_ALL +
                        str(d))

            num_audio_files = len(audio_files)
            track_nums = set([f.tag.track_num[0] for f in audio_files])
            fix_track_nums = set(range(1, num_audio_files + 1)) != track_nums
            new_track_nums = []

        dir_type = self._curr_dir_type
        for f in sorted(audio_files, key=_path):
            print(Style.BRIGHT + Fore.GREEN + u"Checking" + Fore.RESET +
                  Fore.GREY + (" %s" % os.path.basename(f.path)) +
                  Style.RESET_ALL)

            if not f.tag:
                print("\tAdding new tag")
                f.initTag()
                edited_files.add(f)
            tag = f.tag

            if tag.version != ID3_V2_4:
                print("\tConverting to ID3 v2.4")
                tag.version = ID3_V2_4
                edited_files.add(f)

            if (dir_type != SINGLE_TYPE and album_artist != tag.album_artist):
                print(u"\tSetting album artist: %s" % album_artist)
                tag.album_artist = album_artist
                edited_files.add(f)

            if not tag.artist and dir_type in (VARIOUS_TYPE, SINGLE_TYPE):
                # Prompt artist
                tag.artist = prompt("Artist name", default=last["artist"])
                last["artist"] = tag.artist
            elif len(artists) == 1 and tag.artist != artists[0]:
                assert(dir_type != SINGLE_TYPE)
                print(u"\tSetting artist: %s" % artists[0])
                tag.artist = artists[0]
                edited_files.add(f)

            if tag.album != album and dir_type != SINGLE_TYPE:
                print(u"\tSetting album: %s" % album)
                tag.album = album
                edited_files.add(f)

            orig_title = tag.title
            if not tag.title:
                tag.title = prompt("Track title")
            tag.title = tag.title.strip()
            if self.args.fix_case:
                tag.title = _fixCase(tag.title)
            if orig_title != tag.title:
                print(u"\tSetting title: %s" % tag.title)
                edited_files.add(f)

            if dir_type != SINGLE_TYPE:
                # Track numbers
                tnum, ttot = tag.track_num
                update = False
                if ttot != num_audio_files:
                    update = True
                    ttot = num_audio_files

                if fix_track_nums or not (1 <= tnum <= num_audio_files):
                    tnum = None
                    while tnum is None:
                        tnum = int(prompt("Track #", type_=int))
                        if not (1 <= tnum <= num_audio_files):
                            print(Fore.RED + "Out of range: " + Fore.RESET +
                                  "1 <= %d <= %d" % (tnum, num_audio_files))
                            tnum = None
                        elif tnum in new_track_nums:
                            print(Fore.RED + "Duplicate value: " + Fore.RESET +
                                    str(tnum))
                            tnum = None
                        else:
                            update = True
                            new_track_nums.append(tnum)

                if update:
                    tag.track_num = (tnum, ttot)
                    print("\tSetting track numbers: %s" % str(tag.track_num))
                    edited_files.add(f)
            else:
                # Singles
                if tag.track_num != (None, None):
                    tag.track_num = (None, None)
                    edited_files.add(f)

            if dir_type != SINGLE_TYPE:
                # Dates
                if rec_date and tag.recording_date != rec_date:
                    print("\tSetting %s date (%s)" %
                            ("recording", str(rec_date)))
                    tag.recording_date = rec_date
                    edited_files.add(f)
                if rel_date and tag.release_date != rel_date:
                    print("\tSetting %s date (%s)" % ("release", str(rel_date)))
                    tag.release_date = rel_date
                    edited_files.add(f)
                if orel_date and tag.original_release_date != orel_date:
                    print("\tSetting %s date (%s)" % ("original release",
                                                      str(orel_date)))
                    tag.original_release_date = orel_date
                    edited_files.add(f)

            for frame in list(tag.frameiter(["USER", "PRIV"])):
                print("\tRemoving %s frames: %s" %
                        (frame.id,
                         frame.owner_id if frame.id == b"PRIV" else frame.text))
                tag.frame_set[frame.id].remove(frame)
                edited_files.add(f)

            # Add TLEN
            tlen = tag.getTextFrame("TLEN")
            real_tlen = f.info.time_secs * 1000
            if tlen is None or int(tlen) != real_tlen:
                print("\tSetting TLEN (%d)" % real_tlen)
                tag.setTextFrame("TLEN", UnicodeType(real_tlen))
                edited_files.add(f)

            # Add custom album type if special and otherwise not able to be
            # determined.
            curr_type = tag.album_type
            if curr_type != dir_type:
                print("\tSetting %s = %s" % (TXXX_ALBUM_TYPE, dir_type))
                tag.album_type = dir_type
                edited_files.add(f)

        try:
            if not self._checkCoverArt(directory, audio_files):
                if not prompt("Proceed without valid cover file", default=True):
                    return
        finally:
            self._dir_images = []

        # Determine other changes, like file and/or directory renames
        # so they can be reported before save confirmation.

        # File renaming
        file_renames = []
        if self.args.file_rename_pattern:
            format_str = self.args.file_rename_pattern
        else:
            if dir_type == SINGLE_TYPE:
                format_str = SINGLE_FNAME_FORMAT
            elif dir_type in (VARIOUS_TYPE, COMP_TYPE):
                format_str = VARIOUS_FNAME_FORMAT
            else:
                format_str = NORMAL_FNAME_FORMAT

        for f in audio_files:
            orig_name, orig_ext = os.path.splitext(os.path.basename(f.path))
            new_name = TagTemplate(format_str).substitute(f.tag, zeropad=True)
            if orig_name != new_name:
                printMsg(u"Rename file to %s%s" % (new_name, orig_ext))
                file_renames.append((f, new_name, orig_ext))

        # Directory renaming
        dir_rename = None
        if dir_type != SINGLE_TYPE:
            if self.args.dir_rename_pattern:
                dir_format = self.args.dir_rename_pattern
            else:
                if dir_type == LIVE_TYPE:
                    dir_format = LIVE_DNAME_FORMAT
                else:
                    dir_format = NORMAL_DNAME_FORMAT
            template = TagTemplate(dir_format,
                                   dotted_dates=self.args.dotted_dates)

            pref_dir = template.substitute(audio_files[0].tag, zeropad=True)
            if os.path.basename(directory) != pref_dir:
                new_dir = os.path.join(os.path.dirname(directory), pref_dir)
                printMsg("Rename directory to %s" % new_dir)
                dir_rename = (directory, new_dir)

        # Cruft files to remove
        file_removes = []
        if self._dir_files_to_remove:
            for f in self._dir_files_to_remove:
                print("Remove file: " + os.path.basename(f))
                file_removes.append(f)
        self._dir_files_to_remove = set()

        if not self.args.dry_run:
            confirmed = False

            if (edited_files or file_renames or dir_rename or file_removes):
                confirmed = prompt("\nSave changes", default=True)

            if confirmed:
                for f in edited_files:
                    print(u"Saving %s" % os.path.basename(f.path))
                    f.tag.save(version=ID3_V2_4, preserve_file_time=True)

                for f, new_name, orig_ext in file_renames:
                    printMsg(u"Renaming file to %s%s" % (new_name, orig_ext))
                    f.rename(new_name, preserve_file_time=True)

                if file_removes:
                    for f in file_removes:
                        printMsg("Removing file %s" % os.path.basename(f))
                        os.remove(f)

                if dir_rename:
                    printMsg("Renaming directory to %s" % dir_rename[1])
                    s = os.stat(dir_rename[0])
                    os.rename(dir_rename[0], dir_rename[1])
                    # With a rename use the origianl access time
                    os.utime(dir_rename[1], (s.st_atime, s.st_atime))

        else:
            printMsg("\nNo changes made (run without -n/--dry-run)")
Example #37
0
    def handleFile(self, f, *args, **kwargs):
        super().handleFile(f)

        if self.audio_file and self.audio_file.tag:
            xml = self.getXML(self.audio_file)
            printMsg(xml)
Example #38
0
 def handleDone(self):
     if not self._handled_one:
         printMsg("Nothing to do")
Example #39
0
    def handleFile(self, f):
        super(Xep118Plugin, self).handleFile(f)

        if self.audio_file and self.audio_file.tag:
            xml = self.getXML(self.audio_file)
            printMsg(xml)
Example #40
0
    def handleFile(self, f):
        parse_version = self.args.tag_version

        super(ClassicPlugin, self).handleFile(f, tag_version=parse_version)

        if not self.audio_file:
            return

        self.printHeader(f)
        printMsg("-" * 79)

        new_tag = False
        if not self.audio_file.tag or self.handleRemoves(self.audio_file.tag):
            self.audio_file.initTag(version=parse_version)
            new_tag = True

        save_tag = (
            self.handleEdits(self.audio_file.tag)
            or self.handlePadding(self.audio_file.tag)
            or self.args.force_update
            or self.args.convert_version
        )

        self.printAudioInfo(self.audio_file.info)

        if not save_tag and new_tag:
            printError("No ID3 %s tag found!" % id3.versionToString(self.args.tag_version))
            return

        self.printTag(self.audio_file.tag)

        if save_tag:
            # Use current tag version unless a convert was supplied
            version = self.args.convert_version or self.audio_file.tag.version
            printWarning("Writing ID3 version %s" % id3.versionToString(version))

            # DEFAULT_MAX_PADDING is not set up as argument default,
            # because we don't want to rewrite the file if the user
            # did not trigger that explicitly:
            max_padding = self.args.max_padding
            if max_padding is True:
                max_padding = DEFAULT_MAX_PADDING

            self.audio_file.tag.save(
                version=version,
                encoding=self.args.text_encoding,
                backup=self.args.backup,
                preserve_file_time=self.args.preserve_file_time,
                max_padding=max_padding,
            )

        if self.args.rename_pattern:
            # Handle file renaming.
            from eyed3.id3.tag import TagTemplate

            template = TagTemplate(self.args.rename_pattern)
            name = template.substitute(self.audio_file.tag, zeropad=True)
            orig = self.audio_file.path
            try:
                self.audio_file.rename(name)
                printWarning("Renamed '%s' to '%s'" % (orig, self.audio_file.path))
            except IOError as ex:
                printError(ex.message)

        printMsg("-" * 79)