def process_directory_listing(self, root, queue, result=None, error=None): try: # Read directory listing if result is not None and error is None: files = [] directories = deque() try: for path in result: path = os.path.join(root, path) if os.path.isdir(path): directories.appendleft(path) else: try: files.append(decode_filename(path)) except UnicodeDecodeError: self.log.warning("Failed to decode filename: %r", path) continue finally: if files: self.add_files(files) queue.extendleft(directories) finally: # Scan next directory in the queue try: path = queue.popleft() except IndexError: pass else: self.other_queue.put( ( partial(os.listdir, path), partial(self.process_directory_listing, path, queue), QtCore.Qt.LowEventPriority, ) )
def contextMenuEvent(self, event): item = self.itemAt(event.pos()) if not item: return menu = QtGui.QMenu(self) tag = self.tag_names[item.row()] if tag != "~length": column = item.column() if column == 1: if self.tag_status(tag) == "changed" and tag not in self.new_tags.different: copy_to_new_action = QtGui.QAction(_(u"Copy to New Value"), self.parent) copy_to_new_action.triggered.connect(partial(self.copy_to_new, tag)) menu.addAction(copy_to_new_action) menu.addSeparator() elif column == 2: edit_tag_action = QtGui.QAction(_(u"Edit..."), self.parent) edit_tag_action.triggered.connect(partial(self.edit_tag, tag)) menu.addAction(edit_tag_action) if self.tag_status(tag) != "removed": remove_tag_action = QtGui.QAction(_(u"Remove"), self.parent) remove_tag_action.triggered.connect(partial(self.remove_tag, tag)) menu.addAction(remove_tag_action) menu.addSeparator() menu.addAction(self.add_tag_action) menu.addSeparator() menu.addAction(self.changes_first_action) menu.exec_(event.globalPos()) event.accept()
def process_directory_listing(self, root, queue, result=None, error=None): try: # Read directory listing if result is not None and error is None: files = [] directories = deque() try: for path in result: path = os.path.join(root, path) if os.path.isdir(path): directories.appendleft(path) else: try: files.append(decode_filename(path)) except UnicodeDecodeError: self.log.warning( "Failed to decode filename: %r", path) continue finally: if files: self.add_files(files) queue.extendleft(directories) finally: # Scan next directory in the queue try: path = queue.popleft() except IndexError: pass else: self.other_queue.put( (partial(os.listdir, path), partial(self.process_directory_listing, path, queue), QtCore.Qt.LowEventPriority))
def _lookup_fingerprint(self, next, filename, result=None, error=None): try: file = self.tagger.files[filename] del self._analyze_tasks[file] except KeyError: # The file has been removed. do nothing return if result is None or result[0] is None or error is not None: next(file, result=None) return fingerprint, length = result self.tagger.window.set_statusbar_message( N_("Looking up the fingerprint for file %s..."), file.filename) self.tagger.xmlws.query_musicdns(partial(self._lookup_finished, partial(next, file)), rmt='0', lkt='1', cid=MUSICDNS_KEY, cvr="MusicBrainz Picard-%s" % version_string, fpt=fingerprint, dur=str(file.metadata.length or length), brt=str(file.metadata.get("~#bitrate", 0)), fmt=file.metadata["~format"], art=file.metadata["artist"], ttl=file.metadata["title"], alb=file.metadata["album"], tnm=file.metadata["tracknumber"], gnr=file.metadata["genre"], yrr=file.metadata["date"][:4])
def contextMenuEvent(self, event): menu = QtGui.QMenu(self) if self.objects: item = self.itemAt(event.pos()) tag = self.tag_names[item.row()] if item else "" if item and tag != "~length": edit_tag_action = QtGui.QAction(_(u"Edit..."), self.parent) edit_tag_action.triggered.connect(partial(self.edit_tag, tag)) menu.addAction(edit_tag_action) if self.tag_is_removable(tag): remove_tag_action = QtGui.QAction(_(u"Remove"), self.parent) remove_tag_action.triggered.connect(partial(self.remove_tag, tag)) menu.addAction(remove_tag_action) if self.tag_status(tag) in ("changed", "removed") and not \ (tag in self.orig_tags.different or tag in self.new_tags.different): use_orig_value_action = QtGui.QAction(_(u"Use Original Value"), self.parent) use_orig_value_action.triggered.connect(partial(self.use_orig_value, tag)) menu.addAction(use_orig_value_action) menu.addSeparator() menu.addSeparator() menu.addAction(self.add_tag_action) menu.addSeparator() menu.addAction(self.changes_first_action) menu.exec_(event.globalPos()) event.accept()
def callback(self, objs): albums = [o for o in objs if isinstance(o, Album)] for album in albums: self.tagger.other_queue.put( (partial(self._calculate_albumgain, album), partial(self._albumgain_callback, album), QtCore.Qt.NormalEventPriority))
def _lookup_fingerprint(self, next, filename, result=None, error=None): try: file = self.tagger.files[filename] del self._analyze_tasks[file] except KeyError: # The file has been removed. do nothing return if result is None or result[0] is None or error is not None: next(file, result=None) return fingerprint, length = result self.tagger.window.set_statusbar_message( N_("Looking up the fingerprint for file %s..."), file.filename) self.tagger.xmlws.query_musicdns( partial(self._lookup_finished, partial(next, file)), rmt='0', lkt='1', cid=MUSICDNS_KEY, cvr="MusicBrainz Picard-%s" % version_string, fpt=fingerprint, dur=str(file.metadata.length or length), brt=str(file.metadata.get("~#bitrate", 0)), fmt=file.metadata["~format"], art=file.metadata["artist"], ttl=file.metadata["title"], alb=file.metadata["album"], tnm=file.metadata["tracknumber"], gnr=file.metadata["genre"], yrr=file.metadata["date"][:4])
def callback(self, objs): albums = [o for o in objs if isinstance(o, Album)] for album in albums: self.tagger.other_queue.put(( partial(self._calculate_albumgain, album), partial(self._albumgain_callback, album), QtCore.Qt.NormalEventPriority))
def analyze(self, file, next): # return cached PUID puids = file.metadata.getall('musicip_puid') if puids: next(result=puids[0]) return # use cached fingerpring fingerprints = file.metadata.getall('musicip_fingerprint') if fingerprints: self._lookup_fingerprint(self.tagger.analyze_queue.next, file.filename, result=(fingerprints[0], 0)) return # calculate fingerprint if ofa is not None: if file not in self._analyze_tasks: task = (partial(self.calculate_fingerprint, file.filename), partial(self._lookup_fingerprint, self.tagger._lookup_puid, file.filename), QtCore.Qt.LowEventPriority + 1) self._analyze_tasks[file] = task self.tagger.analyze_queue.put(task) return # no PUID next(result=None)
def save(self, next, settings): self.set_pending() metadata = Metadata() metadata.copy(self.metadata) self.tagger.save_queue.put( (partial(self._save_and_rename, self.filename, metadata, settings), partial(self._saving_finished, next), QtCore.Qt.LowEventPriority + 2))
def save(self, next, settings): self.set_pending() metadata = Metadata() metadata.copy(self.metadata) self.tagger.save_queue.put(( partial(self._save_and_rename, self.filename, metadata, settings), partial(self._saving_finished, next), QtCore.Qt.LowEventPriority + 2))
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 analyze(self, objs): """Analyze the file(s).""" files = self.get_files_from_objects(objs) for file in files: file.set_pending() if self.use_acoustid: self._acoustid.analyze(file, partial(file._lookup_finished, "acoustid")) else: self._ofa.analyze(file, partial(self._lookup_puid, file))
def analyze(self, objs): """Analyze the file(s).""" files = self.get_files_from_objects(objs) for file in files: file.set_pending() if self.use_acoustid: self._acoustid.analyze(file, partial(file._lookup_finished, 'acoustid')) else: self._ofa.analyze(file, partial(self._lookup_puid, file))
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 contextMenuEvent(self, event): menu = QtGui.QMenu(self) if self.objects: rows = sorted(set(item.row() for item in self.selectedItems())) tags = [ self.tag_names[r] for r in rows if self.tag_names[r] != "~length" ] if len(tags) == 1: edit_tag_action = QtGui.QAction(_(u"Edit..."), self.parent) edit_tag_action.triggered.connect( partial(self.edit_tag, tags[0])) menu.addAction(edit_tag_action) removals = [] useorigs = [] for tag in tags: if self.tag_is_removable(tag): removals.append(partial(self.remove_tag, tag)) if self.tag_status(tag) in ("changed", "removed"): if tag in self.orig_tags.different or tag in self.new_tags.different: for file in self.files: objects = [file] if file.parent in self.tracks and len( self.files & set(file.parent.linked_files)) == 1: objects.append(file.parent) orig_values = list( file.orig_metadata._items.get(tag, [""])) useorigs.append( partial(self.set_tag_values, tag, orig_values, objects)) else: useorigs.append(partial(self.use_orig_value, tag)) if removals: remove_tag_action = QtGui.QAction(_(u"Remove"), self.parent) remove_tag_action.triggered.connect( lambda: [f() for f in removals]) menu.addAction(remove_tag_action) if useorigs: name = ungettext("Use Original Value", "Use Original Values", len(useorigs)) use_orig_value_action = QtGui.QAction(name, self.parent) use_orig_value_action.triggered.connect( lambda: [f() for f in useorigs]) menu.addAction(use_orig_value_action) menu.addSeparator() if len(tags) == 1 or removals or useorigs: menu.addSeparator() menu.addAction(self.add_tag_action) menu.addSeparator() menu.addAction(self.changes_first_action) menu.exec_(event.globalPos()) event.accept()
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 callback(self, objs): albums = filter( lambda o: isinstance(o, Album) and not isinstance(o, NatAlbum), objs) nats = filter(lambda o: isinstance(o, NatAlbum), objs) for album in albums: thread.run_task(partial(self._calculate_albumgain, album), partial(self._albumgain_callback, album)) for natalbum in nats: thread.run_task(partial(self._calculate_natgain, natalbum), partial(self._albumgain_callback, natalbum))
def _run_next_task(self): try: file, next = self._queue.popleft() except IndexError: return fpcalc = self.config.setting["acoustid_fpcalc"] or "fpcalc" self._running += 1 process = QtCore.QProcess(self) process.setProperty('picard_finished', QtCore.QVariant(False)) process.finished.connect(partial(self._on_fpcalc_finished, next, file)) process.error.connect(partial(self._on_fpcalc_error, next, file)) process.start(fpcalc, ["-length", "120", file.filename]) self.log.debug("Starting fingerprint calculator %r %r", fpcalc, file.filename)
def callback(self, objs): albums = filter(lambda o: isinstance(o, Album) and not isinstance(o, NatAlbum), objs) nats = filter(lambda o: isinstance(o, NatAlbum), objs) for album in albums: thread.run_task( partial(self._calculate_albumgain, album), partial(self._albumgain_callback, album)) for natalbum in nats: thread.run_task( partial(self._calculate_natgain, natalbum), partial(self._albumgain_callback, natalbum))
def callback(self, objs): album = objs[0] library_path = self.config.setting['cdripper_library_path'] artist_name = album.metadata['albumartist'] album_name = album.metadata['album'] self.target_path = os.path.join(library_path, artist_name, album_name) try: os.makedirs(self.target_path) except OSError: pass self.tagger.other_queue.put( (partial(self._rip_and_encode, album), partial(self._done_callback, album), QtCore.Qt.NormalEventPriority))
def __init__(self, parent): QtGui.QTableWidget.__init__(self, parent) self.parent = parent self.setAccessibleName(_("metadata view")) self.setAccessibleDescription(_("Displays original and new tags for the selected files")) self.setColumnCount(3) self.setHorizontalHeaderLabels((_("Tag"), _("Original Value"), _("New Value"))) self.horizontalHeader().setStretchLastSection(True) self.horizontalHeader().setClickable(False) self.verticalHeader().setDefaultSectionSize(21) self.verticalHeader().setVisible(False) self.setSelectionMode(QtGui.QAbstractItemView.ExtendedSelection) self.setTabKeyNavigation(False) self.setStyleSheet("QTableWidget {border: none;}") self.setAttribute(QtCore.Qt.WA_MacShowFocusRect, 1) self.colors = { TagStatus.NoChange: self.palette().color(QtGui.QPalette.Text), TagStatus.Removed: QtGui.QBrush(QtGui.QColor("red")), TagStatus.Added: QtGui.QBrush(QtGui.QColor("green")), TagStatus.Changed: QtGui.QBrush(QtGui.QColor("darkgoldenrod")), } self.files = set() self.tracks = set() self.objects = set() self.selection_mutex = QtCore.QMutex() self.selection_dirty = False self.editing = None # the QTableWidgetItem being edited self.clipboard = [""] self.add_tag_action = QtGui.QAction(_(u"Add New Tag..."), parent) self.add_tag_action.triggered.connect(partial(self.edit_tag, "")) self.changes_first_action = QtGui.QAction(_(u"Show Changes First"), parent) self.changes_first_action.setCheckable(True) self.changes_first_action.setChecked(config.persist["show_changes_first"]) self.changes_first_action.toggled.connect(self.toggle_changes_first)
def move_file_to_nat(self, file, trackid, node=None): self.create_nats() file.move(self.nats.unmatched_files) nat = self.load_nat(trackid, node=node) nat.run_when_loaded(partial(file.move, nat)) if nat.loaded: self.emit(QtCore.SIGNAL("album_updated"), self.nats)
def load(self): self.metadata.copy(self.album.metadata) self.metadata["title"] = u"[loading track information]" self.loaded = False self.tagger.nats.update(True) mblogin = False inc = ["artist-credits", "artists", "aliases"] if self.config.setting["track_ars"]: inc += [ "artist-rels", "url-rels", "recording-rels", "work-rels", "work-level-rels" ] if self.config.setting["folksonomy_tags"]: if self.config.setting["only_my_tags"]: mblogin = True inc += ["user-tags"] else: inc += ["tags"] if self.config.setting["enable_ratings"]: mblogin = True inc += ["user-ratings"] self.tagger.xmlws.get_track_by_id( self.id, partial(self._recording_request_finished), inc, mblogin=mblogin)
def __init__(self, parent): QtGui.QTableWidget.__init__(self, parent) self.parent = parent self.setColumnCount(3) self.setHorizontalHeaderLabels((N_("Tag"), N_("Original Value"), N_("New Value"))) self.horizontalHeader().setStretchLastSection(True) self.horizontalHeader().setClickable(False) self.verticalHeader().setDefaultSectionSize(21) self.verticalHeader().setVisible(False) self.setSelectionMode(QtGui.QAbstractItemView.SingleSelection) self.setStyleSheet("QTableWidget {border: none;}") self.itemChanged.connect(self.item_changed) self.colors = { "default": self.palette().color(QtGui.QPalette.Text), "removed": QtGui.QBrush(QtGui.QColor("red")), "added": QtGui.QBrush(QtGui.QColor("green")), "changed": QtGui.QBrush(QtGui.QColor("darkgoldenrod")), } self.files = set() self.tracks = set() self.objects = set() self.orig_tags = TagCounter() self.new_tags = TagCounter() self.selection_mutex = QtCore.QMutex() self.updating = False self.update_pending = False self.selection_dirty = False self.editing = False # true if a QTableWidgetItem is being edited self.clipboard = [""] self.add_tag_action = QtGui.QAction(_(u"Add New Tag..."), parent) self.add_tag_action.triggered.connect(partial(self.edit_tag, "")) self.changes_first_action = QtGui.QAction(_(u"Show Changes First"), parent) self.changes_first_action.setCheckable(True) self.changes_first_action.setChecked(self.config.persist["show_changes_first"]) self.changes_first_action.toggled.connect(self.toggle_changes_first)
def get( self, host, port, path, handler, xml=True, priority=False, important=False, mblogin=False, cacheloadcontrol=None ): func = partial( self._start_request, "GET", host, port, path, None, handler, xml, mblogin, cacheloadcontrol=cacheloadcontrol ) return self.add_task(func, host, port, priority, important=important)
def get_tags(album, metadata, path, min_usage, ignore, next, current): """Get tags from an URL.""" url = str(QtCore.QUrl.fromPercentEncoding(path)) if url in _cache: _tags_finalize(album, metadata, current + _cache[url], next) else: # If we have already sent a request for this URL, delay this call until later if url in _pending_xmlws_requests: _pending_xmlws_requests[url].append(partial(get_tags, album, metadata, path, min_usage, ignore, next, current)) else: _pending_xmlws_requests[url] = [] album._requests += 1 album.tagger.xmlws.get(LASTFM_HOST, LASTFM_PORT, path, partial(_tags_downloaded, album, metadata, min_usage, ignore, next, current), priority=True, important=True)
def lookup_puid(self, puid): """ Try to identify the file using the PUID. """ self.tagger.window.set_statusbar_message( N_("Looking up the PUID for file %s..."), self.filename) self.clear_lookup_task() self.lookup_task = self.tagger.xmlws.lookup_puid( puid, partial(self._lookup_finished, 'puid'))
def submit(self): fingerprints = list(self._unsubmitted()) if not fingerprints: self._check_unsubmitted() return self.tagger.window.set_statusbar_message(N_('Submitting AcoustIDs...')) self.tagger.xmlws.submit_acoustid_fingerprints(fingerprints, partial(self.__fingerprint_submission_finished, fingerprints))
def _lookup_fingerprint(self, next, filename, result=None, error=None): try: file = self.tagger.files[filename] except KeyError: # The file has been removed. do nothing return if not result: self.tagger.window.set_statusbar_message( N_("Could not find AcoustID for file %s"), file.filename) file.clear_pending() return self.tagger.window.set_statusbar_message( N_("Looking up the fingerprint for file %s..."), file.filename) params = dict(meta='recordings releasegroups releases tracks compress') if result[0] == 'fingerprint': type, fingerprint, length = result file.acoustid_fingerprint = fingerprint file.acoustid_length = length self.tagger.acoustidmanager.add(file, None) params['fingerprint'] = fingerprint params['duration'] = str( (file.metadata.length or 1000 * length) / 1000) else: type, trackid = result params['trackid'] = trackid self.tagger.xmlws.query_acoustid( partial(self._on_lookup_finished, next, file), **params)
def move_file_to_nat(self, file, trackid, node=None): self.create_nats() file.move(self.nats.unmatched_files) nat = self.load_nat(trackid, node=node) nat.run_when_loaded(partial(file.move, nat)) if nat.loaded: self.nats.update()
def submit(self): """Submit PUIDs to MusicBrainz.""" puids = {} for puid, trackid in self.__unsubmitted(): puids[trackid] = puid self.tagger.window.set_statusbar_message(N_('Submitting PUIDs...')) self.tagger.xmlws.submit_puids(puids, partial(self.__puid_submission_finished, puids))
def finalize_genres(styles, metadata, target, albumtitle, albumartist, album, html): if styles == [] and target == "album_data" and albumartist != "Various Artists": album._requests += 1 album.tagger.xmlws.add_task(partial(artist_search, album, metadata, albumtitle, albumartist), position=1) elif styles == [] and (target == "artist_data" or target == "artist_search"): album._requests += 1 album.tagger.xmlws.add_task( partial(scrape_genres, html, album, "scrape_genre", albumtitle, albumartist, metadata), position=1 ) elif styles == []: print " * Dang, couldn't find anything!\n" else: metadata["genre"] = styles for track in album._new_tracks: track.metadata["genre"] = styles print "\n"
def load_user_collections(callback=None): tagger = QtCore.QObject.tagger def request_finished(document, reply, error): if error: tagger.window.set_statusbar_message(_("Error loading collections: %s"), unicode(reply.errorString())) return collection_list = document.metadata[0].collection_list[0] if "collection" in collection_list.children: new_collections = set() for node in collection_list.collection: new_collections.add(node.id) collection = user_collections.get(node.id) if collection is None: user_collections[node.id] = Collection(node.id, node.name[0].text, node.release_list[0].count) else: collection.name = node.name[0].text collection.size = int(node.release_list[0].count) for id in set(user_collections.iterkeys()) - new_collections: del user_collections[id] if callback: callback() if config.setting["username"] and config.setting["password"]: tagger.xmlws.get_collection_list(partial(request_finished))
def submit(self): """Submit PUIDs to MusicBrainz.""" puids = {} for puid, trackid in self.__unsubmitted(): puids[trackid] = puid self.tagger.window.set_statusbar_message(N_('Submitting PUIDs...')) self.tagger.xmlws.submit_puids( puids, partial(self.__puid_submission_finished, puids))
def _add_other_versions(): releases_menu.removeAction(loading) for version in obj.release_group.versions: action = releases_menu.addAction(version["name"]) action.setCheckable(True) if obj.id == version["id"]: action.setChecked(True) action.triggered.connect(partial(obj.switch_release_version, version["id"]))
def submit(self): fingerprints = list(self._unsubmitted()) if not fingerprints: self._check_unsubmitted() return self.tagger.window.set_statusbar_message(N_('Submitting AcoustIDs...')) self.tagger.xmlws.submit_acoustid_fingerprints( fingerprints, partial(self.__fingerprint_submission_finished, fingerprints))
def delete(self, host, port, path, handler, priority=True, important=True, mblogin=True): func = partial(self._start_request, "DELETE", host, port, path, None, handler, False, mblogin) return self.add_task(func, host, port, priority, important=important)
def contextMenuEvent(self, event): menu = QtGui.QMenu(self) if self.objects: rows = sorted(set(item.row() for item in self.selectedItems())) tags = [self.tag_names[r] for r in rows if self.tag_names[r] != "~length"] if len(tags) == 1: edit_tag_action = QtGui.QAction(_(u"Edit..."), self.parent) edit_tag_action.triggered.connect(partial(self.edit_tag, tags[0])) menu.addAction(edit_tag_action) removals = [] useorigs = [] for tag in tags: if self.tag_is_removable(tag): removals.append(partial(self.remove_tag, tag)) if self.tag_status(tag) in ("changed", "removed"): if tag in self.orig_tags.different or tag in self.new_tags.different: for file in self.files: objects = [file] if file.parent in self.tracks and len(self.files & set(file.parent.linked_files)) == 1: objects.append(file.parent) orig_values = list(file.orig_metadata._items.get(tag, [""])) useorigs.append(partial(self.set_tag_values, tag, orig_values, objects)) else: useorigs.append(partial(self.use_orig_value, tag)) if removals: remove_tag_action = QtGui.QAction(_(u"Remove"), self.parent) remove_tag_action.triggered.connect(lambda: [f() for f in removals]) menu.addAction(remove_tag_action) if useorigs: name = ungettext("Use Original Value", "Use Original Values", len(useorigs)) use_orig_value_action = QtGui.QAction(name, self.parent) use_orig_value_action.triggered.connect(lambda: [f() for f in useorigs]) menu.addAction(use_orig_value_action) menu.addSeparator() if len(tags) == 1 or removals or useorigs: menu.addSeparator() menu.addAction(self.add_tag_action) menu.addSeparator() menu.addAction(self.changes_first_action) menu.exec_(event.globalPos()) event.accept()
def get(self, host, port, path, handler, xml=True, priority=False, important=False, mblogin=False): func = partial(self._start_request, "GET", host, port, path, None, handler, xml, mblogin) return self.add_task(func, host, port, priority, important=important)
def process_track(album, metadata, release, track): tagger = album.tagger use_track_tags = tagger.config.setting["lastfm_use_track_tags"] use_artist_tags = tagger.config.setting["lastfm_use_artist_tags"] min_tag_usage = tagger.config.setting["lastfm_min_tag_usage"] ignore_tags = tagger.config.setting["lastfm_ignore_tags"].lower().split(",") if use_track_tags or use_artist_tags: artist = metadata["artist"] title = metadata["title"] if artist: if use_artist_tags: get_artist_tags_func = partial(get_artist_tags, album, metadata, artist, min_tag_usage, ignore_tags, None) else: get_artist_tags_func = None if title and use_track_tags: func = partial(get_track_tags, album, metadata, artist, title, min_tag_usage, ignore_tags, get_artist_tags_func, []) elif get_artist_tags_func: func = partial(get_artist_tags_func, []) if func: album._requests += 1 tagger.xmlws.add_task(func, position=1)
def put(self, host, port, path, data, handler, priority=True, important=True, mblogin=True): func = partial(self._start_request, "PUT", host, port, path, data, handler, False, mblogin) return self.add_task(func, host, port, priority, important=important)
def allmusic_genre(album, metadata, release): if metadata["albumartist"] != "Various Artists": albumartist = translate_artist(metadata["artist"], metadata["artistsort"]) else: albumartist = metadata["albumartist"] albumtitle = clean_album_title(metadata["album"]) albumartist = unicode(ununicode(albumartist)) albumtitle = unicode(ununicode(albumtitle)) print " * Looking for " + albumtitle + " by " + albumartist print " * Sending album search request", album._requests += 1 album.tagger.xmlws.add_task(partial(album_search, album, metadata, albumtitle, albumartist), position=1)
def analyze(self, file, next): fpcalc_next = partial(self._lookup_fingerprint, next, file.filename) # use cached fingerprint fingerprints = file.metadata.getall('acoustid_fingerprint') if fingerprints: fpcalc_next(result=('fingerprint', fingerprints[0], 0)) return # calculate the fingerprint task = (file, fpcalc_next) self._queue.append(task) if self._running < self._max_processes: self._run_next_task()
def lookup_metadata(self): """ Try to identify the file using the existing metadata. """ self.tagger.window.set_statusbar_message(N_("Looking up the metadata for file %s..."), self.filename) self.clear_lookup_task() self.lookup_task = self.tagger.xmlws.find_tracks(partial(self._lookup_finished, 'metadata'), track=self.metadata.get('title', ''), artist=self.metadata.get('artist', ''), release=self.metadata.get('album', ''), tnum=self.metadata.get('tracknumber', ''), tracks=self.metadata.get('totaltracks', ''), qdur=str(self.metadata.length / 2000), limit=25)
def coverart(album, metadata, release, try_list=None): """ Gets all cover art URLs from the metadata and then attempts to download the album art. """ # try_list will be None for the first call if try_list is None: try_list = [] # MB web service indicates if CAA has artwork # http://tickets.musicbrainz.org/browse/MBS-4536 has_caa_artwork = False caa_types = map(unicode.lower, config.setting["caa_image_types"].split()) if 'cover_art_archive' in release.children: caa_node = release.children['cover_art_archive'][0] has_caa_artwork = (caa_node.artwork[0].text == 'true') if len(caa_types) == 2 and ('front' in caa_types or 'back' in caa_types): # The OR cases are there to still download and process the CAA # JSON file if front or back is enabled but not in the CAA and # another type (that's neither front nor back) is enabled. # For example, if both front and booklet are enabled and the # CAA only has booklet images, the front element in the XML # from the webservice will be false (thus front_in_caa is False # as well) but it's still necessary to download the booklet # images by using the fact that back is enabled but there are # no back images in the CAA. front_in_caa = caa_node.front[0].text == 'true' or 'front' not in caa_types back_in_caa = caa_node.back[0].text == 'true' or 'back' not in caa_types has_caa_artwork = has_caa_artwork and (front_in_caa or back_in_caa) elif len(caa_types) == 1 and ('front' in caa_types or 'back' in caa_types): front_in_caa = caa_node.front[0].text == 'true' and 'front' in caa_types back_in_caa = caa_node.back[0].text == 'true' and 'back' in caa_types has_caa_artwork = has_caa_artwork and (front_in_caa or back_in_caa) if config.setting['ca_provider_use_caa'] and has_caa_artwork\ and len(caa_types) > 0: log.debug("There are suitable images in the cover art archive for %s" % release.id) album._requests += 1 album.tagger.xmlws.download( "coverartarchive.org", 80, "/release/%s/" % metadata["musicbrainz_albumid"], partial(_caa_json_downloaded, album, metadata, release, try_list), priority=True, important=True) else: log.debug("There are no suitable images in the cover art archive for %s" % release.id) _fill_try_list(album, release, try_list) _walk_try_list(album, metadata, release, try_list)
def _add_other_versions(): releases_menu.removeAction(loading) actions = [] for i, version in enumerate(obj.other_versions): keys = ("date", "country", "labels", "catnums", "tracks", "format") name = " / ".join([version[k] for k in keys if version[k]]).replace("&", "&&") if name == version["tracks"]: name = "%s / %s" % (_('[no release info]'), name) action = releases_menu.addAction(name) action.setCheckable(True) if obj.id == version["mbid"]: action.setChecked(True) action.triggered.connect(partial(obj.switch_release_version, version["mbid"]))
def load(self): inc = ["artist-credits"] mblogin = False if self.config.setting["folksonomy_tags"]: if self.config.setting["only_my_tags"]: mblogin = True inc += ["user-tags"] else: inc += ["tags"] if self.config.setting["enable_ratings"]: mblogin = True inc += ["user-ratings"] self.tagger.xmlws.get_track_by_id(self.id, partial(self._recording_request_finished), inc, mblogin=mblogin)
def get_tags(album, metadata, path, min_usage, ignore, next, current): """Get tags from an URL.""" try: if path in _cache: _tags_finalize(album, metadata, current + _cache[path], next) else: album._requests += 1 album.tagger.xmlws.get("ws.audioscrobbler.com", 80, path, partial(_tags_downloaded, album, metadata, min_usage, ignore, next, current), position=1) finally: album._requests -= 1 album._finalize_loading(None) return False
def lookup_metadata(self): """ Try to identify the file using the existing metadata. """ self.tagger.window.set_statusbar_message( N_("Looking up the metadata for file %s..."), self.filename) self.clear_lookup_task() self.lookup_task = self.tagger.xmlws.find_tracks( partial(self._lookup_finished, 'metadata'), track=self.metadata.get('title', ''), artist=self.metadata.get('artist', ''), release=self.metadata.get('album', ''), tnum=self.metadata.get('tracknumber', ''), tracks=self.metadata.get('totaltracks', ''), qdur=str(self.metadata.length / 2000), limit=25)
def post(self, host, port, path, data, handler, xml=True, priority=True, important=True, mblogin=True): self.log.debug("POST-DATA %r", data) func = partial(self._start_request, "POST", host, port, path, data, handler, xml, mblogin) return self.add_task(func, host, port, priority, important=important)
def queue_downloads(self): release_group_id = self.metadata["musicbrainz_releasegroupid"] path = "/v3/music/albums/%s?api_key=%s&client_key=%s" % \ (release_group_id, str(QUrl.toPercentEncoding(API_KEY)), str(QUrl.toPercentEncoding(self._client_key))) log.debug("CoverArtProviderFanartTv.queue_downloads: %s" % path) self.album.tagger.xmlws.download(FANART_HOST, FANART_PORT, path, partial(self._json_downloaded, release_group_id), priority=True, important=False) self.album._requests += 1 return CoverArtProvider.WAIT
def _add_other_versions(): releases_menu.removeAction(loading) actions = [] for i, version in enumerate(obj.other_versions): keys = ("date", "country", "labels", "catnums", "tracks", "format") name = " / ".join([version[k] for k in keys if version[k]]).replace("&", "&&") if name == version["tracks"]: name = "%s / %s" % (_('[no release info]'), name) action = releases_menu.addAction(name) action.setCheckable(True) if obj.id == version["mbid"]: action.setChecked(True) action.triggered.connect( partial(obj.switch_release_version, version["mbid"]))
def __init__(self, parent): QtGui.QTableWidget.__init__(self, parent) self.parent = parent self.setColumnCount(3) self.setHorizontalHeaderLabels( (_("Tag"), _("Original Value"), _("New Value"))) self.horizontalHeader().setStretchLastSection(True) self.horizontalHeader().setClickable(False) self.verticalHeader().setDefaultSectionSize(21) self.verticalHeader().setVisible(False) self.setSelectionMode(QtGui.QAbstractItemView.ExtendedSelection) self.setTabKeyNavigation(False) self.setStyleSheet("QTableWidget {border: none;}") self.setAttribute(QtCore.Qt.WA_MacShowFocusRect, 1) self.itemChanged.connect(self.item_changed) self.colors = { "default": self.palette().color(QtGui.QPalette.Text), "removed": QtGui.QBrush(QtGui.QColor("red")), "added": QtGui.QBrush(QtGui.QColor("green")), "changed": QtGui.QBrush(QtGui.QColor("darkgoldenrod")), } self.files = set() self.tracks = set() self.objects = set() self.orig_tags = TagCounter() self.new_tags = TagCounter() self.selection_mutex = QtCore.QMutex() self.updating = False self.update_pending = False self.selection_dirty = False self.editing = False # true if a QTableWidgetItem is being edited self.clipboard = [""] self.add_tag_action = QtGui.QAction(_(u"Add New Tag..."), parent) self.add_tag_action.triggered.connect(partial(self.edit_tag, "")) self.changes_first_action = QtGui.QAction(_(u"Show Changes First"), parent) self.changes_first_action.setCheckable(True) self.changes_first_action.setChecked( self.config.persist["show_changes_first"]) self.changes_first_action.toggled.connect(self.toggle_changes_first)
def load(self): inc = ["artist-credits", "artists", "aliases"] mblogin = False if self.config.setting["track_ars"]: inc += [ "artist-rels", "url-rels", "recording-rels", "work-rels", "work-level-rels" ] if self.config.setting["folksonomy_tags"]: if self.config.setting["only_my_tags"]: mblogin = True inc += ["user-tags"] else: inc += ["tags"] if self.config.setting["enable_ratings"]: mblogin = True inc += ["user-ratings"] self.tagger.xmlws.get_track_by_id( self.id, partial(self._recording_request_finished), inc, mblogin=mblogin)