I developed Deezerart

Tags: #<Tag:0x00007fd29d787018> #<Tag:0x00007fd29d786ed8> #<Tag:0x00007fd29d786de8>

Hi,

I developed Deezerart, a Picard plugin to fetch cover arts from Deezer, a music streaming platform. Deezer provides free APIs with a reasonable time limit that are perfect for such a plugin.

Deezerart has been tested from Python 3.5 to Python 3.8, to maximize compatibility, although I only tested it in Picard 2.4 since that’s the version my distro ships.
I tried to use all the cover-art-related APIs in Picard so that every menu entry and error message appears in the right place, well integrated with the overall application.

It is my intention to create a pull request to add my plugin to the official third party Picard plugins, should you wave the green flag.

I hope you’ll enjoy Deezerart!

15 Likes

Thanks a lot, this looks very cool. Also cleanly coded. Would indeed be great to have this in the official plugin list.

I have not yet looked over it in too much detail, but I don’t think there is much to complain. One thing I noted though:

There is custom code for redirect handling, which runs on the main thread and hence adds a noticeable delay. That made me wonder why this is needed, because the web service module should handle redirects just well. Turns out it is because the CoverArtImage does not handle query arguments correctly, which in turn results a URL like https://api.deezer.com/album/393516/image?size=big getting queried as https://api.deezer.com/album/393516/image%3Fsize=big and there is not even a redirect involved.

So that’s a bug, I’ll see to get this fixed for the 2.5 release. But then we could get rid of the custom redirect handling in the plugin. Which would be great: Not only does it currently block the main thread, it also makes the app crash without any exception logged on Windows (if using the official binaries). I don’t know why exactly, but there might be something missing in the package because Picard otherwise does not use the http.client module.

Update: We’ll have a fix for the next release

5 Likes

Thanks for looking into it, @outsidecontext. Also, wow, you discovered a bug just by supposing why I wrote a workaround O_O

I’ll patch Deezerart to avoid the workaround for Picard versions greater or equal to 2.5, tag a v1.0.1 and then I’ll submit a PR.

3 Likes

@livingsilver94 Could you put a working add-on file here, it looks like a great job, I’d love to test it.

You can find it here: https://github.com/livingsilver94/deezerart/releases/tag/v1.0 the non-source link.

Thanks for testing! In a couple of days I should be able to tag the next release.

2 Likes

I have installed Picard 2.5 and Deezerart. I do not know if it is a 2.5 issue but the plugin does not work, ie when I call lookup files when picard wants to find the cover, the program crashes automatically.

Manually modifying init.py
PLUGIN_API_VERSIONS = ['2.2', '2.3', '2.4', '2.5']
also did not help.

My settings:
obraz

Yes, that’s basically part of the issue discussed above. On Windows the plugin will currently crash when querying data.

@hbrtkp I released a new version: https://github.com/livingsilver94/deezerart/releases/tag/v1.0.1

You can try this version in Picard 2.5 and make sure it doesn’t crash, if you will.

3 Likes

Thank you. Quick test, plugin installed, doesn’t crash Picard and looks like it’s working. Settings for test:

obraz

Big size means: 400x400px
Large is: 1000x1000px

With this album plugin has problem, doesn’t find cover:



Log:

