like malachite (atproto-lastfm-importer) but in go and bluer
go spotify tealfm lastfm atproto
at main 89 lines 4.1 kB view raw view rendered
1# Lazuli 2 3Import Last.fm and Spotify listening history to teal.fm. 4 5## Overview 6 7Lazuli is a command-line tool that parses listening history exports from Last.fm and Spotify, merges them to remove duplicates, and publishes them to teal.fm as `fm.teal.alpha.feed.play` records. 8 9Re-written from <https://tangled.org/ewancroft.uk/atproto-lastfm-importer>. 10 11## Usage 12 13### Authentication 14 15Set your Bluesky credentials via environment variables or flags: 16 17```sh 18export LAZULI_HANDLE="your-handle.bsky.social" 19export LAZULI_PASSWORD="your-app-password" 20``` 21 22### Commands 23 24| Command | Usage | 25| :------- | :------------------------------------------------------- | 26| `export` | Parse and merge Last.fm/Spotify exports into a JSON file | 27| `import` | Import new records to Bluesky (auto-skips existing) | 28| `sync` | Refresh the local cache with records from Bluesky | 29| `stats` | Show database status and daily rate limit consumption | 30| `failed` | List records that failed to import | 31| `retry` | Attempt to re-import failed records | 32| `dedupe` | Remove duplicate records from your Bluesky profile | 33| `debug` | Dump raw records from Bluesky for troubleshooting | 34 35### Advanced Options 36 37- **Rate Limiting**: Lazuli automatically respects Bluesky/ATProto rate limits (default 9,000 writes/day). Use `lazuli stats` to see your remaining quota. 38- **Automatic Resume**: The local cache tracks which records were successfully imported. If a process is interrupted, re-running the same command will skip already-published entries. 39- **Output Formats**: Most commands support `--output-format=json` for machine-readable output. 40- **Fresh Sync**: Use `--fresh` to bypass the local cache and fetch everything directly from the server. 41- **CAR Export**: Use `--car` with `sync` and `dedupe` commands to fetch the entire repository via `com.atproto.sync.getRepo` (much faster for large repos, uses a single API call). 42 43## Environment Variables 44 45| Variable | Description | 46| ----------------- | ----------------------------------------- | 47| `LAZULI_HANDLE` | Bluesky handle (e.g., `user.bsky.social`) | 48| `LAZULI_PASSWORD` | Bluesky app password | 49| `LAZULI_LASTFM` | Path to Last.fm CSV file | 50| `LAZULI_SPOTIFY` | Path to Spotify JSON file/directory/zip | 51| `LAZULI_DRY_RUN` | Preview without publishing | 52| `LAZULI_VERBOSE` | Enable verbose logging | 53| `LAZULI_REVERSE` | Process records in reverse order | 54| `LAZULI_USE_CAR` | Use CAR export for sync/dedupe (1/true) | 55 56## Input Formats 57 58### Last.fm 59 60Export your listening history from Last.fm. The CSV file should have columns: 61 62- UTC timestamp 63- Artist name 64- Album name 65- Track name 66- MusicBrainz IDs (optional) 67 68### Spotify 69 70Lazuli is designed to work with your **Extended Streaming History** from Spotify. You can request this from your [Spotify Privacy Settings](https://www.spotify.com/account/privacy/). 71 72The recommended way to use Spotify data is by passing the **ZIP archive** you receive from Spotify directly. Lazuli will automatically find and parse all streaming history files within it. 73 74Lazuli accepts: 75 76- **ZIP archives** containing extended history (Recommended) 77- Directories containing `Streaming_History_Audio_*.json` files 78- Single `Streaming_History_Audio_*.json` files 79 80> [!IMPORTANT] 81> Make sure to request "Extended streaming history", as the standard "Account data" export does not contain your full listening history. 82 83## Features 84 85- **Cross-source deduplication**: Merges Last.fm and Spotify data, removing duplicates within a configurable time tolerance 86- **Rate limiting**: Respects ATProto rate limits with configurable batch sizes and delays 87- **Automatic resume**: Cache tracks imported records - re-running skips already-imported entries 88- **Dry-run mode**: Preview imports without publishing 89- **Cache management**: Caches teal records for faster subsequent operations