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.

Files changed (125) hide show
  1. diglibrary-1.1.1/LICENSE +21 -0
  2. diglibrary-1.1.1/PKG-INFO +452 -0
  3. diglibrary-1.1.1/README.md +418 -0
  4. diglibrary-1.1.1/pyproject.toml +115 -0
  5. diglibrary-1.1.1/setup.cfg +4 -0
  6. diglibrary-1.1.1/src/diglibrary/__init__.py +5 -0
  7. diglibrary-1.1.1/src/diglibrary/__main__.py +107 -0
  8. diglibrary-1.1.1/src/diglibrary/application/__init__.py +1 -0
  9. diglibrary-1.1.1/src/diglibrary/application/acoustic.py +289 -0
  10. diglibrary-1.1.1/src/diglibrary/application/api.py +10060 -0
  11. diglibrary-1.1.1/src/diglibrary/application/artwork.py +542 -0
  12. diglibrary-1.1.1/src/diglibrary/application/bench.py +559 -0
  13. diglibrary-1.1.1/src/diglibrary/application/composition.py +625 -0
  14. diglibrary-1.1.1/src/diglibrary/application/contracts.py +224 -0
  15. diglibrary-1.1.1/src/diglibrary/application/identification.py +1636 -0
  16. diglibrary-1.1.1/src/diglibrary/application/quality.py +421 -0
  17. diglibrary-1.1.1/src/diglibrary/cachedir.py +141 -0
  18. diglibrary-1.1.1/src/diglibrary/config/__init__.py +6 -0
  19. diglibrary-1.1.1/src/diglibrary/config/credentials.py +118 -0
  20. diglibrary-1.1.1/src/diglibrary/config/default.toml +113 -0
  21. diglibrary-1.1.1/src/diglibrary/config/home.py +81 -0
  22. diglibrary-1.1.1/src/diglibrary/config/loader.py +319 -0
  23. diglibrary-1.1.1/src/diglibrary/config/models.py +111 -0
  24. diglibrary-1.1.1/src/diglibrary/connectors/__init__.py +36 -0
  25. diglibrary-1.1.1/src/diglibrary/connectors/contracts.py +155 -0
  26. diglibrary-1.1.1/src/diglibrary/connectors/models.py +471 -0
  27. diglibrary-1.1.1/src/diglibrary/connectors/slskd/__init__.py +21 -0
  28. diglibrary-1.1.1/src/diglibrary/connectors/slskd/client.py +584 -0
  29. diglibrary-1.1.1/src/diglibrary/connectors/slskd/configuration.py +76 -0
  30. diglibrary-1.1.1/src/diglibrary/connectors/slskd/connector.py +307 -0
  31. diglibrary-1.1.1/src/diglibrary/connectors/slskd/exceptions.py +239 -0
  32. diglibrary-1.1.1/src/diglibrary/connectors/slskd/mapper.py +343 -0
  33. diglibrary-1.1.1/src/diglibrary/connectors/slskd/models.py +46 -0
  34. diglibrary-1.1.1/src/diglibrary/database/__init__.py +6 -0
  35. diglibrary-1.1.1/src/diglibrary/database/connection.py +232 -0
  36. diglibrary-1.1.1/src/diglibrary/database/copies.py +324 -0
  37. diglibrary-1.1.1/src/diglibrary/database/library_store.py +2790 -0
  38. diglibrary-1.1.1/src/diglibrary/database/migrations.py +1133 -0
  39. diglibrary-1.1.1/src/diglibrary/database/repositories.py +41 -0
  40. diglibrary-1.1.1/src/diglibrary/database/serialization.py +163 -0
  41. diglibrary-1.1.1/src/diglibrary/desktop/__init__.py +15 -0
  42. diglibrary-1.1.1/src/diglibrary/desktop/bundle.py +161 -0
  43. diglibrary-1.1.1/src/diglibrary/desktop/icon.py +215 -0
  44. diglibrary-1.1.1/src/diglibrary/desktop/restore.py +83 -0
  45. diglibrary-1.1.1/src/diglibrary/engines/__init__.py +21 -0
  46. diglibrary-1.1.1/src/diglibrary/engines/contracts.py +61 -0
  47. diglibrary-1.1.1/src/diglibrary/harmonic/__init__.py +0 -0
  48. diglibrary-1.1.1/src/diglibrary/harmonic/analyzer.py +154 -0
  49. diglibrary-1.1.1/src/diglibrary/harmonic/keys.py +161 -0
  50. diglibrary-1.1.1/src/diglibrary/harmonic/mixing.py +100 -0
  51. diglibrary-1.1.1/src/diglibrary/harmonic/tempo.py +132 -0
  52. diglibrary-1.1.1/src/diglibrary/identity.py +17 -0
  53. diglibrary-1.1.1/src/diglibrary/library/__init__.py +50 -0
  54. diglibrary-1.1.1/src/diglibrary/library/artwork.py +653 -0
  55. diglibrary-1.1.1/src/diglibrary/library/atomicwrite.py +120 -0
  56. diglibrary-1.1.1/src/diglibrary/library/audio.py +84 -0
  57. diglibrary-1.1.1/src/diglibrary/library/audio_key.py +212 -0
  58. diglibrary-1.1.1/src/diglibrary/library/containers.py +191 -0
  59. diglibrary-1.1.1/src/diglibrary/library/executor.py +810 -0
  60. diglibrary-1.1.1/src/diglibrary/library/extras.py +184 -0
  61. diglibrary-1.1.1/src/diglibrary/library/fingerprint.py +147 -0
  62. diglibrary-1.1.1/src/diglibrary/library/hints.py +630 -0
  63. diglibrary-1.1.1/src/diglibrary/library/integrity.py +246 -0
  64. diglibrary-1.1.1/src/diglibrary/library/matching.py +1918 -0
  65. diglibrary-1.1.1/src/diglibrary/library/medleys.py +211 -0
  66. diglibrary-1.1.1/src/diglibrary/library/models.py +90 -0
  67. diglibrary-1.1.1/src/diglibrary/library/naming.py +1140 -0
  68. diglibrary-1.1.1/src/diglibrary/library/planner.py +1113 -0
  69. diglibrary-1.1.1/src/diglibrary/library/report.py +309 -0
  70. diglibrary-1.1.1/src/diglibrary/library/scanner.py +416 -0
  71. diglibrary-1.1.1/src/diglibrary/library/series.py +255 -0
  72. diglibrary-1.1.1/src/diglibrary/library/signature.py +56 -0
  73. diglibrary-1.1.1/src/diglibrary/library/spelling.py +202 -0
  74. diglibrary-1.1.1/src/diglibrary/library/tagrelease.py +329 -0
  75. diglibrary-1.1.1/src/diglibrary/library/tags.py +320 -0
  76. diglibrary-1.1.1/src/diglibrary/library/xattrs.py +194 -0
  77. diglibrary-1.1.1/src/diglibrary/logging/__init__.py +5 -0
  78. diglibrary-1.1.1/src/diglibrary/logging/setup.py +132 -0
  79. diglibrary-1.1.1/src/diglibrary/metadata/__init__.py +27 -0
  80. diglibrary-1.1.1/src/diglibrary/metadata/acoustid.py +148 -0
  81. diglibrary-1.1.1/src/diglibrary/metadata/authentication.py +54 -0
  82. diglibrary-1.1.1/src/diglibrary/metadata/cache.py +111 -0
  83. diglibrary-1.1.1/src/diglibrary/metadata/coverart.py +207 -0
  84. diglibrary-1.1.1/src/diglibrary/metadata/discogs.py +309 -0
  85. diglibrary-1.1.1/src/diglibrary/metadata/itunes.py +314 -0
  86. diglibrary-1.1.1/src/diglibrary/metadata/matching.py +24 -0
  87. diglibrary-1.1.1/src/diglibrary/metadata/models.py +21 -0
  88. diglibrary-1.1.1/src/diglibrary/metadata/musicbrainz.py +304 -0
  89. diglibrary-1.1.1/src/diglibrary/metadata/normalization.py +105 -0
  90. diglibrary-1.1.1/src/diglibrary/metadata/rate_limit.py +32 -0
  91. diglibrary-1.1.1/src/diglibrary/metadata/retry.py +69 -0
  92. diglibrary-1.1.1/src/diglibrary/metadata/service.py +187 -0
  93. diglibrary-1.1.1/src/diglibrary/metadata/spotify.py +284 -0
  94. diglibrary-1.1.1/src/diglibrary/metadata/transport.py +181 -0
  95. diglibrary-1.1.1/src/diglibrary/providers/__init__.py +5 -0
  96. diglibrary-1.1.1/src/diglibrary/providers/capabilities.py +25 -0
  97. diglibrary-1.1.1/src/diglibrary/providers/contracts.py +55 -0
  98. diglibrary-1.1.1/src/diglibrary/providers/manager.py +229 -0
  99. diglibrary-1.1.1/src/diglibrary/providers/models.py +162 -0
  100. diglibrary-1.1.1/src/diglibrary/providers/registry.py +65 -0
  101. diglibrary-1.1.1/src/diglibrary/providers/soulseek.py +394 -0
  102. diglibrary-1.1.1/src/diglibrary/providers/types.py +30 -0
  103. diglibrary-1.1.1/src/diglibrary/quality/__init__.py +41 -0
  104. diglibrary-1.1.1/src/diglibrary/quality/analysis.py +399 -0
  105. diglibrary-1.1.1/src/diglibrary/quality/confidence.py +199 -0
  106. diglibrary-1.1.1/src/diglibrary/quality/models.py +391 -0
  107. diglibrary-1.1.1/src/diglibrary/quality/spectrogram.py +276 -0
  108. diglibrary-1.1.1/src/diglibrary/quality/verdict.py +578 -0
  109. diglibrary-1.1.1/src/diglibrary/ui/__init__.py +1 -0
  110. diglibrary-1.1.1/src/diglibrary/ui/app.py +245 -0
  111. diglibrary-1.1.1/src/diglibrary/ui/audio.py +314 -0
  112. diglibrary-1.1.1/src/diglibrary/ui/drops.py +95 -0
  113. diglibrary-1.1.1/src/diglibrary/ui/folders.py +108 -0
  114. diglibrary-1.1.1/src/diglibrary/ui/wakefulness.py +83 -0
  115. diglibrary-1.1.1/src/diglibrary/ui/web/app.js +10845 -0
  116. diglibrary-1.1.1/src/diglibrary/ui/web/index.html +1183 -0
  117. diglibrary-1.1.1/src/diglibrary/ui/web/strings.js +1805 -0
  118. diglibrary-1.1.1/src/diglibrary/ui/web/styles.css +3829 -0
  119. diglibrary-1.1.1/src/diglibrary.egg-info/PKG-INFO +452 -0
  120. diglibrary-1.1.1/src/diglibrary.egg-info/SOURCES.txt +123 -0
  121. diglibrary-1.1.1/src/diglibrary.egg-info/dependency_links.txt +1 -0
  122. diglibrary-1.1.1/src/diglibrary.egg-info/entry_points.txt +2 -0
  123. diglibrary-1.1.1/src/diglibrary.egg-info/requires.txt +10 -0
  124. diglibrary-1.1.1/src/diglibrary.egg-info/top_level.txt +1 -0
  125. diglibrary-1.1.1/tests/test_cachedir.py +99 -0
@@ -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
+ ![Three stages: install the tools, get DigLibrary, open it](https://raw.githubusercontent.com/cankblunt/diglibrary/v1.1.1/docs/images/steps.svg)
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
+ ![What the Terminal looks like](https://raw.githubusercontent.com/cankblunt/diglibrary/v1.1.1/docs/images/terminal.svg)
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
+ ![The install, typing itself](https://raw.githubusercontent.com/cankblunt/diglibrary/v1.1.1/docs/images/install.gif)
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
+ ![The Library screen](https://raw.githubusercontent.com/cankblunt/diglibrary/v1.1.1/docs/images/screen-library.png)
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
+ ![The Mixing screen](https://raw.githubusercontent.com/cankblunt/diglibrary/v1.1.1/docs/images/screen-mixing.png)
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).