Example #1
0
        def parse_line(line):
            orig_line = line
            try:
                line = line.split()
                if line[0] == "GET" and "?" in line[1]:
                    parsed = urlparse(line[1])
                    args = parse_qs(parsed.query)
                    if 'id' in args and args['id']:
                        mbid = args['id'][0]
                        if not mbid_validate(mbid):
                            log.error("Browser integration failed: bad mbid %r", mbid)
                            return False

                        def load_it(loader):
                            self.tagger.bring_tagger_front()
                            loader(mbid)
                            return True
                        action = parsed.path
                        if action == '/openalbum':
                            return load_it(self.tagger.load_album)
                        elif action == '/opennat':
                            return load_it(self.tagger.load_nat)
            except Exception as e:
                log.error("Browser integration failed with %r on line %r", e, orig_line)
                return False
            log.error("Browser integration failed: cannot parse %r", orig_line)
            return False
Example #2
0
 def _release_request_finished(self, document, http, error):
     if self.load_task is None:
         return
     self.load_task = None
     parsed = False
     try:
         if error:
             self.log.error("%r", unicode(http.errorString()))
             # Fix for broken NAT releases
             if error == QtNetwork.QNetworkReply.ContentNotFoundError:
                 nats = False
                 nat_name = self.config.setting["nat_name"]
                 files = list(self.unmatched_files.files)
                 for file in files:
                     trackid = file.metadata["musicbrainz_trackid"]
                     if mbid_validate(trackid) and file.metadata["album"] == nat_name:
                         nats = True
                         self.tagger.move_file_to_nat(file, trackid)
                         self.tagger.nats.update()
                 if nats and not self.get_num_unmatched_files():
                     self.tagger.remove_album(self)
                     error = False
         else:
             try:
                 parsed = self._parse_release(document)
             except:
                 error = True
                 self.log.error(traceback.format_exc())
     finally:
         self._requests -= 1
         if parsed or error:
             self._finalize_loading(error)
Example #3
0
 def _file_loaded(self, result=None, error=None):
     file = result
     if file is not None and error is None and not file.has_error():
         puid = file.metadata['musicip_puid']
         trackid = file.metadata['musicbrainz_trackid']
         albumid = file.metadata['musicbrainz_albumid']
         self.puidmanager.add(puid, trackid)
         if mbid_validate(albumid):
             if mbid_validate(trackid):
                 self.move_file_to_track(file, albumid, trackid)
             else:
                 self.move_file_to_album(file, albumid)
         elif mbid_validate(trackid):
             self.move_file_to_nat(file, trackid)
         elif self.config.setting['analyze_new_files']:
             self.analyze([file])
Example #4
0
 def _file_loaded(self, file, target=None):
     if file is not None and not file.has_error():
         trackid = file.metadata['musicbrainz_trackid']
         if target is not None:
             self.move_files([file], target)
         elif not config.setting["ignore_file_mbids"]:
             albumid = file.metadata['musicbrainz_albumid']
             if mbid_validate(albumid):
                 if mbid_validate(trackid):
                     self.move_file_to_track(file, albumid, trackid)
                 else:
                     self.move_file_to_album(file, albumid)
             elif mbid_validate(trackid):
                 self.move_file_to_nat(file, trackid)
             elif config.setting['analyze_new_files'] and file.can_analyze():
                 self.analyze([file])
         elif config.setting['analyze_new_files'] and file.can_analyze():
             self.analyze([file])
Example #5
0
 def test_ok(self):
     self.assertTrue(util.mbid_validate('2944824d-4c26-476f-a981-be849081942f'))
     self.assertTrue(util.mbid_validate('2944824D-4C26-476F-A981-be849081942f'))
     self.assertFalse(util.mbid_validate(''))
     self.assertFalse(util.mbid_validate('Z944824d-4c26-476f-a981-be849081942f'))
     self.assertFalse(util.mbid_validate('22944824d-4c26-476f-a981-be849081942f'))
     self.assertFalse(util.mbid_validate('2944824d-4c26-476f-a981-be849081942ff'))
     self.assertFalse(util.mbid_validate('2944824d-4c26.476f-a981-be849081942f'))
