Exemple #1
0
 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,
                 )
             )
Exemple #2
0
 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()
Exemple #3
0
 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))
Exemple #4
0
    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])
Exemple #5
0
 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()
Exemple #6
0
 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))
Exemple #7
0
    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])
Exemple #8
0
 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))
Exemple #9
0
 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)
Exemple #10
0
 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))
Exemple #11
0
 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))
Exemple #12
0
 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,
         )
     )
Exemple #13
0
 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))
Exemple #14
0
 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))
Exemple #15
0
    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))
Exemple #16
0
 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()
Exemple #17
0
    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)
        )
Exemple #18
0
    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))
Exemple #19
0
 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)
Exemple #20
0
    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))
Exemple #21
0
 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)
Exemple #22
0
    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))
Exemple #23
0
 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)
Exemple #24
0
 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)
Exemple #25
0
 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)
Exemple #26
0
 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)
Exemple #27
0
 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)
Exemple #28
0
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)
Exemple #29
0
 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'))
Exemple #30
0
 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))
Exemple #31
0
 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)
Exemple #32
0
 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()
Exemple #33
0
 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()
Exemple #34
0
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)
Exemple #35
0
 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"
Exemple #37
0
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))
Exemple #38
0
 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))
Exemple #39
0
 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"]))
Exemple #40
0
 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))
Exemple #41
0
 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)
Exemple #42
0
 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()
Exemple #43
0
 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)
Exemple #44
0
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)
Exemple #45
0
 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)
Exemple #47
0
 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()
Exemple #48
0
 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()
Exemple #49
0
 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)
Exemple #50
0
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)
Exemple #51
0
 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"]))
Exemple #52
0
 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)
Exemple #53
0
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
Exemple #54
0
 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)
Exemple #55
0
 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)
Exemple #56
0
 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
Exemple #57
0
 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"]))
Exemple #58
0
 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)
Exemple #59
0
 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)