diff --git a/picard/musicdns/webservice.py b/picard/musicdns/webservice.py new file mode 100644 index 000000000..2161f50c9 --- /dev/null +++ b/picard/musicdns/webservice.py @@ -0,0 +1,72 @@ +# -*- coding: utf-8 -*- +# +# Picard, the next-generation MusicBrainz tagger +# Copyright (C) 2006 Lukáš Lalinský +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +import musicbrainz2.webservice +import urllib +from musicbrainz2.webservice import ResponseError +from musicbrainz2.wsxml import MbXmlParser, ParseError + + +class TrackFilter(musicbrainz2.webservice.IFilter): + + def __init__(self, clientId=None, clientVersion=None, fingerprint=None, + puid=None, fileSha1=None, acousticSha1=None, metadata=None, + bitrate=None, format=None, length=None, artist=None, + title=None, album=None, trackNum=None, genre=None, year=None, + composer=None, conductor=None, orchestra=None, encoding=None, + lookupType=None): + self._params = [ + ('lkt', lookupType), + ('cid', clientId), + ('cvr', clientVersion), + ('fpt', fingerprint), + ('uid', puid), + ('s1f', fileSha1), + ('s1a', acousticSha1), + ('rmd', metadata), + ('brt', bitrate), + ('fmt', format), + ('dur', length), + ('art', artist), + ('ttl', title), + ('alb', album), + ('tnm', trackNum), + ('gnr', genre), + ('yrr', year), + ('cmp', composer), + ('cnd', conductor), + ('orc', orchestra), + ('enc', encoding), + ] + + def createParameters(self): + return musicbrainz2.webservice._createParameters(self._params) + + +class Query(musicbrainz2.webservice.Query): + + def getTrack(self, filter): + params = filter.createParameters() + stream = self._ws.post("track", "", urllib.urlencode(params, True)) + try: + parser = MbXmlParser() + return parser.parse(stream).getTrack() + except ParseError, e: + raise ResponseError(str(e), e) + diff --git a/picard/tagger.py b/picard/tagger.py index 1bf5812b7..544d17d4f 100644 --- a/picard/tagger.py +++ b/picard/tagger.py @@ -117,7 +117,8 @@ class Tagger(QtGui.QApplication, ComponentManager, Component): console = logging.StreamHandler(sys.stdout) console.setFormatter(logging.Formatter(u"%(thread)s %(asctime)s %(message)s", u"%H:%M:%S")) - self.log = logging.getLogger("picard") + self.log = logging.getLogger() +# self.log = logging.getLogger("picard") self.log.addHandler(console) self.log.setLevel(logging.DEBUG) @@ -655,10 +656,23 @@ class Tagger(QtGui.QApplication, ComponentManager, Component): self.thread_assist.spawn(self.__analyze_thread, (files,)) def __analyze_thread(self, files): + from picard.musicdns.webservice import TrackFilter, Query + ws = self.get_web_service() + ws._host = "ofa.musicdns.org" + ws._pathPrefix = "/ofa" for file in files: file.lock_for_read() try: filename = file.filename + artist = file.metadata["artist"] + title = file.metadata["title"] + album = file.metadata["album"] + trackNum = file.metadata["tracknumber"] + genre = file.metadata["genre"] + year = file.metadata["date"][:4] + format = file.metadata["~format"] + bitrate = str(file.metadata.get("~#bitrate", 0)) + length = file.metadata.get("~#length", 0) finally: file.unlock() self.log.debug("Analyzing file %s", filename) @@ -667,6 +681,34 @@ class Tagger(QtGui.QApplication, ComponentManager, Component): fingerprint, duration = result self.log.debug("File %s analyzed.\nFingerprint: %s\n" "Duration: %s", filename, fingerprint, duration) + if not length: + length = duration + q = Query(ws) + track = q.getTrack(TrackFilter( + clientId="80eaa76658f99dbac1c58cc06aa44779", + clientVersion="picard-0.9", fingerprint=fingerprint, + artist=artist, title=title, album=album, trackNum=trackNum, + genre=genre, year=year, bitrate=bitrate, format=format, + length=str(length), metadata="1", lookupType="1", + encoding="")) + if track: + artist = "" + if track.artist: + artist = track.artist.name or "" + self.log.debug("Fingerprint looked up.\nPUID: %s\nTitle: %s\n" + "Artist: %s", track.puids, track.title or "", + artist) + if track.puids: + file.lock_for_write() + try: + file.metadata["musicip_puid"] = track.puids[0] + finally: + file.unlock() + else: + self.log.debug("Fingerprint looked up, no PUID found.") + + + def set_wait_cursor(self): """Sets the waiting cursor.""" diff --git a/picard/util/cachedws.py b/picard/util/cachedws.py index 3feaf9ada..0a0dbc51e 100644 --- a/picard/util/cachedws.py +++ b/picard/util/cachedws.py @@ -58,6 +58,28 @@ class CachedWebService(WebService): self._log.debug(u"(Cached) GET %s", url) return open(filename, 'rb') + def post(self, entity, id_, data, version='1'): + url = self._makeUrl(entity, id_, version=version, type_=None) + filename = self._make_cache_filename(url + data) + if not os.path.isfile(filename): + stream = WebService.post(self, entity, id_, data, version) + try: + outfile = open(filename, 'wb') + except IOError: + self._log.error('Couldn\'t create cache file %s', filename) + return stream + else: + data = stream.read() + if self._host == "ofa.musicdns.org": + data = data.replace("http://musicbrainz.org/ns/mmd/1/", + "http://musicbrainz.org/ns/mmd-1.0#") + outfile.write(data) + outfile.close() + stream.close() + else: + self._log.debug(u"(Cached) POST %s", url) + return open(filename, 'rb') + def get_from_url(self, url): filename = self._make_cache_filename(url) if not os.path.isfile(filename):