def _prompt(prompt, default=None, required=True, Type=unicode): yes_no = default is True or default is False if yes_no: default_str = "Yn" if default is True else "yN" else: default_str = str(default) if default else None if default is not None: prompt = "%s [%s]" % (prompt, default_str) prompt += ": " if not yes_no else "? " resp = None while not resp: if NEVER_PROMPT: print(prompt + "\n--no-prompt in effect, exiting.") sys.exit(2) resp = raw_input(prompt).decode(LOCAL_ENCODING) if not resp: resp = default elif yes_no: resp = True if resp in ("yes", "y", "Y") else False if resp is not None: if yes_no: return bool(resp) else: try: return Type(resp) except Exception as ex: printError(str(ex)) resp = None elif not required: return None
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 handleFile(self, f, *args, **kwargs): if self.args.pattern_help: return if self.__return_code != 0: return super(DisplayPlugin, self).handleFile(f) if not self.audio_file: return try: print(self.__pattern.output_for(self.audio_file), end=self.__output_ending) except PatternCompileException as e: self.__return_code = 1 console.printError(e.message) except DisplayException as e: self.__return_code = 1 console.printError(e.message)
def handleFile(self, f, *args, **kwargs): '''Loads ``f`` and sets ``self.audio_file`` to an instance of :class:`eyed3.core.AudioFile` or ``None`` if an error occurred or the file is not a recognized type. The ``*args`` and ``**kwargs`` are passed to :func:`eyed3.core.load`. ''' self.audio_file = None try: self.audio_file = core.load(f, *args, **kwargs) except NotImplementedError as ex: # Frame decryption, for instance... printError(str(ex)) return if self.audio_file: self._num_loaded += 1 if self._file_cache is not None: self._file_cache.append(self.audio_file)
def start(self, args, config): super(DisplayPlugin, self).start(args, config) if args.pattern_help: self.__print_pattern_help() return if not _have_grako: console.printError(u"Unknown module 'grako'" + os.linesep + u"Please install grako! " + u"E.g. $ pip install grako") self.__return_code = 2 return if args.pattern_string is not None: self.__pattern = Pattern(args.pattern_string) if args.pattern_file is not None: pfile = open(args.pattern_file, "r") self.__pattern = Pattern(''.join(pfile.read().splitlines())) pfile.close() self.__output_ending = "" if args.no_newline else os.linesep
def _run(self): session = self.db_session _output = [] def _addOutput(_k, _v): _output.append(tuple((_k, _v))) def _printOutput(_format, _olist, key_fg=None): k_width = max([len(k) for k, v in _olist if k]) for k, v in _olist: print(_format % (cformat(k.ljust(k_width), key_fg), v) if k else "") _olist.clear() cprint(figlet_format("``MishMash``", font="graffiti"), Fore.GREEN, styles=[Style.BRIGHT]) _addOutput("Version", version) _addOutput("Database URL", self.config.db_url) try: meta = session.query(Meta).one() except (ProgrammingError, OperationalError) as ex: printError("\nError querying metadata. Database may not be " "initialized: %s" % str(ex)) return 1 _addOutput("Database version", meta.version) _addOutput("Last sync", meta.last_sync or "Never") _addOutput("Configuration file ", self.args.config.filename or "None") _printOutput("%s : %s", _output, key_fg=Fore.BLUE) _addOutput(None, None) for name, orm_type in [("tracks", Track), ("artists", Artist), ("albums", Album), ("tags", Tag), ]: count = session.query(orm_type).count() _addOutput(str(count), name) _printOutput("%s music %s", _output)
def handleFile(self, f, *args, **kwargs): """Loads ``f`` and sets ``self.audio_file`` to an instance of :class:`eyed3.core.AudioFile` or ``None`` if an error occurred or the file is not a recognized type. The ``*args`` and ``**kwargs`` are passed to :func:`eyed3.core.load`. """ self.audio_file = None try: self.audio_file = core.load(f, *args, **kwargs) except NotImplementedError as ex: # Frame decryption, for instance... printError(str(ex)) return if self.audio_file: self._num_loaded += 1 if self._file_cache is not None: self._file_cache.append(self.audio_file) elif self._dir_images is not None: mt = guessMimetype(f) if mt and mt.startswith("image/"): self._dir_images.append(f)
def handleFile(self, f, *args, **kwargs): '''Loads ``f`` and sets ``self.audio_file`` to an instance of :class:`eyed3.core.AudioFile` or ``None`` if an error occurred or the file is not a recognized type. The ``*args`` and ``**kwargs`` are passed to :func:`eyed3.core.load`. ''' self.audio_file = None try: self.audio_file = core.load(f, *args, **kwargs) except NotImplementedError as ex: # Frame decryption, for instance... printError(str(ex)) return if self.audio_file: self._num_loaded += 1 if self._file_cache is not None: self._file_cache.append(self.audio_file) elif self._dir_images is not None: mt = guessMimetype(f) if mt and mt.startswith("image/"): self._dir_images.append(f)
from __future__ import print_function import os import re import abc from argparse import ArgumentTypeError from eyed3 import id3 from eyed3.utils import console, formatSize, formatTime from eyed3.plugins import LoaderPlugin try: from eyed3.plugins._display_parser import DisplayPatternParser _have_grako = True except ImportError: _have_grako = False console.printError(u"Unknown module 'grako'" + os.linesep + u"Please install grako! E.g. with $ pip install grako") class Pattern(object): def __init__(self, text=None, sub_patterns=None): self.__text = text self.__sub_patterns = sub_patterns def output_for(self, audio_file): output = u"" for sub_pattern in self.sub_patterns or []: output += sub_pattern.output_for(audio_file) return output def __get_sub_patterns(self): if self.__sub_patterns is None and self.__text is not None:
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 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)