Example #6
0
 def test_ok(self):
     self.assertTrue(util.mbid_validate('2944824d-4c26-476f-a981-be849081942f'))
     self.assertTrue(util.mbid_validate('2944824D-4C26-476F-A981-be849081942f'))
     self.assertFalse(util.mbid_validate(''))
     self.assertFalse(util.mbid_validate('Z944824d-4c26-476f-a981-be849081942f'))
     self.assertFalse(util.mbid_validate('22944824d-4c26-476f-a981-be849081942f'))
     self.assertFalse(util.mbid_validate('2944824d-4c26-476f-a981-be849081942ff'))
     self.assertFalse(util.mbid_validate('2944824d-4c26.476f-a981-be849081942f'))
Example #7
0
 def _file_loaded(self, result=None, error=None):
     file = result
     if file is not None and error is None and not file.has_error():
         puid = file.metadata['musicip_puid']
         trackid = file.metadata['musicbrainz_trackid']
         self.puidmanager.add(puid, trackid)
         if not self.config.setting["ignore_file_mbids"]:
             albumid = file.metadata['musicbrainz_albumid']
             if mbid_validate(albumid):
                 if mbid_validate(trackid):
                     self.move_file_to_track(file, albumid, trackid)
                 else:
                     self.move_file_to_album(file, albumid)
             elif mbid_validate(trackid):
                 self.move_file_to_nat(file, trackid)
             elif self.config.setting['analyze_new_files']:
                 self.analyze([file])
         elif self.config.setting['analyze_new_files']:
             self.analyze([file])
Example #8
0
 def _file_loaded(self, file, target=None):
     if file is not None and not file.has_error():
         recordingid = file.metadata['musicbrainz_recordingid']
         if target is not None:
             self.move_files([file], target)
         elif not config.setting["ignore_file_mbids"]:
             albumid = file.metadata['musicbrainz_albumid']
             if mbid_validate(albumid):
                 if mbid_validate(recordingid):
                     self.move_file_to_track(file, albumid, recordingid)
                 else:
                     self.move_file_to_album(file, albumid)
             elif mbid_validate(recordingid):
                 self.move_file_to_nat(file, recordingid)
             elif config.setting['analyze_new_files'] and file.can_analyze(
             ):
                 self.analyze([file])
         elif config.setting['analyze_new_files'] and file.can_analyze():
             self.analyze([file])
Example #9
0
 def _load_mbid(self, type, args):
     if 'id' in args and args['id']:
         mbid = args['id'][0]
         if not mbid_validate(mbid):
             self._response(400, '"id" is not a valid MBID.')
         else:
             tagger = QtCore.QCoreApplication.instance()
             to_main(tagger.load_mbid, type, mbid)
             self._response(200, 'MBID "%s" loaded' % mbid)
     else:
         self._response(400, 'Missing parameter "id".')
Example #10
0
 def _file_loaded(self, file, target=None):
     if file is not None and not file.has_error():
         recordingid = (
             file.metadata.getall("musicbrainz_recordingid")[0] if "musicbrainz_recordingid" in file.metadata else ""
         )
         if target is not None:
             self.move_files([file], target)
         elif not config.setting["ignore_file_mbids"]:
             albumid = (
                 file.metadata.getall("musicbrainz_albumid")[0] if "musicbrainz_albumid" in file.metadata else ""
             )
             if mbid_validate(albumid):
                 if mbid_validate(recordingid):
                     self.move_file_to_track(file, albumid, recordingid)
                 else:
                     self.move_file_to_album(file, albumid)
             elif mbid_validate(recordingid):
                 self.move_file_to_nat(file, recordingid)
             elif config.setting["analyze_new_files"] and file.can_analyze():
                 self.analyze([file])
         elif config.setting["analyze_new_files"] and file.can_analyze():
             self.analyze([file])
Example #11
0
    def _file_loaded(self, file, target=None):
        if file is None or file.has_error():
            return

        if target is not None:
            self.move_files([file], target)
            return

        if not config.setting["ignore_file_mbids"]:
            recordingid = file.metadata['musicbrainz_recordingid']
            is_valid_recordingid = mbid_validate(recordingid)

            albumid = file.metadata['musicbrainz_albumid']
            is_valid_albumid = mbid_validate(albumid)

            if is_valid_albumid and is_valid_recordingid:
                log.debug(
                    "%r has release (%s) and recording (%s) MBIDs, moving to track...",
                    file, albumid, recordingid)
                self.move_file_to_track(file, albumid, recordingid)
                return

            if is_valid_albumid:
                log.debug("%r has only release MBID (%s), moving to album...",
                          file, albumid)
                self.move_file_to_album(file, albumid)
                return

            if is_valid_recordingid:
                log.debug(
                    "%r has only recording MBID (%s), moving to non-album track...",
                    file, recordingid)
                self.move_file_to_nat(file, recordingid)
                return

        # fallback on analyze if nothing else worked
        if config.setting['analyze_new_files'] and file.can_analyze():
            log.debug("Trying to analyze %r ...", file)
            self.analyze([file])
