navidrome-scripts 0.14.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- navidrome_scripts-0.14.0/PKG-INFO +485 -0
- navidrome_scripts-0.14.0/README.md +469 -0
- navidrome_scripts-0.14.0/navidrome_scripts/__init__.py +1 -0
- navidrome_scripts-0.14.0/navidrome_scripts/artist_ratings.py +424 -0
- navidrome_scripts-0.14.0/navidrome_scripts/catalog.py +45 -0
- navidrome_scripts-0.14.0/navidrome_scripts/date_evidence.py +265 -0
- navidrome_scripts-0.14.0/navidrome_scripts/dates.py +369 -0
- navidrome_scripts-0.14.0/navidrome_scripts/duplicates.py +356 -0
- navidrome_scripts-0.14.0/navidrome_scripts/indexed_duplicates.py +370 -0
- navidrome_scripts-0.14.0/navidrome_scripts/library_review.py +281 -0
- navidrome_scripts-0.14.0/navidrome_scripts/lidarr.py +43 -0
- navidrome_scripts-0.14.0/navidrome_scripts/locking.py +88 -0
- navidrome_scripts-0.14.0/navidrome_scripts/maintenance.py +308 -0
- navidrome_scripts-0.14.0/navidrome_scripts/metadata.py +46 -0
- navidrome_scripts-0.14.0/navidrome_scripts/navidrome_guard.py +202 -0
- navidrome_scripts-0.14.0/navidrome_scripts/playlists.py +313 -0
- navidrome_scripts-0.14.0/navidrome_scripts/provider_review.py +122 -0
- navidrome_scripts-0.14.0/navidrome_scripts/reconciliation.py +210 -0
- navidrome_scripts-0.14.0/navidrome_scripts/rename_rollback.py +273 -0
- navidrome_scripts-0.14.0/navidrome_scripts/renames.py +360 -0
- navidrome_scripts-0.14.0/navidrome_scripts/spotify.py +131 -0
- navidrome_scripts-0.14.0/navidrome_scripts/subsonic.py +166 -0
- navidrome_scripts-0.14.0/navidrome_scripts/tag_repair.py +382 -0
- navidrome_scripts-0.14.0/navidrome_scripts/unmapped.py +317 -0
- navidrome_scripts-0.14.0/navidrome_scripts.egg-info/PKG-INFO +485 -0
- navidrome_scripts-0.14.0/navidrome_scripts.egg-info/SOURCES.txt +46 -0
- navidrome_scripts-0.14.0/navidrome_scripts.egg-info/dependency_links.txt +1 -0
- navidrome_scripts-0.14.0/navidrome_scripts.egg-info/entry_points.txt +11 -0
- navidrome_scripts-0.14.0/navidrome_scripts.egg-info/requires.txt +12 -0
- navidrome_scripts-0.14.0/navidrome_scripts.egg-info/top_level.txt +1 -0
- navidrome_scripts-0.14.0/pyproject.toml +31 -0
- navidrome_scripts-0.14.0/setup.cfg +4 -0
- navidrome_scripts-0.14.0/tests/test_date_evidence.py +170 -0
- navidrome_scripts-0.14.0/tests/test_dates.py +133 -0
- navidrome_scripts-0.14.0/tests/test_duplicates.py +257 -0
- navidrome_scripts-0.14.0/tests/test_filesystem_api.py +98 -0
- navidrome_scripts-0.14.0/tests/test_indexed_duplicates.py +239 -0
- navidrome_scripts-0.14.0/tests/test_library_review.py +85 -0
- navidrome_scripts-0.14.0/tests/test_maintenance.py +149 -0
- navidrome_scripts-0.14.0/tests/test_package.py +12 -0
- navidrome_scripts-0.14.0/tests/test_playlists.py +312 -0
- navidrome_scripts-0.14.0/tests/test_provider_review.py +96 -0
- navidrome_scripts-0.14.0/tests/test_reconciliation.py +149 -0
- navidrome_scripts-0.14.0/tests/test_rename_rollback.py +181 -0
- navidrome_scripts-0.14.0/tests/test_renames.py +265 -0
- navidrome_scripts-0.14.0/tests/test_scan_barrier.py +58 -0
- navidrome_scripts-0.14.0/tests/test_tag_repair.py +234 -0
- navidrome_scripts-0.14.0/tests/test_unmapped.py +245 -0
|
@@ -0,0 +1,485 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: navidrome-scripts
|
|
3
|
+
Version: 0.14.0
|
|
4
|
+
Summary: Navidrome ratings and music library review tools
|
|
5
|
+
Requires-Python: >=3.10
|
|
6
|
+
Description-Content-Type: text/markdown
|
|
7
|
+
Requires-Dist: requests>=2.32
|
|
8
|
+
Requires-Dist: python-dotenv>=1.0
|
|
9
|
+
Requires-Dist: mutagen>=1.47
|
|
10
|
+
Provides-Extra: tags
|
|
11
|
+
Requires-Dist: mediafile>=0.17; extra == "tags"
|
|
12
|
+
Provides-Extra: matching
|
|
13
|
+
Requires-Dist: beets<3,>=2.14.1; extra == "matching"
|
|
14
|
+
Provides-Extra: test
|
|
15
|
+
Requires-Dist: imageio-ffmpeg>=0.6; extra == "test"
|
|
16
|
+
|
|
17
|
+
# navidrome-scripts
|
|
18
|
+
|
|
19
|
+
Tools for Navidrome ratings and music library review.
|
|
20
|
+
|
|
21
|
+
| Command | Purpose |
|
|
22
|
+
| --- | --- |
|
|
23
|
+
| `navidrome-artist-ratings` | Change one artist's tracks from a selected rating to another through the Subsonic API. |
|
|
24
|
+
| `navidrome-library-review` | Review Lidarr unmapped files and optional invalid-date exports without changing the library. |
|
|
25
|
+
| `navidrome-dates` | Audit embedded dates and review reversible date repairs. |
|
|
26
|
+
| `navidrome-playlists` | Match Spotify playlist tracks to your library and update a reviewed Navidrome playlist or export M3U8. |
|
|
27
|
+
| `navidrome-unmapped` | Plan and verify scoped, in-place Lidarr matching; separately review missing catalog additions. |
|
|
28
|
+
| `navidrome-maintenance` | Schedule read-only reviews and process explicitly approved metadata handoffs. |
|
|
29
|
+
| `navidrome-duplicates` | Review duplicate copies, quarantine extras and preserve indexed history. |
|
|
30
|
+
| `navidrome-guard` | Snapshot song identities and personal data, then verify preservation after a new full scan. |
|
|
31
|
+
| `navidrome-renames` | Review album renames and rollback, with backups and Navidrome history checks. |
|
|
32
|
+
| `navidrome-tags` | Review and reversibly fill missing core metadata from an exact Beets/catalog match. |
|
|
33
|
+
|
|
34
|
+
## Install
|
|
35
|
+
|
|
36
|
+
From this checkout:
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
python3 -m venv .venv
|
|
40
|
+
source .venv/bin/activate
|
|
41
|
+
pip install -e .
|
|
42
|
+
cp .env.example .env
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Edit `.env` for the command you want to use. All commands support `--help`.
|
|
46
|
+
Filesystem checks also use Navidrome's native API with the same credentials;
|
|
47
|
+
the base URL must expose `/auth` and `/api`, as well as `/rest`.
|
|
48
|
+
For automation such as arr-scripts, install a released package version and invoke
|
|
49
|
+
its console command; this package does not depend on the other music helpers.
|
|
50
|
+
It has not been published to PyPI yet.
|
|
51
|
+
|
|
52
|
+
## Artist track ratings
|
|
53
|
+
|
|
54
|
+
Accepts an artist name or Navidrome artist ID (`--artist-id` forces ID mode).
|
|
55
|
+
Preview first, then remove `--dry-run` to write ratings:
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
navidrome-artist-ratings --env-file .env --dry-run
|
|
59
|
+
navidrome-artist-ratings --env-file .env --batch-size 100
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Use `--max-albums 2 --batch-size 3` with an artist ID for a small preview.
|
|
63
|
+
Updates are batched; rerunning skips tracks that no longer match `FROM_RATING`.
|
|
64
|
+
Each run writes a timestamped log under `logs/`.
|
|
65
|
+
|
|
66
|
+
## Library review
|
|
67
|
+
|
|
68
|
+
Set `LIDARR_URL` and `LIDARR_API_KEY` in `.env`, then give the local path that
|
|
69
|
+
corresponds to Lidarr's `/music`:
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
navidrome-library-review --library-root /path/to/Music-Library
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Reports are saved as HTML, CSV and JSON under `logs/library-review/`.
|
|
76
|
+
Use `--check-catalog 10` to search MusicBrainz and Apple Music for the first ten
|
|
77
|
+
album groups. Spotify links are manual searches. Existing MusicBrainz IDs and
|
|
78
|
+
search results are candidates to review, not proof of the correct edition.
|
|
79
|
+
|
|
80
|
+
For offline input use `--unmapped-json files.json`. Optional `--date-seeds dates.json`
|
|
81
|
+
includes an offline date-audit export; this command never opens a service database.
|
|
82
|
+
It does not change tags, move files, import albums or submit catalog edits.
|
|
83
|
+
For confirmed MusicBrainz gaps, the separately installed musicbrainz-helper's
|
|
84
|
+
`musicbrainz-new-artist APPLE_ALBUM_URL` prepares editor forms for manual review.
|
|
85
|
+
Ambiguous catalog/import decisions and indexed-copy history migration still require manual review.
|
|
86
|
+
|
|
87
|
+
## Duplicate review
|
|
88
|
+
|
|
89
|
+
Start with one album folder; audit produces JSON plus a readable HTML comparison:
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
navidrome-duplicates --library-root /music audit --path "Artist/Album" --output logs/duplicates.json
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Recording IDs alone do not establish duplicate files. Different encodes, masters,
|
|
96
|
+
editions and tag variations remain for review. No keeper is automatically chosen.
|
|
97
|
+
After reviewing byte-identical copies, choose paths relative to the music root:
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
navidrome-duplicates --library-root /music plan --audit logs/duplicates.json \\
|
|
101
|
+
--keep "Artist/Album/song.flac" --quarantine-file "Artist/Album/copy.flac" \\
|
|
102
|
+
--quarantine-dir /quarantine --navidrome-prefix Music-Library --output logs/quarantine-plan.json
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Use the prefix shown at the start of Navidrome's API paths; omit it when its paths
|
|
106
|
+
are already relative to your music root. Planning needs Lidarr and Navidrome
|
|
107
|
+
credentials. A complete administrator index is checked in pages, retaining only
|
|
108
|
+
selected paths. Active scans, incomplete coverage, multiple libraries, indexed
|
|
109
|
+
copies, mapped duplicates, hardlinks, unique lyrics and local playlist/cue files
|
|
110
|
+
require separate review. The keeper must already be mapped and indexed.
|
|
111
|
+
|
|
112
|
+
Run changes on the server with native library paths while scans/tag writers are
|
|
113
|
+
idle. Review the plan, then quarantine or restore:
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
navidrome-duplicates --library-root /music apply --plan logs/quarantine-plan.json --journal logs/quarantine-run.json
|
|
117
|
+
navidrome-duplicates --library-root /music restore --plan logs/quarantine-plan.json --journal logs/quarantine-run.json
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Quarantine stays outside the library. Copies are hash-verified before their
|
|
121
|
+
original paths are removed; no service records, directories, artwork or sidecars
|
|
122
|
+
are deleted. A changed Navidrome state triggers restoration of original paths when
|
|
123
|
+
possible, with unresolved cases retained for review. Restore never overwrites new
|
|
124
|
+
content and retains quarantine backups. Lidarr may retain missing unmapped rows
|
|
125
|
+
until its next scoped artist rescan. This does not merge indexed song histories.
|
|
126
|
+
|
|
127
|
+
For **already indexed copies**, use the separate reviewed workflow below. It needs
|
|
128
|
+
Navidrome's native `missing fix` command (tested on 0.64.2) and a local/native backup
|
|
129
|
+
directory mapping. `roots.json` maps Navidrome library IDs to local filesystem roots,
|
|
130
|
+
for example `{"1":"/music"}`. `native-command.json` contains an argument array for
|
|
131
|
+
the official CLI, such as `["docker","exec","navidrome","/app/navidrome","--datafolder","/data"]`.
|
|
132
|
+
|
|
133
|
+
```bash
|
|
134
|
+
navidrome-duplicates --library-root /music indexed-plan --roots roots.json --keep-id KEEP_AUDIO_ID --quarantine-id OTHER_ID --native-command native-command.json --backup-root /path/to/navidrome/backups --native-backup-root /data/backups --quarantine-dir /quarantine/reviewed-pair-1 --output logs/indexed-plan.json
|
|
135
|
+
navidrome-duplicates --library-root /music indexed-apply --plan logs/indexed-plan.json --journal logs/indexed-run.json
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
Review `logs/indexed-plan.html` first. The selected audio is kept; the other ID is
|
|
139
|
+
retained by Navidrome's remap and both copies' playlist references follow it.
|
|
140
|
+
Overlapping user annotations/bookmarks and file-backed/smart playlists stay in
|
|
141
|
+
review. Different bytes require `--allow-alternate-encode`; different editions or
|
|
142
|
+
unverified track identities are refused. Backups include all users' private data.
|
|
143
|
+
Keep backups and quarantine outside every music library and source control.
|
|
144
|
+
|
|
145
|
+
After quarantine, complete a full Navidrome scan and repeat `indexed-apply`.
|
|
146
|
+
After remapping, complete another full scan and run `indexed-verify` with the same
|
|
147
|
+
plan/journal. `indexed-restore-files` restores quarantined audio without overwriting
|
|
148
|
+
new files and prints the separate **offline** database-recovery command. It never
|
|
149
|
+
restores the database while Navidrome is running.
|
|
150
|
+
|
|
151
|
+
## Verify Navidrome preservation
|
|
152
|
+
|
|
153
|
+
Capture a baseline before a reviewed repair, using your Navidrome song IDs:
|
|
154
|
+
|
|
155
|
+
```bash
|
|
156
|
+
navidrome-guard capture --song-id SONG_ID --output logs/navidrome-before.json
|
|
157
|
+
# After the repair and a completed full Navidrome scan:
|
|
158
|
+
navidrome-guard verify --snapshot logs/navidrome-before.json
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
This checks the same IDs/paths, ratings/stars, nondecreasing play history and visible
|
|
162
|
+
playlist IDs/ordered membership. It checks only the authenticated account; repeat
|
|
163
|
+
for other users when validating their data. A stale or still-running scan cannot
|
|
164
|
+
prove preservation. For a separately reviewed rename, `--path-map FILE.json` supplies
|
|
165
|
+
an explicit old-path to new-path mapping; the original song IDs must still survive.
|
|
166
|
+
|
|
167
|
+
## Match unmapped files
|
|
168
|
+
|
|
169
|
+
Start with one album folder. These commands use `LIDARR_URL` and `LIDARR_API_KEY`:
|
|
170
|
+
|
|
171
|
+
```bash
|
|
172
|
+
navidrome-unmapped --library-root /path/to/Music-Library plan --path "/music/Artist/Album" --output logs/import-plan.json
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
Review the plan. `ready` files match the exact tagged release, position, title,
|
|
176
|
+
duration and available recording IDs. Conflicting artists/editions, existing track
|
|
177
|
+
files and duplicate copies remain for review. Files must already be in the correct
|
|
178
|
+
Lidarr artist folder. This command will not move files into place.
|
|
179
|
+
|
|
180
|
+
Apply reviewed matches and verify their assignment, original bytes and timestamps:
|
|
181
|
+
|
|
182
|
+
```bash
|
|
183
|
+
navidrome-unmapped --library-root /path/to/Music-Library apply --plan logs/import-plan.json --journal logs/import-run.json
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
Queued commands can be checked by repeating the same command; imports are not
|
|
187
|
+
blindly reissued. Keep the plan and journal. Lidarr's File Date must be `None` and
|
|
188
|
+
tag writing must be `Never` or `For new downloads only`; existing files stay untouched.
|
|
189
|
+
|
|
190
|
+
For `catalog_missing` rows that include a `catalog_proposal`, explicitly run
|
|
191
|
+
`add-catalog --plan logs/import-plan.json --journal logs/catalog-run.json` with the
|
|
192
|
+
same `--library-root`. This only adds an unmonitored album to an existing artist,
|
|
193
|
+
without searching for downloads. After metadata refresh, generate a fresh import
|
|
194
|
+
plan. Excluded catalog entries and mismatched artist IDs are refused.
|
|
195
|
+
|
|
196
|
+
After verified mapping, a `.metadata-queue.json` handoff is saved beside the import
|
|
197
|
+
journal. Existing-file imports do not trigger ordinary download notifications;
|
|
198
|
+
the optional arr-scripts worker processes this handoff only after approval.
|
|
199
|
+
|
|
200
|
+
## Optional maintenance with arr-scripts
|
|
201
|
+
|
|
202
|
+
After publishing/installing the matching package release, set
|
|
203
|
+
`enableLibraryMaintenance="true"` and `navidromeScriptsVersion="X.Y.Z"` in
|
|
204
|
+
arr-scripts' `extended.conf`, then rerun container setup. The default is disabled;
|
|
205
|
+
no unreleased version is automatically installed or enabled.
|
|
206
|
+
|
|
207
|
+
The service generates a read-only unmapped-file report every seven days and
|
|
208
|
+
processes approved jobs one album at a time. Optional full date audits are off by
|
|
209
|
+
default. Review and import one album, then approve its metadata handoff:
|
|
210
|
+
|
|
211
|
+
```bash
|
|
212
|
+
bash /config/extended/LibraryMaintenance.bash --plan "/music/Artist/Album" /config/logs/import-plan.json
|
|
213
|
+
bash /config/extended/LibraryMaintenance.bash --import /config/logs/import-plan.json /config/logs/import-run.json
|
|
214
|
+
bash /config/extended/LibraryMaintenance.bash --approve /config/logs/import-run.metadata-queue.json
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
The worker checks the whole album folder for extra/unmapped audio before work.
|
|
218
|
+
Beets runs as a read-only exact-release preview with a separate scratch library;
|
|
219
|
+
use the separate reviewed `navidrome-tags` workflow below to apply tag changes. Missing
|
|
220
|
+
ReplayGain is repaired and verified, then missing lyrics are enqueued. Lyrics
|
|
221
|
+
completion remains in the lyrics worker; queueing does not mean embedding finished.
|
|
222
|
+
Retries preserve completed steps; settings changes pause incompatible approvals.
|
|
223
|
+
|
|
224
|
+
Logs: `/config/logs/library-maintenance.log`. Reports, approvals, step logs and
|
|
225
|
+
status files: `/config/extended/library-maintenance/`. This does not enable
|
|
226
|
+
MusicBrainz submissions, date repair, file moves or duplicate deletion. Stop other
|
|
227
|
+
tag writers while approving/processing a repair album.
|
|
228
|
+
|
|
229
|
+
## Missing metadata
|
|
230
|
+
|
|
231
|
+
After correcting an existing catalog entry, refresh that album's Lidarr metadata separately:
|
|
232
|
+
|
|
233
|
+
```bash
|
|
234
|
+
navidrome-unmapped --library-root /path/to/Music-Library refresh-plan --album-id 123 --output logs/refresh.json
|
|
235
|
+
# Review refresh.html, then:
|
|
236
|
+
navidrome-unmapped --library-root /path/to/Music-Library refresh --plan logs/refresh.json --journal logs/refresh-journal.json
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
This checks artist/edition identity and backs up mapped audio and sidecars before
|
|
240
|
+
submitting one metadata refresh. Repeat the same command to check a queued result.
|
|
241
|
+
Unknown or stale upstream dates remain for review; nothing invents a date or
|
|
242
|
+
automatically renames files. Lidarr tag writing must be `Never` and File Date `None`.
|
|
243
|
+
|
|
244
|
+
From this checkout, install `pip install -e '.[tags,matching]'`, then preview one mapped
|
|
245
|
+
album. Lidarr audio-tag writing must be `Never` and File Date must be `None`:
|
|
246
|
+
|
|
247
|
+
```bash
|
|
248
|
+
navidrome-tags --library-root /path/to/Music-Library plan --album-id 123 --output logs/tags.json
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
Open `logs/tags.html`. This checks Beets' exact-edition match against MusicBrainz
|
|
252
|
+
track identities and durations, then proposes missing titles, artist credits,
|
|
253
|
+
album names, track/disc numbers and MusicBrainz IDs. Existing values are retained;
|
|
254
|
+
conflicts remain for review. Dates use the separate date workflow below.
|
|
255
|
+
|
|
256
|
+
After review, with other tag writers stopped:
|
|
257
|
+
|
|
258
|
+
```bash
|
|
259
|
+
navidrome-tags --library-root /path/to/Music-Library apply --plan logs/tags.json --journal logs/tags-repair.jsonl
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
Every selected format is tested on a temporary copy before originals are touched.
|
|
263
|
+
Full-file backups and staging need roughly twice the selected files' size in free
|
|
264
|
+
space. Lyrics, artwork, ReplayGain, unrelated tags, paths and modification times
|
|
265
|
+
are checked. Repeat the same command to resume; altered files require review.
|
|
266
|
+
Supported formats are MP3, FLAC, M4A, Opus and Ogg Vorbis.
|
|
267
|
+
|
|
268
|
+
To restore unchanged repaired files exactly:
|
|
269
|
+
|
|
270
|
+
```bash
|
|
271
|
+
navidrome-tags --library-root /path/to/Music-Library rollback --journal logs/tags-repair.jsonl
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
Complete a full Navidrome scan after tags change and before planning any rename.
|
|
275
|
+
Use `navidrome-guard` snapshots to check personal data across the scan.
|
|
276
|
+
|
|
277
|
+
## Invalid dates
|
|
278
|
+
|
|
279
|
+
Audit without changing files, then generate and review a repair plan:
|
|
280
|
+
|
|
281
|
+
```bash
|
|
282
|
+
mkdir -p logs
|
|
283
|
+
navidrome-dates --library-root /path/to/Music-Library audit --output logs/dates.jsonl
|
|
284
|
+
navidrome-dates --library-root /path/to/Music-Library plan --lookup-dates --audit logs/dates.jsonl --output logs/date-plan.json
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
The audit records progress, errors and elapsed time. Review `date-plan.html` beside
|
|
288
|
+
the JSON plan. Exact release and track identities must match before MusicBrainz
|
|
289
|
+
dates can replace invalid values. Edition and original dates stay separate, and
|
|
290
|
+
year-only dates stay year-only. Missing or conflicting evidence remains for review;
|
|
291
|
+
invalid placeholders may be removed without inventing replacements. Omit
|
|
292
|
+
`--lookup-dates` for a removal-only plan. Folder renaming remains separate.
|
|
293
|
+
|
|
294
|
+
Add `--apple-review` to the lookup plan for storefront dates, track-list comparisons
|
|
295
|
+
and links to review the existing MusicBrainz entry (`--country us` selects the
|
|
296
|
+
storefront). These results are context for manual catalog corrections; they never
|
|
297
|
+
authorize a tag replacement themselves. Lookup failures and differing/incomplete
|
|
298
|
+
track lists remain visible. Storefront requests are paced and cached per release.
|
|
299
|
+
|
|
300
|
+
Install `pip install 'navidrome-scripts[tags]'` for replacement dates, then apply the
|
|
301
|
+
reviewed plan while other tag writers are stopped:
|
|
302
|
+
|
|
303
|
+
```bash
|
|
304
|
+
navidrome-dates --library-root /path/to/Music-Library apply --plan logs/date-plan.json --journal logs/date-repair.jsonl
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
This rechecks source evidence, verifies file hashes, tests replacement writes on
|
|
308
|
+
temporary copies, saves full-file backups alongside the journal, checks unrelated
|
|
309
|
+
tags, and preserves modification times. Allow roughly twice the selected files'
|
|
310
|
+
size for backups and staging. Hardlinked files require separate review. Repairs
|
|
311
|
+
share a library lock; repeating the same command skips completed files. An
|
|
312
|
+
interruption during an unconfirmed write requires backup review before continuing.
|
|
313
|
+
|
|
314
|
+
To restore the exact originals, provided files have not changed since repair:
|
|
315
|
+
|
|
316
|
+
```bash
|
|
317
|
+
navidrome-dates --library-root /path/to/Music-Library rollback --journal logs/date-repair.jsonl
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
Keep the plan, journal and backups together. Reconcile incorrect source metadata
|
|
321
|
+
before running another tagger, or it could write the placeholders again. File moves
|
|
322
|
+
and date corrections remain separate operations.
|
|
323
|
+
|
|
324
|
+
## Album folder and filename repairs
|
|
325
|
+
|
|
326
|
+
Correct the album's current Lidarr metadata first. Finish tag repairs and a full
|
|
327
|
+
Navidrome scan before changing paths. Then review one album's proposed names:
|
|
328
|
+
|
|
329
|
+
```bash
|
|
330
|
+
navidrome-renames --library-root /path/to/Music-Library plan --album-id 123 --navidrome-prefix Music-Library --output logs/rename-plan.json
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
Use the prefix shown in Navidrome's native filesystem paths; omit it if paths start directly with
|
|
334
|
+
the artist. Open `logs/rename-plan.html` to review audio, artwork and lyric paths.
|
|
335
|
+
Existing destination folders, extra unmapped audio and local playlist/cue files
|
|
336
|
+
require separate review. Both services' credentials belong in `.env`.
|
|
337
|
+
Use the same library root for repairs and renaming. The helper records completed
|
|
338
|
+
tag writes separately from file mtimes and refuses an older full scan; resume or
|
|
339
|
+
roll back an interrupted repair before renaming.
|
|
340
|
+
|
|
341
|
+
Apply only the reviewed plan, with other writers stopped and enough space for
|
|
342
|
+
full-file backups:
|
|
343
|
+
|
|
344
|
+
```bash
|
|
345
|
+
navidrome-renames --library-root /path/to/Music-Library apply --plan logs/rename-plan.json --journal logs/rename.json
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
This submits one scoped Lidarr command. Repeat that exact command to check a queued
|
|
349
|
+
or interrupted result; it does not submit another rename. Artwork and lyrics follow
|
|
350
|
+
the reviewed paths. Changed contents or timestamps stop the workflow for review.
|
|
351
|
+
Original bytes remain in `rename.json.backups`; the plan records their old paths.
|
|
352
|
+
After a full Navidrome scan, verify the forward rename:
|
|
353
|
+
|
|
354
|
+
```bash
|
|
355
|
+
navidrome-renames --library-root /path/to/Music-Library verify --plan logs/rename-plan.json --journal logs/rename.json
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
To undo a rename, review a rollback plan before restoring paths:
|
|
359
|
+
|
|
360
|
+
```bash
|
|
361
|
+
navidrome-renames --library-root /path/to/Music-Library rollback-plan --plan logs/rename-plan.json --journal logs/rename.json --output logs/rollback-plan.json
|
|
362
|
+
navidrome-renames --library-root /path/to/Music-Library rollback --plan logs/rollback-plan.json --journal logs/rollback.json
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
Open `logs/rollback-plan.html` first. Stop other writers and wait for Lidarr jobs
|
|
366
|
+
to finish. Rollback retains the backups, restores original paths and verifies a
|
|
367
|
+
scoped Lidarr rescan. Changed files stop for review. Repeat the same command to
|
|
368
|
+
resume a queued or interrupted rollback. After a new full Navidrome scan, run:
|
|
369
|
+
|
|
370
|
+
```bash
|
|
371
|
+
navidrome-renames --library-root /path/to/Music-Library rollback-verify --plan logs/rollback-plan.json --journal logs/rollback.json
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
Preservation checks cover the configured account. Other users need their own
|
|
375
|
+
`navidrome-guard` snapshots. A failed verification remains unresolved in the journal.
|
|
376
|
+
|
|
377
|
+
## Spotify playlists
|
|
378
|
+
|
|
379
|
+
Set `NAVIDROME_URL`, `NAVIDROME_USERNAME`, and `NAVIDROME_PASSWORD` in `.env`.
|
|
380
|
+
For Spotify, use a user OAuth access token (`SPOTIFY_ACCESS_TOKEN`) or
|
|
381
|
+
`SPOTIFY_CLIENT_ID` and `SPOTIFY_REFRESH_TOKEN` (plus `SPOTIFY_CLIENT_SECRET`
|
|
382
|
+
for a confidential client). Include `playlist-read-private` for private lists.
|
|
383
|
+
Client credentials alone do not provide user playlist access. Spotify currently
|
|
384
|
+
restricts playlist-item access to lists you own or collaborate on; see the
|
|
385
|
+
[Spotify API documentation](https://developer.spotify.com/documentation/web-api/reference/get-playlists-items).
|
|
386
|
+
|
|
387
|
+
```bash
|
|
388
|
+
navidrome-playlists plan --spotify-playlist PLAYLIST_URL --output logs/playlist-plan.json
|
|
389
|
+
# Review the JSON matches and unresolved items before applying:
|
|
390
|
+
navidrome-playlists apply --plan logs/playlist-plan.json
|
|
391
|
+
```
|
|
392
|
+
|
|
393
|
+
Repeat `plan` with a new output filename and `apply` to sync changes. The saved
|
|
394
|
+
state keeps the same Navidrome playlist ID. Order and repeated tracks are preserved;
|
|
395
|
+
ambiguous copies, unavailable items and missing songs require review. `--allow-partial`
|
|
396
|
+
explicitly permits omitting unresolved items; lookup errors always block updates.
|
|
397
|
+
To update an existing playlist, pass its `--playlist-id` when planning.
|
|
398
|
+
|
|
399
|
+
State, prior playlist contents and refreshed Spotify tokens are stored under
|
|
400
|
+
`logs/spotify-playlists/`; retain this directory between runs and keep it private.
|
|
401
|
+
`--state FILE` and `SPOTIFY_TOKEN_FILE` select separate locations for other accounts.
|
|
402
|
+
Unknown write outcomes remain pending until verified; rerun the same apply command
|
|
403
|
+
to recover rather than deleting state or creating another playlist.
|
|
404
|
+
|
|
405
|
+
For a local playlist, use `navidrome-playlists export --plan logs/playlist-plan.json
|
|
406
|
+
--output playlist.m3u8` (one command). Paths are relative to your music root; place
|
|
407
|
+
the resulting M3U8 there. Export reads Navidrome's native API using the same
|
|
408
|
+
credentials to resolve real filenames; virtual Subsonic paths are not exported.
|
|
409
|
+
`--source-json FILE` can replace `--spotify-playlist` when
|
|
410
|
+
planning from a complete API export. `restore --plan FILE` restores a previously
|
|
411
|
+
existing playlist's contents if nobody has edited it since synchronization.
|
|
412
|
+
|
|
413
|
+
## Validation
|
|
414
|
+
|
|
415
|
+
Install test dependencies with `pip install -e '.[tags,test]'`, then run
|
|
416
|
+
`python -m unittest discover -s tests`. The opt-in `tests/integration_navidrome.py`
|
|
417
|
+
also exercises real scans against an isolated local server: set
|
|
418
|
+
`NAVIDROME_TEST_EXE` to a trusted Navidrome binary and run the script with this
|
|
419
|
+
checkout on `PYTHONPATH`. It generates audio and a temporary database, checks
|
|
420
|
+
ratings/playlists across separate tag and move scans, and stops its own server.
|
|
421
|
+
Production music, accounts and databases are never used by this test.
|
|
422
|
+
|
|
423
|
+
With Docker running, `python tests/run_lidarr_sandbox.py` exercises the full
|
|
424
|
+
Lidarr/Navidrome workflow with generated audio in disposable containers. Results
|
|
425
|
+
go under `logs/nav-fixture-*`; the script removes its test services afterward.
|
|
426
|
+
|
|
427
|
+
## Run as Python modules
|
|
428
|
+
|
|
429
|
+
From the repository root, the same implementations run without console commands
|
|
430
|
+
once their dependencies are installed:
|
|
431
|
+
|
|
432
|
+
```bash
|
|
433
|
+
python -m navidrome_scripts.artist_ratings --help
|
|
434
|
+
python -m navidrome_scripts.library_review --help
|
|
435
|
+
python -m navidrome_scripts.dates --help
|
|
436
|
+
python -m navidrome_scripts.playlists --help
|
|
437
|
+
python -m navidrome_scripts.unmapped --help
|
|
438
|
+
python -m navidrome_scripts.maintenance --help
|
|
439
|
+
python -m navidrome_scripts.duplicates --help
|
|
440
|
+
python -m navidrome_scripts.navidrome_guard --help
|
|
441
|
+
python -m navidrome_scripts.renames --help
|
|
442
|
+
python -m navidrome_scripts.tag_repair --help
|
|
443
|
+
```
|
|
444
|
+
|
|
445
|
+
## Docker
|
|
446
|
+
|
|
447
|
+
```bash
|
|
448
|
+
docker build -t navidrome-scripts .
|
|
449
|
+
mkdir -p logs
|
|
450
|
+
docker run --rm --env-file .env \
|
|
451
|
+
-v /path/to/Music-Library:/music:ro -v "$PWD/logs:/work/logs" \
|
|
452
|
+
navidrome-scripts --library-root /music
|
|
453
|
+
```
|
|
454
|
+
|
|
455
|
+
Use a Lidarr URL reachable from the container; `localhost` refers to the container.
|
|
456
|
+
To run the ratings command instead, use `--entrypoint navidrome-artist-ratings`
|
|
457
|
+
before the image name, followed by `--dry-run` or other ratings options.
|
|
458
|
+
|
|
459
|
+
## .env support and auth methods
|
|
460
|
+
|
|
461
|
+
The script can load defaults from a `.env` file. Either pass `--env-file` or
|
|
462
|
+
place a `.env` in the working directory. CLI args override environment values.
|
|
463
|
+
|
|
464
|
+
Supported variables:
|
|
465
|
+
|
|
466
|
+
- `BASE_URL` - Navidrome base URL
|
|
467
|
+
- `USERNAME` - Navidrome/Subsonic username
|
|
468
|
+
- `PASSWORD` - Navidrome/Subsonic password
|
|
469
|
+
- `TOKEN` or `API_TOKEN` - optional Subsonic JWT token if your setup exposes one
|
|
470
|
+
- `ARTIST` - artist name or internal artist id
|
|
471
|
+
- `FROM_RATING` - default source rating (default 5)
|
|
472
|
+
- `TO_RATING` - default destination rating (default 2)
|
|
473
|
+
|
|
474
|
+
Example `.env`:
|
|
475
|
+
|
|
476
|
+
```env
|
|
477
|
+
BASE_URL=http://localhost:4533
|
|
478
|
+
USERNAME=your_username
|
|
479
|
+
PASSWORD=your_password
|
|
480
|
+
ARTIST=3Lu5a2hhygk22VnEcfKkwY
|
|
481
|
+
FROM_RATING=5
|
|
482
|
+
TO_RATING=2
|
|
483
|
+
```
|
|
484
|
+
|
|
485
|
+
The script prefers `PASSWORD` when both password and token are provided.
|