def handleFile(self, f): super().handleFile(f) if len(self.args.paths) != 1: printError('Autotag operates on only a single album at a time') return # set album metadata once if self.meta is None: # ensure args is set in classic plugin self.classic.args = self.args # handle current directoty notation if self.args.paths[0] == '.': path = os.getcwd() else: path = self.args.paths[0] try: # extract album metadata from directory name self.parseDirectoryName(path) except AppException as e: printError(str(e)) sys.exit(1) if not self.audio_file: if os.path.basename(f) != 'folder.jpg': printWarning('Unknown type: {}'.format(os.path.basename(f))) else: track_num, artist, title = self.smart_split(os.path.basename(f)) self.tagFile(os.path.basename(f), track_num, artist, title)
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)
def test_printWarning(): eyed3.utils.console.USE_ANSI = False with RedirectStdStreams() as out: printWarning("Built To Spill") assert_equal(out.stderr.read(), "Built To Spill\n") eyed3.utils.console.USE_ANSI = True with RedirectStdStreams() as out: printWarning("Built To Spill") assert_equal(out.stderr.read(), "%sBuilt To Spill%s\n" % (WARNING_COLOR(), Fore.RESET))
def test_printWarning(): eyed3.utils.console.USE_ANSI = False with RedirectStdStreams() as out: printWarning("Built To Spill") assert (out.stdout.read() == "Built To Spill\n") eyed3.utils.console.USE_ANSI = True with RedirectStdStreams() as out: printWarning("Built To Spill") assert (out.stdout.read() == "%sBuilt To Spill%s\n" % (WARNING_COLOR(), Fore.RESET))
def handleRemoves(self, tag): remove_version = 0 status = False rm_str = "" if self.args.remove_all: remove_version = id3.ID3_ANY_VERSION rm_str = "v1.x and/or v2.x" elif self.args.remove_v1: remove_version = id3.ID3_V1 rm_str = "v1.x" elif self.args.remove_v2: remove_version = id3.ID3_V2 rm_str = "v2.x" if remove_version: status = id3.Tag.remove(tag.file_info.name, remove_version) printWarning("Removing ID3 %s tag: %s" % (rm_str, "SUCCESS" if status else "FAIL")) return status
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, _)
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 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, _)
def handleEdits(self, tag): retval = False # --remove-all-*, Handling removes first means later options are still # applied for what, arg, fid in (("comments", self.args.remove_all_comments, id3.frames.COMMENT_FID), ("lyrics", self.args.remove_all_lyrics, id3.frames.LYRICS_FID), ("images", self.args.remove_all_images, id3.frames.IMAGE_FID), ("objects", self.args.remove_all_objects, id3.frames.OBJECT_FID), ): if arg and tag.frame_set[fid]: printWarning("Removing all %s..." % what) del tag.frame_set[fid] retval = True # --artist, --title, etc. All common/simple text frames. for (what, arg, setFunc) in ( ("artist", self.args.artist, tag._setArtist), ("album", self.args.album, tag._setAlbum), ("title", self.args.title, tag._setTitle), ("genre", self.args.genre, tag._setGenre), ("release date", self.args.release_date, tag._setReleaseDate), ("original release date", self.args.orig_release_date, tag._setOrigReleaseDate), ("recording date", self.args.recording_date, tag._setRecordingDate), ("encoding date", self.args.encoding_date, tag._setEncodingDate), ("tagging date", self.args.tagging_date, tag._setTaggingDate), ("beats per minute", self.args.bpm, tag._setBpm), ("publisher", self.args.publisher, tag._setPublisher), ): if arg is not None: printWarning("Setting %s: %s" % (what, arg)) setFunc(arg or None) retval = True def _checkNumberedArgTuples(curr, new): n = None if new not in [(None, None), curr]: n = [None] * 2 for i in (0, 1): if new[i] == 0: n[i] = None else: n[i] = new[i] or curr[i] n = tuple(n) # Returing None means do nothing, (None, None) would clear both vals return n # --track, --track-total track_info = _checkNumberedArgTuples(tag.track_num, (self.args.track, self.args.track_total)) if track_info is not None: printWarning("Setting track info: %s" % str(track_info)) tag.track_num = track_info retval = True # --disc-num, --disc-total disc_info = _checkNumberedArgTuples(tag.disc_num, (self.args.disc_num, self.args.disc_total)) if disc_info is not None: printWarning("Setting disc info: %s" % str(disc_info)) tag.disc_num = disc_info retval = True # -Y, --release-year if self.args.release_year is not None: # empty string means clean, None means not given year = self.args.release_year printWarning("Setting release year: %s" % year) tag.release_date = int(year) if year else None retval = True # -c , simple comment if self.args.simple_comment: # Just add it as if it came in --add-comment self.args.comments.append((self.args.simple_comment, u"", id3.DEFAULT_LANG)) # --remove-comment, remove-lyrics, --remove-image, --remove-object for what, arg, accessor in (("comment", self.args.remove_comment, tag.comments), ("lyrics", self.args.remove_lyrics, tag.lyrics), ("image", self.args.remove_image, tag.images), ("object", self.args.remove_object, tag.objects), ): for vals in arg: frame = accessor.remove(*vals) if frame: printWarning("Removed %s %s" % (what, str(vals))) retval = True else: printError("Removing %s failed, %s not found" % (what, str(vals))) # --add-comment, --add-lyrics for what, arg, accessor in (("comment", self.args.comments, tag.comments), ("lyrics", self.args.lyrics, tag.lyrics), ): for text, desc, lang in arg: printWarning("Setting %s: %s/%s" % (what, desc, lang)) accessor.set(text, desc, lang) retval = True # --play-count playcount_arg = self.args.play_count if playcount_arg: increment, pc = playcount_arg if increment: printWarning("Incrementing play count by %d" % pc) tag.play_count += pc else: printWarning("Setting play count to %d" % pc) tag.play_count = pc retval = True # --add-popularty for email, rating, play_count in self.args.popularities: tag.popularities.set(email, rating, play_count) retval = True # --remove-popularity for email in self.args.remove_popularity: popm = tag.popularities.remove(email) if popm: retval = True # --text-frame, --url-frame for what, arg, setter in ( ("text frame", self.args.text_frames, tag.setTextFrame), ("url frame", self.args.url_frames, tag._setUrlFrame), ): for fid, text in arg: if text: printWarning("Setting %s %s to '%s'" % (fid, what, text)) else: printWarning("Removing %s %s" % (fid, what)) setter(fid, text) retval = True # --user-text-frame, --user-url-frame for what, arg, accessor in ( ("user text frame", self.args.user_text_frames, tag.user_text_frames), ("user url frame", self.args.user_url_frames, tag.user_url_frames), ): for desc, text in arg: if text: printWarning("Setting '%s' %s to '%s'" % (desc, what, text)) accessor.set(text, desc) else: printWarning("Removing '%s' %s" % (desc, what)) accessor.remove(desc) retval = True # --add-image for img_path, img_type, img_mt, img_desc in self.args.images: assert(img_path) printWarning("Adding image %s" % img_path) if img_mt != ImageFrame.URL_MIME_TYPE: with open(img_path, "rb") as img_fp: tag.images.set(img_type, img_fp.read(), img_mt, img_desc) else: tag.images.set(img_type, None, None, img_desc, img_url=img_path) retval = True # --add-object for obj_path, obj_mt, obj_desc, obj_fname in self.args.objects or []: assert(obj_path) printWarning("Adding object %s" % obj_path) with open(obj_path, "rb") as obj_fp: tag.objects.set(obj_fp.read(), obj_mt, obj_desc, obj_fname) retval = True # --unique-file-id for arg in self.args.unique_file_ids: owner_id, id = arg if not id: if tag.unique_file_ids.remove(owner_id): printWarning("Removed unique file ID '%s'" % owner_id) retval = True else: printWarning("Unique file ID '%s' not found" % owner_id) else: tag.unique_file_ids.set(id, owner_id) printWarning("Setting unique file ID '%s' to %s" % (owner_id, id)) retval = True # --remove-frame for fid in self.args.remove_fids: if fid in tag.frame_set: del tag.frame_set[fid] retval = True return retval
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)))
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, _)
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)