Example #12
0
    def _match_files(self, files, recordingid=None, threshold=0):
        """Match files to tracks on this album, based on metadata similarity or recordingid."""
        tracks_cache = defaultdict(lambda: None)

        def build_tracks_cache():
            for track in self.tracks:
                tm_recordingid = track.orig_metadata['musicbrainz_recordingid']
                tm_tracknumber = track.orig_metadata['tracknumber']
                tm_discnumber = track.orig_metadata['discnumber']
                for tup in (
                    (tm_recordingid, tm_tracknumber, tm_discnumber),
                    (tm_recordingid, tm_tracknumber),
                    (tm_recordingid, )):
                    tracks_cache[tup] = track

        SimMatchAlbum = namedtuple('SimMatchAlbum', 'similarity track')

        for file in list(files):
            if file.state == File.REMOVED:
                continue
            # if we have a recordingid to match against, use that in priority
            recid = recordingid or file.metadata['musicbrainz_recordingid']
            if recid and mbid_validate(recid):
                if not tracks_cache:
                    build_tracks_cache()
                tracknumber = file.metadata['tracknumber']
                discnumber = file.metadata['discnumber']
                track = (tracks_cache[(recid, tracknumber, discnumber)]
                         or tracks_cache[(recid, tracknumber)]
                         or tracks_cache[(recid, )])
                if track:
                    yield (file, track)
                    continue

            # try to match by similarity
            def candidates():
                for track in self.tracks:
                    yield SimMatchAlbum(
                        similarity=track.metadata.compare(file.orig_metadata),
                        track=track
                    )
                    QtCore.QCoreApplication.processEvents()

            no_match = SimMatchAlbum(similarity=-1, track=self.unmatched_files)
            best_match = find_best_match(candidates, no_match)

            if best_match.similarity < threshold:
                yield (file, no_match.track)
            else:
                yield (file, best_match.result.track)
Example #13
0
File: tagger.py Project: phw/picard
    def _file_loaded(self, file, target=None):
        if file is None or file.has_error():
            return

        if target is not None:
            self.move_files([file], target)
            return

        if not config.setting["ignore_file_mbids"]:
            recordingid = file.metadata['musicbrainz_recordingid']
            is_valid_recordingid = mbid_validate(recordingid)

            albumid = file.metadata['musicbrainz_albumid']
            is_valid_albumid = mbid_validate(albumid)

            if is_valid_albumid and is_valid_recordingid:
                log.debug("%r has release (%s) and recording (%s) MBIDs, moving to track...",
                          file, albumid, recordingid)
                self.move_file_to_track(file, albumid, recordingid)
                return

            if is_valid_albumid:
                log.debug("%r has only release MBID (%s), moving to album...",
                          file, albumid)
                self.move_file_to_album(file, albumid)
                return

            if is_valid_recordingid:
                log.debug("%r has only recording MBID (%s), moving to non-album track...",
                          file, recordingid)
                self.move_file_to_nat(file, recordingid)
                return

        # fallback on analyze if nothing else worked
        if config.setting['analyze_new_files'] and file.can_analyze():
            log.debug("Trying to analyze %r ...", file)
            self.analyze([file])
