From 78e353fc10886c2b612cac6edd7426dd7886627f Mon Sep 17 00:00:00 2001 From: David Kellner <52860029+kellnerd@users.noreply.github.com> Date: Thu, 4 Jul 2024 20:10:41 +0200 Subject: [PATCH] chore: Drop elbisaur CLI, it is now a separate package --- README.md | 2 +- cli/README.md | 235 ------------------- cli/elbisaur.ts | 608 ------------------------------------------------ deno.json | 6 +- utils.ts | 83 ------- 5 files changed, 2 insertions(+), 932 deletions(-) delete mode 100644 cli/README.md delete mode 100644 cli/elbisaur.ts delete mode 100644 utils.ts diff --git a/README.md b/README.md index a41452b..74b5437 100644 --- a/README.md +++ b/README.md @@ -60,7 +60,7 @@ The following parsers are available in the `listenbrainz/parser/*` submodules: `elbisaur` is a CLI which can be used to submit and manage listens. [Learn more][elbisaur]. [documentation]: https://jsr.io/@kellnerd/listenbrainz/doc -[elbisaur]: https://github.com/kellnerd/listenbrainz-ts/blob/main/cli/README.md +[elbisaur]: https://github.com/kellnerd/elbisaur [MusicBrainz]: https://musicbrainz.org/ [ListenBrainz]: https://listenbrainz.org/ [ListenBrainz API]: https://listenbrainz.readthedocs.io/en/latest/users/api/index.html diff --git a/cli/README.md b/cli/README.md deleted file mode 100644 index 87d1e7e..0000000 --- a/cli/README.md +++ /dev/null @@ -1,235 +0,0 @@ -# elbisaur - -Command line app to manage your ListenBrainz listens and process listen dumps. - -If you want to give it a try to see what you get, you can safely execute it with [Deno]. -Run the following command to see its integrated help, Deno will prompt you for the necessary permissions: - -```sh -deno run https://deno.land/x/listenbrainz/cli/elbisaur.ts -``` - -## Setup - -If 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: - -```sh -deno install --allow-env=LB_USER,LB_TOKEN,ELBISAUR_LISTEN_TEMPLATE --allow-net=api.listenbrainz.org,musicbrainz.org --allow-read --allow-write https://deno.land/x/listenbrainz/cli/elbisaur.ts -``` - -Now 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`. -This is your ListenBrainz user token which is required to submit listens and can be obtained from your [ListenBrainz settings] page. -Running `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: - -```conf -# example token below, insert your own -LB_TOKEN = "3b851ecc-474d-44eb-a4d0-db3bbb5ef8b8" -# user name is optional, but it sometimes saves an API request if it is specified -LB_USER = "Your LB user name here" -``` - -## Commands - -elbisaur is a modular command line app with multiple subcommands which you can execute with `elbisaur `. -The following commands are available: - -| Command | Description | -| ------------ | ---------------------------------------------------------------------- | -| `history` | Show the listening history of yourself or another user | -| `delete` | Delete listens in the given JSON file from your history | -| `import` | Import listens from the given JSON file | -| `listen` | Submit listens for selected tracks from a release (given by its URL) | -| `parse` | [Parse listens](#parsers) from a file and write them into a JSONL file | -| `statistics` | Show statistics for the given JSON file | -| `transform` | Modify listens from a JSON input file and write them into a JSONL file | - -You can view the integrated help of each command with `elbisaur --help`. - -All commands which accept JSON files as input also accept JSONL files (one JSON object per line). -These 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). -JSONL files which are written by elbisaur also follow this format. - -## Parsers - -The following formats can be parsed by elbisaur (in addition to native JSON and JSONL listens): - -- **.scrobbler.log** (`*.log`): Log file which is generated by some portable music players for later submission to Last.fm. -- **Spotify** (`*.json`): JSON files from an Extended Streaming History download. - -See the [parser documentation](../README.md#parsers) for implementation details. - -> [!NOTE] -> The parsers perform no filtering of listens, so you have to detect potential duplicates and skipped listens yourself. - -## Examples - -### Listening History - -View your most recent listening history using the `history` command: - -```sh -elbisaur history -``` - -In order to see the listening history of another user, specify their name with the `-u, --user` option: - -```sh -elbisaur history --user listenbrainz -``` - -You can filter listens by listening time (`-a, --after` and `-b, --before`, happens on the server) and metadata (`-f, --filter`, happens locally). -If you want to apply metadata filters (locally), ensure that the API returns enough results by specifying a higher count with `-c, --count`. - -Downloaded results can be stored as JSONL file by specifying an output path with `-o, --output`. -If the file already exists, the new listens will be appended to it. - -Download your listens for all tracks by Jane Doe to which you listened on 17th January 2024: - -```sh -elbisaur history -f "artist_name==Jane Doe" -a 2024-01-17 -b 2024-01-18 -c 200 -o jane.jsonl -``` - -### Importing Listens - -Importing listens is straightforward if you have a JSON file which contains one or multiple listens. -Such a file can be a ListenBrainz listening history export, the result of another elbisaur command or the content from a ListenBrainz “Inspect listen” dialog. - -Before 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: - -```sh -elbisaur import listens.json --preview -``` - -Only if you are satisfied with what you see, you should proceed: - -```sh -elbisaur import listens.json -``` - -### Manually Submitting Listens - -You can also use `elbisaur` to submit listens for selected tracks from a release manually. - -If you want to quickly submit a single listen with track title (Love Song) and artist (John Doe), you can use: - -```sh -elbisaur listen "John Doe - Love Song" --at "2024-03-17 15:24:36" -``` - -Or quickly submit a playing now notification for that track: - -```sh -elbisaur listen "John Doe - Love Song" --now -``` - -Alternatively you can also submit multiple listens using the MusicBrainz URL of a release. -Say you started listening to side A of a vinyl record today at 12:34:56 and want to submit listens for these tracks. -The app automatically calculates the listening timestamps for all tracks based on the track lengths. - -```sh -elbisaur listen https://musicbrainz.org/release/d6010be3-98f8-422c-a6c9-787e2e491e58 A --at 12:34:56 -``` - -Of course you can also specify the time when you finished listening (to the last track): - -```sh -elbisaur listen https://musicbrainz.org/release/d6010be3-98f8-422c-a6c9-787e2e491e58 A --until 12:59:52 -``` - -And if you finished listening to side B right now (this second), you can simply omit the time option: - -```sh -elbisaur listen https://musicbrainz.org/release/d6010be3-98f8-422c-a6c9-787e2e491e58 B -``` - -Instead of specifying the track number prefix (here: the side number `A`), you could also explicitly type the track range `A1-A6`. -For 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). - -### Deleting Listens - -If you want to delete some of your listens, you need to obtain a JSON file which contains the bad listens. -You can either use a filtered listening history export for this or create the file using `elbisaur history`. - -The 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. - -Before 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: - -```sh -elbisaur delete bad-listens.jsonl --preview -``` - -Only if you are satisfied with what you see, you should proceed: - -```sh -elbisaur delete bad-listens.jsonl -``` - -Please 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. - -### Parsing .scrobbler.log Files - -Parse a `.scrobbler.log` file (for example from a Rockbox player) and discard all scrobbles which are marked as skipped: - -```sh -elbisaur parse .scrobbler.log --filter skipped!=1 -``` - -You can also run the parser again and write skipped scrobbles to a separate file for manual review: - -```sh -elbisaur parse .scrobbler.log --filter skipped==1 skipped-listens.jsonl -``` - -> [!NOTE] -> Timestamps are automatically converted from your local timezone to UTC as Rockbox players are usually not timezone-aware. - -### Parsing Spotify Extended Streaming History - -If you have requested your Extended Streaming History from Spotify, you receive one or more `Streaming_History_Audio_*.json` files. -These files can be parsed with elbisaur, but they also contain skipped streams which are sometimes not marked as such. - -Parse Spotify history file and only keep streams which were not skipped *and* were played for at least 30 seconds: - -```sh -elbisaur parse Streaming_History_Audio_2024.json --filter "skipped!=1&&ms_played>=30e3" -``` - -While 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). - -You might have to experiment with the filter options a bit or do multiple passes to get optimal results. -Limiting 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. - -> [!NOTE] -> This parser calculates the correct listen (start) timestamp from stream end time and duration. -> -> In some cases this time is completely inaccurate because the logged end timestamp is wrong and does not indicate when the track stopped playing. -> It appears to be the next time when Spotify was opened again after the app or the web player had been closed unexpectedly. -> -> In those cases the parser uses the so called “offline” timestamp which, despite its name, is not exclusively used to track offline playback. -> 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. -> -> You can specify the `-d, --debug` flag to include all possible timestamp data in the `additional_info` properties of each parsed listen. - -### Modifying Listens - -Correct a typo in the release name property of a few listens from a JSON file: - -```sh -elbisaur transform input.jsonl -f "release_name==Exmaple" -e "release_name=Example" fixed.jsonl -``` - -Inject (or correct) the release MBID for all listens with a given release name: - -```sh -elbisaur transform input.jsonl -f "release_name==Example" -e "release_mbid=bf9e91ea-8029-4a04-a26a-224e00a83266" output.jsonl -``` - -Compensate a wrong listen time offset of an hour for all listens (by adding 3600 seconds): - -```sh -elbisaur transform wrong-time.jsonl -t 3600 correct-time.jsonl -``` - -[Deno]: https://deno.com/ -[install]: https://docs.deno.com/runtime/manual/tools/script_installer -[ListenBrainz settings]: https://listenbrainz.org/settings/ diff --git a/cli/elbisaur.ts b/cli/elbisaur.ts deleted file mode 100644 index f31b021..0000000 --- a/cli/elbisaur.ts +++ /dev/null @@ -1,608 +0,0 @@ -import { ListenBrainzClient } from "../client.ts"; -import { - type AdditionalTrackInfo, - cleanListen, - formatListen, - type Listen, - setSubmissionClient, - type Track, -} from "../listen.ts"; -import { timestamp } from "../timestamp.ts"; -import { JsonLogger, readListensFile } from "../utils.ts"; -import { parseMusicBrainzRelease } from "../parser/musicbrainz.ts"; -import { parseScrobblerLog } from "../parser/scrobbler_log.ts"; -import { parseSpotifyExtendedHistory } from "../parser/spotify.ts"; -import { MusicBrainzClient } from "@kellnerd/musicbrainz"; -import { parseTrackRange } from "@kellnerd/musicbrainz/utils/track"; -import { extname } from "@std/path/extname"; -import { parse as parseYaml } from "jsr:@std/yaml@^1.0.0-rc.1"; -import { Command, ValidationError } from "jsr:@cliffy/command@1.0.0-rc.5"; -import { brightBlue as opt, brightMagenta as cmd } from "@std/fmt/colors"; - -/** MusicBrainz URLs which are accepted by the CLI. */ -const musicBrainzUrlPattern = new URLPattern({ - pathname: "/release/:mbid([0-9a-f-]{36})", -}); - -const contactUrl = "https://github.com/kellnerd/listenbrainz-ts"; - -export const cli = new Command() - .name("elbisaur") - .version("0.8.2") - .description("Manage your ListenBrainz listens and process listen dumps.") - .globalEnv("LB_TOKEN=", "ListenBrainz user token.", { - prefix: "LB_", - required: true, - }) - .globalEnv( - "ELBISAUR_LISTEN_TEMPLATE=