D: 20:15:22,068 ui\itemviews.dropMimeData:779: Drop target = <Cluster ‘Unclustered Files’>
D: 20:15:22,069 ui\itemviews.drop_urls:745: Dropped the URL: ‘file:///E:/%23%23%23/Atticus Ross/Atticus Ross, Leopold Ross & Claudia Sarne - Dispatches From Elsewhere (Music From The Elsewhere Society) [2020] [OST]’
D: 20:15:22,072 tagger.add_files:536: Adding files [<MP3File ‘01. Elsewhere.mp3’>, <MP3File ‘02. Occasionally Scared.mp3’>, <MP3File ‘03. Memory To Media.mp3’>, <MP3File ‘04. I Am You.mp3’>, <MP3File ‘05. The Wise Alone.mp3’>, <MP3File ‘06. Murals.mp3’>, <MP3File ‘07. Letting Go.mp3’>, <MP3File ‘08. Docent.mp3’>, <MP3File “09. Janice’s Theme.mp3”>]
D: 20:15:22,073 formats\id3._load:257: Loading file ‘E:\###\Atticus Ross\Atticus Ross, Leopold Ross & Claudia Sarne - Dispatches From Elsewhere (Music From The Elsewhere Society) [2020] [OST]\01. Elsewhere.mp3’
D: 20:15:22,074 formats\id3._load:257: Loading file ‘E:\###\Atticus Ross\Atticus Ross, Leopold Ross & Claudia Sarne - Dispatches From Elsewhere (Music From The Elsewhere Society) [2020] [OST]\04. I Am You.mp3’
D: 20:15:22,074 formats\id3._load:257: Loading file ‘E:\###\Atticus Ross\Atticus Ross, Leopold Ross & Claudia Sarne - Dispatches From Elsewhere (Music From The Elsewhere Society) [2020] [OST]\02. Occasionally Scared.mp3’
D: 20:15:22,074 formats\id3._load:257: Loading file ‘E:\###\Atticus Ross\Atticus Ross, Leopold Ross & Claudia Sarne - Dispatches From Elsewhere (Music From The Elsewhere Society) [2020] [OST]\05. The Wise Alone.mp3’
D: 20:15:22,076 formats\id3._load:257: Loading file ‘E:\###\Atticus Ross\Atticus Ross, Leopold Ross & Claudia Sarne - Dispatches From Elsewhere (Music From The Elsewhere Society) [2020] [OST]\06. Murals.mp3’
D: 20:15:22,076 formats\id3._load:257: Loading file ‘E:\###\Atticus Ross\Atticus Ross, Leopold Ross & Claudia Sarne - Dispatches From Elsewhere (Music From The Elsewhere Society) [2020] [OST]\03. Memory To Media.mp3’
D: 20:15:22,078 formats\id3._load:257: Loading file ‘E:\###\Atticus Ross\Atticus Ross, Leopold Ross & Claudia Sarne - Dispatches From Elsewhere (Music From The Elsewhere Society) [2020] [OST]\07. Letting Go.mp3’
D: 20:15:22,078 file.update:641: Updating file <MP3File ‘01. Elsewhere.mp3’>
D: 20:15:22,079 formats\id3._load:257: Loading file ‘E:\###\Atticus Ross\Atticus Ross, Leopold Ross & Claudia Sarne - Dispatches From Elsewhere (Music From The Elsewhere Society) [2020] [OST]\08. Docent.mp3’
D: 20:15:22,080 formats\id3._load:257: Loading file “E:\###\Atticus Ross\Atticus Ross, Leopold Ross & Claudia Sarne - Dispatches From Elsewhere (Music From The Elsewhere Society) [2020] [OST]\09. Janice’s Theme.mp3”
D: 20:15:22,085 tagger._file_loaded:440: <MP3File ‘01. Elsewhere.mp3’> has release (bdeec58d-2d9a-41a4-92e5-7c3e2f958741) and recording (bd32dfd3-3ac3-4784-b90b-4f076e7d9ceb) MBIDs, moving to track…
D: 20:15:22,088 ui\mainwindow.set_statusbar_message:392: Loading album bdeec58d-2d9a-41a4-92e5-7c3e2f958741 …
D: 20:15:22,090 file.update:641: Updating file <MP3File ‘04. I Am You.mp3’>
D: 20:15:22,091 tagger._file_loaded:440: <MP3File ‘04. I Am You.mp3’> has release (bdeec58d-2d9a-41a4-92e5-7c3e2f958741) and recording (50401bb1-7435-41f6-a368-56644b567995) MBIDs, moving to track…
D: 20:15:22,091 tagger.load_album:659: Album bdeec58d-2d9a-41a4-92e5-7c3e2f958741 already loaded.
D: 20:15:22,092 file.update:641: Updating file <MP3File ‘02. Occasionally Scared.mp3’>
D: 20:15:22,092 tagger._file_loaded:440: <MP3File ‘02. Occasionally Scared.mp3’> has release (bdeec58d-2d9a-41a4-92e5-7c3e2f958741) and recording (39e9bca2-2799-4b20-a0bd-f1bb78b2bf08) MBIDs, moving to track…
D: 20:15:22,093 tagger.load_album:659: Album bdeec58d-2d9a-41a4-92e5-7c3e2f958741 already loaded.
D: 20:15:22,093 file.update:641: Updating file <MP3File ‘06. Murals.mp3’>
D: 20:15:22,094 tagger._file_loaded:440: <MP3File ‘06. Murals.mp3’> has release (bdeec58d-2d9a-41a4-92e5-7c3e2f958741) and recording (b5d6a020-f37b-4a6a-81ad-efb4f14b5f58) MBIDs, moving to track…
D: 20:15:22,094 tagger.load_album:659: Album bdeec58d-2d9a-41a4-92e5-7c3e2f958741 already loaded.
D: 20:15:22,094 file.update:641: Updating file <MP3File ‘05. The Wise Alone.mp3’>
D: 20:15:22,095 tagger._file_loaded:440: <MP3File ‘05. The Wise Alone.mp3’> has release (bdeec58d-2d9a-41a4-92e5-7c3e2f958741) and recording (231825c0-ad98-47f2-9438-ed2f517a19f3) MBIDs, moving to track…
D: 20:15:22,095 tagger.load_album:659: Album bdeec58d-2d9a-41a4-92e5-7c3e2f958741 already loaded.
D: 20:15:22,097 file.update:641: Updating file <MP3File ‘03. Memory To Media.mp3’>
D: 20:15:22,097 tagger.file_loaded:440: <MP3File ‘03. Memory To Media.mp3’> has release (bdeec58d-2d9a-41a4-92e5-7c3e2f958741) and recording (844705dd-384f-4d1f-ae24-e4b22aaa6e70) MBIDs, moving to track…
D: 20:15:22,097 tagger.load_album:659: Album bdeec58d-2d9a-41a4-92e5-7c3e2f958741 already loaded.
D: 20:15:22,098 webservice\ratecontrol.get_delay_to_next_request:118: (‘musicbrainz.org’, 443): Last request was 57337 ms ago, starting another one
D: 20:15:22,098 webservice\ratecontrol.increment_requests:138: (‘musicbrainz.org’, 443): Incrementing requests to: 1
D: 20:15:22,099 file.update:641: Updating file <MP3File ‘07. Letting Go.mp3’>
D: 20:15:22,100 tagger.file_loaded:440: <MP3File ‘07. Letting Go.mp3’> has release (bdeec58d-2d9a-41a4-92e5-7c3e2f958741) and recording (51fa2be6-e70a-4b5f-b048-6707e062be5d) MBIDs, moving to track…
D: 20:15:22,100 tagger.load_album:659: Album bdeec58d-2d9a-41a4-92e5-7c3e2f958741 already loaded.
D: 20:15:22,101 file.update:641: Updating file <MP3File ‘08. Docent.mp3’>
D: 20:15:22,101 tagger.file_loaded:440: <MP3File ‘08. Docent.mp3’> has release (bdeec58d-2d9a-41a4-92e5-7c3e2f958741) and recording (93daa233-e15e-48d0-9f96-618761c3a326) MBIDs, moving to track…
D: 20:15:22,101 tagger.load_album:659: Album bdeec58d-2d9a-41a4-92e5-7c3e2f958741 already loaded.
D: 20:15:22,102 file.update:641: Updating file <MP3File “09. Janice’s Theme.mp3”>
D: 20:15:22,102 tagger.file_loaded:440: <MP3File “09. Janice’s Theme.mp3”> has release (bdeec58d-2d9a-41a4-92e5-7c3e2f958741) and recording (3981580b-cc2e-46c2-9e54-80a5e184da3a) MBIDs, moving to track…
D: 20:15:22,103 tagger.load_album:659: Album bdeec58d-2d9a-41a4-92e5-7c3e2f958741 already loaded.
D: 20:15:22,219 webservice\ratecontrol.decrement_requests:146: (‘musicbrainz.org’, 443): Decrementing requests to: 0
D: 20:15:22,220 webservice_init
.handle_reply:472: Received reply for https://musicbrainz.org:443/ws/2/release/bdeec58d-2d9a-41a4-92e5-7c3e2f958741?inc=release-groups+media+discids+recordings+artist-credits+artists+aliases+labels+isrcs+collections+user-collections+artist-rels+release-rels+url-rels+recording-rels+work-rels+genres: HTTP 200 (OK)
D: 20:15:22,221 album.parse_release:186: Loading release ‘bdeec58d-2d9a-41a4-92e5-7c3e2f958741’ …
D: 20:15:22,222 coverart_init
.retrieve_coverart:243: New CoverArt for <Album bdeec58d-2d9a-41a4-92e5-7c3e2f958741 ‘’>
D: 20:15:22,222 coverart\providers_init
.cover_art_providers:87: CA Providers order: Deezer [x] > Local Files [ ] > Cover Art Archive [ ] > UrlRelationships [ ] > CaaReleaseGroup [ ]
D: 20:15:22,222 coverart_init
.next_in_queue:150: Trying cover art provider Deezer …
D: 20:15:22,223 webservice\ratecontrol.out_of_backoff:229: (‘musicbrainz.org’, 443): oobackoff; delay: 1000ms -> 1000ms; slow start; window size 6.000 -> 7.000
D: 20:15:22,223 webservice\ratecontrol.get_delay_to_next_request:118: (‘api.deezer.com’, 443): Last request was 58330 ms ago, starting another one
D: 20:15:22,224 webservice\ratecontrol.increment_requests:138: (‘api.deezer.com’, 443): Incrementing requests to: 1
D: 20:15:22,297 webservice\ratecontrol.decrement_requests:146: (‘api.deezer.com’, 443): Decrementing requests to: 0
D: 20:15:22,298 webservice_init
.handle_reply:472: Received reply for https://api.deezer.com:443/search?q=artist:"Atticus Ross, Leopold Ross %26 Claudia Sarne%22 album:%22Dispatches From Elsewhere (Music From The Elsewhere Society)%22: HTTP 200 (OK)
D: 20:15:22,298 coverart_init
.next_in_queue:154: Skipping cover art provider Local Files …
D: 20:15:22,299 coverart_init
.next_in_queue:154: Skipping cover art provider Cover Art Archive …
D: 20:15:22,299 coverart_init
.next_in_queue:154: Skipping cover art provider UrlRelationships …
D: 20:15:22,299 coverart_init
.next_in_queue:154: Skipping cover art provider CaaReleaseGroup …
D: 20:15:22,300 webservice\ratecontrol.out_of_backoff:229: (‘api.deezer.com’, 443): oobackoff; delay: 1000ms -> 1000ms; slow start; window size 5.000 -> 6.000
D: 20:15:22,300 webservice\ratecontrol.get_delay_to_next_request:122: (‘api.deezer.com’, 443): Last request was 75 ms ago, waiting 925 ms before starting another one
D: 20:15:23,229 webservice\ratecontrol.get_delay_to_next_request:118: (‘api.deezer.com’, 443): Last request was 1005 ms ago, starting another one
D: 20:15:23,230 webservice\ratecontrol.increment_requests:138: (‘api.deezer.com’, 443): Incrementing requests to: 1
D: 20:15:23,303 webservice\ratecontrol.decrement_requests:146: (‘api.deezer.com’, 443): Decrementing requests to: 0
D: 20:15:23,303 webservice_init
._handle_reply:472: Received reply for https://api.deezer.com:443/search?q=artist:"Atticus Ross, Leopold Ross %26 Claudia Sarne%22: HTTP 200 (OK)

