From f2e2188ba49ee5dd46eacf584915bd026bbc1a35 Mon Sep 17 00:00:00 2001 From: Antonio Larrosa Date: Thu, 9 Feb 2017 08:15:37 +0100 Subject: [PATCH] Fix various cover drop issues This patch adds https support, so users can drag covers from amazon. Also fixes the imgurl query handling so users can drag covers from google images thumbnails (but large resolution images will be downloaded). It also adds support for dropped octet-stream data, so chromium users can drag "opened" images from google images even if the link actually points to the url containing the image, since chromium adds the image data to the drop event. Unfortunately, firefox doesn't do that, so firefox users will have to drag thumbnails (but the same large resolution image will be used in any case) --- picard/ui/coverartbox.py | 45 +++++++++++++++++++++++++++++----------- 1 file changed, 33 insertions(+), 12 deletions(-) diff --git a/picard/ui/coverartbox.py b/picard/ui/coverartbox.py index fc5158776..31b21deb4 100644 --- a/picard/ui/coverartbox.py +++ b/picard/ui/coverartbox.py @@ -33,7 +33,7 @@ class ActiveLabel(QtGui.QLabel): """Clickable QLabel.""" clicked = QtCore.pyqtSignal() - imageDropped = QtCore.pyqtSignal(QtCore.QUrl) + imageDropped = QtCore.pyqtSignal(QtCore.QUrl, QtCore.QByteArray) def __init__(self, active=True, *args): QtGui.QLabel.__init__(self, *args) @@ -54,16 +54,20 @@ class ActiveLabel(QtGui.QLabel): def dragEnterEvent(self, event): for url in event.mimeData().urls(): - if url.scheme() in ('http', 'file'): + if url.scheme() in ('https', 'http', 'file'): event.acceptProposedAction() break def dropEvent(self, event): accepted = False + # Chromium includes the actual data of the dragged image in the drop event. This + # is useful for Google Images, where the url links to the page that contains the image + # so we use it if the downloaded url is not an image. + droppedData = event.mimeData().data('application/octet-stream') for url in event.mimeData().urls(): - if url.scheme() in ('http', 'file'): + if url.scheme() in ('https', 'http', 'file'): accepted = True - self.imageDropped.emit(url) + self.imageDropped.emit(url, droppedData) if accepted: event.acceptProposedAction() @@ -150,15 +154,19 @@ class CoverArtBox(QtGui.QGroupBox): lookup = self.tagger.get_file_lookup() lookup.albumLookup(self.release) - def fetch_remote_image(self, url): + def fetch_remote_image(self, url, fallbackData=None): if self.item is None: return - if url.scheme() == 'http': + if url.scheme() in ('https', 'http'): path = url.encodedPath() if url.hasQuery(): path += '?' + url.encodedQuery() - self.tagger.xmlws.get(url.encodedHost(), url.port(80), path, - partial(self.on_remote_image_fetched, url), + if url.scheme() == 'https': + port = 443 + else: + port = 80 + self.tagger.xmlws.get(str(url.encodedHost()), url.port(port), str(path), + partial(self.on_remote_image_fetched, url, fallbackData=fallbackData), xml=False, priority=True, important=True) elif url.scheme() == 'file': @@ -169,16 +177,29 @@ class CoverArtBox(QtGui.QGroupBox): data = f.read() self.load_remote_image(url, mime, data) - def on_remote_image_fetched(self, url, data, reply, error): + def on_remote_image_fetched(self, url, data, reply, error, fallbackData=None): mime = reply.header(QtNetwork.QNetworkRequest.ContentTypeHeader) if mime in ('image/jpeg', 'image/png'): self.load_remote_image(url, mime, data) - elif reply.url().hasQueryItem("imgurl"): + elif url.hasQueryItem("imgurl"): # This may be a google images result, try to get the URL which is encoded in the query - url = QtCore.QUrl(reply.url().queryItemValue("imgurl")) + url = QtCore.QUrl(url.queryItemValue("imgurl")) self.fetch_remote_image(url) else: - log.warning("Can't load image with MIME-Type %s", mime) + log.warning("Can't load remote image with MIME-Type %s", mime) + if fallbackData: + # Tests for image format obtained from file-magic + if fallbackData[:2]=='\xff\xd8': + mime = 'image/jpeg' + elif fallbackData[:8]=='\x89PNG\x0d\x0a\x1a\x0a': + mime = 'image/png' + else: + mime = None + + if mime: + log.warning("Trying the dropped %s data", mime) + self.load_remote_image(url, mime, fallbackData) + def load_remote_image(self, url, mime, data): try: