Sign inSign up

giof71/upnp-scrobbler

By giof71

Updated about 1 month ago

Scrobble to last.fm from your WiiM device

Image
0

10K+

giof71/upnp-scrobbler repository overview

UPnP Scrobbler

A simple LAST.fm scrobbler for WiiM devices.
It can now also scrobble to subsonic servers.

References

I started taking the code published in this post as the starting point.
It seems that I cannot get a valid link to the user profile on that board, but anyway the nickname is cc_rider.
A big thank you goes to him/her for the code he/she shared.
I then used pylast, as suggested in that thread, for the actual operations on last.fm.
I also use subsonic-connector for subsonic scrobbling.

REPOSITORY TYPELINK
Git RepositoryGitHub
Docker ImagesDocker Hub

Task List

  • Scrobbling from a WiiM device as a generic UPnP Renderer
  • Scrobbling from a WiiM device when using Tidal Connect
  • Scrobbling to gmrender-resurrect (Source and Docker image) as a generic UPnP Renderer
  • Scrobbling to mpd + upmpdcli in UPnP-AV mode
  • Scrobbling to a subsonic server
  • Enable "now playing" for subsonic
  • Enable song matching for subsonic
  • Allow multiple subsonic servers
  • Scrobbling to listenbrainz
  • Scrobbling to libre.fm

Build

You can build the docker image by typing:

docker build . -t giof71/upnp-scrobbler

Configuration

Create your API key and secret

Open your browser at this, follow the instruction and accurately store the generated values.
Those will be needed for the configuration.

