-
Notifications
You must be signed in to change notification settings - Fork 21
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support album artwork ('albumart' command) and binary responses #57
base: main
Are you sure you want to change the base?
Conversation
20c0ee0
to
8d64840
Compare
8d64840
to
10a74a1
Compare
50c5edc
to
42bd5ac
Compare
42bd5ac
to
21ce51f
Compare
Updated Fixed linter warnings and added unit tests to cover |
21ce51f
to
be4776c
Compare
@djmattyg007 Test coverage is finalized, should now be ready to be merged :) |
I tested this code an ran into a lot of issues. Problems are in the script album_art.py:
The good news is that when issues 1-3 are corrected the images are successfully downloaded via the MPD protocol. However, as explained in issue 5 the images are wrong when downloaded from a library list. |
As a follow up on yesterdays comments I tried to improve the album_art.py code, see commit gvc0@59bb77c . It's working fine in Home Assistant (web GUI as well as mobile app). It now also works fine in MAFA, a solid and well maintained Android MPD client which offers more advanced MPD functionality than Home Assistant. This is my first attempt at developing code for Mopidy so all feedback is welcome. I also would like to have some advice please on how to translate an image uri retrieved from the database to a uri type and absolute file path. For now I hard coded it, see line 69, as I couldn't figure out how to deal with this. What I need is: Note: I also tested some other MPD clients and noticed most use uri's in their albumart requests in a different format than Mopidy uses. If we want to support all these variations we'll need to implement a request uri normalization function. I didn't get to it yet because I didn't find another MPD client yet worth the effort. |
I finished my work on album_art.py and I think it's ready for a first release. Made a lot of improvements and tested with different clients, all looks fine. I created a pull requests (on branch @leso-kn). As I don't have any experience with Mopidy development and it's release process, please let me know if anything more is required from me. |
Update: Added @gvc0's changes for file://-support and improved exception handling. Note: |
Rebase on master for fixed tests. Sorry about that. |
No worries, thanks for the quick fix :) Rebase done, all tests pass through Github Actions on my side now! |
I'll try and carve out some time to go through this in the next few days. |
You want a reverse lookup? This isn't possible. This is/was the blocking problem IIRC. I'll have to look closer. |
Don't bother, I solved that already months ago (before I commented my code was finished). Nothing hard coded anymore, altough I think you might be able to improve my way of accessing Mopidy config. |
Update: Coverage raised to 94% (patch coverage). Should pass codecov now. |
c85fa74
to
a0e10f9
Compare
Update
|
daad059
to
27e73d8
Compare
Do you want to open a new pull request for leso-kn:feature/album-art ? |
Oh, you force pushed it here, that's fine. ignore me |
if art_url is None: | ||
return b"binary: 0\n" | ||
|
||
cover_cache[uri] = urlopen(art_url).read() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Needs error handling. And does it need to support a timeout, retries, proxy config. Lots to handle here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A core API makes more and more sense here. This is a whole world of pain to add to Mopidy-MPD and it's really the job of each backend to provide data. Would a get_images_data()
API be useful to other backends, I don't know (but it's not a requirement, we can do it similarly to get_distinct
). Can mpris provide image data (https://gitlab.freedesktop.org/mpris/mpris-spec/-/issues/17)? It might also be useful in the case where the backend can't provide publicly accessible images.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@jodal @adamcik do you have any thoughts about what to here?
- New core api
get_image_data(uris)
with an implementation for downloading over HTTP. - As above but as the default implementation for a matching backend extension API, allows backends to provide custom implementation I.e. Mopidy-Local would provide images directly
- above functionality part of Mopidy-MPD, anything weird or more complicated is not supported.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One additional remark about my part of the code that was not accepted. I had foreseen a maximum (preferred) image size for images retrieved from -Local. The current code uses the largest images available (line 8), which is very inefficient (slow) for MPD clients that prefetch the images for all local albums. Ideally max preferred image size would be a config setting, in -MPD and/or -Local.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@kingosticks I see. When I took recourse to urlopen
in the initial implementation I indeed didn't quite consider that mopidy-mpd
in general utilitizes calls to the core API for fetching data.
I believe your suggestion 2 sounds like the most clean way forward (new core api get_image_data(uris)
/ HTTP download per default with an option for custom implementations by backends which require so).
I am currently implementing your other feedback – thanks for the through code-review :) – I'll leave this part of the code as is for the moment, as it's likely that things will move to the core (I did however implement ACK_ERROR_NO_EXIST
as suggested by your other above review).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A quick note aswell: I foreseeably won't be available during the upcoming week. I'll try to upload adjustments in response to your feedback before leaving as far as possible, leaving this very part out for now as described above.
result = network.LineProtocol.join_lines( | ||
self.mock, ["1".encode(), "2".encode()] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
result = network.LineProtocol.join_lines( | |
self.mock, ["1".encode(), "2".encode()] | |
assert b"1\n2\n" == network.LineProtocol.join_lines( | |
self.mock, [b"1", b"2"] |
) | ||
assert "1\n2\n".encode() == result |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
assert "1\n2\n".encode() == result |
album=Album(uri="something:àlbum:12345"), | ||
) | ||
self.backend.library.dummy_library = [track] | ||
self.core.tracklist.add(uris=[track.uri]).get() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do we need to add to the tracklist and play the track in these tests?
return result | ||
|
||
|
||
class AlbumArtTest(protocol.BaseTestCase): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Needs tests for the image width sorting, caching, and offset
. And all the many ways urlopen can fail.
): | ||
self.send_request("albumart file:///home/test/music.flac 0") | ||
|
||
self.assertInResponse("binary: " + str(len(expected))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
self.assertInResponse("binary: " + str(len(expected))) | |
self.assertInResponse("size: " + str(len(expected))) | |
self.assertInResponse("binary: " + str(len(expected))) | |
self.assertInResponse("OK") |
Unfortunately, I think self.assertInResponse("result")
is also going to be true. Which is wrong.... Maybe we need to fix the MockConnection
so we work entirely in bytes
when testing commands that provide binary responses?
27e73d8
to
12ca0fa
Compare
Included in this PR:
albumart
command, making it possible to fetch album artwork for any media source that provides an artwork url