112 KiB
Vrobbler Project
- Overview
- Features
- Backlog
[1/23]- Create small utility to clean up tracks scrobbled with wonky playback times
- Move to using more robust mopidy-webhooks pacakge form pypi
- Allow auto trail tracking via email with Garmin LiveTrack URLs
- Fix exporting so it works reliably
- Add AllTrails as a source for Trail data
- Add `garmin_activity_id` to the TrailLogData class
- Fix how we show notes and descriptions from scrobbles to users
- Add CSV endpoint for book scrobbles that LibraryThing can ingest
- Make IMAP and WebDAV configurable
- Add an exception list of artists as a constant that are exempted from splitting
- Before enriching anything, trust the POST data
- Allow browing a user's favorited media
- Find page numbers for comic books from ComicVine
- Implement loguru into project
- Scrape ComicBookRoundUp ratings for comic book metadata
- Make podcast date format configurable in settings
- Extract zombie scrobble query into custom manager
- Allow profile to set start of week
- Add constants for data dictionary keys (multiple files)
- Deduplicate BGG plays before posting
- Clean up naming of
bgsplayparsing - Is there way to create unique slugs for media instances
- Fix bug in creating people when importing course plays
- Version 56.1
[1/1] - Version 56.0
[1/1] - Version 55.6
[1/1] - Version 55.5
[1/1] - Version 55.4
[1/1] - Version 55.3
[3/3] - Version 55.2
[2/2] - Version 55.1
[1/1] - Version 55.0
[3/3] - Version 54.5
[1/1] - Version 54.4
[2/2] - Version 54.3
[1/1] - Version 54.2
[4/4] - Version 54.1
[1/1] - Version 54.0
[3/3] - Version 53.1
[1/1] - Version 53.0
[5/5] - Version 52.2
[1/1] - Version 52.1
[1/1] - Version 52.0
[5/5] - Version 51.4
[1/1] - Version 51.3
[1/1] - Version 51.2
[2/2] - Version 51.1
[1/1] - Version 51.0
[3/3] - Version 50.2
[2/2] - Version 50.1
[1/1] - Version 50.0
[2/2] - Version 49.1
[1/1] - Version 49.0
[1/1] - Version 48.3
[1/1] - Version 48.2
[1/1] - Version 48.1
[2/2] - Version 48.0
[2/2] - Version 47.2
[1/1] - Version 47.1
[1/1] - Version 47.0
[1/1] - Version 46.0
[1/1] - Version 45.1
[1/1] - Version 45.0
[1/1] - Version 44.0
[1/1] - Version 43.0
[5/5] - Version 42.0
[1/1] - Version 41.0
[5/5] - Version 40.2
[1/1] - Version 40.1
[2/2] - Version 40.0
[2/2] - Version 39.3
[2/2] - Version 39.2
[2/2] - Version 39.1
[1/1] - Version 39.0
[3/3] - Version 38.0
[38/38]- Fix release flow to be easier to trigger
- Move imported retroarch lrtl files to processed/ directory on WebDAV
- Add listenbrainz support for similar tracks
- Consolidate albums in the same musicbrainz_releasegroup_id
- Clean up metadata on music tracks
- Make artists_m2m field source of artist truth for albums
- Fix various artist album problem with Superwolves (track with multiple artists)
- Move imported eBird CSV files to processed/ directory on WebDAV
- Move imported Board Game CSV files to processed/ directory on WebDAV
- Move imported Scale CSV files to processed/ directory on WebDAV
- Allow special parameter to re-import already processed GPX files
- Move imported GPX files to processed/ directory on WebDAV
- Add CSS Grid calendar view for scrobbles
- Come up with a possible flow using WebDAV and super-productivity for tasks
- Fix PuzzleLogData has no attribute form
- Add PuzzleLogData class with with_people and completed
- Add weather lookup to the mood check-in flow
- Add importing of openScale CSV files to Tasks
- Add ability to track Birding sessions via BirdingLocation scrobbles
- List only the last 20 scrobbles per category on the home page
- Fix display of notes so they look like stickies
- Add searching to scrobbles
- Fix uniqueness of imdb_id messing up youtube videos
- Fix genearting chart records
- Save raw scrobble request data to every scrobble log
- Clean up follow up notifications for if you're still scrobbling
- Fix lookup of music tracks from Musicbrainz
- Check opencode about a way to present stats like movies per month
- Fix bug in Jellyfin audio track playback
- Auto calc duration if no playback time seconds present
- Fix bug in video find_or_create
- Update admin page to be easier to use
- Fix migrations and update repo
- Add recipe parsing for food lookups
- Videos are scrobbling duplicates again
- Fix board games not saving BGG id on lookup
- Fix board game lookup with name like Unmatched Game System
- Fix raw text webpage title not truncating to 254 chars
- Version 37.0
[4/4] - Version 36.0
[1/1] - Version 35.0
[3/3] - Version 34.0
[4/4] - Version 33.0
[3/3] - Version 32.0
[2/2] - Version 31.0
[3/3] - Version 30.0
[3/3] - Version 29.0
[1/1] - Version 28.0
[1/1] - Version 27.0
[3/3] - Version 26.0
[3/3] - Version 25.0
[3/3] - Version 24.0
[2/2] - Version 23.0
[3/3] - Version 19.0
[1/1] - Version 18.7
[1/1] - Version 18.4
[2/2] - Version 18.3
[1/1] - Version 18
[4/4]- Condense tracks of the same title by the same artist with multiple albums
- Import from BG stats a "learning" log field when "Learning to play" is in the comment
- Add email importer for BG stats file uploads
- Fix task app to only use one tag for the context a task was done in and allow configurable contexts by user profile
- Version 17.0
[6/6] - Version 0.16.0
[19/19]- Jellyfin, bandcamp tracks from Mopidy create duplicate music tracks
- Add a user profile page with ability to change settings
- What to do with Youtube videos from LastFM and web-scrobbler
- Consider a purge command for duplicated and stuck in-progress scrobbles
- Add a "stop_timestamp" so we don't rely on content length
- Fix bug with Various Artist albums being labeled with first artist as album artist
- Fix bug with weekly aggregator being blank on Sundays
- Fix KoReader scrobbling to use pages rather than time of last read
- Add django-storage to store files on S3
- Fix vrobbler settings not using booleans
- Update weekly live chart to be 7-day continuous rather than weekly
- Implement a detail view for TV shows
- Implement a detail view for Movies
- Add "service provider" to TV Series, and use that for source when available
- Add view for long-play content (books, video games) to restart them
- Add live chart view like Maloja
- Figure out how to add to web-scrobbler
- Add Amazon scraper to look up books when OL fails
- Fix bug in Jellyfin scrobbles that spam more scrobbles after completion
- Version 0.11.4
[9/9]- Add rudimentary video game scrobbling
- Add ability to scrobble from KOReader statistics files
- Fix fetching artwork without release group
- Fix Jellyfin music scrobbling N+1 past 90 completion percent
- Add support for Audioscrobbler tab-separated file uploads
- Allow scrobbling music without MB IDs by grabbing them before scrobble
- When updating musicbrainz IDs, clear and run fetch artwrok
- Add ability to manually scrobble albums or tracks from MB
- Implement keeping track of week/month/year chart-toppers
We should convert this PROJECT file to put tickets in a subdirectory, tickets, with each ticket having it's own shortid_title.org
Overview
Vrobbler began humbly enough as a way to use Jellyfin's webhook to keep track of the shows and movies I was watching. More specifically, I broke my ankle a few days after Christmas in 2022 and spent the next four months very slowly recovering after surgical repair. So once I had the webhook working, and scrobbling videos, it was only a matter of time till I expaned it to mopidy to replicate LastFM. Then I added board games, books via KoReader, sports events, podcasts … it just keeps going. Vrobbler is now a sort of Frankenstein's monster of scrobbling an entire life.
I am still unconvinced I can keep this going, but being able to scrobble org tasks, Todoist tasks, web pages I've read and trails I've hiked has turned out to be sometimes cathartic and sometimes functional as I try to remember when I did a thing.
Features
Beer
Triggers
Bookmarklet
Manual
Metadata sources
Untappd
Book
Triggers
Webdav via KoReader
Manual
Metadata sources
Google Books
This is the preferred method at this time. Also, the Book model implements a `find_or_create` classmethod which is an example of an interface we can use for other data models to get metadata in a way that provides easy testing, bulk fetching and simple saving.
OpenLibrary
ComicVine
Board Game
Triggers
IMAP import
Bookmarklet
Manual
Location
Triggers
GPSLogger (Android)
Metadata sources
User input
Music
Triggers
Last.FM
Rockbox files
Mopidy
Jellyfin
Metadata sources
Musicbrainz
Podcast
Triggers
Mopidy
Metadata sources
Google Podcasts
PodcastIndex
Sport
Triggers
Bookmarklet
Manual
Metadata sources
Thes Sports DB
Task
Triggers
Todoist
Org-mode
Metadata sources
User profile
Trails
Video
Triggers
Jellyfin
Bookmarklet
Manual
Metadata sources
IMDB
Youtube
Web Page
Triggers
Bookmarklet
Metadata sources
Scraper
Backlog [1/23] vrobbler project personal
TODO [C] Create small utility to clean up tracks scrobbled with wonky playback times bug music scrobbles
TODO [C] Move to using more robust mopidy-webhooks pacakge form pypi utility improvement
Example payloads from mopidy-webhooks
Podcast playback ended
{
"type": "event",
"event": "track_playback_ended",
"data": {
"tl_track": {
"__model__": "TlTrack",
"tlid": 13,
"track": {
"__model__": "Track",
"uri": "file:///var/lib/mopidy/media/podcasts/The%20Prince/2022-09-28-Wolf-warriors.mp3",
"name": "Wolf warriors",
"artists": [
{
"__model__": "Artist",
"name": "The Economist"
}
],
"album": {
"__model__": "Album",
"name": "The Prince",
"date": "2022"
},
"genre": "Blues",
"date": "2022",
"length": 2437778,
"bitrate": 127988
}
},
"time_position": 3290
}
}
Podcast playback state changes
{
"type": "event",
"event": "playback_state_changed",
"data": {
"old_state": "paused",
"new_state": "playing"
}
}
{
"type": "event",
"event": "playback_state_changed",
"data": {
"old_state": "stopped",
"new_state": "playing"
}
}
Podcast playback started
{
"type": "event",
"event": "track_playback_started",
"data": {
"tl_track": {
"__model__": "TlTrack",
"tlid": 13,
"track": {
"__model__": "Track",
"uri": "file:///var/lib/mopidy/media/podcasts/The%20Prince/2022-09-28-Wolf-warriors.mp3",
"name": "Wolf warriors",
"artists": [
{
"__model__": "Artist",
"name": "The Economist"
}
],
"album": {
"__model__": "Album",
"name": "The Prince",
"date": "2022"
},
"genre": "Blues",
"date": "2022",
"length": 2437778,
"bitrate": 127988
}
}
}
}
Podcast playback paused
{
"type": "status",
"data": {
"state": "paused",
"current_track": {
"__model__": "Track",
"uri": "file:///var/lib/mopidy/media/podcasts/The%20Prince/2022-09-28-Wolf-warriors.mp3",
"name": "Wolf warriors",
"artists": [
{
"__model__": "Artist",
"name": "The Economist"
}
],
"album": {
"__model__": "Album",
"name": "The Prince",
"date": "2022"
},
"genre": "Blues",
"date": "2022",
"length": 2437778,
"bitrate": 127988
},
"time_position": 2350
}
}
Track playback started
{
"type": "event",
"event": "track_playback_started",
"data": {
"tl_track": {
"__model__": "TlTrack",
"tlid": 14,
"track": {
"__model__": "Track",
"uri": "local:track:Various%20Artists%20-%202008%20-%20Twilight%20OST/01-muse-supermassive_black_hole.mp3",
"name": "Supermassive Black Hole",
"artists": [
{
"__model__": "Artist",
"uri": "local:artist:md5:250dd6551b66a58a6b4897aa697f200c",
"name": "Muse",
"musicbrainz_id": "9c9f1380-2516-4fc9-a3e6-f9f61941d090"
}
],
"album": {
"__model__": "Album",
"uri": "local:album:md5:455343d54cdd89cb5a3b5ad537ea99d0",
"name": "Twilight: Original Motion Picture Soundtrack",
"artists": [
{
"__model__": "Artist",
"uri": "local:artist:md5:54e4db2d5624f80b0cc290346e696756",
"name": "Various Artists",
"musicbrainz_id": "89ad4ac3-39f7-470e-963a-56509c546377"
}
],
"num_tracks": 12,
"num_discs": 1,
"date": "2008-11-04",
"musicbrainz_id": "b4889eaf-d9f4-434c-a68d-69227b12b6a4"
},
"composers": [
{
"__model__": "Artist",
"uri": "local:artist:md5:4d49cbca0b347e0a89047bb019d2779d",
"name": "Matt Bellamy"
}
],
"genre": "Rock",
"track_no": 1,
"disc_no": 1,
"date": "2008-11-04",
"length": 211121,
"musicbrainz_id": "ff1e3e1a-f6e8-4692-b426-355880383bb6",
"last_modified": 1672712949510
}
}
}
}
Track playback in progress
{
"type": "status",
"data": {
"state": "playing",
"current_track": {
"__model__": "Track",
"uri": "local:track:Various%20Artists%20-%202008%20-%20Twilight%20OST/01-muse-supermassive_black_hole.mp3",
"name": "Supermassive Black Hole",
"artists": [
{
"__model__": "Artist",
"uri": "local:artist:md5:250dd6551b66a58a6b4897aa697f200c",
"name": "Muse",
"musicbrainz_id": "9c9f1380-2516-4fc9-a3e6-f9f61941d090"
}
],
"album": {
"__model__": "Album",
"uri": "local:album:md5:455343d54cdd89cb5a3b5ad537ea99d0",
"name": "Twilight: Original Motion Picture Soundtrack",
"artists": [
{
"__model__": "Artist",
"uri": "local:artist:md5:54e4db2d5624f80b0cc290346e696756",
"name": "Various Artists",
"musicbrainz_id": "89ad4ac3-39f7-470e-963a-56509c546377"
}
],
"num_tracks": 12,
"num_discs": 1,
"date": "2008-11-04",
"musicbrainz_id": "b4889eaf-d9f4-434c-a68d-69227b12b6a4"
},
"composers": [
{
"__model__": "Artist",
"uri": "local:artist:md5:4d49cbca0b347e0a89047bb019d2779d",
"name": "Matt Bellamy"
}
],
"genre": "Rock",
"track_no": 1,
"disc_no": 1,
"date": "2008-11-04",
"length": 211121,
"musicbrainz_id": "ff1e3e1a-f6e8-4692-b426-355880383bb6",
"last_modified": 1672712949510
},
"time_position": 17031
}
}
Track event playback paused
{
"type": "event",
"event": "track_playback_paused",
"data": {
"tl_track": {
"__model__": "TlTrack",
"tlid": 14,
"track": {
"__model__": "Track",
"uri": "local:track:Various%20Artists%20-%202008%20-%20Twilight%20OST/01-muse-supermassive_black_hole.mp3",
"name": "Supermassive Black Hole",
"artists": [
{
"__model__": "Artist",
"uri": "local:artist:md5:250dd6551b66a58a6b4897aa697f200c",
"name": "Muse",
"musicbrainz_id": "9c9f1380-2516-4fc9-a3e6-f9f61941d090"
}
],
"album": {
"__model__": "Album",
"uri": "local:album:md5:455343d54cdd89cb5a3b5ad537ea99d0",
"name": "Twilight: Original Motion Picture Soundtrack",
"artists": [
{
"__model__": "Artist",
"uri": "local:artist:md5:54e4db2d5624f80b0cc290346e696756",
"name": "Various Artists",
"musicbrainz_id": "89ad4ac3-39f7-470e-963a-56509c546377"
}
],
"num_tracks": 12,
"num_discs": 1,
"date": "2008-11-04",
"musicbrainz_id": "b4889eaf-d9f4-434c-a68d-69227b12b6a4"
},
"composers": [
{
"__model__": "Artist",
"uri": "local:artist:md5:4d49cbca0b347e0a89047bb019d2779d",
"name": "Matt Bellamy"
}
],
"genre": "Rock",
"track_no": 1,
"disc_no": 1,
"date": "2008-11-04",
"length": 211121,
"musicbrainz_id": "ff1e3e1a-f6e8-4692-b426-355880383bb6",
"last_modified": 1672712949510
}
},
"time_position": 67578
}
}
TODO [C] Allow auto trail tracking via email with Garmin LiveTrack URLs trails feature
TODO [C] Fix exporting so it works reliably exporting feature
Description
The existing export function is very naieve. It runs in the web process, takes too long and just dumps tracks. We should make it more robust by creating one CSV file per scrobble media type and writing them into a zip file that gets placed in the media directory:
`/media/exports/user_<user_id>/<timestamp>-export.zip`
And this should all be done in a celery task that is just kicked off by the "Export" button on the frontend
TODO [B] Add AllTrails as a source for Trail data trails feature
Description
Pretty clear, I would love to make trails more useful. Historically I wasn't hiking a lot, which made the source for this a bit silly. But it's clear that AllTrails is the best source, though having TrailForks is nice to.
TODO [B] Add `garmin_activity_id` to the TrailLogData class trails feature
Description
Would be nice to have some loose connection to the actual event in my Garmin profile.
TODO [B] Fix how we show notes and descriptions from scrobbles to users metadata notes tasks
Description
Currently the display of notes leaves something to be desired. The biggest issue is that they don't look good on mobile and are probably trying to be too cute. Rather than post-it note style, we should just put notes in a list under the description, above the Edit Log toggle, with timestamps for when they were added.
They should also probably support markdown formatting and that should be displayed in the template.
TODO [B] Add CSV endpoint for book scrobbles that LibraryThing can ingest books feature export
TODO [B] Make IMAP and WebDAV configurable webdav feature imap importers
Description
Currently we have webdav able to import post types of file-based incoming data, usually in the form of CSVs but also gpx files, bgstats json files, and audioscrobbler TSV files.
What if the user could specify via their profile (settings) which imports they wanted to use IMAP for and which ones they wanted to use WebDAV for.
Then we'd have two celery tasks that would be kicked off periodically via celerybeat, one for IMAP imports every 12 minutes and one for WebDAV every 3 minutes. Both would be responsible for checking if a user has an configured imports of their type, check if an import needs to run, and dispatch the needed import celery task. This is how the WebDAV celery task currently works.
This would also be an opporunity to clean up the code around WebDAV imports and make them more re-usable for other import services.
TODO [A] Add an exception list of artists as a constant that are exempted from splitting music artists metadata
Description
Certain artists like "Simon & Garfunkel" are actually one artist. While we don't want to mess with splitting up tracks into featured artists, we should have a "LITERAL_ARTIST_TITLES" constant that can have exceptions like this put into it and then we stop trying to pull the artist apart when we run into it.
TODO [A] Before enriching anything, trust the POST data feature scrobbles metadata
Description
Both Jellyfin and Mopidy provide a decent amount of metadata when they POST to our webhooks.
In most cases, we should be able to trust this data to created music tracks or videos rather than going to third-party services to enrich. Thus, for tracks and videos we should search in the local database for imdb_id or musicbrainz_id for the specific content and, if found, not enrich further.
If not found, tracks and videos from mopidy and jellyfin should be created as completely as possible using only the POST data from the webhooks, tagged the scrobble with "webhook-metadata-only" and start the scrobble. A separate celery task should be kicked off to enrich the track or video async with the POST data stored in the log["raw_data"] and used by the celery enrichment task to go try to enrich the media instance. Should this enrichment fail, tag the scrobble as "enrichment-failed" log a warning and move on.
TODO [B] Allow browing a user's favorited media favorites feature
Description
We should have a global view `/favorites/` that shows the logged in users's favorited media objects.
TODO [B] Find page numbers for comic books from ComicVine feature books
TODO [C] Implement loguru into project feature loguru logging
Description
Would be great to formalize how we log so we can search for errors and such more easily. And our exposure to PII is really low at this point in the project, so we can probably use backtrace=True and diagnose=True to help us root cause bugs faster.
TODO [B] Scrape ComicBookRoundUp ratings for comic book metadata books feature comicbook
Description
TODO [C] Make podcast date format configurable in settings podcasts configuration
Description
PODCAST_DATE_FORMAT is hardcoded to "YYYY-MM-DD". Should be in Django settings or environment variables for deploy-specific configuration.
File: vrobbler/apps/podcasts/utils.py (line 13)
TODO [C] Extract zombie scrobble query into custom manager refactoring manager
Description
The zombie scrobble cleanup query lives in a utility function. Should be a
custom model manager method (e.g. Scrobble.objects.zombies()).
File: vrobbler/apps/scrobbles/utils.py (line 204)
TODO [C] Allow profile to set start of week profiles configuration
Description
start_of_week() and end_of_week() use Monday as default. Should be a user
profile setting for different cultural week start conventions.
File: vrobbler/apps/profiles/utils.py (lines 39, 44)
TODO [C] Add constants for data dictionary keys (multiple files) refactoring constants
Description
Multiple files use magic string literals for dict keys. Should be extracted to named constants for maintainability.
-
Files:
vrobbler/apps/locations/models.py(line 63) –"lat","lon"etc.vrobbler/apps/webpages/models.py(line 290) –"url"vrobbler/apps/scrobbles/importers/tsv.py(line 55) –"S"completion status
TODO [A] Deduplicate BGG plays before posting boardgames bgg duplication
Description
No check for existing BGG plays before posting, which can create duplicates.
Should look up past plays by bggeek_id first.
File: vrobbler/apps/boardgames/bgg.py (line 117)
TODO
[C]
Clean up naming of bgsplay parsing importers refactoring
Description
We should rename `email_scrobble_board_game` to reflect the fact that it's just a helper method to create board game scrobbles given a json blob. It's independent of the email flow it was originally creatdd for
TODO [B] Is there way to create unique slugs for media instances media_types
DONE [A] Fix bug in creating people when importing course plays discgolf bug
Version 56.1 [1/1]
DONE [A] Add tests to discgolf app discgolf tests
Version 56.0 [1/1]
DONE [B] Add DiscGolf as a scrobbleable media discgolf
Description
I have a csv file fro the uDisc disc golf scoring app that looks like:
Singles round. Note second row is the par for the course
PlayerName,CourseName,LayoutName,StartDate,EndDate,Total,+/-,RoundRating,Hole1,Hole2,Hole3,Hole4,Hole5,Hole6,Hole7,Hole8,Hole9
Par,DR Front 9,Custom Layout,2026-06-19 1535-0400,2026-06-19 1725-0400,27,,,3,3,3,3,3,3,3,3,3
Colin Powell,DR Front 9,Custom Layout,2026-06-19 1535-0400,2026-06-19 1725-0400,30,3,,2,3,4,4,3,4,3,3,4
Asa Sewell,DR Front 9,Custom Layout,2026-06-19 1535-0400,2026-06-19 1725-0400,44,17,,5,4,4,8,5,5,4,4,5
Emma Sweet,DR Front 9,Custom Layout,2026-06-19 1535-0400,2026-06-19 1725-0400,41,14,,5,4,5,6,3,4,3,5,6
Jane Sewell,DR Front 9,Custom Layout,2026-06-19 1535-0400,2026-06-19 1725-0400,44,17,,4,5,5,5,5,5,4,6,5
Nabby Sewell,DR Front 9,Custom Layout,2026-06-19 1535-0400,2026-06-19 1725-0400,59,32,,6,6,7,7,6,7,6,6,8
Silas Sewell,DR Front 9,Custom Layout,2026-06-19 1535-0400,2026-06-19 1725-0400,41,14,,5,5,4,5,3,5,4,4,6`
Teams of two or more persons. Note second row is the par for the course
PlayerName,CourseName,LayoutName,StartDate,EndDate,Total,+/-,RoundRating,Hole1,Hole2,Hole3,Hole4,Hole5,Hole6,Hole7,Hole8,Hole9
Par,Peninsula Links,Main,2026-06-19 2322-0400,2026-06-19 2323-0400,27,,,3,3,3,3,3,3,3,3,3
Colin Powell + Asa Sewell,Peninsula Links,Main,2026-06-19 2322-0400,2026-06-19 2323-0400,29,2,,3,4,2,3,2,3,5,3,4
Emma Sweet + Jane Sewell,Peninsula Links,Main,2026-06-19 2322-0400,2026-06-19 2323-0400,28,1,,4,3,4,2,3,4,3,3,2
We should add a new app called discgolf that has the following data models:
- DiscGolfRound - scrobblable media + course_id, round_type (Singles, Teams)
- DiscGolfCourse - name, layoutname, number_of_holes
And the logdata for a DiscGolfOuting scrobble should have:
- {person: {hole_number: score}, total: int}
- {team: {name: "", people: [person, person], hole_number: score}, total: int}
- weather
- fun_factor (miserable, not great, so-so, good, excellent, party time)
Version 55.6 [1/1]
DONE [A] Figure out why historical Lastfm imports don't work importers lastfm music
Version 55.5 [1/1]
DONE [B] Fix bug in lastfm import for new users importers lastfm music
Version 55.4 [1/1]
DONE [A] Tighten up the speed of startup and first request perf
Version 55.3 [3/3]
DONE
[C]
alt_names feature for artists (commented out / dead code) :music:dead-code:
Description
File: vrobbler/apps/music/models.py (line 236)
An entire block of code for tracking alternate artist names is commented out. The TODO questions whether it even works. Review: either implement properly or remove the dead code.
DONE [A] Put chart rebuilds in a lower priority task queue charts tasks
DONE [A] Check for existing book scrobble and update page count books scrobbling
Description
File: vrobbler/apps/scrobbles/scrobblers.py (line 330)
When scrobbling a book (comic), the code doesn't check for prior scrobbles to update reading progress. Needed for proper page-count tracking.
Version 55.2 [2/2]
DONE [A] Fix bug in scrobble id in calendar view templates
DONE [A] Video game cleanup script should clear out broken images metadata videogames
Version 55.1 [1/1]
DONE [A] Clean up metadata scrapping for video games metadata videogames
Version 55.0 [3/3]
DONE [B] Use pk ID for scrobble detail view, not uuid scrobbles
DONE [B] Display videogame screenshots on scrobble detail if they exist videogames templates
DONE [B] Add autotagging to webpages based on domain, title webpages metadata
Description
For easier filtering, like we do with tasks, we should auto tag WebPage instances based on the domain name split part by periods (so news.ycombinator.com tags: news, ycombinator, com)
And also based on the nouns in the title.
Version 54.5 [1/1]
DONE Fix bug in generating mood trends trends
Version 54.4 [2/2]
DONE [A] Remove all-time trends trends
Description
All time trends take forever to calculate and don't provide too much data
DONE [B] Add a trend around moods moods trends
Version 54.3 [1/1]
DONE [B] Fix bug in series metadata cleanup script videos metadta
Version 54.2 [4/4]
DONE [B] Add script to clean up TV series metadata videos metadata
DONE [A] Update youtube video detail pages with links to channel videos templates
DONE [A] Concurrent reading trend does not consolidate on single book trends reading
DONE [B] Trends dont seem to look very far back trends
Description
Specificially, looking at reading-pace when run on prod, it claims that I've only had one reading session without music. Which may be true, but perhaps we need to indicate what the time frame we're looking at is (month, week, year) and provide a way to jump back and forward through time, same as charts.
Version 54.1 [1/1]
DONE [A] Concurrent listening trend is inefficient and should be disabled trends scrobbles
Version 54.0 [3/3]
DONE [B] Add peak hour, weekly rhythm and activity dist trends trends scrobbles
DONE [A] Implement YouTube channel info scraping videos youtube stub
Description
File: vrobbler/apps/videos/models.py (line 140)
Video.fix_metadata() is a stub that logs "Not implemented yet" and returns.
Needs actual implementation to scrape channel metadata from YouTube.
DONE [A] Fix Amazon book scraper amazon scraper broken
Description
File: vrobbler/apps/books/amazon.py (line 56)
The scrape_data_from_amazon() function is likely broken due to Amazon blocking
scrapers and changing HTML structure. Needs rewrite or replacement with a proper
API.
Version 53.1 [1/1]
DONE [A] Error with loading logdict scrobbles bug logdata
Version 53.0 [5/5]
DONE [B] Add a trends page that shows trends based on scrobble data feature trends scrobbles
Description
This project is a bit invovled. But we should add a top level URL `trends` that shows various trends as defined either in a static settings file, or dynamically via a database table.
Trends could be things like doing multiple things at the same time, like while driving, what did we listen to this week, or while running, what were listening to this week?
Or more complicated trends like, how time per page changes based on the book I was reading, or if I was doing something else (music or sport event) while reading.
DONE [B] Notify users when Last.fm import completes importers notifications
Description
After a bulk import from Last.fm, users receive no confirmation. Should add a notification (in-app, email, or similar).
File: vrobbler/apps/scrobbles/importers/lastfm.py (line 96)
DONE
[C]
Cleaner GeoLocationLogData deserialization models refactoring
Description
Currently special-cases GeoLocationLogData by reaching into a nested "movement_detection" key. Should be handled at the LogData dataclass level.
File: vrobbler/apps/scrobbles/models.py (line 977)
DONE [B] Webpage scrobbles should diff existing webpages content webpages metadata
Description
Webpages change content between scrobbles. The current model stores the webpage content once, the first time it's scrobbled. When a page has been seen before, we should move the existing content to a new model HistoricalWebPage with the following fields:
webpage_id -> FK to WebPage date -> date from existing WebPage content domain -> same as existing WebPage content extract -> copy of existing WebPage content
Once the HistoricalWebPage instance is successfully created, the new extract data should be saved into the WebPage instance.
DONE [B] Make ArchiveBox push asynchronous archivebox async
Description
push_to_archivebox() runs synchronously during the request. Should be moved to a
Celery task or similar background worker.
File: vrobbler/apps/webpages/models.py (line 133)
Version 52.2 [1/1]
DONE [A] Fix bug in recomputing long play seconds taking forever bug longplay commands
Version 52.1 [1/1]
DONE [C] Show time per scrobble in long play lists and total time playing templates longplay scrobbles
Description
Long play time should be show in the table of scrobbles on a media detail page. The total time spent in a long play that's either no completed yet or completed should be displayed as well. If completed, the date finished should be shown as well.
Version 52.0 [5/5]
DONE [B] Allow marking media as long play complete from detail page templates scrobbles longplay
DONE [A] Fix how long play scrobbles are tracked scrobbles longplay serial
Description
Currently we have this idea of "long_play" scrobbles but there's a lot missing to tie it together.
What we'd prefer is that when a new scrobble is added for a media_type that `is_long_play` the most recent scrobble finished is added as the `last_serial_scrobble` to the log data. But all the other long play stuff exsits as data model fields. We should add `long_play_last_scrobble` as a FK to this scrobble when creating a new longplay scrobble.
Additionally, `long_play_seconds` we should have a recompute management command to walk backward from `long_play_last_scrobble` until a `long_play_complete` scrobble is found (exclusive) and save the time.
We should also ony use `long_play_complete` field on the scrobble … some logdatas have a similar field, but we should make sure that we always use the model field to determine if a long play is finished.
This should include a command to clean up long play data to consolidate around the `long_play_complete` field.
DONE [B] Paginate or limite scrobbles on media admin pages admin scrobbles media
DONE [B] Clean up books admin admin books bug
DONE [B] Clean up favorites admin admin favorites scrobbles
Description
Some FK lookups in admin should be raw_id_fields.
Version 51.4 [1/1]
DONE [A] Clean up metadata comicbook enrichment bug comics books metadata
Description
Still getting wonky results with some comicbooks. Would be nice to be able to tag a Book as a comicbook, and also gather volume information. I also noticed that some books that are found in OL never get their comicvine_id populated. We should make sure we always have comicvine_ids if available.
Version 51.3 [1/1]
DONE [A] Improve speed of index and chart pages bug scrobbles perf
Description
Over the last few releases, the home page and charts pages have gotten really slow.
We should look into what's causing the slowness and maybe do more agressive query optimization or caching.
Version 51.2 [2/2]
DONE [A] Fix bug where last page of book gets separate scrobble bug books importers koreader
Description
The new KoReader code is working great to import books with the correct timezone and what-not. But it has a weird artifact of creating one extra scrobble for the last page read. Need to button that up.
DONE [B] Fix metadata scraping for books books metadata
Version 51.1 [1/1]
DONE [A] Fix scrobbling comic books books scrobbles bug
Description
At some point logdata and log got confused, and now when you try to scrobble a comic book, it just throws errors. We should look into where the confusion happened and fix it.
Version 51.0 [3/3]
DONE [B] Fix koreader scrobble imports to use DST properly bug books imports
- Note taken on [2025-09-25 Thu 10:37] \\ This may already be fixed … need to check.
- Note taken on [2025-02-25 12:34] \\ The page data has the canonical date something was read in it, but it seems to be an hour off. I traced this back to being off during DST, so we just need the importer to be aware of whether a user is using DST or not and roll back an hour for part of the year. Also, we'd need to adjust any old scrobbles that took place with DST off to roll them back by an hour.
Description
This is a long-standing problem when daylight saving time takes effect. Time is manually set on a KoReader device (or at least, always saved in local time). So whatever time KoReader reports, we need to know, given the date and the user profile's historic timezone, how many hours to adjust the KoReader time to get to GMT to save it in the database.
DONE [A] Fix book scrobbles where page_data is a list bug books scrobbles
Description
Comic scrobbling is currently kind of janky. Most of the problems boil down to them storing saved page data in a list of dicts rather than a dict keyed off of the page number that was read.
We need to adjust comic scrobbling to use a dict of pages keyed off the page number, and also write a migration script that runs as a data migration to update any book scrobbles that may have page_data as a list.
Example data
{"notes": null, "page_end": 27, "page_data": [{"notes": null, "end_ts": 1771815895, "duration": 14, "start_ts": 1771815881, "description": null, "page_number": "1"}, {"notes": null, "end_ts": 1771815908, "duration": 13, "start_ts": 1771815895, "description": null, "page_number": "1"}, {"notes": null, "end_ts": 1771815913, "duration": 5, "start_ts": 1771815908, "description": null, "page_number": "2"}, {"notes": null, "end_ts": 1771815933, "duration": 20, "start_ts": 1771815913, "description": null, "page_number": "3"}, {"notes": null, "end_ts": 1771815945, "duration": 12, "start_ts": 1771815933, "description": null, "page_number": "4"}, {"notes": null, "end_ts": 1771815983, "duration": 38, "start_ts": 1771815945, "description": null, "page_number": "5"}, {"notes": null, "end_ts": 1771816007, "duration": 24, "start_ts": 1771815983, "description": null, "page_number": "6"}, {"notes": null, "end_ts": 1771816011, "duration": 4, "start_ts": 1771816007, "description": null, "page_number": "7"}, {"notes": null, "end_ts": 1771816013, "duration": 2, "start_ts": 1771816011, "description": null, "page_number": "8"}, {"notes": null, "end_ts": 1771816052, "duration": 39, "start_ts": 1771816013, "description": null, "page_number": "7"}, {"notes": null, "end_ts": 1771816127, "duration": 75, "start_ts": 1771816052, "description": null, "page_number": "8"}, {"notes": null, "end_ts": 1771816134, "duration": 7, "start_ts": 1771816127, "description": null, "page_number": "9"}, {"notes": null, "end_ts": 1771816196, "duration": 62, "start_ts": 1771816134, "description": null, "page_number": "10"}, {"notes": null, "end_ts": 1771816262, "duration": 66, "start_ts": 1771816196, "description": null, "page_number": "11"}, {"notes": null, "end_ts": 1771816293, "duration": 31, "start_ts": 1771816262, "description": null, "page_number": "12"}, {"notes": null, "end_ts": 1771816322, "duration": 29, "start_ts": 1771816293, "description": null, "page_number": "13"}, {"notes": null, "end_ts": 1771816330, "duration": 8, "start_ts": 1771816322, "description": null, "page_number": "14"}, {"notes": null, "end_ts": 1771816368, "duration": 38, "start_ts": 1771816330, "description": null, "page_number": "15"}, {"notes": null, "end_ts": 1771816388, "duration": 20, "start_ts": 1771816368, "description": null, "page_number": "16"}, {"notes": null, "end_ts": 1771816482, "duration": 94, "start_ts": 1771816388, "description": null, "page_number": "17"}, {"notes": null, "end_ts": 1771816550, "duration": 68, "start_ts": 1771816482, "description": null, "page_number": "18"}, {"notes": null, "end_ts": 1771816567, "duration": 17, "start_ts": 1771816550, "description": null, "page_number": "19"}, {"notes": null, "end_ts": 1771816586, "duration": 19, "start_ts": 1771816567, "description": null, "page_number": "20"}, {"notes": null, "end_ts": 1771816597, "duration": 11, "start_ts": 1771816586, "description": null, "page_number": "21"}, {"notes": null, "end_ts": 1771816616, "duration": 19, "start_ts": 1771816597, "description": null, "page_number": "22"}, {"notes": null, "end_ts": 1771816640, "duration": 24, "start_ts": 1771816616, "description": null, "page_number": "23"}, {"notes": null, "end_ts": 1771816690, "duration": 50, "start_ts": 1771816640, "description": null, "page_number": "24"}, {"notes": null, "end_ts": 1771816702, "duration": 12, "start_ts": 1771816690, "description": null, "page_number": "25"}, {"notes": null, "end_ts": 1771816823, "duration": 121, "start_ts": 1771816702, "description": null, "page_number": "26"}, {"notes": null, "end_ts": null, "duration": null, "start_ts": 1771816823, "description": null, "page_number": "27"}], "page_start": 1, "pages_read": 27, "resume_url": null, "description": null, "koreader_hash": null, "long_play_complete": false}
DONE [A] Lichess imports do not set default visbility boardgames bug importers lichess
Version 50.2 [2/2]
DONE [B] Koreader imports only import single-page scrobbles the next day bug books importers
Description
When you read a single page in a book in Koreader and try to import it, the scrobble is only created the day after, not on the day of the reading.
DONE [A] Fix bugs in celery tasks causing imports to fail bug celery tasks
Description
Seems like all celery tasks are failing for different reasons except the chart updates.
Errors
scrobbles.tasks.send_notification_for_in_progress
KeyError: 'track'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/usr/local/lib/python3.11/site-packages/django/db/backends/utils.py", line 89, in _execute
return self.cursor.execute(sql, params)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
psycopg2.errors.UndefinedColumn: column music_track.artist_id does not exist
LINE 1: ..."."title", "music_track"."base_run_time_seconds", "music_tra...
^
HINT: Perhaps you meant to reference the column "music_track.artist_fk_id".
scrobbles.tasks.import_from_webdav_all_users
File "/usr/local/lib/python3.11/site-packages/vrobbler/apps/scrobbles/importers/webdav.py", line 166, in scan_webdav_for_koreader
if last_import and last_import.webdav_etag and remote_etag:
^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'KoReaderImport' object has no attribute 'webdav_etag'
scrobbles.tasks.process_bgstats_import
Traceback (most recent call last):
File "/usr/local/lib/python3.11/site-packages/django/db/backends/utils.py", line 89, in _execute
return self.cursor.execute(sql, params)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
psycopg2.errors.NotNullViolation: null value in column "visibility" of relation "scrobbles_scrobble" violates not-null constraint
DETAIL: Failing row contains (374463, 2026-06-11 13:27:06.528319+00, 2026-06-11 13:27:06.52834+00, 2026-06-11 13:17:34+00, 180, f, f, BG Stats, 1, null, t, {"players": [{"new": false, "win": false, "rank": 0, "role": "",..., null, null, null, 8e73ceec-b731-4623-9637-712bbf9f76ce, null, null, null, null, , null, BoardGame, 324, null, null, America/New_York, null, null, , null, null, , null, null, null, null, null, null, null, null, null, null, null).
Version 50.1 [1/1]
DONE [B] Fix bug in charts where only #1 is displayed charts templates
Version 50.0 [2/2]
DONE [A] Allow updating all a user's scrobble visibility at once scrobbles sharing feature
Description
We now have the ability to share or unshare scrobbles and create private links. We should add a toggle in the user's settings that will bulk make all their scrobbles public or private, so that a user can either share everything, or lock their account down.
This should not affect scrobbles that are in the "Shared" visibility state.
And users should be able to also control whether all scrobbles of a specific type are shared or not. Maybe this could be a JSONField in profile that contains a media_type key with a visibility type for a value, and if it's not present, sharing defaults to private?
Additionally, users's should have links in their settings to see what scrobbles are either public, shared or private. Probably this could be done with a ?visbility=<> filter on the scrobbles page.
Changes
- Added `media_type_visibility` JSONField to UserProfile (migration 0038)
-
Created `BulkVisibilityView` at `/settings/visibility/` with:
- Radio toggle to make all non-shared scrobbles Public or Private
- Per-media-type dropdown for each of the 20 media types (inherit/public/shared/private)
- Created `BulkVisibilityForm` with dynamic media_type fields
- Created `profiles/visibility_settings.html` template with visibility stats + filter links
- Added link from main settings page to visibility settings
- Added `?visibility=` filter support to `ScrobbleListView` (public/shared/private)
- Added filter indicator to `scrobble_all_list.html`
- Updated `Scrobble.create()` to check `user.profile.media_type_visibility` for media-type-specific defaults before falling back to PRIVATE
DONE [A] Replace columsn of Top Artists, Tracks and Series with Maloja widget templates charts
Description
The tables are fine, but Maloja widgets are better. We should drop the top track table, add top albums and replace top artists and top tv series with the Maloja style widgets.
Version 49.1 [1/1]
DONE [A] Fix bug with missing default visbility for scrobbles bug scrobbles sharing
Description
We can't scrobble anything now because visbility is not null, but has no default value.
Notes
-
Note taken on [2026-06-09 Tue 13:14] The full stack trace:
File "/usr/local/lib/python3.11/site-packages/vrobbler/apps/scrobbles/models.py", line 1430, in create_or_update elif "log" in scrobble_data.keys() and scrobble.log: ^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/local/lib/python3.11/site-packages/vrobbler/apps/scrobbles/models.py", line 1583, in create ) File "/usr/local/lib/python3.11/site-packages/django/db/models/manager.py", line 87, in manager_method return getattr(self.get_queryset(), name)(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/local/lib/python3.11/site-packages/django/db/models/query.py", line 658, in create obj.save(force_insert=True, using=self.db) File "/usr/local/lib/python3.11/site-packages/vrobbler/apps/scrobbles/models.py", line 870, in save if self.media_obj: ^^^^^^^^^^^^ File "/usr/local/lib/python3.11/site-packages/django_extensions/db/models.py", line 22, in save super().save(**kwargs) File "/usr/local/lib/python3.11/site-packages/django/db/models/base.py", line 814, in save self.save_base( File "/usr/local/lib/python3.11/site-packages/django/db/models/base.py", line 877, in save_base updated = self._save_table( ^^^^^^^^^^^^^^^^^ File "/usr/local/lib/python3.11/site-packages/django/db/models/base.py", line 1020, in _save_table results = self._do_insert( ^^^^^^^^^^^^^^^^ File "/usr/local/lib/python3.11/site-packages/django/db/models/base.py", line 1061, in _do_insert return manager._insert( ^^^^^^^^^^^^^^^^ File "/usr/local/lib/python3.11/site-packages/django/db/models/manager.py", line 87, in manager_method return getattr(self.get_queryset(), name)(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/local/lib/python3.11/site-packages/django/db/models/query.py", line 1805, in _insert return query.get_compiler(using=using).execute_sql(returning_fields) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/local/lib/python3.11/site-packages/django/db/models/sql/compiler.py", line 1822, in execute_sql cursor.execute(sql, params) File "/usr/local/lib/python3.11/site-packages/django/db/backends/utils.py", line 67, in execute return self._execute_with_wrappers( ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/local/lib/python3.11/site-packages/django/db/backends/utils.py", line 80, in _execute_with_wrappers return executor(sql, params, many, context) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/local/lib/python3.11/site-packages/django/db/backends/utils.py", line 84, in _execute with self.db.wrap_database_errors: File "/usr/local/lib/python3.11/site-packages/django/db/utils.py", line 91, in __exit__ raise dj_exc_value.with_traceback(traceback) from exc_value File "/usr/local/lib/python3.11/site-packages/django/db/backends/utils.py", line 89, in _execute return self.cursor.execute(sql, params) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ django.db.utils.IntegrityError: null value in column "visibility" of relation "scrobbles_scrobble" violates not-null constraint DETAIL: Failing row contains (373813, 2026-06-09 17:13:38.11355+00, 2026-06-09 17:13:38.113566+00, 2026-06-09 17:13:36+00, 0, f, f, Todoist, 1, null, t, {"title": "Animal chores", "labels": ["chore", "farm"], "todoist..., null, null, null, 68680dbf-f9a9-476c-b1c7-adbd231bbab6, null, null, null, null, , null, Task, null, null, null, America/New_York, null, null, , null, null, , 72, null, null, null, null, null, null, null, null, null, null).
Version 49.0 [1/1]
DONE [A] Fix broken tests with new sharing and add tests scrobbles sharing tests
Version 48.3 [1/1]
DONE [A] Fix bug in missing sqids dep dependencies project
Version 48.2 [1/1]
DONE [A] Lock down scrobbles and use sqids to share them feature sharing scrobbles
Description
Currently all scrobbles are public. Anyone with the uuid can view any other scrobbles. We should use SQIDs to allow shareable links to scrobbles and then make all scrobbles hidden by default.
Version 48.1 [2/2]
DONE [A] Generate a report of tracks with mistmatched metadata music tracks metadata
Description
We should have a management command that outputs a CSV file of track IDs where the log["raw_data"]["Artist"] (for Jellyfin) or log["raw_data"]["artist"] (mopidy) value does not match the Track.artists names.
And we should see the same thing for albums (log["raw_data"]["Album"] or log["raw_data]["album"]).
It should output the fields "track_id", "track_artist_name", "track_album_name", "raw_artist", "raw_album", "source"
Where source is either Jellyfin or Mopidy based on the keys.
Put the file /tmp/metadata-report.csv by default and overwrite exsiting reports.
The command should also accept a file-path to overide this default.
DONE [A] Date parsing failing in eBird imports birds ebird importers
Description
On line 45 in the apps/birds/importer.py file, the import is thorowing this error:
ValueError: time data 'Jun 7, 2026, 5:15 PM' does not match format '%B %d, %Y %I:%M %p'
Historically other files starting on May 24 worked, so I suspect this is a problem of the date formatter expecting Long month names and zero-padded days and the only sample we had was a three-letter month (May) and days with two digites(24 through the 31)
We should also add a "error_log" to the importers so that errors tha occur are surfaced, even when 0 successful files were processed. And we should make sure all importers do this as well.
Version 48.0 [2/2]
DONE [B] Show team or player images on sport detail and scrobble detail sports templates
Description
On the sport event detail page, we should show the images of the teams or players invovled.
Also, those images for the sport event should be shown on the scrobble detail page for sport event scrobble details.
DONE [B] Add fix_metadta method to Video instances videos metadata
Description
Turns out we don't have a fix_metadata method for videos. We should add that using the basic logic from find_or_create on the Video model.
Version 47.2 [1/1]
DONE [B] Add OMDB source as backup when TMDB returns nothing videos metadata imdb
Description
TMDb works great for most cases. There are some edge cases, though where it does not import videos, when TV shows are split up differently in TMDb than in IMDB. One example I stumbled on is the 2020 reboot of Animaniacs. TMDb splits the epiodes up in three parts, while they were always broadcast three-in-one, and that's how IMDB lists them. Thus, the IMDB ID means nothing, and the videos end up unenriched.
Version 47.1 [1/1]
DONE [A] Untangle the sports migrations errors sports bug migrations
Version 47.0 [1/1]
DONE [B] Change sports scrobbling a bit feature sports scrobbles
Description
Currently, the way we scrobble sports means that basically the same event will never be scrobbled again. I will likely never watch the 2025 Monaco Grand Prix again, but I will watch the Monaco Grand Prix again. But I also wont watch one specific game between Arsenal and Man City twice, but I may watch those two teams play multiple times.
What if instead of scrobbling a specific sports event on a specific date, we make the unique Scrobblable item the players or teams in the event?
That would not work for races where the unique item would have to be the name of the event.
Maybe that means SportEvent is too generic, and we'd need the event type to be scrobble items.
A race, the Indy 500 or Coke 600, or Boston Marathon would be scrobblable, while for games, the teams would be unique, so a game between Arsenal and Man City would be unique (with extra logdata context for who's home and who's away, and the location, could even have the weather per scrobble).
And finally, for Tennis, the title would be the round of the event, Roland Garros Women's Semifinal, US Open Men's Final, Miami Invitational Round of 32, with two players, or two teams and a start datetime, which is similar to what we have now. The round becomes not a foreign key, but just a string, and we'd need a FK to an organizer field which would replace league, and would be like "ATP Tour" or "PGA Tour". Season would also need to be a string, and would be something like: 2026 or 2024-2025.
Examples:
- Super Bowl
- Sochaux v Concarneau
- French Open Final
- Carlos Alcaraz v Jannik Sinner
We'd also want a script to reorganize existing sports events and move scrobbles to the right place as best as we're able, and to flag sportsevents and scrobbles that could not automatically be migrated with a unique tag like "migration-failed"
Ultimately I think what we need is to greatly simplify the SportEvent to be just a placeholder for a sport event type for a given league, then each scrobble holds the details of teams, players start, thesportsdb_id, round and season.
Thus, I've already simplified that model, but what we need is a migration script that will move existing complex SportEvent instances into very basic ones, and updating any scrobbles for those events with a new SportEventLogData structure with all the specific details in it. We also need to move the obj.round.season.league into the FK for the given event.
Version 46.0 [1/1]
DONE [C] Add sentiment parsing for Scrobbles with notes scrobbles sentiment
Description
Not sure how useful this would be, but I wonder if we can add a `sentiment` JSONField on each scrobble that can store the output of VADER over the notes in a scrobble with notes.
I'm not sure that the value prop here is worth the storage and processing time.
But if we do add it, it should be a process that scans for scrobbles with both notes and no sentiment field value (unless –overwrite is used) and just run periodically.
Version 45.1 [1/1]
DONE [B] Mopidy favorites or monthly playlist adds should look at all scrobbles bug mopidy favorites tracks
Description
When favoriting a track and trying to add it to the Moidy favorite playlist, it sometimes happens that one scrobble did not come from Mopidy, but an earlier or later one did.
Can we scan all the scrobbles of the track for a given user to see if any have `mopidy_uri` in the log and if so, use that to send along to Mopidy?
Version 45.0 [1/1]
DONE [B] Add ability to add mopidy tracks to Monthly playlists feature favorites tracks
Description
Now that we can favorite a mopidy track and have it added to a Favorites playlist, it would be great if we could also populate a monthly_mopidy_playlist_pattern in a user profile and, if configured, you could press "Add to monthly playlist" button on a given track that has a mopidy_uri in it's log, and it would be added to the playlist.
The patterns would be based on traditional Django date formatting patterns: https://gregbrown.co/code/date-format
So "Y m F" would yield "2026 05 May" if the link is clicked in May of 2026.
Version 44.0 [1/1]
DONE [B] Add favorite feature for scrobbles feature favorites scrobbles
Description
Would be great to have a FavoriteMedia data model that would accept any media_type ID and a user_id marking that media as a favorite for that user.
Additionally, for tracks, we should add the ability to set a "favorites_mopidy_playlist" in a user profile and if populated, and a track media type is favorited, and the track has a mopidy_uri value in a scrobble log, send a POST to the mopidy server RPC endpoint for the favorite playlist and add the track.
Version 43.0 [5/5]
DONE [B] Can we show a graph of all past Weigh-in tasks scale tasks graphs javascript
Description
I wonder if, as a special type of task, Weigh-in's could show a graph of the metrics that are stored against all the past weigh-ins?
The graph would contain all Weigh-in scrobbles for that user, no matter which date is being viewed, and the highlighted value on the graph would be the date being viewed.
Probably could use something like chart.js although maybe that's too heavy?
And can we have each metric overlayed on the same graph?
DONE [B] When viewing scrobbles by tag, sum the total time scrobbles tags
Description
On scrobbles filtered by tags, we should see a sum of the time spent doing those tasks, in a human readable format like "X days, X hours, X minutes and X seconds"
DONE [A] Orgmode tasks are not updated if in progress tasks orgmode bug
Description
Currently if you POST to the orgmode webhook with a task that's already in progress, the request just stops there.
We should add logic where if the task is in-progress, instead of doing nothing, it checks the webhook payload against the in-progress tasks and updates the description of the scrobble.log with the incoming task description if it's different. And the same for comments. If a comment (by timestamp key) is different in the webhook than what's in the scrobble.log, update the comment in the scrobble.log
DONE [A] Ignore tag 'inprogress' for Tasks bug tasks tags
Description
When scrobbling tasks from Todoist, the tag `inprogress` is always in the payload, because that's how we parse tasks starting from the Todoist webhooks.
But we don't really need anything tagged as `inprogress` Can we ignore this tag when applying tags to Task scrobbles coming from Todoist?`
DONE [A] Deploys are now throwing an unknown version error bug tooling releases
Description
Almost everything is working, but for some reason `__version__` does not seem to exist.
out: Installing collected packages: vrobbler
out: Successfully installed vrobbler-42.0
err: WARNING: Running pip as the 'root' user can result in broken permissions and conflicting behaviour with the system package manager. It is recommended to use a virtual environment instead: https://pip.pypa.io/warnings/venv
err: Traceback (most recent call last):
err: File "<string>", line 1, in <module>
err: AttributeError: module 'vrobbler' has no attribute '__version__'
2026/06/04 17:18:15 Process exited with status 1
failed to remove container: Error response from daemon: removal of container c8ac64bee9b6bf5978d2c16f299e5ac271d8bbf7192b7a4023c3712bc2444f8b is already in progress
❌ Failure - Main Install wheel and restart services
exit with `FAILURE`: 1
Version 42.0 [1/1]
DONE [B] Add ability to add track to current Mopidy queue feature mopidy tracks
Version 41.0 [5/5]
DONE [B] For any scrobble detail page with notes display them better templates notes scrobbles
Description
Currently notes are displayed as little post-it notes. This is cute, but not terribly useful.
We should update note rendering to be a simple newest to oldest display in a single column with the timestamp has a small header, and the content rendered as markdown with a small bar or horizontal divider marking them from the next note.
DONE [A] Imports should send notifications feature notifications imports
Description
Currently importing board games sends out a ntfy message when a scrobble is created.
We should do the same thing for other import types; namely: gpx, ebird, and scale.
DONE [A] Board game imports send duplicate ntfy message bug notifications boardgames
Description
When a board game scrobble is created via a bgstats import, ntfy messages are sent.
But right now they are duplicated (two are sent at the same time). Can we review the code to see why this is happening and fix it?
DONE [A] Too many geolocation notifications go out bug notifications geolocations
Description
Currently ntfy gets overwhelemed when there's more than a hundred or so messages left in a queue on a client.
It would be nice if we could not spam ntfy, and this is especially true with Geolocations, where we really don't need to alert folks unless they have a named Geolocation (has a title). Can we adjust the ntfy sending for Geolocations to only send if the scrobbled location has a title?
DONE [C] Fix bug where Weigh-in imports do not set title bug tasks scale
Description
Currently when we import a scale CSV row and create data, the title is left blank which makes it look funny in a list view. Let's save the weight as the title of the Weigh-in task.
Version 40.2 [1/1]
DONE [A] Try fixing deploy bugs again tooling releases bug
Version 40.1 [2/2]
DONE [A] Releases are still broken bug releases tooling
Description
Deploys are still broken, even with them being pulled apart and run separately.
We need to address the way the commit ends up stashed in the codebase.
DONE [C] Fix bug on chart pages where trail titles missing bug trails charts
Description
When trails are rendered on the chart views, there are no titles, which means we don't see anything except the ranking number.
Version 40.0 [2/2]
DONE [A] Fix error in org-mode task sync emacs orgmode tasks bug
Description
File "/usr/local/lib/python3.11/site-packages/vrobbler/apps/tasks/webhooks.py", line 236, in post
emacs_scrobble_update_task(
File "/usr/local/lib/python3.11/site-packages/vrobbler/apps/scrobbles/scrobblers.py", line 844, in emacs_scrobble_update_task
for note in emacs_notes:
TypeError: 'NoneType' object is not iterable
DONE [B] Adjust how similar artists are shown feature templates artists music
Description
Currently we show the top 10 similar artists on the Artist detail page linked to the artist detail page on Vrobbler.
First off, this is very slow. We should look into speeding up the rendering of the similar artists widget.
Second, the artist name in the similar artist list should be a link to the Vrobbler artist detail page, but there should also be a [musicbrainz] link next to it, that links out to the musicbrainz page whether we have the artist in the Vrobbler database or not.
Version 39.3 [2/2]
DONE [A] Issue found when doing a release bug tooling release cicd
Description
err: ERROR: Cannot install vrobbler 0.16.1 (from /var/lib/vrobbler/dist/vrobbler-0.16.1-py3-none-any.whl) and vrobbler 38.0 (from /var/lib/vrobbler/dist/vrobbler-38.0-py3-none-any.whl) because these package versions have conflicting dependencies.
out: The conflict is caused by:
out: The user requested vrobbler 0.16.1 (from /var/lib/vrobbler/dist/vrobbler-0.16.1-py3-none-any.whl)
out: The user requested vrobbler 38.0 (from /var/lib/vrobbler/dist/vrobbler-38.0-py3-none-any.whl)
out: To fix this you could try to:
out: 1. loosen the range of package versions you've specified
out: 2. remove package versions to allow pip attempt to solve the dependency conflict
err: ERROR: ResolutionImpossible: for help visit https://pip.pypa.io/en/latest/topics/dependency-resolution/#dealing-with-dependency-conflicts
2026/06/01 14:15:00 Process exited with status 1
failed to remove container: Error response from daemon: removal of container 3fe0eaf032c5518aca4ab71734b52bda7c54ed406136b82136ab7155bf5ff3c1 is already in progress
DONE [A] Fix deploy actions running twice bug tooling cicd
Description
Turns out we're now running the build-deploy action twice, once on branch push and once on tag push.
We should do builds on each push and build and deploys only when a new tag is detected.
Version 39.2 [2/2]
DONE [B] Releases do not pin commit to the repo for display bug tooling releases
Description
Somewhere in implementing the justfile release flow, we lost the capture of the latest commit in the relesae flow so the footer now always says: vXX.x (unknown)
It should have the first bit of the commit in the parens at the end.
DONE [B] Fix the way timestamps are stored for notes on tasks bug scrobbles tasks
Description
Turns out Todoist uses a human-readable timestamp format for comments. We should adapt that for use from org-mode as well.
Format should be: "%Y-%m-%dT%H:%M:%S.%fZ"
Version 39.1 [1/1]
DONE [A] Fix bug in tests for notes saving bug scrobbles forms
Version 39.0 [3/3]
DONE [B] Clean up org-mode tasks metadata bug tasks metadata
Description
Org-mode tasks have a `Description` subheader, which should populate the "Description" of a task.
The title should come from the actual TODO content, with tags coming from the tags in colons after the task. This behaviour should already work.
Next, any comments should go under a `Comments` subheader. Under these should be a list tag like:
"Note taken on [2026-05-31 Sun 20:03]"
Which declares it's a note with a timestamp like "YYYY-MM-DD d HH:MM".
When scrobbling a task from org-mode, the description should always be copied to the scrobble's log["description"].
Any comments that exist on the task when the scrobble is first created, should be ignored.
Any comments on a task that is updated (a re-POST'd while the task is in progress, should add a comment in the log["notes"], a dictionary, keyed off the timestamp the note string. If a note for that datetime already exists, the content should be replaced with the new comment.
Additionally, when a task is re-POST'd while the task is in progress, the description should also be compared, and if different, the newest description should be used.
Note, the biggest change for this flow is making sure comments that already exist are not added to any new tasks and that both comments and descriptions are added or updated if the new values are different than what is already in the currently in-progress task.
If the task is completed, don't touch it.
Comments
- Note taken on [2026-05-31 Sun 20:03]
DONE [A] Actually push branches up and add a just command to do it release justfile tooling
DONE [A] Try to fix deploy failing with bad release plan release tooling pyproject
Version 38.0 [38/38]
DONE [A] Fix release flow to be easier to trigger pyproject release tooling
Description
We should have a command like `just relesae <major|minor>` that can cut new releases on command by updating the PROJECT.org file with a release header for all DONE tasks and creating the appropriate release commits and tags based on either the new release version type.
It should also update the pyproject file.
DONE [A] Move imported retroarch lrtl files to processed/ directory on WebDAV webdav retroarch importers
- File:
vrobbler/apps/scrobbles/importers/webdav.py(line 439) - Same pattern as the GPX importer: after importing a
.csvfile from WebDAV, move it tovar/retroarch/processed/with a timestamp appended.
DONE [A] Add listenbrainz support for similar tracks feature music metadata
DONE [B] Consolidate albums in the same musicbrainz_releasegroup_id music albums metadata
Description
When we look up albums, we should check if one already exists with the same musicbrainz_releasegroup_id and prefer that one, rather than creating a new album.
Also, we should create a data migration to clean up albums with matching musicbrainz_releasegroup_id fields by consolidating tracks around the first album found.
Whether the track was enriched by musicbrainz or not, the track should get tagged with `musicbrainz_enriched` or `musicbrainz_notfound`
DONE [A] Clean up metadata on music tracks music tracks metadata musicbrainz
Description
There's a over 3K tracks without a musicbrainz_id and almost 30K without a base_run_time_seconds. We should have a clean up script that can run through the ones missing musicbrainz_ids and see about getting metadata from musicbrainz and for the 30K without base_run_time_seconds, check with their musicbrainz_ids to see if we can look up the track length, and if not, tag the track with "missing-metadata" tag.
Also, if the tracks without musicbrainz_ids actually are not in the MB database, we should tag those with "not-in-musicbrainz"
And a big part of this work will probably involve checking for "Various Artists" tracks where the track erroneously got set with a generic artist. In those cases, we should try just looking up by track title.
DONE [B] Make artists_m2m field source of artist truth for albums music bug albums
Description
Albums have an FK for album_artist, but like artists, the M2M should be the source of truth. We should migrate all uses of album_artist to an `artist` property on the Album model and use a data migration to populate artists with the album_artist value.
DONE [A] Fix various artist album problem with Superwolves (track with multiple artists) vrobbler project music bug artists
Description
We have an issue with tracks where there are two artists, like `Matt Sweeney & Bonnie "Prince" Billy`
I think we need to allow creating a single artist with both names, so the Artist is the full name. That said, the ampersand is usually used to split feature artsits (I think) so I'm not sure how this would work reliably.
Also, it's possible musicbrainz does not have dual artist listings. So it's possible the longer term solution is to allow multiple artists per track the way we now allow tracks to be on multiple albums. We could deprecate the Artist FK or at least make it optional, and then require a M2M between Track and Artist.
Then this one would be a Track by both `Matt Sweeney` and `Bonnie "Prince" Billy`
DONE [A] Move imported eBird CSV files to processed/ directory on WebDAV webdav ebird importers
- File:
vrobbler/apps/scrobbles/importers/webdav.py(line 439) - Same pattern as the GPX importer: after importing a
.csvfile from WebDAV, move it tovar/ebird/processed/with a timestamp appended.
DONE [A] Move imported Board Game CSV files to processed/ directory on WebDAV webdav boardgames importers
- File:
vrobbler/apps/scrobbles/importers/webdav.py(line 496) - Same pattern as the GPX importer: after importing a
.csvfile from WebDAV, move it tovar/bgstats/processed/with a timestamp appended.
DONE [A] Move imported Scale CSV files to processed/ directory on WebDAV webdav scale importers
- File:
vrobbler/apps/scrobbles/importers/webdav.py(line 496) - Same pattern as the GPX importer: after importing a
.csvfile from WebDAV, move it tovar/scale/processed/with a timestamp appended.
DONE [A] Allow special parameter to re-import already processed GPX files imports gpx
Description
Now that we stash imported GPX files in the processed/ subdirectory on import, it would be nice to have a flag like –include-processed on the webdav importer that would import files both in the root of gpx/ and also in the processed directory. This would aide testing imports in staging quickly without constantly moving files back and forth.
DONE [A] Move imported GPX files to processed/ directory on WebDAV webdav gpx importers
- File:
vrobbler/apps/scrobbles/importers/webdav.py(line 198) - After importing a GPX/FIT file from WebDAV, move it to a
processed/subdirectory with a timestamp appended. This eliminates the DB lookup for already-imported filenames — any file present in the top-level directory is new. Also makes manual re-imports easy (just move a file back).
DONE [A] Add CSS Grid calendar view for scrobbles vrobbler personal project templates feature
Description
Calendar view at scrobbles/calendar showing select media types (Tasks, Birding, Food, Trails, VideoGames, Books) in a CSS Grid month layout.
- Emoji badges per scrobble on each day cell, hover reveals title
- Click emoji to navigate to scrobble detail
- Prev/Next month navigation
- Based on the CodePen CSS Grid calendar pattern: https://codepen.io/oliviale/pen/QYqybo
DONE [C] Come up with a possible flow using WebDAV and super-productivity for tasks personal feature project vrobbler tasks
DONE [B] Fix PuzzleLogData has no attribute form vrobbler puzzles personal project logdata
DONE [B] Add PuzzleLogData class with with_people and completed vrobbler feature puzzles logdata personal project
DONE Add weather lookup to the mood check-in flow vrobbler project moods feature checkin
<2026-05-20 Wed>
DONE Add importing of openScale CSV files to Tasks vrobbler project personal tasks openscale
DONE Add ability to track Birding sessions via BirdingLocation scrobbles vrobbler project birds feature
DONE List only the last 20 scrobbles per category on the home page vrobbler project scrobbles templates
DONE Fix display of notes so they look like stickies vrobbler project personal notes scrobbles
DONE Add searching to scrobbles vrobbler project personal search scrobbles
DONE Fix uniqueness of imdb_id messing up youtube videos vrobbler project bug videos
Turns out you can't make imdb_id unique by itself or you never get to create youtube videos. Rather, we should make imdb_id and youtube_id unique together so imdb_id can be empty for every youtube_id and vice versa.
DONE Fix genearting chart records vrobbler bug personal project chartrecords
DONE [A] Save raw scrobble request data to every scrobble log vrobbler personal feature scrobbles
The idea here is that no matter where the data comes from, we should just save it in the scrobble for posterity, so we can always in some form recover the original intent of the scrobble.
It may also allow us to clean up junk scrobbles if the data was just horribly wrong.
DONE [B] Clean up follow up notifications for if you're still scrobbling vrobbler personal project beers boardgames notifications feature
- Note taken on [2025-09-30 Tue 09:32] I added this feature in a very rough way, but now we should add "Action" headers so that we can either Finish or Cancel the associated scrobble: https://docs.ntfy.sh/publish/#send-http-request
DONE [A] Fix lookup of music tracks from Musicbrainz vrobbler bug tracks music
Turns out we're not looking up music tracks properly, again.
DONE Check opencode about a way to present stats like movies per month vrobbler scrobbles stats personal project
DONE Fix bug in Jellyfin audio track playback vrobbler personal project bug music jellyfin
ERROR django.request:241 log_response Internal Server Error: /webhook/jellyfin/
Traceback (most recent call last):
File "/usr/local/lib/python3.11/site-packages/django/core/handlers/exception.py", line 55, in inner
response = get_response(request)
^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/site-packages/django/core/handlers/base.py", line 197, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/site-packages/django/views/decorators/csrf.py", line 56, in wrapper_view
return view_func(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/site-packages/django/views/decorators/csrf.py", line 56, in wrapper_view
return view_func(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/site-packages/django/views/generic/base.py", line 104, in view
return self.dispatch(request, *args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/site-packages/rest_framework/views.py", line 509, in dispatch
response = self.handle_exception(exc)
^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/site-packages/rest_framework/views.py", line 469, in handle_exception
self.raise_uncaught_exception(exc)
File "/usr/local/lib/python3.11/site-packages/rest_framework/views.py", line 480, in raise_uncaught_exception
raise exc
File "/usr/local/lib/python3.11/site-packages/rest_framework/views.py", line 506, in dispatch
response = handler(request, *args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/site-packages/rest_framework/decorators.py", line 50, in handler
return func(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/site-packages/vrobbler/apps/scrobbles/views.py", line 494, in jellyfin_webhook
scrobble = jellyfin_scrobble_media(post_data, request.user.id)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/site-packages/vrobbler/apps/scrobbles/scrobblers.py", line 177, in jellyfin_scrobble_media
log["album_id"] = media_obj.album_id
~~~^^^^^^^^^^^^
TypeError: 'tuple' object does not support item assignment
DONE [B] Auto calc duration if no playback time seconds present vrobbler bug scrobbles personal project
DONE Fix bug in video find_or_create vrobbler personal project bug videos
The error:
File "/usr/local/lib/python3.11/site-packages/vrobbler/apps/scrobbles/views.py", line 493, in jellyfin_webhook
scrobble = jellyfin_scrobble_media(post_data, request.user.id)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/site-packages/vrobbler/apps/scrobbles/scrobblers.py", line 149, in jellyfin_scrobble_media
media_obj = Video.find_or_create(imdb_id)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/site-packages/vrobbler/apps/videos/models.py", line 390, in find_or_create
return cls.get_from_imdb_id(source_id, overwrite)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/site-packages/vrobbler/apps/videos/models.py", line 374, in get_from_imdb_id
video.tv_series = Series.find_or_create(
^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/site-packages/vrobbler/apps/videos/models.py", line 203, in find_or_create
vdict, _, cover, genres = lookup_video_from_imdb(
^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/site-packages/vrobbler/apps/videos/sources/imdb.py", line 17, in lookup_video_from_imdb
imdb_result = imdb.get_title(imdb_id)
^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/site-packages/cinemagoerng/web.py", line 127, in get_title
data = _scrape(spec=spec, context=context, headers=headers)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/site-packages/cinemagoerng/web.py", line 120, in _scrape
document = fetch(url, headers=request_headers)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/site-packages/cinemagoerng/web.py", line 44, in fetch
with urlopen(request) as response:
^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/urllib/request.py", line 216, in urlopen
return opener.open(url, data, timeout)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/urllib/request.py", line 525, in open
response = meth(req, response)
^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/urllib/request.py", line 634, in http_response
response = self.parent.error(
^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/urllib/request.py", line 563, in error
return self._call_chain(*args)
^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/urllib/request.py", line 496, in _call_chain
result = func(*args)
^^^^^^^^^^^
File "/usr/local/lib/python3.11/urllib/request.py", line 643, in http_error_default
raise HTTPError(req.full_url, code, msg, hdrs, fp)
urllib.error.HTTPError: HTTP Error 500: Internal Server Error
- Note taken on [2026-03-11 Wed 20:53] It turns out that every time a TV show was scrobbled were were hitting IMDB. Woof.
DONE Update admin page to be easier to use vrobbler djadmin project personal
DONE Fix migrations and update repo vrobbler scrobbles admin personal project
DONE Add recipe parsing for food lookups vrobbler foods project feature personal
DONE [A] Videos are scrobbling duplicates again vrobbler bug videos scrobbles
<2026-03-06 Fri>
DONE Fix board games not saving BGG id on lookup vrobbler bug boardgames
DONE Fix board game lookup with name like Unmatched Game System vrobbler bug boardgames
DONE [A] Fix raw text webpage title not truncating to 254 chars vrobbler personal bug webpages
- Note taken on [2025-09-30 Tue 09:33] This may have already been resolved … need to just confirm it.
Version 37.0 [4/4]
DONE [A] Tasks from org-mode should properly update notes and leave them out of the body vrobbler bug tasks
DONE [A] Allow scrobbling from the Food list page's start links vrobbler bug food scrobbling personal project
DONE [B] Food scrobbles should inherit calories from obj if missing vrobbler feature food personal project
DONE [A] Puzzles (and all longplays) should have a "Completed?" column on their detail page vrobbler bug puzzles personal project
Version 36.0 [1/1]
DONE [A] Refactor how videos are scrobbled vrobbler vidoes feature personal project
Version 35.0 [3/3]
DONE [B] Add youtube link in place of IMDB on video detail page vrobbler feature videos personal project
DONE [B] Add missing API lookups to resolve broken scrobbles endpoint vrobbler feature api scrobbles personal project
DONE [A] IMDB lookups are not working vrobbler bug videos personal project
Version 34.0 [4/4]
DONE [A] Use bgg-api for BoardGameGeek lookups vrobbler feature boardgames personal project
DONE [A] Add classmethod for metadata fetching to tracks vrobbler feature music personal project
- Note taken on [2025-10-29 Wed 21:44] Beyond a classmethod (which I think we have now), we need to update the flow of how we look up tracks. It's a hot mess right now where Various Artists walks over the actual artist, and we often hit MB when we don't have to.
DONE [A] Fix views for TV series where next episode is now None vrobbler bug personal videos
ERROR django.request:241 log_response Internal Server Error: /series/c24100d1-da45-4abe-86bf-27cfce9b1f89/
Traceback (most recent call last):
File "/usr/local/lib/python3.11/site-packages/django/core/handlers/exception.py", line 55, in inner
response = get_response(request)
^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/site-packages/django/core/handlers/base.py", line 197, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/site-packages/django/views/generic/base.py", line 104, in view
return self.dispatch(request, *args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/site-packages/django/contrib/auth/mixins.py", line 73, in dispatch
return super().dispatch(request, *args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/site-packages/django/views/generic/base.py", line 143, in dispatch
return handler(request, *args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/site-packages/django/views/generic/detail.py", line 109, in get
context = self.get_context_data(object=self.object)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.11/site-packages/vrobbler/apps/videos/views.py", line 33, in get_context_data
context_data["next_episode_id"] = "tt" + next_episode_id
~~~~~^~~~~~~~~~~~~~~~~
TypeError: can only concatenate str (not "NoneType") to str
DONE [A] Emacs tasks are duplicating rather than updating vrobbler bug tasks emacs personal project
- Note taken on [2025-10-29 Wed 16:38] Turns out I was misusing `orgmode` for the source of tasks when it shoulda been `Org-mode` A good lesson in using constants for things.
Version 33.0 [3/3]
DONE [A] Fix bug where scrobble is_stale only uses seconds not total_seconds vrobbler bug scrobbles personal project
DONE [B] Fix duplicatged Read next issue for Comic books vrobbler bug books personal project
DONE [A] Add API authentication to BGG calls vrobbler bug boardgames personal project
<2025-10-28 Tue>
Version 32.0 [2/2]
DONE [B] Save path to reading source on book scrobbles and show it on the detail page vrobbler feature books personal project
DONE [B] Move comic resume URL to next page and check if it exists vrobbler feature books personal project
Version 31.0 [3/3]
DONE [A] Stop comic book webpage scrobbles from overwriting old scrobbles vrobbler personal bug books scrobbling
DONE [A] Add page calculation to manually scrobbled books vrobbler personal feature books scrobbling
DONE [A] Fix bug in scrobbling comics where google fails vrobbler personal bug books scrobbling
Version 30.0 [3/3]
DONE [A] Fix readcomicsonline browsing to update pages vrobbler books feature comicbook personal project scrobbling
DONE [B] Redirect webpages back to the original page when starting or stopping vrobbler project webpages bug
DONE [B] Fix ComicVine as source for comic book metadata vrobbler books feature comicbook personal project scrobbling
Version 29.0 [1/1]
DONE HOTFIX podcast lookups, final
Version 28.0 [1/1]
DONE HOTFIX podcast lookups
Version 27.0 [3/3]
DONE [A] Fix bug where podcast scrobbling creates duplicate Podcast project vrobbler scrobbling podcasts bug personal
Rather than pick up an existing Podcast using the podcast title in the mopidy file name, Vrobbler creates a new podcast with no enriched data. Not a big deal for my use as the volume of podcasts I listen to makes manual fixes easy. But it's annoying.
DONE [A] Allow reading comic books from readcomicsoline.ru vrobbler books feature comicbook personal project scrobbling
- Note taken on [2025-09-25 Thu 10:52] Things to consider are whether we scrobble the issue on one page, send it to archivebox? (yes), and how best to enrich the data
DONE [A] Add RSS feed lookups to podcasts vrobbler personal feature podcasts
- Note taken on [2025-10-14 Tue 10:08] Turns out the Podcast plugin for mopidy does a pretty good job of showing the latest file without having to scroll the bottom using only Muse to not parse the podcast title name. BUT, now we're getting urls like this: https://nsf.libsyn.com/rss#77e01251-cb20-4609-b577-d48e985d2e7b This is great, because there's more context there, but it has to read out of the RSS feed. We should add a check in the podcast util to sniff out the file referenced in the # in that url and populate the info from there. This should actually be much more reliable than the current state of the podcast lookup which depends on the file to be name properly.
Version 26.0 [3/3]
DONE Clean up templates for scrobble details vrobbler personal bug templates
DONE Add named locations visited to dashboard vrobbler personal feature locations templates
DONE Add moods to dashboard vrobbler moods feature templates personal
Version 25.0 [3/3]
DONE Add basic food templates and fix urls food vrobbler personal project bug urls
DONE [C] Fix how elapsed time is calculated vrobbler personal project scrobbles bug
DONE Fix templates for videos and dashboard links personal feature project vrobbler templates
Version 24.0 [2/2]
DONE Clean up logdata for various media personal feature project vrobbler logdata
DONE Removed sidebar and add links to headers personal feature templates scrobbles
Version 23.0 [3/3]
DONE Add dynamic forms for LogData classes personal feature vrobbler project forms logdata
DONE Look in comments for a timestamp for start from BG stats if the time is missing vrobbler feature boardgames project personal
DONE Fix long play scrobbles to provide better data vrobbler feature scrobbles longplay personal project
Version 19.0 [1/1]
DONE Add periodic check for mood vrobbler feature moods personal project
Version 18.7 [1/1]
DONE Use the timezone history log to fix old Scrobbles that fall into those timezone blocks vrobbler chore scrobbles project personal
Version 18.4 [2/2]
DONE Track timezone changes for profiles vrobbler feature profiles personal project
[2025-07-11 14:23]
DONE Only create a LastFM import if there are files to import vrobbler feature lastfm importers project personal
- Note taken on [2025-07-20 Sun 16:21] This thing is kicking my butt. As it stands it works, but the scrobbles are not assigned to the tracks properly.
Version 18.3 [1/1]
DONE Add timezone awarness to IMAP importer personal project vrobbler feature importer imap timezones
Version 18 [4/4]
DONE Condense tracks of the same title by the same artist with multiple albums vrobbler feature music project personal
DONE Import from BG stats a "learning" log field when "Learning to play" is in the comment vrobbler feature boardgames project personal
DONE [A] Add email importer for BG stats file uploads vrobbler feature boardgames personal project
{
"about": "This is a Play file that can be read by Board Game Stats. If you see this text, try to use a share, export or open-in function to open it with Board Game Stats.",
"players": [
{
"uuid": "31f8b92e-11d8-4162-88b1-fd9c79eea249",
"id": 2,
"name": "Colin",
"isAnonymous": false,
"modificationDate": "2025-07-01 18:10:32",
"metaData": "{\"isNpc\":0}"
},
{
"uuid": "00074700-cf4e-4ad3-b334-d35805bb0d90",
"id": 4,
"name": "Asa Sewell",
"isAnonymous": false,
"modificationDate": "2025-07-01 18:03:37"
}
],
"locations": [
{
"uuid": "14f7389c-767f-4725-9b35-906c407b293c",
"id": 3,
"name": "Timberwyck Farm",
"modificationDate": "2025-07-01 18:03:38"
}
],
"games": [
{
"uuid": "043a2851-f201-467a-a60c-0b0a7e9c33d2",
"id": 333,
"name": "Ghost Fightin' Treasure Hunters: Anniversary Edition",
"modificationDate": "2025-07-02 01:37:14",
"cooperative": true,
"highestWins": true,
"noPoints": false,
"usesTeams": false,
"urlThumb": "https://cf.geekdo-images.com/DHA-mcH3zzw_OjfDxOPj1A__thumb/img/UhaIm4KIDIiraUc44QIvSAbMUXI=/fit-in/200x150/filters:strip_icc()/pic8266874.jpg",
"urlImage": "https://cf.geekdo-images.com/DHA-mcH3zzw_OjfDxOPj1A__original/img/2-Lb6nLePhn0I0Hh2j1pOtbO4rg=/0x0/filters:format(jpeg)/pic8266874.jpg",
"bggName": "Ghost Fightin' Treasure Hunters: Anniversary Edition",
"bggYear": 2024,
"bggId": 422668,
"designers": "Brian Yu",
"isBaseGame": 1,
"isExpansion": 0,
"rating": 75,
"minPlayerCount": 2,
"maxPlayerCount": 5,
"minPlayTime": 30,
"maxPlayTime": 0,
"minAge": 8
}
],
"plays": [
{
"uuid": "bae3f29e-5e1e-45d8-b409-47a665c8d5b5",
"modificationDate": "2025-07-02 01:37:59",
"entryDate": "2025-07-02 01:31:38",
"playDate": "2025-07-02 01:31:38",
"usesTeams": false,
"durationMin": 23,
"ignored": false,
"manualWinner": true,
"rounds": 3,
"scoresheet": "{\"bggId\":244711,\"version\":1,\"langCode\":\"en\",\"scoreType\":\"bestTotalWins\",\"groups\":[{\"templateId\":\"1\",\"maxRepeat\":-1,\"repetition\":1,\"hasSubTotal\":false,\"hideSingleGroupLabel\":false,\"isExtra\":false,\"rows\":[{\"templateId\":\"vptrack\",\"label\":\"VP track\",\"repetition\":1,\"repeatable\":false,\"negative\":false,\"isExtra\":false,\"scores\":{}},{\"templateId\":\"objectives\",\"label\":\"Objectives\",\"repetition\":1,\"repeatable\":false,\"negative\":false,\"isExtra\":false,\"scores\":{}},{\"templateId\":\"mastercards\",\"label\":\"Master cards\",\"repetition\":1,\"repeatable\":false,\"negative\":false,\"isExtra\":false,\"scores\":{}}]}]}",
"locationRefId": 3,
"gameRefId": 333,
"board": "",
"scoringSetting": 4,
"metaData": "{\"playUsedGameCopy\":2}",
"playerScores": [
{
"score": "",
"winner": true,
"newPlayer": true,
"startPlayer": false,
"playerRefId": 4,
"role": "",
"rank": 0,
"seatOrder": 0,
"metaData": "{\"scoreUuid\":\"00074700-cf4e-4ad3-b334-d35805bb0d90\"}"
},
{
"score": "",
"winner": true,
"newPlayer": true,
"startPlayer": false,
"playerRefId": 2,
"role": "",
"rank": 0,
"seatOrder": 0,
"metaData": "{\"scoreUuid\":\"31f8b92e-11d8-4162-88b1-fd9c79eea249\"}"
}
],
"expansionPlays": []
}
],
"userInfo": {
"meRefId": 2
}
}
DONE [B] Fix task app to only use one tag for the context a task was done in and allow configurable contexts by user profile personal vrobbler feature tasks project
Version 17.0 [6/6]
DONE [A] Fix bug in new task label lookup for Emacs/Org-mode vrobbler bug tasks
DONE [C] Replace commas in the bandcamp URL for artists with nothing vrobbler music bug personal
- Note taken on [2025-06-16 Mon 09:36] This firt appeared with Black Country, New Road, where the RYM slug generator leaves commas in and ends up sending you to a 404. I suspect this wont be the first tweak we'll need to this, as the RYM link creator is really just guessing based on the artist name at the path.
DONE [A] Investigate new source of video metadata personal project video imdb
Cinemagoer broke and I probably should find a more reilable source of video data.
- Note taken on [2025-06-13 Fri 11:19] TMDB is much more reliable, but does require an API key. That's all setup now, so hopefully this breaking IMDB crap is over.
DONE [A] IMDB video lookups are failing personal bug video imdb
<2025-06-13 Fri>
- Note taken on [2025-06-13 Fri 08:24] Looks like Cinemagoer is broken: https://github.com/cinemagoer/cinemagoer/issues/537
DONE [A] Emacs is not syncing notes personal scrobbling emacs bug
<2025-06-12 Thu 9:30>
Not sure if the problem is in my Emacs hook sending or Vrobbler itself.
- Note taken on [2025-06-12 Thu 09:47] Adding a quick note to check on it
- Note taken on [2025-06-12 Thu 09:50] Ah ha. All the messing about with the source field meant that I was looking for `emacs` as a source but the hook was initially setting sources to `orgmode` I think I prefer `orgmode` as the source, so updating it thusly. Fixed in `490d60cbbb1f8bf90b5fc47d8685b15bdc1d485b`
DONE [A] Show the description of a task in the string rep for a scrobble of a Task personal project scrobbling vrobbler feature
Version 0.16.0 [19/19]
DONE [A] Jellyfin, bandcamp tracks from Mopidy create duplicate music tracks bug scrobbling music
Effectively, any track that comes in without a MusicBrainz ID does some funky lookup where it doesn't find a track without an MB id and the track title / artist combination and creates a new track every time. This has to be cleaned up by condensing the duplicated tracks into the original proper track.
But it opens a bigger question about how much MB id should the drive the app lookup. If it can't be depended on to exist from all sources, it really can't be canonical. Instead, the combination of track title / artist is really the best we can do. Last.fm also has this problem, where it doesn't know about albums and definitely does not know or care about MB ids.
DONE Add a user profile page with ability to change settings profiles improvement
- Note taken on [2025-04-04 Fri 10:51]
~/src/code.unbl.ink/secstate/vrobbler/ (magit-rev 93c16d8)
93c16d80ec
DONE What to do with Youtube videos from LastFM and web-scrobbler bug source lastfm
- Note taken on [2025-04-04 Fri 10:46] Nothing. Over the last few months I built out a youtube model in videos and use a bookmarklet scrobbling pattern. Now web-scrobbler is just disabled for Youtube. May want to revisit this at some point and only scrobble tracks from Youtube, because many people use YT for music listening.
DONE [C] Consider a purge command for duplicated and stuck in-progress scrobbles utililty improvement
CLOSED: [2023-04-06 Thu 14:09]
DONE Add a "stop_timestamp" so we don't rely on content length improvement scrobbling
CLOSED: [2023-04-02 Sun 23:58]
Essentially, we currently have the timestamp as when the content began scrobbling and then calculate the finish time from the length of the content. This works pretty well because we know how long most things are.
But in some cases, sports events or long podcasts, we may start mid-way through an event or finish halfway through but still want to mark it as done. In these cases, knowing the finish time could be useful, especially when interfacing with other scrobblers which may have different definitions of when a scrobble finishes or started.
DONE Fix bug with Various Artist albums being labeled with first artist as album artist scrobbling bug music
CLOSED: [2023-03-27 Mon 20:18]
CLOCK: [2023-03-26 Sun 22:01]–[2023-03-27 Mon 01:07] => 3:06
DONE Fix bug with weekly aggregator being blank on Sundays aggregators music bug
CLOSED: [2023-03-26 Sun 13:52]
DONE Fix KoReader scrobbling to use pages rather than time of last read scrobbling books improvement
CLOSED: [2023-03-26 Sun 13:51]
CLOCK: [2023-03-26 Sun 13:11]–[2023-03-26 Sun 13:51] => 0:40
DONE [A] Add django-storage to store files on S3 settings improvement
CLOSED: [2023-03-24 Fri 14:46]
CLOCK: [2023-03-24 Fri 10:47]–[2023-03-24 Fri 14:46] => 3:59 CLOCK: [2023-03-24 Fri 10:36]–[2023-03-24 Fri 10:40] => 0:04
DONE Fix vrobbler settings not using booleans settings bug
CLOSED: [2023-03-24 Fri 10:45]
CLOCK: [2023-03-24 Fri 10:40]–[2023-03-24 Fri 10:46] => 0:06
DONE Update weekly live chart to be 7-day continuous rather than weekly views bug
CLOSED: [2023-03-24 Fri 00:31] The live view will be blank every Monday, no reason to tie it to a day of the week. It should be "the last 7 days"
DONE [B] Implement a detail view for TV shows improvement views
CLOSED: [2023-03-22 Wed 17:05]
DONE [B] Implement a detail view for Movies improvement views
CLOSED: [2023-03-22 Wed 17:05]
DONE Add "service provider" to TV Series, and use that for source when available bug scrobbling
CLOSED: [2023-03-22 Wed 17:04]
DONE Add view for long-play content (books, video games) to restart them views improvement
CLOSED: [2023-03-22 Wed 17:01]
DONE Add live chart view like Maloja improvement views
CLOSED: [2023-03-07 Tue 11:13]
DONE [C] Figure out how to add to web-scrobbler improvement scrobbling
CLOSED: [2023-03-22 Wed 17:06]
An example: https://github.com/web-scrobbler/web-scrobbler/blob/master/src/core/background/scrobbler/maloja-scrobbler.js
This is actually going to be moot because we can import from LastFM, and web-scrobbler integrates well with LastFM. The only thing to think through here now is what to do with all the garbage web-scrobbler sometimes pushes to LastFM from Youtube (all videos get pushed, sigh).
DONE Add Amazon scraper to look up books when OL fails books improvement
This turned out to be a non-starter … Amazon is aggressive at disallowing scraping quality. And all the OSS tools out there are stuck in an arms race trying to keep them from breaking.
That said, Google Books actually has a decent API (for now), and I've built this out using that.
DONE Fix bug in Jellyfin scrobbles that spam more scrobbles after completion scrobbling videos bug
This was fixed a while ago, but there's a new manifested bug. Going to create a separate bug tracking ticket for that.
Version 0.11.4 [9/9]
DONE Add rudimentary video game scrobbling improvement content videogames
CLOSED: [2023-03-07 Tue 11:11]
DONE Add ability to scrobble from KOReader statistics files improvement books content
CLOSED: [2023-03-07 Tue 11:11]
DONE [A] Fix fetching artwork without release group bug
CLOSED: [2023-01-29 Sun 14:27]
When we get artwork from Musicbrianz, and it's not found, we should check for release groups as well. This will stop issues with missing artwork because of obscure MB release matches.
DONE [A] Fix Jellyfin music scrobbling N+1 past 90 completion percent bug
CLOSED: [2023-01-30 Mon 18:31]
CLOCK: [2023-01-30 Mon 18:00]–[2023-01-30 Mon 18:31] => 0:31
If we play music from Jellyfin and the track reaches 90% completion, the scrobbling goes crazy and starts creating new scrobbles with every update.
The cause is pretty simple, but the solution is hard. We want to mark a scrobble as complete for the following conditions:
- Play stopped and percent played beyond 90%
- Play completely finished
But if we keep listening beyond 90, we should basically ignore updates (or just update the existing scrobble)
DONE [A] Add support for Audioscrobbler tab-separated file uploads improvement
CLOSED: [2023-02-03 Fri 16:52]
An example of the format:
,
#AUDIOSCROBBLER/1.1
#TZ/UNKNOWN
#CLIENT/Rockbox sansaclipplus $Revision$
75 Dollar Bill I Was Real I Was Real 4 1015 S 1740494944 64ff5f53-d187-4512-827e-7606c69e66ff
75 Dollar Bill I Was Real I Was Real 4 1015 S 1740494990 64ff5f53-d187-4512-827e-7606c69e66ff
311 311 Down 1 173 S 1740495003 00476c23-fd9e-464b-9b27-a62d69f3d4f4
311 311 Down 1 173 L 1740495049 00476c23-fd9e-464b-9b27-a62d69f3d4f4
311 311 Down 1 173 L 1740495113 00476c23-fd9e-464b-9b27-a62d69f3d4f4
311 311 Random 2 187 S 1740495190 530c09f3-46fe-4d90-b11f-7b63bcb4b373
311 311 Random 2 187 L 1740495194 530c09f3-46fe-4d90-b11f-7b63bcb4b373
311 311 Jackolantern’s Weather 3 204 L 1740495382 cc3b2dec-5d99-47ea-8930-20bf258be4ea
311 311 All Mixed Up 4 182 L 1740495586 980a78b5-5bdd-4f50-9e3a-e13261e2817b
311 311 Hive 5 179 L 1740495768 18f6dc98-d3a2-4f81-b967-97359d14c68c
311 311 Guns (Are for Pussies) 6 137 L 1740495948 5e97ed9f-c8cc-4282-9cbe-f8e17aee5128
311 311 Misdirected Hostility 7 179 S 1740496085 61ff2c1a-fc9c-44c3-8da1-5e50a44245af
,
DONE [B] Allow scrobbling music without MB IDs by grabbing them before scrobble improvement
CLOSED: [2023-02-17 Fri 00:10]
This would allow a few nice flows. One, you'd be able to record the play of an entire album by just dropping the muscibrainz_id in. This could be helpful for offline listening. It would also mean bad metadata from mopidy would not break scrobbling.
DONE When updating musicbrainz IDs, clear and run fetch artwrok improvement
CLOSED: [2023-02-17 Fri 00:11]
DONE [A] Add ability to manually scrobble albums or tracks from MB improvement
CLOSED: [2023-03-07 Tue 11:09]
Given a UUID from musicbrainz, we should be able to scrobble an album or individual track.
DONE [C] Implement keeping track of week/month/year chart-toppers improvement
CLOSED: [2023-03-07 Tue 11:10]
CLOCK: [2023-01-30 Mon 16:30]–[2023-01-30 Mon 18:00] => 1:30
Maloja does this cool thing where artists and tracks get recorded as the top track of a given week, month or year. They get gold, silver or bronze stars for their place in the time period.
I could see this being implemented as a separate Chart table which gets populated at the end of a time period and has a start and end date that defines a period, along with a one, two, three instance.
Of course, it could also be a data model without a table, where it runs some fun calculations, stores it's values in Redis as a long-term lookup table and just has to re-populate when the server restarts.