Environment Variables
NAMEDESCRIPTION
DEVICE_URLDevice URL of your UPnP Device, alternative to DEVICE_UDN and DEVICE_NAME (example: http://192.168.1.7:49152/description.xml)
DEVICE_UDNDevice identifier, alternative to DEVICE_URL and DEVICE_NAME (must match only one device)
DEVICE_NAMEDevice friendly name, alternative to DEVICE_URL and DEVICE_UDN (must match only one device)
DEVICE_TIMEOUT_SEC_INITIALInt value, defaults to 5 seconds
DEVICE_TIMEOUT_SEC_DELTAInt value, defaults to 5 seconds
DEVICE_TIMEOUT_SEC_MAXInt value, defaults to 60 seconds
LAST_FM_API_KEYYour LAST.fm api key, mandatory
LAST_FM_SHARED_SECRETYour LAST.fm api key, mandatory
LAST_FM_USERNAMEYour LAST.fm account username, optional
LAST_FM_PASSWORD_HASHYour LAST.fm account password encoded using md5, optional
LAST_FM_PASSWORDYour LAST.fm account password in clear text, optional, used when LAST_FM_PASSWORD_HASH is not provided
ENABLE_NOW_PLAYINGUpdate now playing information if set to yes (default)
DURATION_THRESHOLDMinimum duration required from scrobbling (unless at least half of the duration has elapsed), defaults to 240
DUMP_UPNP_DATAAdditional logging for UPnP data, defaults to no
DUMP_EVENT_KEYSDump keys from each event keys, defaults to no
DUMP_EVENT_KEY_VALUESDump data from each event keys, defaults to no

Running

The preferred way of running this application is through Docker.

Configuration directory

When using docker, the base configuration directory is /config. When running outside of docker, the code looks for the default config directory using the platformdirs library.

LAST.fm configuration file

LAST.FM related variables can be stored in a file inside the <config-directory> volume, exacly at <config-directory>/upnp-scrobbler/last.fm/last_fm_config.env. Example:

LAST_FM_API_KEY=xxxx
LAST_FM_SHARED_SECRET=xxxx
# optional
LAST_FM_USERNAME=xxxx
# optional
LAST_FM_PASSWORD=xxxx
# optional
LAST_FM_PASSWORD_HASH=xxxx
Subsonic Configuration files

Subsonic related variables should be saved in files inside the <config-directory> volume, with files names like <config-directory>/upnp-scrobbler/subsonic/<subsonic_key>.server.env, and optionally <config-directory>/upnp-scrobbler/subsonic/<subsonic_key>.credentials.env (if you want to separate credentials).
Example file names:

lightweight-music-server.server.env
lightweight-music-server.credentials.env

Example of content for the mentioned files:

SUBSONIC_BASE_URL=https://your-subsonic-server.your-domain.com
# legacy auth
SUBSONIC_LEGACY_AUTH=true
# there is an alias available for variable name SUBSONIC_LEGACYAUTH (it's named this way in upmpdcli)
# SUBSONIC_LEGACYAUTH=true
# optional port, by default it will be `443` if the base url starts with `https`, otherwise `80`
SUBSONIC_PORT=443
# optional server path
# SUBSONIC_SERVER_PATH=server-path
# optional enable now playing, defaults to true
# SUBSONIC_ENABLE_NOW_PLAYING=false
# SUBSONIC_ENABLE_SONG_MATCH=true

and:

SUBSONIC_USERNAME=your-username
# there is an alias available for variable name SUBSONIC_USER (it's named this way in upmpdcli)
# SUBSONIC_USER=your-username
SUBSONIC_PASSWORD=your-password

You can collapse all the variables in one file for each subsonic configuration, but its name must be <subsonic_key>.server.env for each value given to subsonic_key.

The subsonic configuration variables are listed in the following table:

NAMEDESCRIPTION
SUBSONIC_BASE_URLServer base URL, e.g. https://navidrome.mydomain.com
SUBSONIC_PORTServer port, will default to 443 or 80 depending on SUBSONIC_BASE_URL
SUBSONIC_SERVER_PATHOptional server path
SUBSONIC_USERNAMEServer username
SUBSONIC_PASSWORDServer password or key
SUBSONIC_LEGACY_AUTHLegay authentication (true or false), defaults to false
SUBSONIC_ENABLE_SONG_MATCHAllow to find the song by title, artist(s) and album, defaults to true
SUBSONIC_ENABLE_NOW_PLAYINGAllow to scrobble in Now Playing mode when a song is matched (as opposed to found using the id in the track url), defaults to true
LAST.fm authentication

If username and password (hash or plaintext) are not provided, the application will prompt you to authorize the app.
You will need to watch the logs, al least for the first run.
Please note that API key and secret are still required.

Sample compose file

Here is a simple compose file, valid for a WiiM device:

---
version: "3"

services:
  scrobbler:
    image: giof71/upnp-scrobbler:latest
    container_name: wiim-scrobbler
    network_mode: host
    environment:
      - DEVICE_URL=http://192.168.1.7:49152/description.xml
      - LAST_FM_API_KEY=your-lastfm-api-key
      - LAST_FM_SHARED_SECRET=your-lastfm-api-secret
      - LAST_FM_USERNAME=your-lastfm-username
      - LAST_FM_PASSWORD_HASH=your-lastfm-md5-hashed-password
    restart: unless-stopped

It is advisable to put the variable values in a .env file in the same directory with this docker-compose.yaml file.
Start the container with the following:

docker-compose up -d

Change history

DATEDESCRIPTION
2025-11-17Search subsonic tracks using the exact title, compare removing non alphanumeric characters
2025-10-26Add support for "Now Playing" on subsonic (see #16)
2025-10-26Add support for "Now Playing" on subsonic (see #14)
2025-10-10Don't assume LAST.fm is configured (see #12)
2025-09-14Improved logging during authentication
2025-09-12Trigger "Now playing" only if player state is actually playing
2025-08-10Code style improvements
2025-08-09Initial support for gmrender-resurrect
2025-08-09Increasing timeouts
2025-08-09Fixed device search, would fail if first hit is not the expected one
2025-08-08Allow to specify last.fm credentials using an external file (last_fm_config.env)
2025-08-08Allow to specify device by udn (DEVICE_UDN)
2025-08-08Allow to specify device by friendly name (DEVICE_NAME)
2024-12-23Get transport state from LAST_CHANGE if not in TRANSPORT_STATE
2024-12-22Rewrite for better linearity, should avoid sparse management of variables
2024-12-22Avoid to require a g_previous_song in order to trigger a scrobble
2024-12-22Remove handling of impossible situation
2024-12-22Catch empty metadata
2024-12-22Don't consider track_uri as a difference between tracks
2024-12-22Add logs on maybe_scrobble in order to verify calculations
2024-12-22Explicitly return None in get_items
2024-12-22Add logs on maybe_scrobble in order to verify calculations
2024-12-22Add timestamp to log lines, more logging
2024-12-21Add log before scrobbling when metadata changes
2024-12-21Scrobble when metadata changes
2024-12-20More granular handling of events
2024-12-19Algorithm reviewed, should be working now
2024-12-18Now playing is executed when appropriate only
2024-12-18Code refactored
2024-12-11Log host ip
2024-12-10Add debug logging, to be refined
2024-11-29Improved general reliability and management of duration
2024-11-28Fixed parsing of duration
2024-03-26Initial release

Tag summary

Content type

Image

Digest

sha256:e55d43dc4

Size

50.6 MB

Last updated

about 1 month ago

docker pull giof71/upnp-scrobbler