Example #1
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

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

            new_tag = False
            if (not self.audio_file.tag
                    or self.handleRemoves(self.audio_file.tag)):
                # No tag, but there might be edit options coming.
                self.audio_file.tag = id3.Tag()
                self.audio_file.tag.file_info = id3.FileInfo(f)
                self.audio_file.tag.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)

            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
                self.audio_file.rename(name)
                printWarning("Renamed '%s' to '%s'" %
                             (orig, self.audio_file.path))
            printMsg("-" * 79)
        except exceptions.Exception as ex:
            log.error(traceback.format_exc())
            if self.args.debug_pdb:
                import pdb
                pdb.set_trace()
            raise StopIteration()
Example #2
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

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

            new_tag = False
            if (not self.audio_file.tag or
                    self.handleRemoves(self.audio_file.tag)):
                # No tag, but there might be edit options coming.
                self.audio_file.tag = id3.Tag()
                self.audio_file.tag.file_info = id3.FileInfo(f)
                self.audio_file.tag.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)

            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
                self.audio_file.rename(name)
                printWarning("Renamed '%s' to '%s'" % (orig,
                                                       self.audio_file.path))
            printMsg("-" * 79)
        except exceptions.Exception as ex:
            printError("Error: %s" % ex)
            log.error(traceback.format_exc())
            if self.args.debug_pdb:
                import pdb; pdb.set_trace()
            raise StopIteration()
Example #3
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 #4
0
def _getTemplateKeys():
    from eyed3.id3.tag import TagTemplate

    keys = list(TagTemplate("")._makeMapping(None, False).keys())
    keys.sort()
    return ", ".join(["$%s" % v for v in keys])
Example #5
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 #6
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 #7
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 #8
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)