E: 20:15:23,304 album.error_append:287: Deezerart: no results found

D: 20:15:23,316 ui\mainwindow.set_statusbar_message:392: Album bdeec58d-2d9a-41a4-92e5-7c3e2f958741 loaded: Atticus Ross, Leopold Ross & Claudia Sarne - Dispatches From Elsewhere (Music From The Elsewhere Society)
D: 20:15:23,317 file.move:567: Moving <MP3File ‘01. Elsewhere.mp3’> from None to <Cluster bdeec58d-2d9a-41a4-92e5-7c3e2f958741 ‘Dispatches From Elsewhere (Music From The Elsewhere Society)/Unmatched Files’>
D: 20:15:23,319 file.move:567: Moving <MP3File ‘01. Elsewhere.mp3’> from <Cluster bdeec58d-2d9a-41a4-92e5-7c3e2f958741 ‘Dispatches From Elsewhere (Music From The Elsewhere Society)/Unmatched Files’> to <Track bd32dfd3-3ac3-4784-b90b-4f076e7d9ceb ‘Elsewhere’>
D: 20:15:23,322 file.move:567: Moving <MP3File ‘04. I Am You.mp3’> from None to <Cluster bdeec58d-2d9a-41a4-92e5-7c3e2f958741 ‘Dispatches From Elsewhere (Music From The Elsewhere Society)/Unmatched Files’>
D: 20:15:23,324 file.move:567: Moving <MP3File ‘04. I Am You.mp3’> from <Cluster bdeec58d-2d9a-41a4-92e5-7c3e2f958741 ‘Dispatches From Elsewhere (Music From The Elsewhere Society)/Unmatched Files’> to <Track 50401bb1-7435-41f6-a368-56644b567995 ‘I Am You’>
D: 20:15:23,328 file.move:567: Moving <MP3File ‘02. Occasionally Scared.mp3’> from None to <Cluster bdeec58d-2d9a-41a4-92e5-7c3e2f958741 ‘Dispatches From Elsewhere (Music From The Elsewhere Society)/Unmatched Files’>
D: 20:15:23,330 file.move:567: Moving <MP3File ‘02. Occasionally Scared.mp3’> from <Cluster bdeec58d-2d9a-41a4-92e5-7c3e2f958741 ‘Dispatches From Elsewhere (Music From The Elsewhere Society)/Unmatched Files’> to <Track 39e9bca2-2799-4b20-a0bd-f1bb78b2bf08 ‘Occasionally Scared’>
D: 20:15:23,334 file.move:567: Moving <MP3File ‘06. Murals.mp3’> from None to <Cluster bdeec58d-2d9a-41a4-92e5-7c3e2f958741 ‘Dispatches From Elsewhere (Music From The Elsewhere Society)/Unmatched Files’>
D: 20:15:23,336 file.move:567: Moving <MP3File ‘06. Murals.mp3’> from <Cluster bdeec58d-2d9a-41a4-92e5-7c3e2f958741 ‘Dispatches From Elsewhere (Music From The Elsewhere Society)/Unmatched Files’> to <Track b5d6a020-f37b-4a6a-81ad-efb4f14b5f58 ‘Murals’>
D: 20:15:23,339 file.move:567: Moving <MP3File ‘05. The Wise Alone.mp3’> from None to <Cluster bdeec58d-2d9a-41a4-92e5-7c3e2f958741 ‘Dispatches From Elsewhere (Music From The Elsewhere Society)/Unmatched Files’>
D: 20:15:23,342 file.move:567: Moving <MP3File ‘05. The Wise Alone.mp3’> from <Cluster bdeec58d-2d9a-41a4-92e5-7c3e2f958741 ‘Dispatches From Elsewhere (Music From The Elsewhere Society)/Unmatched Files’> to <Track 231825c0-ad98-47f2-9438-ed2f517a19f3 ‘The Wise Alone’>
D: 20:15:23,346 file.move:567: Moving <MP3File ‘03. Memory To Media.mp3’> from None to <Cluster bdeec58d-2d9a-41a4-92e5-7c3e2f958741 ‘Dispatches From Elsewhere (Music From The Elsewhere Society)/Unmatched Files’>
D: 20:15:23,348 file.move:567: Moving <MP3File ‘03. Memory To Media.mp3’> from <Cluster bdeec58d-2d9a-41a4-92e5-7c3e2f958741 ‘Dispatches From Elsewhere (Music From The Elsewhere Society)/Unmatched Files’> to <Track 844705dd-384f-4d1f-ae24-e4b22aaa6e70 ‘Memory To Media’>
D: 20:15:23,351 file.move:567: Moving <MP3File ‘07. Letting Go.mp3’> from None to <Cluster bdeec58d-2d9a-41a4-92e5-7c3e2f958741 ‘Dispatches From Elsewhere (Music From The Elsewhere Society)/Unmatched Files’>
D: 20:15:23,353 file.move:567: Moving <MP3File ‘07. Letting Go.mp3’> from <Cluster bdeec58d-2d9a-41a4-92e5-7c3e2f958741 ‘Dispatches From Elsewhere (Music From The Elsewhere Society)/Unmatched Files’> to <Track 51fa2be6-e70a-4b5f-b048-6707e062be5d ‘Letting Go’>
D: 20:15:23,357 file.move:567: Moving <MP3File ‘08. Docent.mp3’> from None to <Cluster bdeec58d-2d9a-41a4-92e5-7c3e2f958741 ‘Dispatches From Elsewhere (Music From The Elsewhere Society)/Unmatched Files’>
D: 20:15:23,359 file.move:567: Moving <MP3File ‘08. Docent.mp3’> from <Cluster bdeec58d-2d9a-41a4-92e5-7c3e2f958741 ‘Dispatches From Elsewhere (Music From The Elsewhere Society)/Unmatched Files’> to <Track 93daa233-e15e-48d0-9f96-618761c3a326 ‘Docent’>
D: 20:15:23,363 file.move:567: Moving <MP3File “09. Janice’s Theme.mp3”> from None to <Cluster bdeec58d-2d9a-41a4-92e5-7c3e2f958741 ‘Dispatches From Elsewhere (Music From The Elsewhere Society)/Unmatched Files’>
D: 20:15:23,365 file.move:567: Moving <MP3File “09. Janice’s Theme.mp3”> from <Cluster bdeec58d-2d9a-41a4-92e5-7c3e2f958741 ‘Dispatches From Elsewhere (Music From The Elsewhere Society)/Unmatched Files’> to <Track 3981580b-cc2e-46c2-9e54-80a5e184da3a “Janice’s Theme”>
D: 20:15:23,368 webservice\ratecontrol._out_of_backoff:229: (‘api.deezer.com’, 443): oobackoff; delay: 1000ms -> 1000ms; slow start; window size 6.000 -> 7.000

