jellyfin-audio-player icon indicating copy to clipboard operation
jellyfin-audio-player copied to clipboard

Support scrobbling?

Open icyphox opened this issue 3 years ago • 7 comments

Hey, first off -- thanks for making this excellent app. The UI is especially neat.

It would be great if you could add support for "scrobbling" tracks back to the Jellyfin server. I'm not exactly sure how it works, but I'm using https://github.com/lyarenei/jellyfin-plugin-listenbrainz. I suppose there's some API you can hit on the Jellyfin server to facilitate this.

icyphox avatar Nov 28 '21 14:11 icyphox

Hi there! Thanks for your input. This should be very possible to implement if we can find the right API call to make. If you could help me out locating the right call, I can implement it quite quickly.

Cheers!

leinelissen avatar Dec 13 '21 10:12 leinelissen

Hi @leinelissen, these are the endpoints: For now playing: https://api.jellyfin.org/#operation/OnPlaybackStart For scrobbling: https://api.jellyfin.org/#operation/OnPlaybackStopped

Please don't forget to include the optional positionTicks field, as this is necessary to determine how much of the track has been played (i.e.: listenbrainz requires 4 minutes or a half of a track to be considered as played). Thanks! :)

lyarenei avatar Jan 24 '22 20:01 lyarenei

Ah perfect, that's super helpful! I'll try and see if I can make some time for a quick implementation in the coming weeks. Can I ask you for an e-mail, so that I can send you a preview build and double-check everything is sorted out? You can find my e-mail on my profile.

Cheers!

leinelissen avatar Jan 25 '22 09:01 leinelissen

I've updated the GH profile and the e-mail should be now visible. Hit me up once you have it ready. :)

lyarenei avatar Jan 26 '22 21:01 lyarenei

Since Offline Support is a thing in the app now, would plays be cached and pushed to the server if away from home when the Jellyfin server is not publicly accessible?

GlassedSilver avatar Feb 01 '22 05:02 GlassedSilver

At least not initially, because implementing it takes some extra time. We can create a separate issue, as soon as scribbling is available.

leinelissen avatar Feb 01 '22 08:02 leinelissen

At least not initially, because implementing it takes some extra time. We can create a separate issue, as soon as scribbling is available.

Sounds good!

GlassedSilver avatar Feb 05 '22 11:02 GlassedSilver

Hey everyone! I've made a naive implementation, but I need someone to verify that it works as intended. Can anyone help out with this? Also pinging @attie @sseneca and @the-r0cket06...

leinelissen avatar Apr 27 '23 13:04 leinelissen

@leinelissen As long as you are calling these two endpoints I mentioned earlier, it should work without any issues. Also, I recently updated the listenbrainz plugin to optionally handle events for MarkPlayedItem endpoint, effectively supporting offline scenarios @GlassedSilver was talking about.

With that said, I can test it. I don't see any branches, so I assume you have an IPA available somewhere?

lyarenei avatar May 08 '23 20:05 lyarenei

@leinelissen As long as you are calling these two endpoints I mentioned earlier, it should work without any issues. Also, I recently updated the listenbrainz plugin to optionally handle events for MarkPlayedItem endpoint, effectively supporting offline scenarios @GlassedSilver was talking about.

With that said, I can test it. I don't see any branches, so I assume you have an IPA available somewhere?

Is my understanding correct that marking something played isn't meaning the same thing as play count and last played date?

Meaning: Merging of multiple plays from different sources is possible or not?

i.e. sync at home with phone, last played date (and time) is A. Then you play a song, now the last played date is B on the server and the let's say desktop client or something. (or just the server in terms of a web UI play). No further sync happens with the phone as you leave the house shortly after. You play that same song a few more times.... your phone's last played date is C.

Now when the phone syncs with the server when you arrive at home there are two new last played dates. Each device can tell the server the difference between the last played date A and their respective current value and the server should calculate the new total amount of plays like so: A + (B - A) + (C - A) = new total, last played date is set to the highest value and clients are updated accordingly as well to reflect that.

GlassedSilver avatar May 08 '23 22:05 GlassedSilver

I've tried to keep the implementation as simple as possible for now. This means I've implemented the session events I see regular Jellyfin web throwing towards the server. I know that Finamp has also implemented scrobbling in this manner. I'm doing this live, so if a phone is offline, the events are lost.

For details see this file: https://github.com/leinelissen/jellyfin-audio-player/blob/0bf2775c93b4a8fad91d810834411dc01779f8f7/src/utility/PlaybackService.ts

leinelissen avatar May 09 '23 12:05 leinelissen

@lyarenei This would be great! Let me put together a TestFlight build later this week and share it with you. Thanks in advance!

leinelissen avatar May 09 '23 12:05 leinelissen

Is my understanding correct that marking something played isn't meaning the same thing as play count and last played date?

Meaning: Merging of multiple plays from different sources is possible or not?

@GlassedSilver Jellyfin does not care about the last played dates in a way that it would require to be in order or something. The mentioned API endpoint just accepts whatever date was sent (if any) in the call and then simply increments the play count.

