owntone/owntone-server

Feature Request: Get track file via API

jptrsn opened this issue · 10 comments

Hello devs!

I'm currently working on a react native app to let me sync playlists to my phone, giving me a very similar feel to the old itunes sync functionality. The idea is that I would be able to configure the playlists I want, the url of the owntone server, and then let it automatically sync on a regular schedule.

Unfortunately, I can't do this with the current API, due to these limitations:

  • There is no ability to get a file from owntone via API request
  • I cannot update the skip count field via API, but play count and rating are both supported

I know it's a big ask, but since I'm unable to program in C, I was hoping I could get some help from the community to add those endpoints.

Thanks for any help or advice you may be able to offer. Eventually, I'd like this to be a self-contained music player app that will track and sync not just music files, but also metadata such as rating, last played, last skipped, and increment the played/skipped count appropriately. Also possibly allow for id3 tag editing that would let me fix incorrectly parsed songs.

Not a big ask, since this already exists :-) And actually is one of the oldest parts of OwnTone (goes back to mt-daapd).

You can download tracks either via DAAP or RSP, which are both http based. So here's an example for each (assuming the track id is 8 - you get the id from the JSON API):

DAAP:
curl --header "Accept-Codecs: mpeg" http://HOSTNAME:3689/databases/1/items/8.dat -o track.mp3

RSP:
curl --header "Accept-Codecs: mpeg" http://HOSTNAME:3689/rsp/stream/8 -o track.mp3

With comma-separation you can specify multiple codecs that you accept e.g. "mpeg,alac,flac,wav", and then I think you can use "Content-Type" to find out what you are getting.

About skip count you are right, there wasn't any method for that. I've added that now (plus added one for setting play count directly).

Okay, I think I've got it working, but it appears that using the DAAP endpoint counts as having played the song, which throws off all the metadata. It took me a while to figure out why my smart playlists were emptying themselves, I think that's the cause, but it's tough to verify.

Is there a request argument or something I can pass so it won't count the request as a play?

I also realized, is there an API method to retrieve the cover art? I think most of my library has it embedded in the id3 tag, but I couldn't find anything in the json api docs about artwork other than the artwork_url field.

I'm not sure what you mean by "all the metadata" - do you mean the play count? I can't see anything in the code that increases the play count, looks to me like both DAAP and RSP are pretty much just serving the file. I might be missing something, I suppose.

If you set the log level to DEBUG you should see precisely what's going on, including if the database play count is increasing.

I also realized, is there an API method to retrieve the cover art? I think most of my library has it embedded in the id3 tag, but I couldn't find anything in the json api docs about artwork other than the artwork_url field.

Yes, you get it from "artwork_url". This will also return embedded artwork.

Sorry, it was late and my brain was tired, "all the metadata" was actually just a reference to the last played timestamp and play count values, which are used in my smart playlist queries, so doing a playlist "sync" from my app actually makes OwnTone think it has played all of the tracks, modifying the query results for the smart playlist.

I have confirmed that retrieving the file from the DAAP endpoint does update the play_count and time_played values from the GET track endpoint. You can replicate the behaviour in Bruno/Postman by finding a track by ID - in my case, I used /api/library/tracks/1864 to get the track info, which showed me a play count of 0 and no last played date. Making a request to /databases/1/items/1864.dat to get the file works as expected. If I then refresh the get track request, it shows time_played as just now, and play count has been incremented.

Yes, you are right, play_count and time_played are indeed updated, I had overlooked the part of the code that does it. I've added a parameter "no_register_playback" (commit 5d7e3dc) that you can add to the URL, and then they won't be updated. Example:

curl --header "Accept-Codecs: mpeg" "http://HOSTNAME:3689/databases/1/items/8.dat?no_register_playback=1" -o track.mp3

That's fantastic! Thank you so much for being so responsive!

A question about updating play count and skip count - am I also able to set the timestamp for the related field, played or skipped? I would like to make sure that any requests that happen while the device is offline can be cached locally until it can reconnect to owntone to sync the data.

am I also able to set the timestamp for the related field, played or skipped

I've added another change (commit 12f7286) that will let you do that. The parameters are time_played and time_skipped. Note that for various reasons you can't set them to zero.

Thank you so much for being so open to my request, and for making those changes so quickly! I've been using OwnTone for a long, long time, and had previously used iSyncr with iTunes as a bridge to get wireless sync and metadata updates working between my phone and the server. I think OwnTone itself is responsible for my never having gone down the Spotify route, so I still own a bunch of music, and getting the server-to-device sync working will let me stop relying on PlexAmp for music sync (which has never worked as well as I'd hoped).

Those changes were pretty easy :-)

I would love to try your app when it's ready, so I hope you will share it.