def run_extractor(tagger, input_path, extractor_callback, response, reply, error, main_thread=False): duplicate = False # Check if AcousticBrainz server answered with the json file for the recording id if not error: # If it did, mark file as duplicate and skip extraction try: load_json(response) duplicate = True except json.JSONDecodeError: pass if duplicate: # If an entry for the same recording ID already exists # using the same extractor version exists, skip extraction results = (None, 0, "Duplicate") extractor_callback(results, None) else: if main_thread: # Run extractor on main thread, used for testing extractor_callback(extractor(tagger, input_path), None) else: # Run extractor on a different thread and call the callback when done run_task(partial(extractor, tagger, input_path), extractor_callback)
def on_refresh_access_token_finished(self, callback, data, http, error): access_token = None try: if error: log.error("OAuth: access_token refresh failed: %s", data) if http.attribute(QNetworkRequest.HttpStatusCodeAttribute) == 400: response = load_json(data) if response["error"] == "invalid_grant": self.forget_refresh_token() else: response = load_json(data) self.set_access_token(response["access_token"], response["expires_in"]) access_token = response["access_token"] finally: callback(access_token)
def _batch_submit_finished(self, submissions, next_func, document, http, error): if error: try: error = load_json(document) message = error["error"]["message"] except BaseException: message = "" mparms = {'error': http.errorString(), 'message': message} log.error( "AcoustID: submission failed with error '%(error)s': %(message)s" % mparms) self.tagger.window.set_statusbar_message(N_( "AcoustID submission failed with error '%(error)s': %(message)s" ), mparms, echo=None, timeout=3000) else: log.debug('AcoustID: %d fingerprints successfully submitted', len(submissions)) for file, submission in submissions: submission.orig_recordingid = submission.recordingid file.update() self._check_unsubmitted() next_func()
def result(album, metadata, data, reply, error): if error: album._requests -= 1 album._finalize_loading(None) return moods = [] genres = [] try: data = load_json(data).get(metadata["musicbrainz_recordingid"]) if data and "0" in data and "highlevel" in data["0"]: data = data["0"]["highlevel"] for k, v in data.items(): if k.startswith("genre_") and not v["value"].startswith("not_"): genres.append(v["value"]) if k.startswith("mood_") and not v["value"].startswith("not_"): moods.append(v["value"]) metadata["genre"] = genres metadata["mood"] = moods log.debug("%s: Track %s (%s) Parsed response (genres: %s, moods: %s)", PLUGIN_NAME, metadata["musicbrainz_recordingid"], metadata["title"], str(genres), str(moods)) except Exception as e: log.error("%s: Track %s (%s) Error parsing response: %s", PLUGIN_NAME, metadata["musicbrainz_recordingid"], metadata["title"], str(e)) finally: album._requests -= 1 album._finalize_loading(None)
def __fingerprint_submission_finished(self, fingerprints, document, http, error): if error: try: error = load_json(document) message = error["error"]["message"] except : message = "" mparms = { 'error': http.errorString(), 'message': message } log.error( "AcoustID: submission failed with error '%(error)s': %(message)s" % mparms) self.tagger.window.set_statusbar_message( N_("AcoustID submission failed with error '%(error)s': %(message)s"), mparms, echo=None, timeout=3000 ) else: log.debug('AcoustID: successfully submitted') self.tagger.window.set_statusbar_message( N_('AcoustIDs successfully submitted.'), echo=None, timeout=3000 ) for submission in fingerprints: submission.orig_recordingid = submission.recordingid self._check_unsubmitted()
def _extract_error_description(self, http, data): try: response = load_json(data) return response['error_description'] except (JSONDecodeError, KeyError, TypeError): return _('Unexpected request error (HTTP code %s)' ) % self.webservice.http_response_code(http)
def _releases_json_loaded(self, response, reply, error, callback=None): '''Processes response from specified website api query.''' if error: log.error( _("Error loading Picard releases list: {error_message}"). format(error_message=reply.errorString(), )) if self._show_always: QMessageBox.information( self._parent, _("Picard Update"), _("Unable to retrieve the latest version information from the website.\n(https://{url}{endpoint})" ).format( url=PLUGINS_API['host'], endpoint=PLUGINS_API['endpoint']['releases'], ), QMessageBox.Ok, QMessageBox.Ok) else: self._available_versions = load_json(response)['versions'] for key in self._available_versions: log.debug( "Version key '{version_key}' --> {version_information}". format( version_key=key, version_information=self._available_versions[key], )) self._display_results() if callback: callback(not error)
def _json_downloaded(self, release_group_id, data, reply, error): self.album._requests -= 1 if error: if error != QNetworkReply.ContentNotFoundError: error_level = log.error else: error_level = log.debug error_level("Problem requesting metadata in fanart.tv plugin: %s", error) else: try: response = load_json(data) release = response["albums"][release_group_id] if "albumcover" in release: covers = release["albumcover"] types = ["front"] self._select_and_add_cover_art(covers, types) if "cdart" in release and \ (config.setting["fanarttv_use_cdart"] == OPTION_CDART_ALWAYS or (config.setting["fanarttv_use_cdart"] == OPTION_CDART_NOALBUMART and "albumcover" not in release)): covers = release["cdart"] types = ["medium"] if not "albumcover" in release: types.append("front") self._select_and_add_cover_art(covers, types) except: log.error( "Problem processing downloaded metadata in fanart.tv plugin: %s", traceback.format_exc()) self.next_in_queue()
def process_data(self, album, track_metadata, response, reply, error): if error: log.error( "%s: Network error retrieving acousticBrainz data for recordingId %s", PLUGIN_NAME, track_metadata['musicbrainz_recordingid']) self.album_remove_request(album) return try: data = load_json(response) except JSONDecodeError: log.error( "%s: Network error retrieving AcousticBrainz data for recordingId %s", PLUGIN_NAME, track_metadata['musicbrainz_recordingid']) self.album_remove_request(album) return if "tonal" in data: if "key_key" in data["tonal"]: key = data["tonal"]["key_key"] if "key_scale" in data["tonal"]: scale = data["tonal"]["key_scale"] if scale == "minor": key += "m" track_metadata["key"] = key log.debug("%s: Track '%s' is in key %s", PLUGIN_NAME, track_metadata["title"], key) if "rhythm" in data: if "bpm" in data["rhythm"]: bpm = int(data["rhythm"]["bpm"] + 0.5) track_metadata["bpm"] = bpm log.debug("%s: Track '%s' has %s bpm", PLUGIN_NAME, track_metadata["title"], bpm) self.album_remove_request(album)
def on_fetch_username_finished(self, callback, data, http, error): successful = False try: if error: log.error("OAuth: username fetching failed: %s", data) else: response = load_json(data) self.set_username(response["sub"]) successful = True finally: callback(successful)
def _plugins_json_loaded(self, response, reply, error, callback=None): if error: self.tagger.window.set_statusbar_message( N_("Error loading plugins list: %(error)s"), {'error': reply.errorString()}, echo=log.error ) else: self._available_plugins = [PluginData(data, key) for key, data in load_json(response)['plugins'].items()] if callback: callback()
def on_exchange_authorization_code_finished(self, scopes, callback, data, http, error): successful = False try: if error: log.error("OAuth: authorization_code exchange failed: %s", data) else: response = load_json(data) self.set_refresh_token(response["refresh_token"], scopes) self.set_access_token(response["access_token"], response["expires_in"]) successful = True finally: callback(successful)
def on_refresh_access_token_finished(self, callback, data, http, error): access_token = None try: if error: log.error("OAuth: access_token refresh failed: %s", data) if self._http_code(http) == 400: response = load_json(data) if response["error"] == "invalid_grant": self.forget_refresh_token() else: access_token = data["access_token"] self.set_access_token(access_token, data["expires_in"]) except Exception as e: log.error('OAuth: Unexpected error handling access token response: %r', e) finally: callback(access_token=access_token)
def on_refresh_access_token_finished(self, callback, data, http, error): access_token = None try: if error: log.error("OAuth: access_token refresh failed: %s", data) if http.attribute(QNetworkRequest.HttpStatusCodeAttribute) == 400: response = load_json(data) if response["error"] == "invalid_grant": self.forget_refresh_token() else: self.set_access_token(data["access_token"], data["expires_in"]) access_token = data["access_token"] except Exception as e: log.error('OAuth: Unexpected error handling access token response: %r', e) finally: callback(access_token)
def _batch_submit_finished(self, submissions, batch, previous_errors, document, http, error): if error: # re-add batched items to remaining list submissions.extend(batch) response_code = self._acoustid_api.webservice.http_response_code( http) if response_code == 413: self.max_batch_size = int(self.max_batch_size * self.BATCH_SIZE_REDUCTION_FACTOR) log.warn( "AcoustID: payload too large, batch size reduced to %d", self.max_batch_size) else: try: errordoc = load_json(document) message = errordoc["error"]["message"] except BaseException: message = "" mparms = {'error': http.errorString(), 'message': message} previous_errors.append(mparms) log_msg = N_( "AcoustID submission failed with error '%(error)s': %(message)s" ) log.error(log_msg, mparms) self.tagger.window.set_statusbar_message(log_msg, mparms, echo=None, timeout=3000) else: log.debug('AcoustID: %d fingerprints successfully submitted', len(batch)) for file, submission in batch: submission.orig_recordingid = submission.recordingid file.update() self._check_unsubmitted() self._batch_submit(submissions, previous_errors)
def _caa_json_downloaded(self, row, data, http, error): """Handle json reply from CAA server. If server replies without error, try to get small thumbnail of front coverart of the release. """ if not self.table: return cover_cell = self.table.cellWidget(row, len(self.table_headers)-1) if error: cover_cell.not_found() return try: caa_data = load_json(data) except ValueError: cover_cell.not_found() return front = None for image in caa_data["images"]: if image["front"]: front = image break if front: url = front["thumbnails"]["small"] coverartimage = CaaThumbnailCoverArtImage(url=url) self.tagger.xmlws.download( coverartimage.host, coverartimage.port, coverartimage.path, partial(self._cover_downloaded, row), ) else: cover_cell.not_found()
def _caa_json_downloaded(self, data, http, error): """Parse CAA JSON file and queue CAA cover art images for download""" self.album._requests -= 1 if error: if not (error == QNetworkReply.ContentNotFoundError and self.ignore_json_not_found_error): self.error('CAA JSON error: %s' % (http.errorString())) else: try: caa_data = load_json(data) except ValueError: self.error("Invalid JSON: %s" % (http.url().toString())) else: imagesize = config.setting["caa_image_size"] thumbsize = _CAA_THUMBNAIL_SIZE_MAP.get(imagesize, None) for image in caa_data["images"]: if config.setting["caa_approved_only"] and not image["approved"]: continue is_pdf = image["image"].endswith('.pdf') if is_pdf and not config.setting["save_images_to_files"]: log.debug("Skipping pdf cover art : %s" % image["image"]) continue # if image has no type set, we still want it to match # pseudo type 'unknown' if not image["types"]: image["types"] = ["unknown"] else: image["types"] = list(map(str.lower, image["types"])) if self.restrict_types: # only keep enabled caa types types = set(image["types"]).intersection( set(self.caa_types)) else: types = True if types: if thumbsize is None or is_pdf: url = image["image"] else: url = image["thumbnails"][thumbsize] coverartimage = self.coverartimage_class( url, types=image["types"], is_front=image['front'], comment=image["comment"], ) if is_pdf: # thumbnail will be used to "display" PDF in info # dialog thumbnail = self.coverartimage_thumbnail_class( url=image["thumbnails"]['small'], types=image["types"], is_front=image['front'], comment=image["comment"], ) self.queue_put(thumbnail) coverartimage.thumbnail = thumbnail # PDFs cannot be saved to tags (as 2014/05/29) coverartimage.can_be_saved_to_tags = False self.queue_put(coverartimage) if config.setting["caa_save_single_front_image"] and \ config.setting["save_images_to_files"] and \ image["front"]: break self.next_in_queue()
def _caa_json_downloaded(self, data, http, error): """Parse CAA JSON file and queue CAA cover art images for download""" self.album._requests -= 1 if error: if not (error == QNetworkReply.ContentNotFoundError and self.ignore_json_not_found_error): self.error('CAA JSON error: %s' % (http.errorString())) else: try: caa_data = load_json(data) except ValueError: self.error("Invalid JSON: %s" % (http.url().toString())) else: if self.restrict_types: log.debug('CAA types: included: %s, excluded: %s' % ( self.caa_types, self.caa_types_to_omit, )) for image in caa_data["images"]: if config.setting[ "caa_approved_only"] and not image["approved"]: continue is_pdf = image["image"].endswith('.pdf') if is_pdf and not config.setting["save_images_to_files"]: log.debug("Skipping pdf cover art : %s" % image["image"]) continue # if image has no type set, we still want it to match # pseudo type 'unknown' if not image["types"]: image["types"] = ["unknown"] else: image["types"] = list(map(str.lower, image["types"])) if self.restrict_types: # only keep enabled caa types types = set(image["types"]).intersection( set(self.caa_types)) if types and self.caa_types_to_omit: types = not set(image["types"]).intersection( set(self.caa_types_to_omit)) log.debug( 'CAA image {status}: {image_name} {image_types}'. format( status=('accepted' if types else 'rejected'), image_name=image['image'], image_types=image['types'], )) else: types = True if types: urls = caa_url_fallback_list( config.setting["caa_image_size"], image["thumbnails"]) if not urls or is_pdf: url = image["image"] else: #FIXME: try other urls in case of 404 url = urls[0] coverartimage = self.coverartimage_class( url, types=image["types"], is_front=image['front'], comment=image["comment"], ) if urls and is_pdf: # thumbnail will be used to "display" PDF in info # dialog thumbnail = self.coverartimage_thumbnail_class( url=url[0], types=image["types"], is_front=image['front'], comment=image["comment"], ) self.queue_put(thumbnail) coverartimage.thumbnail = thumbnail # PDFs cannot be saved to tags (as 2014/05/29) coverartimage.can_be_saved_to_tags = False self.queue_put(coverartimage) if config.setting["caa_save_single_front_image"] and \ config.setting["save_images_to_files"] and \ image["front"]: break self.next_in_queue()
def _caa_json_downloaded(self, data, http, error): """Parse CAA JSON file and queue CAA cover art images for download""" self.album._requests -= 1 if error: if not (error == QNetworkReply.ContentNotFoundError and self.ignore_json_not_found_error): self.error('CAA JSON error: %s' % (http.errorString())) else: try: caa_data = load_json(data) except ValueError: self.error("Invalid JSON: %s" % (http.url().toString())) else: imagesize = config.setting["caa_image_size"] thumbsize = _CAA_THUMBNAIL_SIZE_MAP.get(imagesize, None) for image in caa_data["images"]: if config.setting[ "caa_approved_only"] and not image["approved"]: continue is_pdf = image["image"].endswith('.pdf') if is_pdf and not config.setting["save_images_to_files"]: log.debug("Skipping pdf cover art : %s" % image["image"]) continue # if image has no type set, we still want it to match # pseudo type 'unknown' if not image["types"]: image["types"] = ["unknown"] else: image["types"] = list(map(str.lower, image["types"])) if self.restrict_types: # only keep enabled caa types types = set(image["types"]).intersection( set(self.caa_types)) else: types = True if types: if thumbsize is None or is_pdf: url = image["image"] else: url = image["thumbnails"][thumbsize] coverartimage = self.coverartimage_class( url, types=image["types"], is_front=image['front'], comment=image["comment"], ) if is_pdf: # thumbnail will be used to "display" PDF in info # dialog thumbnail = self.coverartimage_thumbnail_class( url=image["thumbnails"]['small'], types=image["types"], is_front=image['front'], comment=image["comment"], ) self.queue_put(thumbnail) coverartimage.thumbnail = thumbnail # PDFs cannot be saved to tags (as 2014/05/29) coverartimage.can_be_saved_to_tags = False self.queue_put(coverartimage) if config.setting["caa_save_single_front_image"] and \ config.setting["save_images_to_files"] and \ image["front"]: break self.next_in_queue()