Example #14
0
    def _match_files(self, files, recordingid=None, threshold=0):
        """Match files to tracks on this album, based on metadata similarity or recordingid."""
        tracks_cache = defaultdict(lambda: None)

        def build_tracks_cache():
            for track in self.tracks:
                tm_recordingid = track.orig_metadata['musicbrainz_recordingid']
                tm_tracknumber = track.orig_metadata['tracknumber']
                tm_discnumber = track.orig_metadata['discnumber']
                for tup in (
                    (tm_recordingid, tm_tracknumber, tm_discnumber),
                    (tm_recordingid, tm_tracknumber),
                    (tm_recordingid, )):
                    tracks_cache[tup] = track

        SimMatchAlbum = namedtuple('SimMatchAlbum', 'similarity track')

        for file in list(files):
            if file.state == File.REMOVED:
                continue
            # if we have a recordingid to match against, use that in priority
            recid = recordingid or file.metadata['musicbrainz_recordingid']
            if recid and mbid_validate(recid):
                if not tracks_cache:
                    build_tracks_cache()
                tracknumber = file.metadata['tracknumber']
                discnumber = file.metadata['discnumber']
                track = (tracks_cache[(recid, tracknumber, discnumber)]
                         or tracks_cache[(recid, tracknumber)]
                         or tracks_cache[(recid, )])
                if track:
                    yield (file, track)
                    continue

            # try to match by similarity
            def candidates():
                for track in self.tracks:
                    yield SimMatchAlbum(
                        similarity=track.metadata.compare(file.orig_metadata),
                        track=track
                    )

            no_match = SimMatchAlbum(similarity=-1, track=self.unmatched_files)
            best_match = find_best_match(candidates, no_match)

            if best_match.similarity < threshold:
                yield (file, no_match.track)
            else:
                yield (file, best_match.result.track)
Example #15
0
 def match_files(self, files, use_trackid=True):
     """Match files to tracks on this album, based on metadata similarity or trackid."""
     for file in list(files):
         matches = []
         trackid = file.metadata['musicbrainz_trackid']
         if use_trackid and mbid_validate(trackid):
             matches = self._get_trackid_matches(file, trackid)
         if not matches:
             for track in self.tracks:
                 sim = track.metadata.compare(file.orig_metadata)
                 if sim >= self.config.setting['track_matching_threshold']:
                     matches.append((sim, track))
         if matches:
             matches.sort(reverse=True)
             file.move(matches[0][1])
         else:
             file.move(self.unmatched_files)
Example #16
0
 def match_files(self, files, use_recordingid=True):
     """Match files to tracks on this album, based on metadata similarity or recordingid."""
     for file in list(files):
         if file.state == File.REMOVED:
             continue
         matches = []
         recordingid = file.metadata['musicbrainz_recordingid']
         if use_recordingid and mbid_validate(recordingid):
             matches = self._get_recordingid_matches(file, recordingid)
         if not matches:
             for track in self.tracks:
                 sim = track.metadata.compare(file.orig_metadata)
                 if sim >= config.setting['track_matching_threshold']:
                     matches.append((sim, track))
         if matches:
             matches.sort(reverse=True)
             file.move(matches[0][1])
         else:
             file.move(self.unmatched_files)
Example #17
0
 def match_files(self, files, use_recordingid=True):
     """Match files to tracks on this album, based on metadata similarity or recordingid."""
     for file in list(files):
         if file.state == File.REMOVED:
             continue
         matches = []
         recordingid = file.metadata['musicbrainz_recordingid']
         if use_recordingid and mbid_validate(recordingid):
             matches = self._get_recordingid_matches(file, recordingid)
         if not matches:
             for track in self.tracks:
                 sim = track.metadata.compare(file.orig_metadata)
                 if sim >= config.setting['track_matching_threshold']:
                     matches.append((sim, track))
         if matches:
             matches.sort(key=itemgetter(0), reverse=True)
             file.move(matches[0][1])
         else:
             file.move(self.unmatched_files)
