Skip to content

Conversation

msparkles
Copy link
Contributor

Checklist before requesting a review

Type of change

Please delete options that are not relevant.

  • New feature (non-breaking change which adds functionality)

Describe your changes

Implements the Last.FM API for scrobbling the currently playing track.

The implementation is a bit crude, as we attempted to make the minimally needed changes. Feel free to reject the PR in this state, we just really wanted the feature to work already, and we're submitting the PR out of courtesy.

We've tested that it works on our machine:tm:, though there may be some potential issues with calling the API too often. We're also not ignoring duplicated scrobbles, as we wanted to make minimal changes.

We'll mark the PR as a draft PR for now, as we expect sure changes, since we're not very familiar with the codebase.

A few changes are just eslint being applied, feel free to ask to exclude those changes.

Issue number and link, if applicable

#164 (only the Last.FM part)

msparkles and others added 4 commits June 29, 2025 23:17
… intervals

* Define if scrobble client can update Now Playing based on class property, use this to filter now playing update
* Use thresholds to determine when/if Now Playing should be updated
* Set LastfmScrobbler as supported for Now Playing
* Enable/disable now playing reporting
* WIP source filters for now playing
@FoxxMD
Copy link
Owner

FoxxMD commented Jun 30, 2025

Thanks for the contribution! This is a good start.

I've added some limiters to prevent API spamming and made now playing user-configurable via options in the client

[
  {
    "name": "myLastFmClient",
    "enable": true,
    "configureAs": "client",
    "data": {
      "apiKey": "a89cba1569901a0671d5a9875fed4be1",
      "secret": "ec42e09d5ae0ee0f0816ca151008412a",
      "redirectUri": "http://localhost:9078/lastfm/callback"
    },
    "options": {
      "nowPlaying": false
    }
  }
]

It defaults to true.

Last thing that is needed is to address reporting Now Playing when multiple Sources have Players at the same time. My plan is to

  • Aggregate playerUpdate events, pushed by playingNow, into a list on the AbstractScrobbleClient
  • Implement ToadScheduler in AbstractScrobbleClient
    • Use a SimpleIntervalJob every 5 seconds to sort and filter list of updates based on either (default) alphabetical order of source names or use a user-defined order
    • Pick the first-sorted Source and then the latest update to return
  • Use the sorted/filtered update to report Now Playing

@msparkles
Copy link
Contributor Author

We're not-so-familiar with the codebase still, but is there a way to uniquely identify player instances? If so, perhaps we can just use a map of SomePlayerId->PlayObject where we only update the value if the received update is newer than stored.
And instead of sorting the source names when updating Now Playing, just set the user-defined order to default to a list of existing, configured sources, in alphabetical order, if the user-defined order is undefined or []; and then simply loop through the list to find the first value that's present in the Now Playing status map.

It seems less complicated this way to us, let us know what you think

@FoxxMD
Copy link
Owner

FoxxMD commented Jul 1, 2025

There is a unique player id generated from a PlayPlatformId (device + user) parsed from Play data. However the id is not user friendly, deterministic, or easily predictable -- IE spotify players identify using unique device strings but subsonic players identify using an incrementing numeric value based on how many concurrent players are already playing.

default to a list of existing, configured sources

Scrobble clients are not aware of what Sources are already configured, that responsibility is left up to ScrobbleClients.ts to filter based on scrobbleTo. This is why sorting on-the-fly is necessary. The reasoning behind the scheduled aggregation is that, since the Client doesn't know what Sources are available, it will make a runtime decision as to which has the highest priority based on what updates (sources) are available within the scheduled window.

FoxxMD added 2 commits July 1, 2025 14:55
* Add queue for aggregating Now Playing updates
* Filter play based on 1. source priority and 2. player stickiness or deterministic order
* Use toad scheduler to processing NP queue
@FoxxMD FoxxMD added the safe to test trusted to build image label Jul 1, 2025
@FoxxMD
Copy link
Owner

FoxxMD commented Jul 1, 2025

@msparkles queue/scheduling/filter/sort is all implemented and the image foxxmd/multi-scrobbler:pr-316 should work for the last.fm use case, please test it out and let me know if there are any problems.

Still to-do:

  • Listenbrainz implementation of doPlayingNow
  • Minimal tests
  • Document user config for nowPlaying

@msparkles
Copy link
Contributor Author

We'll test it out today ASAP.

Listenbrainz implementation of doPlayingNow

Should this be a separate PR? We can't test this ourselves since we don't use Listenbrainz.

@FoxxMD
Copy link
Owner

FoxxMD commented Jul 2, 2025

Yeah I can add LZ implementation after merging.

@FoxxMD
Copy link
Owner

FoxxMD commented Jul 2, 2025

@msparkles Please update to the latest foxxmd/multi-scrobbler:pr-316 image. Fixed some bugs discovered by tests.

@msparkles
Copy link
Contributor Author

@FoxxMD We're running the program via systemd, so we can't test the image per-se, but it works on the latest commit!

@msparkles msparkles marked this pull request as ready for review July 2, 2025 19:48
Copy link
Contributor

github-actions bot commented Jul 2, 2025

📦 A new release has been made for this pull request.

To play around with this PR, pull an image:

  • foxxmd/multi-scrobbler:pr-316

Images are available for x86_64 and ARM64.

Latest commit: f885726

@FoxxMD FoxxMD merged commit 389129a into FoxxMD:master Jul 2, 2025
6 checks passed
@FoxxMD
Copy link
Owner

FoxxMD commented Jul 2, 2025

Docs are now updated and I implemented an additional ENV NOW_PLAYING=true (or false) to allow globally enabling/disabling now playing, when it isn't explicitly set in a client file config. The default is true.

Thanks for contributions and feedback. This is available in the master branch and edge docker tag now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
safe to test trusted to build image
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants