diglibrary 1.1.1__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.
Potentially problematic release.
This version of diglibrary might be problematic. Click here for more details.
- diglibrary-1.1.1/LICENSE +21 -0
- diglibrary-1.1.1/PKG-INFO +452 -0
- diglibrary-1.1.1/README.md +418 -0
- diglibrary-1.1.1/pyproject.toml +115 -0
- diglibrary-1.1.1/setup.cfg +4 -0
- diglibrary-1.1.1/src/diglibrary/__init__.py +5 -0
- diglibrary-1.1.1/src/diglibrary/__main__.py +107 -0
- diglibrary-1.1.1/src/diglibrary/application/__init__.py +1 -0
- diglibrary-1.1.1/src/diglibrary/application/acoustic.py +289 -0
- diglibrary-1.1.1/src/diglibrary/application/api.py +10060 -0
- diglibrary-1.1.1/src/diglibrary/application/artwork.py +542 -0
- diglibrary-1.1.1/src/diglibrary/application/bench.py +559 -0
- diglibrary-1.1.1/src/diglibrary/application/composition.py +625 -0
- diglibrary-1.1.1/src/diglibrary/application/contracts.py +224 -0
- diglibrary-1.1.1/src/diglibrary/application/identification.py +1636 -0
- diglibrary-1.1.1/src/diglibrary/application/quality.py +421 -0
- diglibrary-1.1.1/src/diglibrary/cachedir.py +141 -0
- diglibrary-1.1.1/src/diglibrary/config/__init__.py +6 -0
- diglibrary-1.1.1/src/diglibrary/config/credentials.py +118 -0
- diglibrary-1.1.1/src/diglibrary/config/default.toml +113 -0
- diglibrary-1.1.1/src/diglibrary/config/home.py +81 -0
- diglibrary-1.1.1/src/diglibrary/config/loader.py +319 -0
- diglibrary-1.1.1/src/diglibrary/config/models.py +111 -0
- diglibrary-1.1.1/src/diglibrary/connectors/__init__.py +36 -0
- diglibrary-1.1.1/src/diglibrary/connectors/contracts.py +155 -0
- diglibrary-1.1.1/src/diglibrary/connectors/models.py +471 -0
- diglibrary-1.1.1/src/diglibrary/connectors/slskd/__init__.py +21 -0
- diglibrary-1.1.1/src/diglibrary/connectors/slskd/client.py +584 -0
- diglibrary-1.1.1/src/diglibrary/connectors/slskd/configuration.py +76 -0
- diglibrary-1.1.1/src/diglibrary/connectors/slskd/connector.py +307 -0
- diglibrary-1.1.1/src/diglibrary/connectors/slskd/exceptions.py +239 -0
- diglibrary-1.1.1/src/diglibrary/connectors/slskd/mapper.py +343 -0
- diglibrary-1.1.1/src/diglibrary/connectors/slskd/models.py +46 -0
- diglibrary-1.1.1/src/diglibrary/database/__init__.py +6 -0
- diglibrary-1.1.1/src/diglibrary/database/connection.py +232 -0
- diglibrary-1.1.1/src/diglibrary/database/copies.py +324 -0
- diglibrary-1.1.1/src/diglibrary/database/library_store.py +2790 -0
- diglibrary-1.1.1/src/diglibrary/database/migrations.py +1133 -0
- diglibrary-1.1.1/src/diglibrary/database/repositories.py +41 -0
- diglibrary-1.1.1/src/diglibrary/database/serialization.py +163 -0
- diglibrary-1.1.1/src/diglibrary/desktop/__init__.py +15 -0
- diglibrary-1.1.1/src/diglibrary/desktop/bundle.py +161 -0
- diglibrary-1.1.1/src/diglibrary/desktop/icon.py +215 -0
- diglibrary-1.1.1/src/diglibrary/desktop/restore.py +83 -0
- diglibrary-1.1.1/src/diglibrary/engines/__init__.py +21 -0
- diglibrary-1.1.1/src/diglibrary/engines/contracts.py +61 -0
- diglibrary-1.1.1/src/diglibrary/harmonic/__init__.py +0 -0
- diglibrary-1.1.1/src/diglibrary/harmonic/analyzer.py +154 -0
- diglibrary-1.1.1/src/diglibrary/harmonic/keys.py +161 -0
- diglibrary-1.1.1/src/diglibrary/harmonic/mixing.py +100 -0
- diglibrary-1.1.1/src/diglibrary/harmonic/tempo.py +132 -0
- diglibrary-1.1.1/src/diglibrary/identity.py +17 -0
- diglibrary-1.1.1/src/diglibrary/library/__init__.py +50 -0
- diglibrary-1.1.1/src/diglibrary/library/artwork.py +653 -0
- diglibrary-1.1.1/src/diglibrary/library/atomicwrite.py +120 -0
- diglibrary-1.1.1/src/diglibrary/library/audio.py +84 -0
- diglibrary-1.1.1/src/diglibrary/library/audio_key.py +212 -0
- diglibrary-1.1.1/src/diglibrary/library/containers.py +191 -0
- diglibrary-1.1.1/src/diglibrary/library/executor.py +810 -0
- diglibrary-1.1.1/src/diglibrary/library/extras.py +184 -0
- diglibrary-1.1.1/src/diglibrary/library/fingerprint.py +147 -0
- diglibrary-1.1.1/src/diglibrary/library/hints.py +630 -0
- diglibrary-1.1.1/src/diglibrary/library/integrity.py +246 -0
- diglibrary-1.1.1/src/diglibrary/library/matching.py +1918 -0
- diglibrary-1.1.1/src/diglibrary/library/medleys.py +211 -0
- diglibrary-1.1.1/src/diglibrary/library/models.py +90 -0
- diglibrary-1.1.1/src/diglibrary/library/naming.py +1140 -0
- diglibrary-1.1.1/src/diglibrary/library/planner.py +1113 -0
- diglibrary-1.1.1/src/diglibrary/library/report.py +309 -0
- diglibrary-1.1.1/src/diglibrary/library/scanner.py +416 -0
- diglibrary-1.1.1/src/diglibrary/library/series.py +255 -0
- diglibrary-1.1.1/src/diglibrary/library/signature.py +56 -0
- diglibrary-1.1.1/src/diglibrary/library/spelling.py +202 -0
- diglibrary-1.1.1/src/diglibrary/library/tagrelease.py +329 -0
- diglibrary-1.1.1/src/diglibrary/library/tags.py +320 -0
- diglibrary-1.1.1/src/diglibrary/library/xattrs.py +194 -0
- diglibrary-1.1.1/src/diglibrary/logging/__init__.py +5 -0
- diglibrary-1.1.1/src/diglibrary/logging/setup.py +132 -0
- diglibrary-1.1.1/src/diglibrary/metadata/__init__.py +27 -0
- diglibrary-1.1.1/src/diglibrary/metadata/acoustid.py +148 -0
- diglibrary-1.1.1/src/diglibrary/metadata/authentication.py +54 -0
- diglibrary-1.1.1/src/diglibrary/metadata/cache.py +111 -0
- diglibrary-1.1.1/src/diglibrary/metadata/coverart.py +207 -0
- diglibrary-1.1.1/src/diglibrary/metadata/discogs.py +309 -0
- diglibrary-1.1.1/src/diglibrary/metadata/itunes.py +314 -0
- diglibrary-1.1.1/src/diglibrary/metadata/matching.py +24 -0
- diglibrary-1.1.1/src/diglibrary/metadata/models.py +21 -0
- diglibrary-1.1.1/src/diglibrary/metadata/musicbrainz.py +304 -0
- diglibrary-1.1.1/src/diglibrary/metadata/normalization.py +105 -0
- diglibrary-1.1.1/src/diglibrary/metadata/rate_limit.py +32 -0
- diglibrary-1.1.1/src/diglibrary/metadata/retry.py +69 -0
- diglibrary-1.1.1/src/diglibrary/metadata/service.py +187 -0
- diglibrary-1.1.1/src/diglibrary/metadata/spotify.py +284 -0
- diglibrary-1.1.1/src/diglibrary/metadata/transport.py +181 -0
- diglibrary-1.1.1/src/diglibrary/providers/__init__.py +5 -0
- diglibrary-1.1.1/src/diglibrary/providers/capabilities.py +25 -0
- diglibrary-1.1.1/src/diglibrary/providers/contracts.py +55 -0
- diglibrary-1.1.1/src/diglibrary/providers/manager.py +229 -0
- diglibrary-1.1.1/src/diglibrary/providers/models.py +162 -0
- diglibrary-1.1.1/src/diglibrary/providers/registry.py +65 -0
- diglibrary-1.1.1/src/diglibrary/providers/soulseek.py +394 -0
- diglibrary-1.1.1/src/diglibrary/providers/types.py +30 -0
- diglibrary-1.1.1/src/diglibrary/quality/__init__.py +41 -0
- diglibrary-1.1.1/src/diglibrary/quality/analysis.py +399 -0
- diglibrary-1.1.1/src/diglibrary/quality/confidence.py +199 -0
- diglibrary-1.1.1/src/diglibrary/quality/models.py +391 -0
- diglibrary-1.1.1/src/diglibrary/quality/spectrogram.py +276 -0
- diglibrary-1.1.1/src/diglibrary/quality/verdict.py +578 -0
- diglibrary-1.1.1/src/diglibrary/ui/__init__.py +1 -0
- diglibrary-1.1.1/src/diglibrary/ui/app.py +245 -0
- diglibrary-1.1.1/src/diglibrary/ui/audio.py +314 -0
- diglibrary-1.1.1/src/diglibrary/ui/drops.py +95 -0
- diglibrary-1.1.1/src/diglibrary/ui/folders.py +108 -0
- diglibrary-1.1.1/src/diglibrary/ui/wakefulness.py +83 -0
- diglibrary-1.1.1/src/diglibrary/ui/web/app.js +10845 -0
- diglibrary-1.1.1/src/diglibrary/ui/web/index.html +1183 -0
- diglibrary-1.1.1/src/diglibrary/ui/web/strings.js +1805 -0
- diglibrary-1.1.1/src/diglibrary/ui/web/styles.css +3829 -0
- diglibrary-1.1.1/src/diglibrary.egg-info/PKG-INFO +452 -0
- diglibrary-1.1.1/src/diglibrary.egg-info/SOURCES.txt +123 -0
- diglibrary-1.1.1/src/diglibrary.egg-info/dependency_links.txt +1 -0
- diglibrary-1.1.1/src/diglibrary.egg-info/entry_points.txt +2 -0
- diglibrary-1.1.1/src/diglibrary.egg-info/requires.txt +10 -0
- diglibrary-1.1.1/src/diglibrary.egg-info/top_level.txt +1 -0
- diglibrary-1.1.1/tests/test_cachedir.py +99 -0
diglibrary-1.1.1/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Luan Barreto
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,452 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: diglibrary
|
|
3
|
+
Version: 1.1.1
|
|
4
|
+
Summary: Identify your albums, find out whether a FLAC is really lossless, and rename and tag them reversibly.
|
|
5
|
+
Author: DigLibrary Contributors
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/cankblunt/diglibrary
|
|
8
|
+
Project-URL: Changelog, https://github.com/cankblunt/diglibrary/blob/main/CHANGELOG.md
|
|
9
|
+
Project-URL: Issues, https://github.com/cankblunt/diglibrary/issues
|
|
10
|
+
Project-URL: Decision records, https://github.com/cankblunt/diglibrary/tree/main/ADR
|
|
11
|
+
Keywords: music,flac,lossless,audio-quality,spectrogram,metadata,tagging,discogs,musicbrainz,acoustid,dj,rekordbox,serato,playlist,library
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Environment :: MacOS X
|
|
14
|
+
Classifier: Intended Audience :: End Users/Desktop
|
|
15
|
+
Classifier: Natural Language :: English
|
|
16
|
+
Classifier: Operating System :: MacOS :: MacOS X
|
|
17
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Topic :: Multimedia :: Sound/Audio
|
|
20
|
+
Classifier: Topic :: Multimedia :: Sound/Audio :: Analysis
|
|
21
|
+
Requires-Python: >=3.12
|
|
22
|
+
Description-Content-Type: text/markdown
|
|
23
|
+
License-File: LICENSE
|
|
24
|
+
Requires-Dist: mutagen>=1.47
|
|
25
|
+
Requires-Dist: pywebview>=5.0
|
|
26
|
+
Requires-Dist: numpy>=2.0
|
|
27
|
+
Provides-Extra: dev
|
|
28
|
+
Requires-Dist: black>=26.0.0; extra == "dev"
|
|
29
|
+
Requires-Dist: build>=1.3.0; extra == "dev"
|
|
30
|
+
Requires-Dist: coverage>=7.13.0; extra == "dev"
|
|
31
|
+
Requires-Dist: pytest>=9.0.0; extra == "dev"
|
|
32
|
+
Requires-Dist: ruff>=0.15.0; extra == "dev"
|
|
33
|
+
Dynamic: license-file
|
|
34
|
+
|
|
35
|
+
# DigLibrary
|
|
36
|
+
|
|
37
|
+
**🇧🇷 Em português: [LEIAME.md](https://github.com/cankblunt/diglibrary/blob/v1.1.1/LEIAME.md)** — mesmo conteúdo, passo a passo.
|
|
38
|
+
|
|
39
|
+
A desktop application that answers one question about a music collection:
|
|
40
|
+
**what is this album, and is this copy of it any good?**
|
|
41
|
+
|
|
42
|
+
It reads the folders you point it at, identifies each album against Discogs and
|
|
43
|
+
MusicBrainz, measures the audio to find out whether a `.flac` is really lossless,
|
|
44
|
+
and proposes a rename — which you approve, edit, or reject. Nothing is written
|
|
45
|
+
until you say so, and everything written can be reverted.
|
|
46
|
+
|
|
47
|
+
It runs on your machine, against your own accounts. There is no service behind
|
|
48
|
+
it, and nothing leaves your computer except the catalogue lookups you can see.
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## What it does
|
|
53
|
+
|
|
54
|
+
**Identifies albums.** Names and tags are read off the folder and matched
|
|
55
|
+
against Discogs and MusicBrainz, with iTunes as a witness that is shown to you
|
|
56
|
+
and never contributes a written value. When the names are not enough, the audio
|
|
57
|
+
itself is fingerprinted with Chromaprint and looked up on AcoustID.
|
|
58
|
+
|
|
59
|
+
**Measures what the audio actually is.** A `.flac` transcoded from a 128 kbps
|
|
60
|
+
MP3 is still a `.flac` to every other tool. DigLibrary decodes each track, finds
|
|
61
|
+
where the high frequencies stop, and says so — in the folder name if you want it
|
|
62
|
+
there, and in a spectrogram you can look at yourself. `Analyze in depth` reads
|
|
63
|
+
the whole file across fourteen probes when one album deserves the argument.
|
|
64
|
+
|
|
65
|
+
**Renames and tags, reversibly.** Every run is a plan you read before it
|
|
66
|
+
happens, shown as `now → after`, with every name editable — your word outranks
|
|
67
|
+
the catalogue. Files are written on a copy and moved into place, so an
|
|
68
|
+
interrupted write cannot leave a half-made file.
|
|
69
|
+
|
|
70
|
+
**And the reversal is rehearsed before it starts.** Every applied run is in
|
|
71
|
+
History with a `Revert`, which walks the whole undo first and refuses the lot if
|
|
72
|
+
any step of it cannot be taken — a reversal that stops halfway is worse than one
|
|
73
|
+
that never began. It also finds the album if you have filed it away somewhere
|
|
74
|
+
else since, and asks before writing outside the folder it organized.
|
|
75
|
+
|
|
76
|
+
**Finds music,** optionally, over your own [slskd](https://github.com/slskd/slskd)
|
|
77
|
+
instance on the Soulseek network. It is the only acquisition provider, and it
|
|
78
|
+
does nothing until you point it at an slskd you run yourself, with an API key.
|
|
79
|
+
Downloads are followed in **Transfers**, and an album joins the library when
|
|
80
|
+
every file of it has arrived — one file of fourteen is not an album.
|
|
81
|
+
|
|
82
|
+
**Measures key and tempo, and lays them on the Camelot wheel.** The Mixing
|
|
83
|
+
screen shows the tracks you have asked it to measure, with the key, the tempo
|
|
84
|
+
and how sure it is of each — never a track it has not measured.
|
|
85
|
+
|
|
86
|
+
**Plays what you are looking at.** A ▶ on the sleeve queues the album in its own
|
|
87
|
+
track order, in a bar that is simply always there. Rate a record out of five on
|
|
88
|
+
its sleeve, sort and filter the shelf by that, and give an album a cover when
|
|
89
|
+
the archive has none.
|
|
90
|
+
|
|
91
|
+
**Keeps the lists you build.** A queue can be saved under a name, opened again,
|
|
92
|
+
and exported as an `.m3u8` that Rekordbox and Serato import. **Nothing is ever
|
|
93
|
+
written into either application** — DigLibrary writes a file and you import it
|
|
94
|
+
yourself. A list points at recordings rather than at paths, so organizing an
|
|
95
|
+
album or filing it somewhere else does not break it; a track whose file has gone
|
|
96
|
+
stays in the list, marked, until it comes back.
|
|
97
|
+
|
|
98
|
+
**Never invents metadata.** An album it cannot identify with confidence is left
|
|
99
|
+
untouched and sent to review with the reason why. It never touches a Rekordbox
|
|
100
|
+
database.
|
|
101
|
+
|
|
102
|
+
### The six screens
|
|
103
|
+
|
|
104
|
+
| | |
|
|
105
|
+
|---|---|
|
|
106
|
+
| **Library** | Your shelf, as cards or as a list: identify, plan, apply, rate, play. |
|
|
107
|
+
| **Find music** | Search Soulseek through your own slskd and ask for what you find. |
|
|
108
|
+
| **Transfers** | What is downloading, what arrived whole, and what stopped short. |
|
|
109
|
+
| **Quality** | The bench: what a file really is, with a spectrogram and a verdict. |
|
|
110
|
+
| **Mixing** | Key, tempo and the Camelot wheel over the tracks you have measured. |
|
|
111
|
+
| **History** | Every run that wrote to your files, each with a `Revert`. |
|
|
112
|
+
|
|
113
|
+
---
|
|
114
|
+
|
|
115
|
+
## Requirements
|
|
116
|
+
|
|
117
|
+
| What | Why | How |
|
|
118
|
+
|---|---|---|
|
|
119
|
+
| **macOS 12 or later** | Windows and Linux are not supported yet — the folder panel, the stay-awake call during downloads, and the app bundle are macOS | — |
|
|
120
|
+
| **Python 3.12 or later** | The application is Python | `brew install python`, or the [python.org](https://www.python.org/downloads/) installer |
|
|
121
|
+
| **ffmpeg** | Measures audio and draws spectrograms. Without it the application still runs, and the Quality screen says plainly that it cannot measure | `brew install ffmpeg` |
|
|
122
|
+
| **chromaprint** *(optional)* | Audio fingerprinting, for identifying albums by sound | `brew install chromaprint` |
|
|
123
|
+
| **[slskd](https://github.com/slskd/slskd)** *(optional)* | Only for the Find music screen — downloads over Soulseek, which also needs a free Soulseek account | slskd's own docs |
|
|
124
|
+
|
|
125
|
+
If you don't have Homebrew: [brew.sh](https://brew.sh).
|
|
126
|
+
|
|
127
|
+
---
|
|
128
|
+
|
|
129
|
+
## Getting started, step by step
|
|
130
|
+
|
|
131
|
+

|
|
132
|
+
|
|
133
|
+
**You do not need to know how to program.** You do need to type a few lines into
|
|
134
|
+
an application called Terminal, which comes with every Mac. Each step below is
|
|
135
|
+
one line: copy it, paste it, press Return, wait for it to finish. About fifteen
|
|
136
|
+
minutes in total, and steps 1 and 2 are done once and never again.
|
|
137
|
+
|
|
138
|
+
> **Opening Terminal:** press `⌘ Space`, type `terminal`, press Return. A window
|
|
139
|
+
> with text in it appears. That is the whole tool.
|
|
140
|
+
|
|
141
|
+
### 1. Install Homebrew
|
|
142
|
+
|
|
143
|
+
Homebrew is what installs the two things DigLibrary needs. Skip this if you
|
|
144
|
+
already have it (type `brew --version` and see whether it answers).
|
|
145
|
+
|
|
146
|
+
```bash
|
|
147
|
+
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
It will ask for your Mac password — it needs it to install, and it is your own
|
|
151
|
+
Mac asking. Nothing here ever asks for a password for anything else. When it
|
|
152
|
+
finishes it prints two more lines for you to run; run them.
|
|
153
|
+
|
|
154
|
+
### 2. Install Python and ffmpeg
|
|
155
|
+
|
|
156
|
+
```bash
|
|
157
|
+
brew install python ffmpeg
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
Optional, and worth it if you have albums whose names say nothing:
|
|
161
|
+
|
|
162
|
+
```bash
|
|
163
|
+
brew install chromaprint
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
### 3. Download DigLibrary and unpack it
|
|
167
|
+
|
|
168
|
+
Download the ZIP from the
|
|
169
|
+
[latest release](https://github.com/cankblunt/diglibrary/releases/latest) and
|
|
170
|
+
double-click it. You get a folder called something like `diglibrary-1.1.1`,
|
|
171
|
+
normally in **Downloads**. Leave it there or move it wherever you keep things —
|
|
172
|
+
just remember where.
|
|
173
|
+
|
|
174
|
+
### 4. Point the Terminal at that folder
|
|
175
|
+
|
|
176
|
+
Type `cd` and a space, then **drag the folder from Finder onto the Terminal
|
|
177
|
+
window** — it writes the path for you — then press Return.
|
|
178
|
+
|
|
179
|
+
```bash
|
|
180
|
+
cd ~/Downloads/diglibrary-1.1.1
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
### 5. Make a place for it to live
|
|
184
|
+
|
|
185
|
+
```bash
|
|
186
|
+
python3 -m venv .venv
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
This makes a folder called `.venv` inside it, so DigLibrary's parts stay
|
|
190
|
+
together and touch nothing else on your Mac. Nothing is printed. That is normal.
|
|
191
|
+
|
|
192
|
+
### 6. Install it
|
|
193
|
+
|
|
194
|
+
```bash
|
|
195
|
+
.venv/bin/python -m pip install -e .
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
A minute of scrolling text, ending in `Successfully installed diglibrary-…`.
|
|
199
|
+
That line is how you know it worked.
|
|
200
|
+
|
|
201
|
+
### 7. Open it
|
|
202
|
+
|
|
203
|
+
```bash
|
|
204
|
+
.venv/bin/python -m diglibrary
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+

|
|
208
|
+
|
|
209
|
+
Steps 4 to 7, as they actually run — recorded from a real install of this
|
|
210
|
+
release, at its own speed:
|
|
211
|
+
|
|
212
|
+

|
|
213
|
+
|
|
214
|
+
The window opens. **Leave the Terminal open while you use the app** — closing it
|
|
215
|
+
closes DigLibrary. From now on, opening DigLibrary again is steps 4 and 7: point
|
|
216
|
+
the Terminal at the folder, run that one line.
|
|
217
|
+
|
|
218
|
+
### 8. Optional: an icon in the Dock
|
|
219
|
+
|
|
220
|
+
```bash
|
|
221
|
+
.venv/bin/diglibrary make-icon
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
That builds `~/Applications/DigLibrary.app`, which opens the app without the
|
|
225
|
+
Terminal. It points at **this** folder rather than being a copy of the program,
|
|
226
|
+
so it works only on this Mac and only while the folder stays where it is. Do not
|
|
227
|
+
send it to anyone — on their machine it opens nothing. They install from source,
|
|
228
|
+
the same way you just did.
|
|
229
|
+
|
|
230
|
+
### What you see the first time
|
|
231
|
+
|
|
232
|
+
A window offers you two optional services and lets you skip both. Then: press
|
|
233
|
+
**Choose a folder**, pick a folder of albums, press **Scan**. Nothing is written
|
|
234
|
+
to your files until you read a plan and press Apply — and everything that is
|
|
235
|
+
written can be undone from **History**.
|
|
236
|
+
|
|
237
|
+
**The Library**, where your records live. The sleeves are blank here because a
|
|
238
|
+
fresh scan has not fetched any cover art yet — that comes with the first
|
|
239
|
+
identification.
|
|
240
|
+
|
|
241
|
+

|
|
242
|
+
|
|
243
|
+
**Mixing**, for DJs: the key and the tempo of the tracks you asked it to
|
|
244
|
+
measure, laid around the Camelot wheel.
|
|
245
|
+
|
|
246
|
+

|
|
247
|
+
|
|
248
|
+
### When something goes wrong
|
|
249
|
+
|
|
250
|
+
| What it says | What it means |
|
|
251
|
+
|---|---|
|
|
252
|
+
| `command not found: brew` | Step 1 did not finish. Run the two lines Homebrew printed at the end. |
|
|
253
|
+
| `command not found: python3` | Step 2 did not finish, or the Terminal was open before it. Close the Terminal, open it again. |
|
|
254
|
+
| `no such file or directory` after `cd` | The Terminal is not in the right folder. Redo step 4 with the drag trick. |
|
|
255
|
+
| The Quality screen says it cannot measure | `ffmpeg` is missing — step 2. |
|
|
256
|
+
| Something else | Open an [issue](https://github.com/cankblunt/diglibrary/issues) and paste what the Terminal said. |
|
|
257
|
+
|
|
258
|
+
---
|
|
259
|
+
|
|
260
|
+
## Where DigLibrary keeps your things
|
|
261
|
+
|
|
262
|
+
The first run writes `~/.diglibrary/config.toml` and keeps everything beside it
|
|
263
|
+
— the database, the logs, the caches and the backups. **One folder to back up,
|
|
264
|
+
one folder to delete.** Your music is never moved there; DigLibrary only ever
|
|
265
|
+
writes inside the folders you point it at, and only after you approve a plan.
|
|
266
|
+
|
|
267
|
+
## What all these files are
|
|
268
|
+
|
|
269
|
+
The download is the program's own source code, so most of what is in it is for
|
|
270
|
+
people changing DigLibrary rather than using it. **You can ignore all of it.**
|
|
271
|
+
|
|
272
|
+
| | |
|
|
273
|
+
|---|---|
|
|
274
|
+
| `README.md` / `LEIAME.md` | This page. The only two files here written for you. |
|
|
275
|
+
| `CHANGELOG.md` | What changed in each version. |
|
|
276
|
+
| `src/` | The program itself. |
|
|
277
|
+
| `tests/`, `tools/`, `docs/`, `ADR/` | For people who work on DigLibrary: its test suite, its scripts, its documentation, and the record of every decision ever taken about it. |
|
|
278
|
+
| `CLAUDE.md` | The working agreement for anyone — person or AI — changing this code: the rules it may not break, such as never touching your Rekordbox database. Not a document about using the app. |
|
|
279
|
+
| `pyproject.toml`, `LICENSE` | How Python installs it, and the licence (MIT). |
|
|
280
|
+
|
|
281
|
+
**Why `.md` and not `.txt` or `.docx`?** A `.md` file *is* a plain text file —
|
|
282
|
+
double-click it and TextEdit opens it, no special program needed. The difference
|
|
283
|
+
is that GitHub renders it with headings and tables, which a `.txt` does not get,
|
|
284
|
+
and unlike a `.docx` it needs no Word, weighs nothing, and can be read on any
|
|
285
|
+
machine ever made.
|
|
286
|
+
|
|
287
|
+
A `config.toml` in the directory you run from wins over that one, and everything
|
|
288
|
+
it names is resolved beside *it*. That is how a checkout keeps its own
|
|
289
|
+
installation; it is not how a clone starts, because this repository ships no
|
|
290
|
+
`config.toml` of its own.
|
|
291
|
+
|
|
292
|
+
For an icon in the Dock:
|
|
293
|
+
|
|
294
|
+
```bash
|
|
295
|
+
.venv/bin/diglibrary make-icon
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
That builds `~/Applications/DigLibrary.app`. It is a bundle pointing at **your
|
|
299
|
+
own** checkout rather than a self-contained build: it launches the code as it
|
|
300
|
+
stands, so there is nothing to rebuild after an edit — and for the same reason
|
|
301
|
+
it cannot be copied to another machine, where it would launch nothing. Install
|
|
302
|
+
from source there instead.
|
|
303
|
+
|
|
304
|
+
### Two local ports, while the app is open
|
|
305
|
+
|
|
306
|
+
Both are bound to `127.0.0.1`, neither is reachable from your network, and both
|
|
307
|
+
stop when the application does.
|
|
308
|
+
|
|
309
|
+
**The audio port.** Playing a track needs a URL, so the application serves audio
|
|
310
|
+
to its own window. It hands out only files you have opened in the app, it never
|
|
311
|
+
accepts a path — a request names an opaque id — and every request carries a
|
|
312
|
+
token minted fresh each run. A request without the token gets the same answer as
|
|
313
|
+
a request for something that does not exist, so the port cannot be used to ask
|
|
314
|
+
whether your library holds a given album.
|
|
315
|
+
|
|
316
|
+
**The window port.** The interface is HTML, and its script is an ES module,
|
|
317
|
+
which a browser engine refuses to load from a `file://` address. So pywebview
|
|
318
|
+
serves the four files of the window itself. That directory is all it serves.
|
|
319
|
+
|
|
320
|
+
### What leaves your machine
|
|
321
|
+
|
|
322
|
+
Only what is needed to identify an album, and only when you ask:
|
|
323
|
+
|
|
324
|
+
- **Album and track names, durations and any barcode** go to MusicBrainz, and to
|
|
325
|
+
Discogs and iTunes when those are switched on, to find which release you have.
|
|
326
|
+
- **An acoustic fingerprint** — a compact summary of the sound, not the audio —
|
|
327
|
+
goes to AcoustID, and only if you installed `chromaprint` and supplied a key.
|
|
328
|
+
The audio itself is never uploaded.
|
|
329
|
+
- **Nothing else.** No telemetry, no crash reporting, no analytics, no account.
|
|
330
|
+
Your library never leaves the machine, and neither does the database.
|
|
331
|
+
|
|
332
|
+
The log at `logs/diglibrary.jsonl` stays local and records the full path of
|
|
333
|
+
folders it worked on, so read it before attaching it to a bug report.
|
|
334
|
+
|
|
335
|
+
## Credentials — none are required
|
|
336
|
+
|
|
337
|
+
**It works with nothing configured.** Albums are identified against MusicBrainz,
|
|
338
|
+
covers come from the Cover Art Archive, iTunes is asked as a witness, and every
|
|
339
|
+
audio measurement happens on your own machine. The first time you open it, a
|
|
340
|
+
window says so and offers the optional services below; you can skip it and
|
|
341
|
+
connect them later from Settings.
|
|
342
|
+
|
|
343
|
+
DigLibrary ships **no API keys**. An open-source desktop application cannot keep
|
|
344
|
+
a secret, so the two optional ones are keys you create and hold yourself. Paste
|
|
345
|
+
them into that window and they are written to `~/.diglibrary/env`, readable only
|
|
346
|
+
by you — never into `config.toml`, never into a log, and never read back out to
|
|
347
|
+
the window, which is only ever told *whether* a service is connected.
|
|
348
|
+
|
|
349
|
+
| Service | What it adds | Needed? |
|
|
350
|
+
|---|---|---|
|
|
351
|
+
| **Discogs** | Matches get much better, especially for catalogues outside the US and UK, where Discogs is often the only source listing the pressing you actually have. [Create a token](https://www.discogs.com/settings/developers). | Optional, and the one worth doing |
|
|
352
|
+
| **AcoustID** | Identifies an album by the sound of the audio when the names say nothing useful. Also needs `chromaprint`. [Register an application](https://acoustid.org/new-application). | Optional |
|
|
353
|
+
| **slskd** | Your own slskd instance, for the Find music screen. Needs the `readwrite` role. | Only for downloads |
|
|
354
|
+
| **Spotify** | Lets you paste a Spotify album link and search for that record by name. The link is read as *words* — an artist and an album — and nothing it returns is ever stored, cached or written to a file. [Create an app](https://developer.spotify.com/dashboard). | Optional |
|
|
355
|
+
|
|
356
|
+
If you would rather not use the window, the same environment variables still
|
|
357
|
+
work, and still win over anything stored:
|
|
358
|
+
|
|
359
|
+
```bash
|
|
360
|
+
export DIGLIBRARY_DISCOGS_TOKEN="…"
|
|
361
|
+
export DIGLIBRARY_ACOUSTID_KEY="…"
|
|
362
|
+
export DIGLIBRARY_SLSKD_API_KEY="…"
|
|
363
|
+
export DIGLIBRARY_SPOTIFY_CLIENT_ID="…"
|
|
364
|
+
export DIGLIBRARY_SPOTIFY_CLIENT_SECRET="…"
|
|
365
|
+
# Only if you want your own address on your own MusicBrainz traffic; the
|
|
366
|
+
# application identifies itself by default, which is what MusicBrainz asks for.
|
|
367
|
+
export DIGLIBRARY_MUSICBRAINZ_CONTACT="you@example.com"
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
An application launched from the Dock inherits no shell environment, which is
|
|
371
|
+
why `~/.diglibrary/env` exists: the bundle sources it at launch, and nothing
|
|
372
|
+
else reads it.
|
|
373
|
+
|
|
374
|
+
## Configuration
|
|
375
|
+
|
|
376
|
+
`~/.diglibrary/config.toml` is yours to edit and nothing rewrites it. Its own
|
|
377
|
+
comments explain each setting; the ones people change first are the naming
|
|
378
|
+
style, whether cover art is fetched, and the cache limits. Naming templates are
|
|
379
|
+
in there too, if none of the six shipped styles is how you name things.
|
|
380
|
+
|
|
381
|
+
`--config /some/other.toml` runs against a different installation entirely.
|
|
382
|
+
|
|
383
|
+
## Copies of your database, and putting one back
|
|
384
|
+
|
|
385
|
+
A compressed copy of the database is written whenever the window opens on
|
|
386
|
+
something that changed, and before any schema upgrade. Each one is read back
|
|
387
|
+
before it is accepted — opened as a database and unpacked to check its
|
|
388
|
+
checksum — so a copy that exists is a copy that worked.
|
|
389
|
+
|
|
390
|
+
They are the only record of your library outside the live file, so point
|
|
391
|
+
`copies_directory` at somewhere that is **not** beside the database:
|
|
392
|
+
|
|
393
|
+
```toml
|
|
394
|
+
[database]
|
|
395
|
+
copies_directory = "~/Documents/DigLibrary-database-copies"
|
|
396
|
+
```
|
|
397
|
+
|
|
398
|
+
To see what there is, and to put one back:
|
|
399
|
+
|
|
400
|
+
```bash
|
|
401
|
+
.venv/bin/diglibrary restore-copy
|
|
402
|
+
```
|
|
403
|
+
|
|
404
|
+
With no arguments it lists them. `--newest` restores the most recent, or name a
|
|
405
|
+
file to choose. Quit DigLibrary first. The database being replaced is renamed
|
|
406
|
+
aside rather than deleted, so undoing a restore is one `mv`.
|
|
407
|
+
|
|
408
|
+
**This is not a backup.** Every copy lives on the same disk as the original.
|
|
409
|
+
Configure Time Machine, or copy that folder somewhere else — a disk that fails
|
|
410
|
+
takes the library and its history together.
|
|
411
|
+
|
|
412
|
+
---
|
|
413
|
+
|
|
414
|
+
## What it will not do
|
|
415
|
+
|
|
416
|
+
- **It will not touch your Rekordbox database.** Ever, by design.
|
|
417
|
+
- **It will not write metadata it is unsure of.** No trusted match means the
|
|
418
|
+
files are left exactly as they were, and the album is queued for your review.
|
|
419
|
+
- **It will not require an AI service** on any essential path.
|
|
420
|
+
- **It will not reverse-engineer anything.** Every integration is an official
|
|
421
|
+
API or a documented protocol, and each one's published terms were read and
|
|
422
|
+
recorded in `ADR/` before it was written.
|
|
423
|
+
|
|
424
|
+
Cover art comes from the [Cover Art Archive](https://musicbrainz.org/doc/Cover_Art_Archive/API).
|
|
425
|
+
Those images are copyrighted by their respective owners and provided for
|
|
426
|
+
archival purposes; using them is at your own risk. DigLibrary re-hosts nothing
|
|
427
|
+
and writes only into your own files. Discogs images are never downloaded or
|
|
428
|
+
embedded — their terms do not permit it.
|
|
429
|
+
|
|
430
|
+
## For contributors
|
|
431
|
+
|
|
432
|
+
```bash
|
|
433
|
+
.venv/bin/python -m pip install -e ".[dev]"
|
|
434
|
+
.venv/bin/python -m pytest # the suite must stay green
|
|
435
|
+
.venv/bin/python -m ruff check .
|
|
436
|
+
.venv/bin/python -m black --check .
|
|
437
|
+
```
|
|
438
|
+
|
|
439
|
+
`CLAUDE.md` is the working agreement: the architectural boundaries — which are
|
|
440
|
+
enforced by tests rather than by convention — and the non-negotiables. `ADR/`
|
|
441
|
+
holds every decision and is authoritative; when another document disagrees with
|
|
442
|
+
an ADR, the ADR is right. [CHANGELOG](https://github.com/cankblunt/diglibrary/blob/v1.1.1/CHANGELOG.md) says what each release
|
|
443
|
+
changed for the files on your disk.
|
|
444
|
+
|
|
445
|
+
Deeper references: [Architecture](https://github.com/cankblunt/diglibrary/blob/v1.1.1/docs/Architecture.md),
|
|
446
|
+
[Technical Specification](https://github.com/cankblunt/diglibrary/blob/v1.1.1/docs/Technical_Specification.md),
|
|
447
|
+
[Decision Engine](https://github.com/cankblunt/diglibrary/blob/v1.1.1/docs/Decision_Engine_Specification.md),
|
|
448
|
+
[Extending DigLibrary](https://github.com/cankblunt/diglibrary/blob/v1.1.1/docs/EXTENDING.md).
|
|
449
|
+
|
|
450
|
+
## License
|
|
451
|
+
|
|
452
|
+
MIT — see [LICENSE](https://github.com/cankblunt/diglibrary/blob/v1.1.1/LICENSE).
|