Example #18
0
    def _match_files(self, files, recordingid=None, threshold=0):
        """Match files to tracks on this album, based on metadata similarity or recordingid."""
        tracks_cache = defaultdict(lambda: None)

        def build_tracks_cache():
            for track in self.tracks:
                tm_recordingid = track.orig_metadata['musicbrainz_recordingid']
                tm_tracknumber = track.orig_metadata['tracknumber']
                tm_discnumber = track.orig_metadata['discnumber']
                for tup in (
                    (tm_recordingid, tm_tracknumber, tm_discnumber),
                    (tm_recordingid, tm_tracknumber),
                    (tm_recordingid, )):
                    tracks_cache[tup] = track

        for file in list(files):
            if file.state == File.REMOVED:
                continue
            # if we have a recordingid to match against, use that in priority
            recid = recordingid or file.metadata['musicbrainz_recordingid']
            if recid and mbid_validate(recid):
                if not tracks_cache:
                    build_tracks_cache()
                tracknumber = file.metadata['tracknumber']
                discnumber = file.metadata['discnumber']
                track = (tracks_cache[(recid, tracknumber, discnumber)]
                         or tracks_cache[(recid, tracknumber)]
                         or tracks_cache[(recid, )])
                if track:
                    yield (file, track)
                    continue
            # try to match by similarity
            # TODO: find a way to speed up this part, it needs to iterate all
            # tracks for each file, and metadata.compare() is rather complex
            best_track = None
            best_score = -1
            for track in self.tracks:
                sim = track.metadata.compare(file.orig_metadata)
                if sim >= threshold and sim > best_score:
                    best_track, best_score = track, sim
            yield (file, best_track or self.unmatched_files)
Example #19
0
 def _release_request_finished(self, document, http, error):
     if self.load_task is None:
         return
     self.load_task = None
     parsed = False
     try:
         if error:
             self.error_append(http.errorString())
             # Fix for broken NAT releases
             if error == QtNetwork.QNetworkReply.NetworkError.ContentNotFoundError:
                 config = get_config()
                 nats = False
                 nat_name = config.setting["nat_name"]
                 files = list(self.unmatched_files.files)
                 for file in files:
                     recordingid = file.metadata["musicbrainz_recordingid"]
                     if mbid_validate(recordingid) and file.metadata[
                             "album"] == nat_name:
                         nats = True
                         self.tagger.move_file_to_nat(file, recordingid)
                         self.tagger.nats.update()
                 if nats and not self.get_num_unmatched_files():
                     self.tagger.remove_album(self)
                     error = False
         else:
             try:
                 parsed = self._parse_release(document)
                 config = get_config()
                 if not parsed and config.setting['track_ars']:
                     log.debug(
                         'Recording relationships not loaded in initial request for %r, issuing separate requests'
                         % self)
                     self._request_recording_relationships(config=config)
             except Exception:
                 error = True
                 self.error_append(traceback.format_exc())
     finally:
         self._requests -= 1
         if parsed or error:
             self._finalize_loading(error)
Example #20
0
    def _file_loaded(self,
                     file,
                     target=None,
                     remove_file=False,
                     unmatched_files=None):
        config = get_config()
        self._pending_files_count -= 1
        if self._pending_files_count == 0:
            self.window.set_sorting(True)

        if remove_file:
            file.remove()
            return

        if file is None:
            return

        if file.has_error():
            self.unclustered_files.add_file(file)
            return

        file_moved = False
        if not config.setting["ignore_file_mbids"]:
            recordingid = file.metadata.getall('musicbrainz_recordingid')
            recordingid = recordingid[0] if recordingid else ''
            is_valid_recordingid = mbid_validate(recordingid)

            albumid = file.metadata.getall('musicbrainz_albumid')
            albumid = albumid[0] if albumid else ''
            is_valid_albumid = mbid_validate(albumid)

            if is_valid_albumid and is_valid_recordingid:
                log.debug(
                    "%r has release (%s) and recording (%s) MBIDs, moving to track...",
                    file, albumid, recordingid)
                self.move_file_to_track(file, albumid, recordingid)
                file_moved = True
            elif is_valid_albumid:
                log.debug("%r has only release MBID (%s), moving to album...",
                          file, albumid)
                self.move_file_to_album(file, albumid)
                file_moved = True
            elif is_valid_recordingid:
                log.debug(
                    "%r has only recording MBID (%s), moving to non-album track...",
                    file, recordingid)
                self.move_file_to_nat(file, recordingid)
                file_moved = True

        if not file_moved:
            target = self.move_file(file, target)
            if target and target != self.unclustered_files:
                file_moved = True

        if not file_moved and unmatched_files is not None:
            unmatched_files.append(file)

        # fallback on analyze if nothing else worked
        if not file_moved and config.setting[
                'analyze_new_files'] and file.can_analyze():
            log.debug("Trying to analyze %r ...", file)
            self.analyze([file])

        # Auto cluster newly added files if they are not explicitly moved elsewhere
        if self._pending_files_count == 0 and unmatched_files and config.setting[
                "cluster_new_files"]:
            self.cluster(unmatched_files)