I wonder if it would be possible to obtain custom ID3 tags from a music track. I am interested in ReplayGain tags; my utility adds the following:
I know that some tags are returned in the Track object, but of course only a limited set. Also it might not be feasible to carry all of them around. What about returning them in another call, maybe
get_current_track() is not OK)?
We use gstreamer for audio. If gstreamer can read these tags, we can potentially expose them. If these are non-standard tags then that sounds unlikely.
audio/scan.py reads them. The excerpt above was made by running it on a file:
$ python3 /usr/lib/python3/dist-packages/mopidy/audio/scan.py file.mp3
title ['Anitras Tanz']
artist ['Peter Gynt Suite 1,2, Holberg Suite']
album ['Grieg, Edvard (1843-1907)']
container-format ['ID3 tag']
album-artist ['Peter Gynt Suite 1,2, Holberg Suite']
That’s a start but we only expose certain fields in our models, hence the ‘potentially’. We don’t have any way currently of exposing anything outside of what’s in our fixed data model. I don’t think there’s much call for it so you’ll have to hack something up yourself.
I’m also highly interested in such a feature. I understand that the models must remain as they are. There can’t be a solution to add each abitrary field. But I don’t get why it should be a problem to expose such a function as @gkzsolt suggested to the core API? If the scanner module can provide this data, such function should be just a thin rapper around it, shouldn’t it? So I would think that this is a library function that each backend can implement. So could the local back-end read the ID3 tags. What then Spotify or Soundcloud do is their business.
My use-case are lyrics. I store them into my audio files (using a beets plugin while importing). I would love to display them in my custom web-frontend design.
It’s not a problem per-se, I meant we don’t have anything in our current Core API that supports this. Since there’s not much demand it’s never been on our roadmap and so we’d need someone to drive the idea and ideally the implementation also.
Having Mopidy Core pass Backend-specific requests from clients to Backends is something we have so far managed to avoid but I don’t think there’s any technical reason blocking that. One potential issue is that different Backends could have very different ideas of how to answer a given query if there are no conventions defined by our API. However, we could solve that with a
uris argument, similar to what LibraryController.search accepts. Alternatively we could define some conventions but then you’d have to ask why aren’t they just new fields added to the models?
I’ll also point out that the Local backend does not currently lookup/scan media outside of doing
mopidy local scan i.e. not while answering Core API requests during normal operation. In fact, all our Backends currently have the luxury of relying on there being a well-defined and restricted set of data they need to store/cache/handle. It would probably be OK in the case of Mopidy-Local to support scanning tracks on demand in order to retrieve arbitrary tags as:
- We already handle all data types that GST might return to us
- It should be relatively quick to do
But it may have more of an impact for other Backends that rely on caching to be performant enough for use.
I can’t find any existing issues for this (other than https://github.com/mopidy/mopidy/issues/1644 which is slightly different because it wants to also store arbitrary tags) so if you are interested in fleshing this out a bit more do you want to create a new feature request?
Thanks for the exhaustive answer!
I think you said a lot of good things. I agree that it would be the best to use
uris as argument for such interface extension.
I understand the idea behind defining a convention, but honestly I think this is pretty hard. But if you still want to do an attempt, I would split this into two features.
I’m not sure about the caching. After all ID3 tags should not be much data, even including all non-standard data fields. So those backends could simply extend their cache to store the full response they retrieve from the certain service. Then depending on what the backend responds to, it selects the data fields of interest. Now they do this after fetching the data. Now they would do this for each request. But that should be not much load and cost most-likely no resource.