def _move_additional_files(self, old_filename, new_filename): """Move extra files, like playlists...""" old_path = encode_filename(os.path.dirname(old_filename)) new_path = encode_filename(os.path.dirname(new_filename)) patterns = encode_filename(config.setting["move_additional_files_pattern"]) patterns = filter(bool, [p.strip() for p in patterns.split()]) try: names = os.listdir(old_path) except os.error: log.error("Error: {} directory not found".format(old_path)) return filtered_names = filter(lambda x: x[0] != '.', names) for pattern in patterns: pattern_regex = re.compile(fnmatch.translate(pattern), re.IGNORECASE) file_names = names if pattern[0] != '.': file_names = filtered_names for old_file in file_names: if pattern_regex.match(old_file): new_file = os.path.join(new_path, old_file) old_file = os.path.join(old_path, old_file) # FIXME we shouldn't do this from a thread! if self.tagger.files.get(decode_filename(old_file)): log.debug("File loaded in the tagger, not moving %r", old_file) continue log.debug("Moving %r to %r", old_file, new_file) shutil.move(old_file, new_file)
def _save(self, filename, metadata): """Save metadata to the file.""" log.debug("Saving file %r", filename) try: tags = mutagen.apev2.APEv2(encode_filename(filename)) except mutagen.apev2.APENoHeaderError: tags = mutagen.apev2.APEv2() if config.setting["clear_existing_tags"]: tags.clear() elif metadata.images_to_be_saved_to_tags: for name, value in tags.items(): if name.lower().startswith('cover art') and value.kind == mutagen.apev2.BINARY: del tags[name] temp = {} for name, value in metadata.items(): if name.startswith("~"): continue if name.startswith('lyrics:'): name = 'Lyrics' elif name == "date": name = "Year" # tracknumber/totaltracks => Track elif name == 'tracknumber': name = 'Track' if 'totaltracks' in metadata: value = '%s/%s' % (value, metadata['totaltracks']) # discnumber/totaldiscs => Disc elif name == 'discnumber': name = 'Disc' if 'totaldiscs' in metadata: value = '%s/%s' % (value, metadata['totaldiscs']) elif name in ('totaltracks', 'totaldiscs'): continue # "performer:Piano=Joe Barr" => "Performer=Joe Barr (Piano)" elif name.startswith('performer:') or name.startswith('comment:'): name, desc = name.split(':', 1) name = name.title() if desc: value += ' (%s)' % desc elif name in self.__rtranslate: name = self.__rtranslate[name] else: name = name.title() temp.setdefault(name, []).append(value) for name, values in temp.items(): tags[str(name)] = values for image in metadata.images_to_be_saved_to_tags: cover_filename = 'Cover Art (Front)' cover_filename += image.extension tags['Cover Art (Front)'] = mutagen.apev2.APEValue(cover_filename + '\0' + image.data, mutagen.apev2.BINARY) break # can't save more than one item with the same name # (mp3tags does this, but it's against the specs) self._remove_deleted_tags(metadata, tags) tags.save(encode_filename(filename))
def _save(self, filename, metadata): """Save metadata to the file.""" log.debug("Saving file %r", filename) try: tags = mutagen.apev2.APEv2(encode_filename(filename)) except mutagen.apev2.APENoHeaderError: tags = mutagen.apev2.APEv2() if config.setting["clear_existing_tags"]: tags.clear() elif metadata.images_to_be_saved_to_tags: for name, value in tags.items(): if name.lower().startswith("cover art") and value.kind == mutagen.apev2.BINARY: del tags[name] temp = {} for name, value in metadata.items(): if name.startswith("~"): continue if name.startswith("lyrics:"): name = "Lyrics" elif name == "date": name = "Year" # tracknumber/totaltracks => Track elif name == "tracknumber": name = "Track" if "totaltracks" in metadata: value = "%s/%s" % (value, metadata["totaltracks"]) # discnumber/totaldiscs => Disc elif name == "discnumber": name = "Disc" if "totaldiscs" in metadata: value = "%s/%s" % (value, metadata["totaldiscs"]) elif name in ("totaltracks", "totaldiscs"): continue # "performer:Piano=Joe Barr" => "Performer=Joe Barr (Piano)" elif name.startswith("performer:") or name.startswith("comment:"): name, desc = name.split(":", 1) name = name.title() if desc: value += " (%s)" % desc elif name in self.__rtranslate: name = self.__rtranslate[name] else: name = name.title() temp.setdefault(name, []).append(value) for name, values in temp.items(): tags[str(name)] = values for image in metadata.images_to_be_saved_to_tags: cover_filename = "Cover Art (Front)" cover_filename += image.extension tags["Cover Art (Front)"] = mutagen.apev2.APEValue(cover_filename + "\0" + image.data, mutagen.apev2.BINARY) break # can't save more than one item with the same name # (mp3tags does this, but it's against the specs) tags.save(encode_filename(filename))
def _next_filename(self, filename, counters): if counters[filename]: new_filename = "%s (%d)" % (decode_filename(filename), counters[filename]) else: new_filename = filename counters[filename] += 1 return encode_filename(new_filename)
def drop_urls(urls, target): files = [] new_files = [] for url in urls: if url.scheme() == "file" or not url.scheme(): # Dropping a file from iTunes gives a filename with a NULL terminator filename = os.path.normpath( os.path.realpath(unicode(url.toLocalFile()).rstrip("\0"))) file = BaseTreeView.tagger.files.get(filename) if file: files.append(file) elif os.path.isdir(encode_filename(filename)): BaseTreeView.tagger.add_directory(filename) else: new_files.append(filename) elif url.scheme() in ("http", "https"): path = unicode(url.path()) match = re.search(r"/(release|recording)/([0-9a-z\-]{36})", path) if match: entity = match.group(1) mbid = match.group(2) if entity == "release": BaseTreeView.tagger.load_album(mbid) elif entity == "recording": BaseTreeView.tagger.load_nat(mbid) if files: BaseTreeView.tagger.move_files(files, target) if new_files: BaseTreeView.tagger.add_files(new_files, target=target)
def drop_urls(urls, target): files = [] new_files = [] for url in urls: log.debug("Dropped the URL: %r", url.toString(QtCore.QUrl.RemoveUserInfo)) if url.scheme() == "file" or not url.scheme(): filename = os.path.normpath(os.path.realpath(url.toLocalFile().rstrip("\0"))) file = BaseTreeView.tagger.files.get(filename) if file: files.append(file) elif os.path.isdir(encode_filename(filename)): BaseTreeView.tagger.add_directory(filename) else: new_files.append(filename) elif url.scheme() in ("http", "https"): path = url.path() match = re.search(r"/(release|recording)/([0-9a-z\-]{36})", path) if match: entity = match.group(1) mbid = match.group(2) if entity == "release": BaseTreeView.tagger.load_album(mbid) elif entity == "recording": BaseTreeView.tagger.load_nat(mbid) if files: BaseTreeView.tagger.move_files(files, target) if new_files: BaseTreeView.tagger.add_files(new_files, target=target)
def format_file_info(file_): info = [] info.append((_('Filename:'), file_.filename)) if '~format' in file_.orig_metadata: info.append((_('Format:'), file_.orig_metadata['~format'])) try: size = os.path.getsize(encode_filename(file_.filename)) sizestr = "%s (%s)" % (bytes1human.decimal(size), bytes2human.binary(size)) info.append((_('Size:'), sizestr)) except: pass if file_.orig_metadata.length: info.append((_('Length:'), format_time(file_.orig_metadata.length))) if '~bitrate' in file_.orig_metadata: info.append( (_('Bitrate:'), '%s kbps' % file_.orig_metadata['~bitrate'])) if '~sample_rate' in file_.orig_metadata: info.append( (_('Sample rate:'), '%s Hz' % file_.orig_metadata['~sample_rate'])) if '~bits_per_sample' in file_.orig_metadata: info.append((_('Bits per sample:'), str(file_.orig_metadata['~bits_per_sample']))) if '~channels' in file_.orig_metadata: ch = file_.orig_metadata['~channels'] if ch == '1': ch = _('Mono') elif ch == '2': ch = _('Stereo') info.append((_('Channels:'), ch)) return '<br/>'.join( map(lambda i: '<b>%s</b> %s' % (htmlescape(i[0]), htmlescape(i[1])), info))
def _save_images(self, filename, metadata, settings): """Save the cover images to disk.""" if not metadata.images: return overwrite = settings["save_images_overwrite"] image_filename = self._script_to_filename( settings["cover_image_filename"], metadata, settings) if not image_filename: image_filename = "cover" if os.path.isabs(image_filename): filename = image_filename else: filename = os.path.join(os.path.dirname(filename), image_filename) if settings['windows_compatible_filenames'] or sys.platform == 'win32': filename = filename.replace('./', '_/').replace('.\\', '_\\') filename = encode_filename(filename) i = 0 for mime, data in metadata.images: image_filename = filename ext = mimetype.get_extension(mime, ".jpg") if i > 0: image_filename = "%s (%d)" % (filename, i) i += 1 while os.path.exists(image_filename + ext) and not overwrite: if os.path.getsize(image_filename + ext) == len(data): self.log.debug("Identical file size, not saving %r", image_filename) break image_filename = "%s (%d)" % (filename, i) i += 1 else: self.log.debug("Saving cover images to %r", image_filename) f = open(image_filename + ext, "wb") f.write(data) f.close()
def _save(self, filename, metadata): log.debug("Saving file %r", filename) file = ASF(encode_filename(filename)) if config.setting["clear_existing_tags"]: file.tags.clear() if config.setting["save_images_to_tags"]: cover = [] for image in metadata.images: if not save_this_image_to_tags(image): continue tag_data = pack_image(image["mime"], image["data"], image_type_as_id3_num(image["type"]), image["desc"]) cover.append(ASFByteArrayAttribute(tag_data)) if cover: file.tags["WM/Picture"] = cover for name, values in metadata.rawitems(): if name.startswith("lyrics:"): name = "lyrics" elif name == "~rating": values[0] = int(values[0]) * 99 / (config.setting["rating_steps"] - 1) if name not in self.__TRANS: continue name = self.__TRANS[name] file.tags[name] = map(unicode, values) file.save()
def _display_info_tab(self): file = self.obj info = [] info.append((_('Filename:'), file.filename)) if '~format' in file.orig_metadata: info.append((_('Format:'), file.orig_metadata['~format'])) try: size = os.path.getsize(encode_filename(file.filename)) if size < 1024: size = '%d B' % size elif size < 1024 * 1024: size = '%0.1f kB' % (size / 1024.0) else: size = '%0.1f MB' % (size / 1024.0 / 1024.0) info.append((_('Size:'), size)) except: pass if file.orig_metadata.length: info.append((_('Length:'), format_time(file.orig_metadata.length))) if '~bitrate' in file.orig_metadata: info.append((_('Bitrate:'), '%s kbps' % file.orig_metadata['~bitrate'])) if '~sample_rate' in file.orig_metadata: info.append((_('Sample rate:'), '%s Hz' % file.orig_metadata['~sample_rate'])) if '~bits_per_sample' in file.orig_metadata: info.append((_('Bits per sample:'), str(file.orig_metadata['~bits_per_sample']))) if '~channels' in file.orig_metadata: ch = file.orig_metadata['~channels'] if ch == 1: ch = _('Mono') elif ch == 2: ch = _('Stereo') else: ch = str(ch) info.append((_('Channels:'), ch)) text = '<br/>'.join(map(lambda i: '<b>%s</b><br/>%s' % i, info)) self.ui.info.setText(text)
def _save(self, filename, metadata): log.debug("Saving file %r", filename) file = ASF(encode_filename(filename)) tags = file.tags if config.setting['clear_existing_tags']: tags.clear() cover = [] for image in metadata.images_to_be_saved_to_tags: tag_data = pack_image(image.mimetype, image.data, image_type_as_id3_num(image.maintype), image.comment) cover.append(ASFByteArrayAttribute(tag_data)) if cover: tags['WM/Picture'] = cover for name, values in metadata.rawitems(): if name.startswith('lyrics:'): name = 'lyrics' elif name == '~rating': values[0] = int( values[0]) * 99 // (config.setting['rating_steps'] - 1) elif name == 'discnumber' and 'totaldiscs' in metadata: values[0] = '%s/%s' % (metadata['discnumber'], metadata['totaldiscs']) if name not in self.__TRANS: continue name = self.__TRANS[name] tags[name] = values self._remove_deleted_tags(metadata, tags) file.save()
def format_file_info(file_): info = [] info.append((_('Filename:'), file_.filename)) if '~format' in file_.orig_metadata: info.append((_('Format:'), file_.orig_metadata['~format'])) try: size = os.path.getsize(encode_filename(file_.filename)) sizestr = "%s (%s)" % (bytes1human.decimal(size), bytes2human.binary(size)) info.append((_('Size:'), sizestr)) except BaseException: pass if file_.orig_metadata.length: info.append((_('Length:'), format_time(file_.orig_metadata.length))) if '~bitrate' in file_.orig_metadata: info.append((_('Bitrate:'), '%s kbps' % file_.orig_metadata['~bitrate'])) if '~sample_rate' in file_.orig_metadata: info.append((_('Sample rate:'), '%s Hz' % file_.orig_metadata['~sample_rate'])) if '~bits_per_sample' in file_.orig_metadata: info.append((_('Bits per sample:'), str(file_.orig_metadata['~bits_per_sample']))) if '~channels' in file_.orig_metadata: ch = file_.orig_metadata['~channels'] if ch == '1': ch = _('Mono') elif ch == '2': ch = _('Stereo') info.append((_('Channels:'), ch)) return '<br/>'.join(map(lambda i: '<b>%s</b> %s' % (htmlescape(i[0]), htmlescape(i[1])), info))
def _save(self, filename, metadata, settings): self.log.debug("Saving file %r", filename) file = ASF(encode_filename(filename)) if settings['clear_existing_tags']: file.tags.clear() if settings['save_images_to_tags']: cover = [] for image in metadata.images: if self.config.setting["save_only_front_images_to_tags"] and image["type"] != "front": continue imagetype = ID3_IMAGE_TYPE_MAP.get(image["type"], 0) tag_data = pack_image(image["mime"], image["data"], imagetype, image["description"]) cover.append(ASFByteArrayAttribute(tag_data)) if cover: file.tags['WM/Picture'] = cover for name, values in metadata.rawitems(): if name.startswith('lyrics:'): name = 'lyrics' elif name == '~rating': values[0] = int(values[0]) * 99 / (settings['rating_steps'] - 1) if name not in self.__TRANS: continue name = self.__TRANS[name] file.tags[name] = map(unicode, values) file.save()
def _shorten_to_bytes_length(text, length): """Truncates a unicode object to the given number of bytes it would take when encoded in the "filesystem encoding". """ assert isinstance(text, str), "This function only works on unicode" raw = encode_filename(text) # maybe there's no need to truncate anything if len(raw) <= length: return text # or maybe there's nothing multi-byte here if len(raw) == len(text): return text[:length] # if we're dealing with utf-8, we can use an efficient algorithm # to deal with character boundaries if _re_utf8.match(_io_encoding): i = length # a UTF-8 intermediate byte starts with the bits 10xxxxxx, # so ord(char) & 0b11000000 = 0b10000000 while i > 0 and (raw[i] & 0xC0) == 0x80: i -= 1 return decode_filename(raw[:i]) # finally, a brute force approach i = length while i > 0: try: return decode_filename(raw[:i]) except UnicodeDecodeError: pass i -= 1 # hmm. we got here? return ""
def _load(self, filename): log.debug("Loading file %r", filename) file = ASF(encode_filename(filename)) metadata = Metadata() for name, values in file.tags.items(): if name == 'WM/Picture': for image in values: (mime, data, type, description) = unpack_image(image.value) try: coverartimage = TagCoverArtImage( file=filename, tag=name, types=types_from_id3(type), comment=description, support_types=True, data=data, ) except CoverArtImageError as e: log.error('Cannot load image from %r: %s' % (filename, e)) else: metadata.append_image(coverartimage) continue elif name not in self.__RTRANS: continue elif name == 'WM/SharedUserRating': # Rating in WMA ranges from 0 to 99, normalize this to the range 0 to 5 values[0] = int(round(int(unicode(values[0])) / 99.0 * (config.setting['rating_steps'] - 1))) name = self.__RTRANS[name] values = filter(bool, map(unicode, values)) if values: metadata[name] = values self._info(metadata, file) return metadata
def _save(self, filename, metadata): log.debug("Saving file %r", filename) file = ASF(encode_filename(filename)) if config.setting['clear_existing_tags']: file.tags.clear() cover = [] for image in metadata.images_to_be_saved_to_tags: tag_data = pack_image(image.mimetype, image.data, image_type_as_id3_num(image.maintype), image.comment) cover.append(ASFByteArrayAttribute(tag_data)) if cover: file.tags['WM/Picture'] = cover for name, values in metadata.rawitems(): if name.startswith('lyrics:'): name = 'lyrics' elif name == '~rating': values[0] = int(values[0]) * 99 / (config.setting['rating_steps'] - 1) elif name == 'discnumber' and 'totaldiscs' in metadata: values[0] = '%s/%s' % (metadata['discnumber'], metadata['totaldiscs']) if name not in self.__TRANS: continue name = self.__TRANS[name] file.tags[name] = map(unicode, values) file.save()
def _load(self, filename): log.debug("Loading file %r", filename) file = ASF(encode_filename(filename)) metadata = Metadata() for name, values in file.tags.items(): if name == 'WM/Picture': for image in values: (mime, data, type, description) = unpack_image(image.value) extras = { 'desc': description, 'type': image_type_from_id3_num(type) } metadata.add_image(mime, data, extras=extras) continue elif name not in self.__RTRANS: continue elif name == 'WM/SharedUserRating': # Rating in WMA ranges from 0 to 99, normalize this to the range 0 to 5 values[0] = int(round(int(unicode(values[0])) / 99.0 * (config.setting['rating_steps'] - 1))) name = self.__RTRANS[name] values = filter(bool, map(unicode, values)) if values: metadata[name] = values self._info(metadata, file) return metadata
def _display_info_tab(self): file = self.obj info = [] info.append((_('Filename:'), file.filename)) if '~format' in file.orig_metadata: info.append((_('Format:'), file.orig_metadata['~format'])) try: size = os.path.getsize(encode_filename(file.filename)) sizestr = "%s (%s)" % (bytes2human.decimal(size), bytes2human.binary(size)) info.append((_('Size:'), sizestr)) except: pass if file.orig_metadata.length: info.append((_('Length:'), format_time(file.orig_metadata.length))) if '~bitrate' in file.orig_metadata: info.append((_('Bitrate:'), '%s kbps' % file.orig_metadata['~bitrate'])) if '~sample_rate' in file.orig_metadata: info.append((_('Sample rate:'), '%s Hz' % file.orig_metadata['~sample_rate'])) if '~bits_per_sample' in file.orig_metadata: info.append((_('Bits per sample:'), str(file.orig_metadata['~bits_per_sample']))) if '~channels' in file.orig_metadata: ch = file.orig_metadata['~channels'] if ch == 1: ch = _('Mono') elif ch == 2: ch = _('Stereo') else: ch = str(ch) info.append((_('Channels:'), ch)) text = '<br/>'.join(map(lambda i: '<b>%s</b><br/>%s' % (cgi.escape(i[0]), cgi.escape(i[1])), info)) self.ui.info.setText(text)
def drop_urls(urls, target): files = [] new_files = [] for url in urls: if url.scheme() == "file" or not url.scheme(): # Dropping a file from iTunes gives a filename with a NULL terminator filename = os.path.normpath(os.path.realpath(unicode(url.toLocalFile()).rstrip("\0"))) file = BaseTreeView.tagger.files.get(filename) if file: files.append(file) elif os.path.isdir(encode_filename(filename)): BaseTreeView.tagger.add_directory(filename) else: new_files.append(filename) elif url.scheme() in ("http", "https"): path = unicode(url.path()) match = re.search(r"/(release|recording)/([0-9a-z\-]{36})", path) if match: entity = match.group(1) mbid = match.group(2) if entity == "release": BaseTreeView.tagger.load_album(mbid) elif entity == "recording": BaseTreeView.tagger.load_nat(mbid) if files: BaseTreeView.tagger.move_files(files, target) if new_files: BaseTreeView.tagger.add_files(new_files, target=target)
def _save(self, filename, metadata): log.debug("Saving file %r", filename) file = ASF(encode_filename(filename)) if config.setting['clear_existing_tags']: file.tags.clear() if config.setting['save_images_to_tags']: cover = [] for image in metadata.images: if not save_this_image_to_tags(image): continue tag_data = pack_image(image.mimetype, image.data, image_type_as_id3_num(image.maintype()), image.description) cover.append(ASFByteArrayAttribute(tag_data)) if cover: file.tags['WM/Picture'] = cover for name, values in metadata.rawitems(): if name.startswith('lyrics:'): name = 'lyrics' elif name == '~rating': values[0] = int(values[0]) * 99 / (config.setting['rating_steps'] - 1) if name not in self.__TRANS: continue name = self.__TRANS[name] file.tags[name] = map(unicode, values) file.save()
def _shorten_to_bytes_length(text, length): """Truncates a unicode object to the given number of bytes it would take when encoded in the "filesystem encoding". """ assert isinstance(text, unicode), "This function only works on unicode" raw = encode_filename(text) # maybe there's no need to truncate anything if len(raw) <= length: return text # or maybe there's nothing multi-byte here if len(raw) == len(text): return text[:length] # if we're dealing with utf-8, we can use an efficient algorithm # to deal with character boundaries if _re_utf8.match(_io_encoding): i = length # a UTF-8 intermediate byte starts with the bits 10xxxxxx, # so ord(char) & 0b11000000 = 0b10000000 while i > 0 and (ord(raw[i]) & 0xC0) == 0x80: i -= 1 return decode_filename(raw[:i]) # finally, a brute force approach i = length while i > 0: try: return decode_filename(raw[:i]) except UnicodeDecodeError: pass i -= 1 # hmm. we got here? return u""
def _save(self, filename, metadata): log.debug("Saving file %r", filename) file = MP4(encode_filename(self.filename)) if file.tags is None: file.add_tags() if config.setting["clear_existing_tags"]: file.tags.clear() for name, values in metadata.rawitems(): if name.startswith('lyrics:'): name = 'lyrics' if name in self.__r_text_tags: file.tags[self.__r_text_tags[name]] = values elif name in self.__r_bool_tags: file.tags[self.__r_bool_tags[name]] = (values[0] == '1') elif name in self.__r_int_tags: try: file.tags[self.__r_int_tags[name]] = [ int(value) for value in values ] except ValueError: pass elif name in self.__r_freeform_tags: values = [v.encode("utf-8") for v in values] file.tags[self.__r_freeform_tags[name]] = values elif name == "musicip_fingerprint": file.tags["----:com.apple.iTunes:fingerprint"] = [ "MusicMagic Fingerprint%s" % str(v) for v in values ] if "tracknumber" in metadata: if "totaltracks" in metadata: file.tags["trkn"] = [(int(metadata["tracknumber"]), int(metadata["totaltracks"]))] else: file.tags["trkn"] = [(int(metadata["tracknumber"]), 0)] if "discnumber" in metadata: if "totaldiscs" in metadata: file.tags["disk"] = [(int(metadata["discnumber"]), int(metadata["totaldiscs"]))] else: file.tags["disk"] = [(int(metadata["discnumber"]), 0)] if config.setting['save_images_to_tags']: covr = [] for image in metadata.images: if not save_this_image_to_tags(image): continue mime = image["mime"] if mime == "image/jpeg": covr.append(MP4Cover(image["data"], MP4Cover.FORMAT_JPEG)) elif mime == "image/png": covr.append(MP4Cover(image["data"], MP4Cover.FORMAT_PNG)) if covr: file.tags["covr"] = covr file.save()
def _save(self, filename, metadata): log.debug("Saving file %r", filename) file = MP4(encode_filename(self.filename)) tags = file.tags if tags is None: file.add_tags() if config.setting["clear_existing_tags"]: tags.clear() for name, values in metadata.rawitems(): if name.startswith('lyrics:'): name = 'lyrics' if name in self.__r_text_tags: tags[self.__r_text_tags[name]] = values elif name in self.__r_bool_tags: tags[self.__r_bool_tags[name]] = (values[0] == '1') elif name in self.__r_int_tags: try: tags[self.__r_int_tags[name]] = [ int(value) for value in values ] except ValueError: pass elif name in self.__r_freeform_tags: values = [v.encode("utf-8") for v in values] tags[self.__r_freeform_tags[name]] = values elif name == "musicip_fingerprint": tags["----:com.apple.iTunes:fingerprint"] = [ b"MusicMagic Fingerprint%s" % v.encode('ascii') for v in values ] if "tracknumber" in metadata: if "totaltracks" in metadata: tags["trkn"] = [(int(metadata["tracknumber"]), int(metadata["totaltracks"]))] else: tags["trkn"] = [(int(metadata["tracknumber"]), 0)] if "discnumber" in metadata: if "totaldiscs" in metadata: tags["disk"] = [(int(metadata["discnumber"]), int(metadata["totaldiscs"]))] else: tags["disk"] = [(int(metadata["discnumber"]), 0)] covr = [] for image in metadata.images_to_be_saved_to_tags: if image.mimetype == "image/jpeg": covr.append(MP4Cover(image.data, MP4Cover.FORMAT_JPEG)) elif image.mimetype == "image/png": covr.append(MP4Cover(image.data, MP4Cover.FORMAT_PNG)) if covr: tags["covr"] = covr self._remove_deleted_tags(metadata, tags) file.save()
def _move_additional_files(self, old_filename, new_filename): """Move extra files, like playlists...""" old_path = encode_filename(os.path.dirname(old_filename)) new_path = encode_filename(os.path.dirname(new_filename)) patterns = encode_filename(config.setting["move_additional_files_pattern"]) patterns = filter(bool, [p.strip() for p in patterns.split()]) for pattern in patterns: # FIXME glob1 is not documented, maybe we need our own implemention? for old_file in glob.glob1(old_path, pattern): new_file = os.path.join(new_path, old_file) old_file = os.path.join(old_path, old_file) # FIXME we shouldn't do this from a thread! if self.tagger.files.get(decode_filename(old_file)): log.debug("File loaded in the tagger, not moving %r", old_file) continue log.debug("Moving %r to %r", old_file, new_file) shutil.move(old_file, new_file)
def callback(self, objs): files = [o for o in objs if isinstance(o, File)] for file in files: if self.fix(encode_filename(file.filename)): self.log.info("fix_mp4_meta: %s - Fixed", file.filename) else: self.log.info("fix_mp4_meta: %s - Not needed", file.filename) QtCore.QCoreApplication.processEvents()
def _rename(self, old_filename, metadata): new_filename, ext = os.path.splitext(self._make_filename(old_filename, metadata)) if old_filename != new_filename + ext: new_dirname = os.path.dirname(new_filename) if not os.path.isdir(encode_filename(new_dirname)): os.makedirs(new_dirname) tmp_filename = new_filename i = 1 while not pathcmp(old_filename, new_filename + ext) and os.path.exists(encode_filename(new_filename + ext)): new_filename = "%s (%d)" % (tmp_filename, i) i += 1 new_filename = new_filename + ext log.debug("Moving file %r => %r", old_filename, new_filename) shutil.move(encode_filename(old_filename), encode_filename(new_filename)) return new_filename else: return old_filename
def _save(self, filename, metadata): if config.setting['aac_save_ape']: super()._save(filename, metadata) elif config.setting['remove_ape_from_aac']: try: mutagen.apev2.delete(encode_filename(filename)) except BaseException: log.exception('Error removing APEv2 tags from %s', filename)
def _save_and_rename(self, old_filename, metadata): """Save the metadata.""" # Check that file has not been removed since thread was queued # Also don't save if we are stopping. if self.state == File.REMOVED: log.debug("File not saved because it was removed: %r", self.filename) return None if self.tagger.stopping: log.debug("File not saved because %s is stopping: %r", PICARD_APP_NAME, self.filename) return None new_filename = old_filename if not config.setting["dont_write_tags"]: encoded_old_filename = encode_filename(old_filename) info = os.stat(encoded_old_filename) self._save(old_filename, metadata) if config.setting["preserve_timestamps"]: try: os.utime(encoded_old_filename, (info.st_atime, info.st_mtime)) except OSError: log.warning("Couldn't preserve timestamp for %r", old_filename) # Rename files if config.setting["rename_files"] or config.setting["move_files"]: new_filename = self._rename(old_filename, metadata) # Move extra files (images, playlists, etc.) if config.setting["move_files"] and config.setting["move_additional_files"]: self._move_additional_files(old_filename, new_filename) # Delete empty directories if config.setting["delete_empty_dirs"]: dirname = encode_filename(os.path.dirname(old_filename)) try: self._rmdir(dirname) head, tail = os.path.split(dirname) if not tail: head, tail = os.path.split(head) while head and tail: try: self._rmdir(head) except: break head, tail = os.path.split(head) except EnvironmentError: pass # Save cover art images if config.setting["save_images_to_files"]: self._save_images(os.path.dirname(new_filename), metadata) return new_filename
def _save(self, filename, metadata): """Save metadata to the file.""" log.debug("Saving file %r", filename) try: tags = mutagen.apev2.APEv2(encode_filename(filename)) except mutagen.apev2.APENoHeaderError: tags = mutagen.apev2.APEv2() if config.setting["clear_existing_tags"]: tags.clear() elif metadata.images_to_be_saved_to_tags: for name, value in tags.items(): if name.lower().startswith('cover art') and value.kind == mutagen.apev2.BINARY: del tags[name] temp = {} for name, value in metadata.items(): if name.startswith("~") or not self.supports_tag(name): continue real_name = self._get_tag_name(name) # tracknumber/totaltracks => Track if name == 'tracknumber': if 'totaltracks' in metadata: value = '%s/%s' % (value, metadata['totaltracks']) # discnumber/totaldiscs => Disc elif name == 'discnumber': if 'totaldiscs' in metadata: value = '%s/%s' % (value, metadata['totaldiscs']) elif name in ('totaltracks', 'totaldiscs'): continue # "performer:Piano=Joe Barr" => "Performer=Joe Barr (Piano)" elif name.startswith('performer:') or name.startswith('comment:'): name, desc = name.split(':', 1) if desc: value += ' (%s)' % desc temp.setdefault(real_name, []).append(value) for name, values in temp.items(): tags[name] = values for image in metadata.images_to_be_saved_to_tags: cover_filename = 'Cover Art (Front)' cover_filename += image.extension tags['Cover Art (Front)'] = mutagen.apev2.APEValue(cover_filename.encode('ascii') + b'\0' + image.data, mutagen.apev2.BINARY) break # can't save more than one item with the same name # (mp3tags does this, but it's against the specs) self._remove_deleted_tags(metadata, tags) tags.save(encode_filename(filename))
def _load(self, filename): log.debug("Loading file %r", filename) config = get_config() self.__casemap = {} file = ASF(encode_filename(filename)) metadata = Metadata() for name, values in file.tags.items(): if name == 'WM/Picture': for image in values: try: (mime, data, image_type, description) = unpack_image(image.value) except ValueError as e: log.warning('Cannot unpack image from %r: %s', filename, e) continue try: coverartimage = TagCoverArtImage( file=filename, tag=name, types=types_from_id3(image_type), comment=description, support_types=True, data=data, id3_type=image_type, ) except CoverArtImageError as e: log.error('Cannot load image from %r: %s' % (filename, e)) else: metadata.images.append(coverartimage) continue elif name == 'WM/SharedUserRating': # Rating in WMA ranges from 0 to 99, normalize this to the range 0 to 5 values[0] = int( round( int(str(values[0])) / 99.0 * (config.setting['rating_steps'] - 1))) elif name == 'WM/PartOfSet': disc = str(values[0]).split("/") if len(disc) > 1: metadata["totaldiscs"] = disc[1] values[0] = disc[0] name_lower = name.lower() if name in self.__RTRANS: name = self.__RTRANS[name] elif name_lower in self.__RTRANS_CI: orig_name = name name = self.__RTRANS_CI[name_lower] self.__casemap[name] = orig_name else: continue values = [str(value) for value in values if value] if values: metadata[name] = values self._info(metadata, file) return metadata
def _save_and_rename(self, old_filename, metadata): """Save the metadata.""" new_filename = old_filename if not config.setting["dont_write_tags"]: encoded_old_filename = encode_filename(old_filename) info = os.stat(encoded_old_filename) self._save(old_filename, metadata) if config.setting["preserve_timestamps"]: try: os.utime(encoded_old_filename, (info.st_atime, info.st_mtime)) except OSError: log.warning("Couldn't preserve timestamp for %r", old_filename) # Rename files if config.setting["rename_files"] or config.setting["move_files"]: new_filename = self._rename(old_filename, metadata) # Move extra files (images, playlists, etc.) if config.setting["move_files"] and config.setting[ "move_additional_files"]: self._move_additional_files(old_filename, new_filename) #changes, delete extra files if config.setting["move_files"] and config.setting[ "delete_additional_files"]: self._delete_additional_files(old_filename) # Delete empty directories if config.setting["delete_empty_dirs"]: dirname = encode_filename(os.path.dirname(old_filename)) try: self._rmdir(dirname) head, tail = os.path.split(dirname) if not tail: head, tail = os.path.split(head) while head and tail: try: self._rmdir(head) except: break head, tail = os.path.split(head) except EnvironmentError: pass # Save cover art images if config.setting["save_images_to_files"]: self._save_images(os.path.dirname(new_filename), metadata) return new_filename
def _rename(self, old_filename, metadata): old_dir = os.path.dirname(self.filename) new_dir = os.path.dirname(encode_filename( self._make_filename(old_filename, metadata ))) filename = os.path.basename(old_filename) new_filename = os.path.join(new_dir, filename) audiofile = " ".join(self.fileline.split()[0:-1]).strip('"') old_audiofile = os.path.join(old_dir, audiofile) new_audiofile = os.path.join(new_dir, audiofile) if not os.path.isdir(new_dir): os.makedirs(new_dir) if os.path.exists(old_filename): self.log.debug("Moving file %r => %r", old_filename, new_filename) shutil.move(encode_filename(old_filename), encode_filename(new_filename)) if os.path.exists(old_audiofile): self.log.debug("Moving file %r => %r", old_audiofile, new_audiofile) shutil.move(encode_filename(old_audiofile), encode_filename(new_audiofile)) # wavpack wvc_filename = old_audiofile.replace(".wv", ".wvc") if os.path.isfile(wvc_filename): new_wvc_filename = new_audiofile.replace(".wv", ".wvc") shutil.move(encode_filename(wvc_filename), encode_filename(new_wvc_filename)) return new_filename
def add_directory(self, path): path = encode_filename(path) self.other_queue.put( ( partial(os.listdir, path), partial(self.process_directory_listing, path, deque()), QtCore.Qt.LowEventPriority, ) )
def _load(self, filename): self.log.debug("Loading file %r", filename) file = self._File(encode_filename(filename)) file.tags = file.tags or {} metadata = Metadata() for origname, values in file.tags.items(): for value in values: name = origname if name == "date" or name == "originaldate": # YYYY-00-00 => YYYY value = sanitize_date(value) elif name == 'performer' or name == 'comment': # transform "performer=Joe Barr (Piano)" to "performer:Piano=Joe Barr" name += ':' if value.endswith(')'): start = value.rfind(' (') if start > 0: name += value[start + 2:-1] value = value[:start] elif name.startswith('rating'): try: name, email = name.split(':', 1) except ValueError: email = '' if email != self.config.setting['rating_user_email']: continue name = '~rating' value = unicode( int( round( (float(value) * (self.config.setting['rating_steps'] - 1))))) elif name == "fingerprint" and value.startswith( "MusicMagic Fingerprint"): name = "musicip_fingerprint" value = value[22:] elif name == "tracktotal" and "totaltracks" not in file.tags: name = "totaltracks" elif name == "metadata_block_picture": image = mutagen.flac.Picture( base64.standard_b64decode(value)) metadata.add_image(image.mime, image.data) continue metadata.add(name, value) if self._File == mutagen.flac.FLAC: for image in file.pictures: metadata.add_image(image.mime, image.data) # Read the unofficial COVERART tags, for backward compatibillity only if not "metadata_block_picture" in file.tags: try: for index, data in enumerate(file["COVERART"]): metadata.add_image(file["COVERARTMIME"][index], base64.standard_b64decode(data)) except KeyError: pass self._info(metadata, file) return metadata
def write(self): b_lines = [] for header in self.headers: b_lines.append(header.encode("utf-8")) for entry in self.entries: for row in entry: b_lines.append(unicode(row).encode("utf-8")) with open(encode_filename(self.filename), "wt") as f: f.writelines(b_lines)
def _load(self, filename): log.debug("Loading file %r", filename) self.__casemap = {} file = self._File(encode_filename(filename)) metadata = Metadata() if file.tags: for origname, values in file.tags.items(): name_lower = origname.lower() if (values.kind == mutagen.apev2.BINARY and name_lower.startswith("cover art")): if b'\0' in values.value: descr, data = values.value.split(b'\0', 1) try: coverartimage = TagCoverArtImage( file=filename, tag=name_lower, data=data, ) except CoverArtImageError as e: log.error('Cannot load image from %r: %s' % (filename, e)) else: metadata.images.append(coverartimage) # skip EXTERNAL and BINARY values if values.kind != mutagen.apev2.TEXT: continue for value in values: name = name_lower if name == "year": name = "date" value = sanitize_date(value) elif name == "track": name = "tracknumber" track = value.split("/") if len(track) > 1: metadata["totaltracks"] = track[1] value = track[0] elif name == "disc": name = "discnumber" disc = value.split("/") if len(disc) > 1: metadata["totaldiscs"] = disc[1] value = disc[0] elif name == 'performer' or name == 'comment': name = name + ':' if value.endswith(')'): start = value.rfind(' (') if start > 0: name += value[start + 2:-1] value = value[:start] elif name in self.__rtranslate: name = self.__rtranslate[name] self.__casemap[name] = origname metadata.add(name, value) self._info(metadata, file) return metadata
def _load(self, filename): log.debug("Loading file %r", filename) self.__casemap = {} file = MP4(encode_filename(filename)) tags = file.tags or {} metadata = Metadata() for name, values in tags.items(): name_lower = name.lower() if name in self.__text_tags: for value in values: metadata.add(self.__text_tags[name], value) elif name in self.__bool_tags: metadata.add(self.__bool_tags[name], values and '1' or '0') elif name in self.__int_tags: for value in values: metadata.add(self.__int_tags[name], str(value)) elif name in self.__freeform_tags: for value in values: value = value.decode("utf-8", "replace").strip("\x00") metadata.add(self.__freeform_tags[name], value) elif name_lower in self.__freeform_tags_ci: for value in values: value = value.decode("utf-8", "replace").strip("\x00") tag_name = self.__freeform_tags_ci[name_lower] metadata.add(tag_name, value) self.__casemap[tag_name] = name elif name == "----:com.apple.iTunes:fingerprint": for value in values: value = value.decode("utf-8", "replace").strip("\x00") if value.startswith("MusicMagic Fingerprint"): metadata.add("musicip_fingerprint", value[22:]) elif name == "trkn": metadata["tracknumber"] = str(values[0][0]) metadata["totaltracks"] = str(values[0][1]) elif name == "disk": metadata["discnumber"] = str(values[0][0]) metadata["totaldiscs"] = str(values[0][1]) elif name == "covr": for value in values: if value.imageformat not in (value.FORMAT_JPEG, value.FORMAT_PNG): continue try: coverartimage = TagCoverArtImage( file=filename, tag=name, data=value, ) except CoverArtImageError as e: log.error('Cannot load image from %r: %s' % (filename, e)) else: metadata.images.append(coverartimage) self._info(metadata, file) return metadata
def _load(self, filename): self.log.debug("Loading file %r", filename) f = wave.open(encode_filename(filename), "rb") metadata = Metadata() metadata['~#channels'] = f.getnchannels() metadata['~#bits_per_sample'] = f.getsampwidth() * 8 metadata['~#sample_rate'] = f.getframerate() metadata.length = 1000 * f.getnframes() / f.getframerate() metadata['~format'] = 'Microsoft WAVE' return metadata
def run(self): device = self.config.setting["cd_lookup_device"].split(",", 1)[0] disc = Disc() disc.read(encode_filename(device)) self.discid = disc.id self.log.debug('CD has discid: %s', disc.id) self.rip() result = self.widget.exec_() if result == self.widget.Rejected: self._cleanup()
def _save(self, filename, metadata): log.debug("Saving file %r", filename) file = MP4(encode_filename(self.filename)) if file.tags is None: file.add_tags() if config.setting["clear_existing_tags"]: file.tags.clear() for name, values in metadata.rawitems(): if name.startswith('lyrics:'): name = 'lyrics' if name in self.__r_text_tags: file.tags[self.__r_text_tags[name]] = values elif name in self.__r_bool_tags: file.tags[self.__r_bool_tags[name]] = (values[0] == '1') elif name in self.__r_int_tags: try: file.tags[self.__r_int_tags[name]] = [int(value) for value in values] except ValueError: pass elif name in self.__r_freeform_tags: values = [v.encode("utf-8") for v in values] file.tags[self.__r_freeform_tags[name]] = values elif name == "musicip_fingerprint": file.tags["----:com.apple.iTunes:fingerprint"] = ["MusicMagic Fingerprint%s" % str(v) for v in values] if "tracknumber" in metadata: if "totaltracks" in metadata: file.tags["trkn"] = [(int(metadata["tracknumber"]), int(metadata["totaltracks"]))] else: file.tags["trkn"] = [(int(metadata["tracknumber"]), 0)] if "discnumber" in metadata: if "totaldiscs" in metadata: file.tags["disk"] = [(int(metadata["discnumber"]), int(metadata["totaldiscs"]))] else: file.tags["disk"] = [(int(metadata["discnumber"]), 0)] if config.setting['save_images_to_tags']: covr = [] for image in metadata.images: if not save_this_image_to_tags(image): continue mime = image["mime"] if mime == "image/jpeg": covr.append(MP4Cover(image["data"], MP4Cover.FORMAT_JPEG)) elif mime == "image/png": covr.append(MP4Cover(image["data"], MP4Cover.FORMAT_PNG)) if covr: file.tags["covr"] = covr file.save()
def _load(self, filename): log.debug("Loading file %r", filename) file = self._File(encode_filename(filename)) metadata = Metadata() if file.tags: for origname, values in file.tags.items(): if origname.lower().startswith("cover art") and values.kind == mutagen.apev2.BINARY: if '\0' in values.value: descr, data = values.value.split('\0', 1) try: coverartimage = TagCoverArtImage( file=filename, tag=origname, data=data, ) except CoverArtImageError as e: log.error('Cannot load image from %r: %s' % (filename, e)) else: metadata.append_image(coverartimage) # skip EXTERNAL and BINARY values if values.kind != mutagen.apev2.TEXT: continue for value in values: name = origname if name == "Year": name = "date" value = sanitize_date(value) elif name == "Track": name = "tracknumber" track = value.split("/") if len(track) > 1: metadata["totaltracks"] = track[1] value = track[0] elif name == "Disc": name = "discnumber" disc = value.split("/") if len(disc) > 1: metadata["totaldiscs"] = disc[1] value = disc[0] elif name == 'Performer' or name == 'Comment': name = name.lower() + ':' if value.endswith(')'): start = value.rfind(' (') if start > 0: name += value[start + 2:-1] value = value[:start] elif name in self.__translate: name = self.__translate[name] else: name = name.lower() metadata.add(name, value) self._info(metadata, file) return metadata
def _make_image_filename(self, image_filename, dirname, metadata): image_filename = self._script_to_filename(image_filename, metadata) if not image_filename: image_filename = "cover" if os.path.isabs(image_filename): filename = image_filename else: filename = os.path.join(dirname, image_filename) if config.setting['windows_compatibility'] or sys.platform == 'win32': filename = filename.replace('./', '_/').replace('.\\', '_\\') return encode_filename(filename)
def _rename(self, old_filename, metadata, settings): new_filename, ext = os.path.splitext( self._make_filename(old_filename, metadata, settings)) if old_filename != new_filename + ext: new_dirname = os.path.dirname(new_filename) if not os.path.isdir(encode_filename(new_dirname)): os.makedirs(new_dirname) tmp_filename = new_filename i = 1 while (not pathcmp(old_filename, new_filename + ext) and os.path.exists(encode_filename(new_filename + ext))): new_filename = "%s (%d)" % (tmp_filename, i) i += 1 new_filename = new_filename + ext self.log.debug("Moving file %r => %r", old_filename, new_filename) shutil.move(encode_filename(old_filename), encode_filename(new_filename)) return new_filename else: return old_filename
def _load(self, filename): self.log.debug("Loading file %r", filename) file = self._File(encode_filename(filename)) file.tags = file.tags or {} metadata = Metadata() for origname, values in file.tags.items(): for value in values: name = origname if name == "date" or name == "originaldate": # YYYY-00-00 => YYYY value = sanitize_date(value) elif name == 'performer' or name == 'comment': # transform "performer=Joe Barr (Piano)" to "performer:Piano=Joe Barr" name += ':' if value.endswith(')'): start = value.rfind(' (') if start > 0: name += value[start + 2:-1] value = value[:start] elif name.startswith('rating'): try: name, email = name.split(':', 1) except ValueError: email = '' if email != self.config.setting['rating_user_email']: continue name = '~rating' value = unicode(int(round((float(value) * (self.config.setting['rating_steps'] - 1))))) elif name == "fingerprint" and value.startswith("MusicMagic Fingerprint"): name = "musicip_fingerprint" value = value[22:] elif name == "tracktotal": if "totaltracks" in file.tags: continue name = "totaltracks" elif name == "disctotal": if "totaldiscs" in file.tags: continue name = "totaldiscs" elif name == "metadata_block_picture": image = mutagen.flac.Picture(base64.standard_b64decode(value)) metadata.add_image(image.mime, image.data) continue metadata.add(name, value) if self._File == mutagen.flac.FLAC: for image in file.pictures: metadata.add_image(image.mime, image.data) # Read the unofficial COVERART tags, for backward compatibillity only if not "metadata_block_picture" in file.tags: try: for index, data in enumerate(file["COVERART"]): metadata.add_image(file["COVERARTMIME"][index], base64.standard_b64decode(data)) except KeyError: pass self._info(metadata, file) return metadata
def _make_image_filename(self, image_filename, dirname, metadata): image_filename = self._script_to_filename(image_filename, metadata) if not image_filename: image_filename = "cover" if os.path.isabs(image_filename): filename = image_filename else: filename = os.path.join(dirname, image_filename) if config.setting['windows_compatible_filenames'] or sys.platform == 'win32': filename = filename.replace('./', '_/').replace('.\\', '_\\') return encode_filename(filename)
def _delete_additional_files(self, old_filename): """Delete all other files of type that are not being saved..""" """Retrieve path of saved file""" old_path = encode_filename(os.path.dirname(old_filename)) """Retrieve patterns(types) to be deleted""" patterns = encode_filename( config.setting["delete_additional_files_pattern"]) patterns = filter(bool, [p.strip() for p in patterns.split()]) for pattern in patterns: # FIXME glob1 is not documented, maybe we need our own implementation? for old_file in glob.glob1(old_path, pattern): old_file = os.path.join(old_path, old_file) # FIXME we shouldn't do this from a thread! if self.tagger.files.get(decode_filename(old_file)): """Ensures file being saved is not deleted""" log.debug("File loaded in the tagger, not deleting %r", old_file) continue log.debug("Deleting %r", old_file) os.remove(old_file)
def _make_image_filename(self, image_filename, dirname, metadata): image_filename = self._script_to_filename(image_filename, metadata) if not image_filename: image_filename = "cover" if os.path.isabs(image_filename): filename = image_filename else: filename = os.path.join(dirname, image_filename) if config.setting["windows_compatible_filenames"] or sys.platform == "win32": filename = filename.replace("./", "_/").replace(".\\", "_\\") return encode_filename(filename)
def calculate_replay_gain_for_files(files, format, tagger): """Calculates the replay gain for a list of files in album mode.""" file_list = ['%s' % encode_filename(f.filename) for f in files] if format in REPLAYGAIN_COMMANDS \ and tagger.config.setting[REPLAYGAIN_COMMANDS[format][0]]: command = tagger.config.setting[REPLAYGAIN_COMMANDS[format][0]] options = tagger.config.setting[REPLAYGAIN_COMMANDS[format][1]].split(' ') tagger.log.debug('%s %s %s' % (command, ' '.join(options), decode_filename(' '.join(file_list)))) check_call([command] + options + file_list) else: raise Exception('ReplayGain: Unsupported format %s' % (format))
def lookup_cd(self, action=None): """Reads CD from the selected drive and tries to lookup the DiscID on MusicBrainz.""" if action is None: device = self.config.setting["cd_lookup_device"].split(",", 1)[0] else: device = unicode(action.text()) disc = Disc() self.set_wait_cursor() self.other_queue.put((partial(disc.read, encode_filename(device)), partial(self._lookup_disc, disc), QtCore.Qt.LowEventPriority))
def install_plugin(self, path): path = encode_filename(path) file = os.path.basename(path) dest = os.path.join(self.tagger.user_plugin_dir, file) if os.path.exists(dest): msgbox = QtGui.QMessageBox(self) msgbox.setText("A plugin named %s is already installed." % file) msgbox.setInformativeText("Do you want to overwrite the existing plugin?") msgbox.setStandardButtons(QtGui.QMessageBox.Yes | QtGui.QMessageBox.No) msgbox.setDefaultButton(QtGui.QMessageBox.No) if msgbox.exec_() == QtGui.QMessageBox.No: return self.tagger.pluginmanager.install_plugin(path, dest)
def drop_urls(urls, target): files = [] new_files = [] for url in urls: log.debug("Dropped the URL: %r", url.toString(QtCore.QUrl.RemoveUserInfo)) if url.scheme() == "file" or not url.scheme(): # Workaround for https://bugreports.qt.io/browse/QTBUG-40449 # OSX Urls follow the NSURL scheme and need to be converted if sys.platform == 'darwin' and unicode( url.path()).startswith('/.file/id='): if NSURL_IMPORTED: filename = os.path.normpath( os.path.realpath( unicode( NSURL.URLWithString_(str(url.toString())). filePathURL().path()).rstrip("\0"))) log.debug( 'OSX NSURL path detected. Dropped File is: %r', filename) else: log.error("Unable to get appropriate file path for %r", url.toString(QtCore.QUrl.RemoveUserInfo)) continue else: # Dropping a file from iTunes gives a filename with a NULL terminator filename = os.path.normpath( os.path.realpath( unicode(url.toLocalFile()).rstrip("\0"))) file = BaseTreeView.tagger.files.get(filename) if file: files.append(file) elif os.path.isdir(encode_filename(filename)): BaseTreeView.tagger.add_directory(filename) else: new_files.append(filename) elif url.scheme() in ("http", "https"): path = unicode(url.path()) match = re.search(r"/(release|recording)/([0-9a-z\-]{36})", path) if match: entity = match.group(1) mbid = match.group(2) if entity == "release": BaseTreeView.tagger.load_album(mbid) elif entity == "recording": BaseTreeView.tagger.load_nat(mbid) if files: BaseTreeView.tagger.move_files(files, target) if new_files: BaseTreeView.tagger.add_files(new_files, target=target)
def lookup_cd(self, action): """Reads CD from the selected drive and tries to lookup the DiscID on MusicBrainz.""" if isinstance(action, QtWidgets.QAction): device = action.text() elif config.setting["cd_lookup_device"] != '': device = config.setting["cd_lookup_device"].split(",", 1)[0] else: # rely on python-discid auto detection device = None disc = Disc() self.set_wait_cursor() thread.run_task(partial(disc.read, encode_filename(device)), partial(self._lookup_disc, disc))
def write(self): lines = [] for track in self.tracks: num = track.index for line in track: indent = 0 if num > 0: if line[0] == "TRACK": indent = 2 elif line[0] != "FILE": indent = 4 line2 = u" ".join([self.quote(s) for s in line]) lines.append(" " * indent + line2.encode("UTF-8") + "\n") with open(encode_filename(self.filename), "wt") as f: f.writelines(lines)