Oh thanks, I found some errors in how I get the album information from the CoverArtProvider. I misunderstood a part of it. I’m fixing the issue.

1 Like

One idea for improvement: Currently the plugin always does searches for artist and release on Deezer. But some releases might actually have a Deezer URL set. The plugin could use those directly.

The relationships are of type “free streaming” and point to a deezer.com domain. See e.g. https://musicbrainz.org/ws/2/release/1dd9a32b-1a40-4da3-88ab-c34d1fa1e7f6?inc=url-rels&fmt=json

Using this from a cover art plugin is actually rather simple, the CoverArtProvider provides a method match_url_relations you could use with something like this:

class Provider(CoverArtProvider):

    def queue_images(self):
        self.match_url_relations(['free streaming'],
                                 self._queue_from_url_relation)
        # Also queue your current search
        # ...
        return self.WAIT

    def _queue_from_url_relation(self, url):
        if is_deezer_url(url):
            # extract the ID from URL, do the necessary requests to get cover art
            # ...

The Amazon plugin is an example of using this, see https://github.com/metabrainz/picard-plugins/blob/2.0/plugins/amazon/amazon.py

For your case in Deezerart you probably want to choose to use the URL or the search, not both. If so this would require some additional handling. But _queue_from_url_relation could just set a flag.

4 Likes

Hey @outsidecontext,

I did not disappear, just had some busy days. That is a very nice improvement!! I wasn’t aware of those Deezer pointers. Gonna add it this Sunday, probably.

I also encountered a limit in the Picard API I think, but I’ll provide details once I’m sure I cannot work around it.

2 Likes

I implemented what you suggested! Now, some more refinement and Deezerart should be ready for another release.

2 Likes

We have it! https://github.com/livingsilver94/deezerart/releases/tag/v1.1.0
I tested some corner cases and all passed. Feel free to give it a try anyway, otherwise I’ll proceed with filing a PR.

4 Likes