The plugin I talked about only subcribes to selected events emitted by the server and then acts accordingly. When I mentioned offline support, I meant that if the client stores playback history when offline and then, when comes online and reports the history using that API endpoint, the plugin is able (if enabled) to react on the events emitted by that endpoint and pass on the playback data to ListenBrainz.

~@leinelissen Oh you have it in master already? If that's all, then I can just compile the branch and sideload the app, no need to bother with testflight. :)~

Okay, I guess fastlane does not like personal teams, so I guess IPA or testflight from you would be much easier after all. :)

lyarenei avatar May 09 '23 20:05 lyarenei

Hey @lyarenei I managed to get it onto TestFlight. Can you PM me your Apple ID email? Then I'll add you to the release. You can find my contact details on my profile.

leinelissen avatar May 20 '23 21:05 leinelissen

Thanks for the invitation.

I tried to play some stuff, but unfortunately it doesn't look like it's working.

Seeing that the call is made only when the setting is enabled https://github.com/leinelissen/jellyfin-audio-player/blob/0e298c6b996bfd71ac6c288d24c8d7d48d3ed4cd/src/utility/PlaybackService.ts#L44C1-L46

I tried to toggle it a few times to make sure it's enabled, but it didn't make any difference.

Next, I looked at server logs to see if perhaps there is something wrong with the request. Unfortunately, it seems like the server does not receive any playback status requests at all.

From that I can only guess what's happening. But either:

  • The reporting setting toggle is not working correctly and the stored value is always false
  • Something goes wrong before the request is made

I'm not sure if you are able to pull some logs from TestFlight (I honestly have no idea how does it work) to get any clues to what might be the issue. Looking at the code for sendPlaybackEvent, I don't see anything what could cause any issues. Maybe if one of the things pulled from the player was null for some reason?

lyarenei avatar May 23 '23 20:05 lyarenei

Thanks for the effort! I might have made a wrong assumption on the data that is available in the background worker. I can't pull any logs from your device, but I should be able to debug this locally. Let me investigate and get back to you in t he coming week.

leinelissen avatar May 25 '23 14:05 leinelissen

Hey @lyarenei, sorry for not getting back to you earlier, but I might have figured the thing out. I was submitting the payload via GET which obviously doesn't work as it needs to be a POST request 🤦‍♂️. I'm putting it through the TestFlight mill again, would dearly appreciate you trying it out once it's available to you.

leinelissen avatar Jun 13 '23 21:06 leinelissen

@leinelissen Nice catch! :) The requests are now indeed processed by the server, however, the ItemId is not set: start

Also, subsequent progress requests have negative position ticks: progress

lyarenei avatar Jun 18 '23 16:06 lyarenei

Okay, thanks again for checking it out. I've managed to fix the missing ItemId, it would have been missing for the first track in the queue. However, I haven't managed to reproduce the negative position ticks. Do you seen them consistently for all queue items?

leinelissen avatar Jun 18 '23 19:06 leinelissen

However, I haven't managed to reproduce the negative position ticks. Do you seen them consistently for all queue items?

Unfortunately, I can't reproduce it now, so I guess it was just something weird at play.

I did some quick testing and it works when starting playback of an item. After that, the reqeust fails, because the request has a float/double value for playback position instead of int.

There are still 3 decimals remaining after converting to ticks here: https://github.com/leinelissen/jellyfin-audio-player/blob/9aff784580f72e0856f58213a6c6bc3e070b9ef4/src/utility/JellyfinApi.ts#L287

lyarenei avatar Jun 19 '23 20:06 lyarenei

Ah right, that's a great catch. I've solved it now and I'm getting it to TestFlight tomorrow. It's showing up for me in the admin dashboard now, but it's constantly toggling between the playing track and showing an empty card. Any suggestions there by any chance?

leinelissen avatar Jun 19 '23 21:06 leinelissen

The update has just reached TestFlight.

leinelissen avatar Jun 20 '23 08:06 leinelissen

It's showing up for me in the admin dashboard now, but it's constantly toggling between the playing track and showing an empty card. Any suggestions there by any chance?

Hmm, for me it disappears after some time of inactivity. Which I think is a correct behavior. It shows currently playing item just fine during active playback. However, the progress keeps resetting to 1s. Two things on that:

  1. If the position taken from the player is in seconds, then you are off by an order. .NET defines 1 second as 10 000 000 ticks.
  2. You actually don't need to report progress periodically, the server can estimate the position on its own, from the provided playback rate field. So I think you'd be fine with just sending the progress when it actually matters (on pause and seek/resume).

lyarenei avatar Jun 20 '23 17:06 lyarenei

Oof yeah, I completely missed that. I've done the calculation multiple times in the app, but I dropped the ball on this one 😅. I've fixed that and will make the release available as open beta. Solving the ticks also solves the Jellyfin interface issue btw. I'll stick with periodically reporting since the Jellyfin web app is doing so as well. Thanks so much for coaching me throughout this thing, and I hope all the data looks good on your end as well.

leinelissen avatar Jun 20 '23 20:06 leinelissen

Sure, no problem. I did not much testing, but I played few songs and they were tracked correctly (minus the progress resetting). So I believe you are good to go.

lyarenei avatar Jun 22 '23 16:06 lyarenei