README.md (3859B)
1 # corpus 2 [](https://builds.sr.ht/~mtmn/corpus?) 3 4 A self-hosted [ListenBrainz](https://listenbrainz.org) and [Last.fm](https://last.fm) frontend that stores metadata and cover images. 5 6 It stores scrobbles, enriches track metadata and provides an interactive [Elm](https://elm-lang.org) interface. 7 8 ## Documentation 9 10 - [Architecture](docs/architecture.md) — Deep dive into the system components, data flow, and FFI usage. 11 - [DuckDB](docs/duckdb.md) — Schema details, analytical queries, and tools for data exploration. 12 13 ## Usage 14 15 This project uses [just](https://github.com/casey/just) and [Nix](https://nixos.org) for development and deployment. 16 17 ### Development 18 19 ```bash 20 # Enter the development shell 21 just shell 22 23 # Build 24 just nix build 25 26 # Run the binary built by Nix 27 just nix run 28 ``` 29 30 ### Build 31 32 This project uses [pnpm](https://pnpm.io) for dependency management. 33 34 ```bash 35 # Install dependencies 36 pnpm install 37 pnpm spago install 38 39 # Build the project 40 pnpm run build 41 42 # Run tests 43 pnpm test 44 45 # Build an optimized release 46 pnpm run release 47 48 # Run the application 49 pnpm spago run 50 ``` 51 52 ### Scrobbling API 53 54 Corpus provides a [ListenBrainz-compatible](https://listenbrainz.readthedocs.io/en/latest) endpoint for submitting scrobbles directly. This allows you to use any scrobbler that supports custom ListenBrainz endpoints. 55 56 #### Endpoint 57 58 `POST /1/submit-listens` 59 60 #### Authentication 61 62 The API uses token-based authentication. A unique API token is automatically generated for each user when they first start the application. You can find your token in the server logs on startup: 63 64 ```text 65 [INFO] User 'mtmn' token: 550e8400-e29b-41d4-a716-446655440000 66 ``` 67 68 Include the token in the `Authorization` header of your requests: 69 70 ```text 71 Authorization: Token <your-token> 72 ``` 73 74 #### Payload Format 75 76 The endpoint accepts standard ListenBrainz JSON payloads. See the [ListenBrainz API documentation](https://listenbrainz.readthedocs.io/en/latest/users/api/core.html#post--1-submit-listens) for details. 77 78 ### Environment variables 79 80 | Variable | Default | Description | 81 | :--- | :--- | :--- | 82 | `CORPUS_USERS_FILE` | `users.json` | Path to the multi-user config file | 83 | `DATABASE_PATH` | _(cwd)_ | Root directory for all user database files | 84 | `PORT` | `8000` | HTTP port to listen on | 85 | `LASTFM_API_KEY` | — | Last.fm API key (required when any user has `lastfmUser` set; also used for genre and cover art fallback) | 86 | `DISCOGS_TOKEN` | — | Discogs token for cover art and genre fallback | 87 | `S3_BUCKET` | — | S3 bucket name for cover art caching and backups | 88 | `S3_REGION` | `us-east-1` | S3 region | 89 | `AWS_ACCESS_KEY_ID` | — | S3 credentials | 90 | `AWS_SECRET_ACCESS_KEY` | — | S3 credentials | 91 | `AWS_ENDPOINT_URL` | — | S3-compatible endpoint (e.g. for MinIO) | 92 | `AWS_S3_ADDRESSING_STYLE` | — | Set to `path` for path-style S3 URLs | 93 | `COSINE_API_KEY` | — | [cosine.club](https://cosine.club) API key for similar tracks | 94 | `METRICS_ENABLED` | `false` | Set to `true` to expose Prometheus metrics at `/metrics` | 95 | `CORS_ORIGIN` | `*` | Value for the `Access-Control-Allow-Origin` header on `/proxy` responses (e.g. `https://mtmn.name`) | 96 97 ### Per-user configuration 98 99 | Field | Default | Description | 100 | :--- | :--- | :--- | 101 | `slug` | — | URL slug (`""` for root user, `"filip"` for `/u/filip`) | 102 | `name` | — | Display name for the user (defaults to slug if not provided) | 103 | `listenbrainzUser` | — | ListenBrainz username to sync scrobbles from | 104 | `lastfmUser` | — | Last.fm username to sync scrobbles from | 105 | `databaseFile` | `corpus.db` | Path to the user's DuckDB database file | 106 | `coverCacheEnabled` | `true` | Enable cover art caching to S3 | 107 | `backupEnabled` | `false` | Enable database backups to S3 | 108 | `backupIntervalHours` | `24` | Backup frequency in hours |