Skip to content

Custom Tag Playlists

Create automatic YouTube Music playlists based on Last.fm tags and genres. You can define multiple tag-based playlists that fill themselves with matching tracks from your scrobble history.

For example, define a "Breakcore Mix" playlist that only includes tracks tagged breakcore or drill and bass on Last.fm, or a "Chill Electronic" playlist that requires both electronic and ambient tags.

How Tags Are Resolved

The tag system follows the same cache-first approach as the main sync:

  1. Tag overrides - check config/tag_overrides.json (user manual fixes). If the override mode is "replace", the override tags are used directly and steps 2-3 are skipped.
  2. Tag cache - check cache/.tag_cache.json (90-day TTL, configurable via TAG_CACHE_TTL_DAYS)
  3. Last.fm API - fetch via track.getTopTags, falling back to artist.getTopTags if track-level tags are unavailable

After fetching, "add" mode tag overrides are merged into the result (this allows supplementing Last.fm's tags without replacing them entirely).

Tags with fewer votes than TAG_MIN_COUNT (default: 10) are filtered out to avoid noise.

If backfilling is enabled and a playlist has not reached its target track count after filtering, the tool automatically fetches more scrobbles and repeats until the limit is met or no more data is available.


Configuration

Docker: Use the web dashboard to create and manage tag playlists. Tag sync can be triggered manually from the UI, or automatically after each scheduled main sync via AUTO_TAG_SYNC_ENABLED and AUTO_TAG_SYNC_FREQUENCY (see Configuration).

CLI: Edit config/custom_playlists.json directly:

1. Create the config file

cp config/custom_playlists.json.example config/custom_playlists.json

2. Define your playlists

{
  "playlists": [
    {
      "name": "Breakcore Mix (auto)",
      "tags": ["breakcore", "drill and bass"],
      "match": "any",
      "limit": 50,
      "backfill": true,
      "blacklist": []
    },
    {
      "name": "Ambient Electronic (auto)",
      "tags": ["ambient", "electronic"],
      "match": "all",
      "limit": 30,
      "backfill": true,
      "blacklist": ["artist name|unwanted track"]
    }
  ]
}
Field Description
name Playlist name on YouTube Music
description Optional playlist description
tags Last.fm tags to match against
match "any" (track has at least one tag) or "all" (track has every tag)
limit Target number of tracks
backfill Fetch more scrobbles if filtering doesn't reach the limit
blacklist Per-playlist exclusions as "artist\|title" (lowercase)

Environment Variables

Variable Default Description
CUSTOM_PLAYLISTS_FILE config/custom_playlists.json Path to playlist definitions
TAG_CACHE_TTL_DAYS 90 Days before cached tags expire
TAG_MIN_COUNT 10 Minimum Last.fm tag count threshold
TAG_SLEEP_BETWEEN 0.25 Seconds between tag API calls
CUSTOM_PLAYLISTS_PRIVACY (main setting) Privacy for tag playlists (PUBLIC / PRIVATE)
BACKFILL_PASSES 3 Maximum backfill iterations

Tag Overrides

When Last.fm's tag data is wrong or incomplete, you can manually fix it.

Docker: Use the web dashboard's tag management interface.

CLI: Edit config/tag_overrides.json directly:

1. Create the overrides file

cp config/tag_overrides.json.example config/tag_overrides.json

2. Add your override

{
  "_overrides": {
    "artist name|song title": {
      "artist": "Artist Name",
      "title": "Song Title",
      "tags": ["breakcore", "electronic"],
      "mode": "add",
      "reason": "Last.fm only has 'electronic', adding 'breakcore'"
    }
  }
}
Field Description
Key artist\|title in lowercase
tags List of tag names to apply
mode "add" merges with existing Last.fm tags, "replace" overwrites them entirely
reason Optional note for your reference

Running Tag Sync

Tag playlists are synced separately from the main playlist. Use the dedicated entry point:

python run_tags.py  # or: lastfm-ytm-tags

Warning

python run.py only runs the main playlist sync. Tag playlists must be triggered separately via run_tags.py or from the web dashboard.