Navidrome: Support multiple offline playcount increase

Issue description:

Steps to reproduce:

  • Go offline
  • Play a track several times, observing that its local play count increases by more than one
  • Wait for a while
  • Go online and sync with the provider (I’m using Navidrome here)
  • Observe that the play count was reduced, and the last play time becomes the sync time rather than the play time

Logs:

I didn’t enable the debug mode, so I don’t have the app log captured and I don’t think it’s relevant. I can try to capture tomorrow if that is strictly needed.

Instead, I have Wireshark capturing the traffic when doing the syncing, see the attached capture below.

symfonium-wireshark.zip (10.9 KB)

Additional information:

If I search for http.request.uri.path contains "scrobble" in the Wireshark capture above, I can see:

  • /navidrome/rest/scrobble.view?id=009ee9de595709b7f8545c33ee3a67fe&submission=true&u=upsuper&t=[...]&s=[...]&v=1.13.0&c=Symfonium&f=json
  • /navidrome/rest/scrobble.view?id=2da999a547356ae0cb95c4180726833d&submission=true&u=upsuper&t=[...]&s=[...]&v=1.13.0&c=Symfonium&f=json
  • /navidrome/rest/scrobble.view?id=12d55361db1b687629ab1de0cff7fa81&submission=true&u=upsuper&t=[...]&s=[...]&v=1.13.0&c=Symfonium&f=json
  • /navidrome/rest/scrobble.view?id=eaeee98b49b8d86d81676e9956d8619d&submission=true&u=upsuper&t=[...]&s=[...]&v=1.13.0&c=Symfonium&f=json
  • /navidrome/rest/scrobble.view?id=15677b4467f22877d8c5cc1238b72a46&submission=true&u=upsuper&t=[...]&s=[...]&v=1.13.0&c=Symfonium&f=json
  • /navidrome/rest/scrobble.view?id=0377ecec5c96dee3b101c895f25be55e&submission=true&u=upsuper&t=[...]&s=[...]&v=1.13.0&c=Symfonium&f=json
  • /navidrome/rest/scrobble.view?id=118aef8f27eb4682f6293ef07a728a9b&submission=true&u=upsuper&t=[...]&s=[...]&v=1.13.0&c=Symfonium&f=json

There are 7 tracks submitted, however, track 2da999a547356ae0cb95c4180726833d at least played 4 times while the client was offline, but only one was scrobbled. I expect all four times should be submitted.

In addition, according to Subsonic API document, scrobble supports time field to include the last play time, and Navidrome also supports it. It would be good if this information is synced as well.

Furthermore, Subsonic API document also mentions that multiple ids and times can be submitted in a single request, so you should be able to combine all the records into a single request. But this is a minor detail I don’t care too much.

Navidrome’s support can be found here: navidrome/server/subsonic/media_annotation.go at 5773fa0349431ddc855cde97c2e8c239fe490468 · navidrome/navidrome · GitHub

(It didn’t allow me to add another link.)

You are facing the limitations of Subsonic API here.

  1. The time parameter is badly interpreted by half subsonic servers. (seconds vs milliseconds)
  2. The last played value is not officially supported in the API on the other direction (Only Navidrome have something that I support)
  3. The API does not support sending the actual playcount just a scrobble, unfortunately a few servers also bugs when sending multiple requests chained with the same item.
  4. Multiple ids is not supported by 90% of the servers.

There’s a work in progress to improve Subsonic API, but it’s far away.

I try to limit the server specific code to avoid maintenance nightmare, but since I already have some for Navidrome and Navidrome is currently the most used server I can probably make an exception.

I see. That is indeed very problematic…

…, unfortunately a few servers also bugs when sending multiple requests chained with the same item.

I’m curious how to have bugs on this… The worst case I can imagine is that they only increment once if multiple request on the same item comes in a short time? In that case, it shouldn’t be a big problem to do so.

You have no idea how the Subsonic compatible server world is the wild west with strange bugs, subtle differences and all the worst nightmares possible an advanced client :slight_smile:

Not even talking about the API limitations and lack of proper description leading to natural divergence between servers.

I can totally see how messy that could be.

But I guess it might not be a crazy idea to have an allowlist for server impls that do certain features correctly™ (when there is a clearly correct behavior as defined in the API). That way you only need to maintain a baseline behavior and an single optimized behavior guarded by allowed feature set of the given server impl at the given version. This is, to some extent, similar to SIMD optimizations guarded by CPU model.

WDYT?

I mean… you can have a feature set for each server, and provide specific optimized behavior based on the feature set of the server.

But I guess a single guard opt-in everything is also fine, albeit less scalable if other server impls catch up progressively.

That’s not how real world works :wink: (And as the tags says it’s already implemented for Navidrome).

Each function have differences and sometimes multiple versions. Like to sync I need support for empty queries to search3 endpoint there’s 3 different ways depending on servers to send that, and handle the fallback for servers that do not handle correctly that case.

And that also means that I need to fully test and maintain a compatibility matrix for every single functions and all the servers. Something that I absolutely not have time for.

As you can see : Explicit server name and version it was already a lot of work to have servers expose what they are. And there’s still the majority that do not expose their version yet. Meaning I can’t even build that compatibility matrix properly :slight_smile:

So until the work is done with API extensions and servers proper handling of things, every variation is a support burden and time loss for every future changes to manage regressions.


you can have a feature set for each server

I support Emby / Jellyfin / Kodi / Plex / Android / Subsonic. That’s already 6 (8 actually as 3 modes for android) different set of features to maintain and evolve with their versions.
Adding 20 more for 20 different Subsonic servers is just not possible. Specially for edge cases.

Ah I didn’t realize that even the server name and version are not part of the official API, but that makes a lot of sense.

As long as it’s implemented for Navidrome, I’m happy for now :slight_smile:

(If there are enough people care maybe there can eventually be a standard with an open test set developed to have implementations converge… but it’s probably just too hard with many of the projects with just a single maintainer doing it with labor of love.)

Working hard on making thing change :slight_smile:

It will come.