{"id":22890216,"url":"https://github.com/kellnerd/elbisaur","last_synced_at":"2026-04-27T21:31:03.887Z","repository":{"id":265436788,"uuid":"824231213","full_name":"kellnerd/elbisaur","owner":"kellnerd","description":"CLI to manage your ListenBrainz listens and process listen dumps","archived":false,"fork":false,"pushed_at":"2025-06-30T14:26:06.000Z","size":144,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-06-30T15:24:22.608Z","etag":null,"topics":["cliffy","deno","listenbrainz"],"latest_commit_sha":null,"homepage":"https://jsr.io/@kellnerd/elbisaur","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/kellnerd.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-07-04T16:31:07.000Z","updated_at":"2025-06-30T14:06:24.000Z","dependencies_parsed_at":"2024-11-29T21:51:51.276Z","dependency_job_id":null,"html_url":"https://github.com/kellnerd/elbisaur","commit_stats":null,"previous_names":["kellnerd/elbisaur"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/kellnerd/elbisaur","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kellnerd%2Felbisaur","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kellnerd%2Felbisaur/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kellnerd%2Felbisaur/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kellnerd%2Felbisaur/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/kellnerd","download_url":"https://codeload.github.com/kellnerd/elbisaur/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kellnerd%2Felbisaur/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32356596,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-27T20:07:02.737Z","status":"ssl_error","status_checked_at":"2026-04-27T20:07:00.910Z","response_time":128,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cliffy","deno","listenbrainz"],"created_at":"2024-12-13T21:59:54.833Z","updated_at":"2026-04-27T21:31:03.881Z","avatar_url":"https://github.com/kellnerd.png","language":"TypeScript","readme":"# elbisaur\n\nCommand line app to manage your ListenBrainz listens and process listen dumps.\n\nIf you want to give it a try to see what you get, you can safely execute it with [Deno].\nRun the following command to see its integrated help, Deno will prompt you for the necessary permissions:\n\n```sh\ndeno run jsr:@kellnerd/elbisaur\n```\n\n## Setup\n\nIf you don’t want to have to remember the URL and grant permissions every time, you can [install] it with the permissions specified as arguments:\n\n```sh\ndeno install --global --allow-env=LB_USER,LB_TOKEN,ELBISAUR_LISTEN_TEMPLATE --allow-net=jsr.io,api.listenbrainz.org,musicbrainz.org --allow-read --allow-write jsr:@kellnerd/elbisaur\n```\n\nNow you can simply run the app by executing `elbisaur`, which should show you the help and complain about a missing required environment variable `LB_TOKEN`.\nThis is your ListenBrainz user token which is required to submit listens and can be obtained from your [ListenBrainz settings] page.\nRunning `elbisaur` automatically tries to load environment variables from a `.env` file in your working directory, so you can comfortably safe your LB user token inside there:\n\n```conf\n# example token below, insert your own\nLB_TOKEN = \"3b851ecc-474d-44eb-a4d0-db3bbb5ef8b8\"\n# user name is optional, but it sometimes saves an API request if it is specified\nLB_USER = \"Your LB user name here\"\n```\n\n## Commands\n\nelbisaur is a modular command line app with multiple subcommands which you can execute with `elbisaur \u003ccommand\u003e`.\nThe following commands are available:\n\n| Command      | Description                                                            |\n| ------------ | ---------------------------------------------------------------------- |\n| `history`    | Show the listening history of yourself or another user                 |\n| `delete`     | Delete listens in the given JSON file from your history                |\n| `import`     | Import listens from the given JSON file                                |\n| `listen`     | Submit listens for selected tracks from a release (given by its URL)   |\n| `parse`      | [Parse listens](#parsers) from a file and write them into a JSONL file |\n| `statistics` | Show statistics for the given JSON file                                |\n| `transform`  | Modify listens from a JSON input file and write them into a JSONL file |\n\nYou can view the integrated help of each command with `elbisaur \u003ccommand\u003e --help`.\n\nAll commands which accept JSON files as input also accept JSONL files (one JSON object per line).\nThese should contain (one or multiple) serialized `Listen` objects as included in a ListenBrainz listening history export (and as shown by the ListenBrainz “Inspect listen” dialog).\nJSONL files which are written by elbisaur also follow this format.\n\n## Parsers\n\nThe following formats can be parsed by elbisaur (in addition to native JSON and JSONL listens):\n\n- **.scrobbler.log** (`*.log`): Log file which is generated by some portable music players for later submission to Last.fm.\n- **Spotify** (`*.json`): JSON files from an Extended Streaming History download.\n\nSee the [parser documentation](https://jsr.io/@kellnerd/listenbrainz#parsers) for implementation details.\n\n\u003e [!NOTE]\n\u003e The parsers perform no filtering of listens, so you have to detect potential duplicates and skipped listens yourself.\n\n## Examples\n\n### Listening History\n\nView your most recent listening history using the `history` command:\n\n```sh\nelbisaur history\n```\n\nIn order to see the listening history of another user, specify their name with the `-u, --user` option:\n\n```sh\nelbisaur history --user listenbrainz\n```\n\nYou can filter listens by listening time (`-a, --after` and `-b, --before`, happens on the server) and metadata (`-f, --filter`, happens locally).\nIf you want to apply metadata filters (locally), ensure that the API returns enough results by specifying a higher count with `-c, --count`.\n\nDownloaded results can be stored as JSONL file by specifying an output path with `-o, --output`.\nIf the file already exists, the new listens will be appended to it.\n\nDownload your listens for all tracks by Jane Doe to which you listened on 17th January 2024:\n\n```sh\nelbisaur history -f \"artist_name==Jane Doe\" -a 2024-01-17 -b 2024-01-18 -c 200 -o jane.jsonl\n```\n\n### Importing Listens\n\nImporting listens is straightforward if you have a JSON file which contains one or multiple listens.\nSuch a file can be a ListenBrainz listening history export, the result of another elbisaur command or the content from a ListenBrainz “Inspect listen” dialog.\n\nBefore running the actual `import` command itself, it is recommended to run the same command with the `-p, --preview` flag to see which listens would be imported:\n\n```sh\nelbisaur import listens.json --preview\n```\n\nOnly if you are satisfied with what you see, you should proceed:\n\n```sh\nelbisaur import listens.json\n```\n\n### Manually Submitting Listens\n\nYou can also use `elbisaur` to submit listens for selected tracks from a release manually.\n\nIf you want to quickly submit a single listen with track title (Love Song) and artist (John Doe), you can use:\n\n```sh\nelbisaur listen \"John Doe - Love Song\" --at \"2024-03-17 15:24:36\"\n```\n\nOr quickly submit a playing now notification for that track:\n\n```sh\nelbisaur listen \"John Doe - Love Song\" --now\n```\n\nAlternatively you can also submit multiple listens using the MusicBrainz URL of a release.\nSay you started listening to side A of a vinyl record today at 12:34:56 and want to submit listens for these tracks.\nThe app automatically calculates the listening timestamps for all tracks based on the track lengths.\n\n```sh\nelbisaur listen https://musicbrainz.org/release/d6010be3-98f8-422c-a6c9-787e2e491e58 A --at 12:34:56\n```\n\nOf course you can also specify the time when you finished listening (to the last track):\n\n```sh\nelbisaur listen https://musicbrainz.org/release/d6010be3-98f8-422c-a6c9-787e2e491e58 A --until 12:59:52\n```\n\nAnd if you finished listening to side B right now (this second), you can simply omit the time option:\n\n```sh\nelbisaur listen https://musicbrainz.org/release/d6010be3-98f8-422c-a6c9-787e2e491e58 B\n```\n\nInstead of specifying the track number prefix (here: the side number `A`), you could also explicitly type the track range `A1-A6`.\nFor releases with multiple media, you can additionally specify the medium number (`2:1-5`), or even just a medium number (`2:`, since simply `2` would be interpreted as track number prefix).\n\n### Deleting Listens\n\nIf you want to delete some of your listens, you need to obtain a JSON file which contains the bad listens.\nYou can either use a filtered listening history export for this or create the file using `elbisaur history`.\n\nThe file not only contains the necessary data to send deletion requests to the API, it can also serve as a backup in case you accidentally delete the wrong listens.\n\nBefore running the actual `delete` command itself, it is recommended to run the same command with the `-p, --preview` flag to see which listens would be deleted:\n\n```sh\nelbisaur delete bad-listens.jsonl --preview\n```\n\nOnly if you are satisfied with what you see, you should proceed:\n\n```sh\nelbisaur delete bad-listens.jsonl\n```\n\nPlease note that this only marks listens for deletion currently and that it takes until the full hour before the deleted listens finally disappear from ListenBrainz.\n\n### Parsing .scrobbler.log Files\n\nParse a `.scrobbler.log` file (for example from a Rockbox player) and discard all scrobbles which are marked as skipped:\n\n```sh\nelbisaur parse .scrobbler.log --filter skipped!=1\n```\n\nYou can also run the parser again and write skipped scrobbles to a separate file for manual review:\n\n```sh\nelbisaur parse .scrobbler.log --filter skipped==1 skipped-listens.jsonl\n```\n\n\u003e [!NOTE]\n\u003e Timestamps are automatically converted from your local timezone to UTC as Rockbox players are usually not timezone-aware.\n\n### Parsing Spotify Extended Streaming History\n\nIf you have requested your Extended Streaming History from Spotify, you receive one or more `Streaming_History_Audio_*.json` files.\nThese files can be parsed with elbisaur, but they also contain skipped streams which are sometimes not marked as such.\n\nParse Spotify history file and only keep streams which were not skipped *and* were played for at least 30 seconds:\n\n```sh\nelbisaur parse Streaming_History_Audio_2024.json --filter \"skipped!=1\u0026\u0026duration_ms\u003e=30e3\"\n```\n\nWhile some skipped listens can be detected by their `reason_end` properties, bad listens can also have a reason of `trackdone` although Spotify failed to play them (playback duration is only a second or two).\n\nYou might have to experiment with the filter options a bit or do multiple passes to get optimal results.\nLimiting the output by specifying a time range (`-a, --after` and `-b, --before`) makes reviewing the results (using the `-p, --preview` option) a lot more comfortable.\n\n\u003e [!NOTE]\n\u003e This parser calculates the correct listen (start) timestamp from stream end time and duration.\n\u003e\n\u003e In some cases this time is completely inaccurate because the logged end timestamp is wrong and does not indicate when the track stopped playing.\n\u003e It appears to be the next time when Spotify was opened again after the app or the web player had been closed unexpectedly.\n\u003e\n\u003e In those cases the parser uses the so called “offline” timestamp which, despite its name, is not exclusively used to track offline playback.\n\u003e While it seems to be a few seconds off in general, it is pretty accurate for those cases where the logged end time is bogus.\n\u003e\n\u003e You can specify the `-d, --debug` flag to include all possible timestamp data in the `additional_info` properties of each parsed listen.\n\n### Modifying Listens\n\nCorrect a typo in the release name property of a few listens from a JSON file:\n\n```sh\nelbisaur transform input.jsonl -f \"release_name==Exmaple\" -e \"release_name=Example\" fixed.jsonl\n```\n\nInject (or correct) the release MBID for all listens with a given release name:\n\n```sh\nelbisaur transform input.jsonl -f \"release_name==Example\" -e \"release_mbid=bf9e91ea-8029-4a04-a26a-224e00a83266\" output.jsonl\n```\n\nCompensate a wrong listen time offset of an hour for all listens (by adding 3600 seconds):\n\n```sh\nelbisaur transform wrong-time.jsonl -t 3600 correct-time.jsonl\n```\n\n[Deno]: https://deno.com/\n[install]: https://docs.deno.com/runtime/manual/tools/script_installer\n[ListenBrainz settings]: https://listenbrainz.org/settings/\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkellnerd%2Felbisaur","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkellnerd%2Felbisaur","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkellnerd%2Felbisaur/lists"}