music-disc-maker 1.0.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.
Files changed (34) hide show
  1. music_disc_maker-1.0.0/LICENSE +21 -0
  2. music_disc_maker-1.0.0/PKG-INFO +178 -0
  3. music_disc_maker-1.0.0/README.md +159 -0
  4. music_disc_maker-1.0.0/music_disc_maker/__init__.py +12 -0
  5. music_disc_maker-1.0.0/music_disc_maker/__main__.py +18 -0
  6. music_disc_maker-1.0.0/music_disc_maker/assets/disc_layers/layer1_outer.png +0 -0
  7. music_disc_maker-1.0.0/music_disc_maker/assets/disc_layers/layer2_surface.png +0 -0
  8. music_disc_maker-1.0.0/music_disc_maker/assets/disc_layers/layer2_surface_alt.png +0 -0
  9. music_disc_maker-1.0.0/music_disc_maker/assets/disc_layers/layer3_accent.png +0 -0
  10. music_disc_maker-1.0.0/music_disc_maker/assets/disc_layers/layer3_accent_alt.png +0 -0
  11. music_disc_maker-1.0.0/music_disc_maker/assets/disc_layers/layer4_edge.png +0 -0
  12. music_disc_maker-1.0.0/music_disc_maker/assets/disc_layers/layer4_edge_alt.png +0 -0
  13. music_disc_maker-1.0.0/music_disc_maker/assets/disc_layers/layer5_inner_a.png +0 -0
  14. music_disc_maker-1.0.0/music_disc_maker/assets/disc_layers/layer5_inner_a_alt.png +0 -0
  15. music_disc_maker-1.0.0/music_disc_maker/assets/disc_layers/layer6_inner_b.png +0 -0
  16. music_disc_maker-1.0.0/music_disc_maker/assets/disc_layers/layer6_inner_b_alt.png +0 -0
  17. music_disc_maker-1.0.0/music_disc_maker/assets/disc_layers/layer7_center.png +0 -0
  18. music_disc_maker-1.0.0/music_disc_maker/audio.py +43 -0
  19. music_disc_maker-1.0.0/music_disc_maker/classes.py +10 -0
  20. music_disc_maker-1.0.0/music_disc_maker/config.py +3 -0
  21. music_disc_maker-1.0.0/music_disc_maker/config_generator.py +537 -0
  22. music_disc_maker-1.0.0/music_disc_maker/defaults.py +24 -0
  23. music_disc_maker-1.0.0/music_disc_maker/disc_icons.py +289 -0
  24. music_disc_maker-1.0.0/music_disc_maker/generate_js.py +680 -0
  25. music_disc_maker-1.0.0/music_disc_maker/images.py +60 -0
  26. music_disc_maker-1.0.0/music_disc_maker/io_utils.py +65 -0
  27. music_disc_maker-1.0.0/music_disc_maker/loader.py +237 -0
  28. music_disc_maker-1.0.0/music_disc_maker/loot.py +222 -0
  29. music_disc_maker-1.0.0/music_disc_maker/manifests.py +93 -0
  30. music_disc_maker-1.0.0/music_disc_maker/models.py +70 -0
  31. music_disc_maker-1.0.0/music_disc_maker/pack_builder.py +256 -0
  32. music_disc_maker-1.0.0/music_disc_maker/parser.py +48 -0
  33. music_disc_maker-1.0.0/music_disc_maker/validation.py +78 -0
  34. music_disc_maker-1.0.0/pyproject.toml +34 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 DJ Woodward-Magar
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,178 @@
1
+ Metadata-Version: 2.4
2
+ Name: music-disc-maker
3
+ Version: 1.0.0
4
+ Summary: Build scripted Minecraft Bedrock custom music disc add-ons.
5
+ License-File: LICENSE
6
+ Author: DJ Stomp
7
+ Author-email: 85457381+DJStompZone@users.noreply.github.com
8
+ Requires-Python: >=3.12,<4.0
9
+ Classifier: Programming Language :: Python :: 3
10
+ Classifier: Programming Language :: Python :: 3.12
11
+ Classifier: Programming Language :: Python :: 3.13
12
+ Classifier: Programming Language :: Python :: 3.14
13
+ Provides-Extra: dev
14
+ Requires-Dist: pillow (>=12.2.0,<13.0.0)
15
+ Requires-Dist: pytest (>=8.0.0) ; extra == "dev"
16
+ Requires-Dist: tqdm (>=4.66.0,<5.0.0)
17
+ Description-Content-Type: text/markdown
18
+
19
+ # music-disc-maker
20
+
21
+ Build scripted Minecraft Bedrock custom music disc add-ons without globally replacing vanilla sound effects.
22
+
23
+ ## Single-disc mode
24
+
25
+ ```bash
26
+ music-disc-maker song.mp3 --id whiplash --title "Whiplash!"
27
+ ```
28
+
29
+ The CLI also works as a module:
30
+
31
+ ```bash
32
+ python -m music_disc_maker song.mp3 --id whiplash --title "Whiplash!"
33
+ ```
34
+
35
+ ## Config mode
36
+
37
+ `music_disc_maker.toml`:
38
+
39
+ ```toml
40
+ pack_id = "custom_discs"
41
+ pack_title = "Custom Music Discs"
42
+ namespace = "custom"
43
+ output_root = "dist"
44
+ dummy_sound_event = "pre_ram.screamer"
45
+ server_module_version = "2.8.0-beta"
46
+ item_format_version = "1.21.70"
47
+ sound_definitions_format_version = "1.20.20"
48
+ min_engine_version = [1, 21, 70]
49
+ default_comparator_signal = 13
50
+ comparator_signal_min = 1
51
+ comparator_signal_max = 13
52
+ pack_icon_size = 256
53
+ loot_enabled = true
54
+ # Optional: point at a custom layer directory or zip matching the bundled layer names.
55
+ # icon_layer_source = "disc_layers"
56
+
57
+ [[discs]]
58
+ input = "audio/whiplash.mp3"
59
+ id = "whiplash"
60
+ title = "Whiplash!"
61
+ comparator_signal = 13
62
+
63
+ [[discs]]
64
+ input = "audio/doom_banjo.mp3"
65
+ id = "doom_banjo"
66
+ title = "Doom Banjo"
67
+ sound_id = "record.doom_banjo"
68
+ comparator_signal = 11
69
+ ```
70
+
71
+ Run it:
72
+
73
+ ```bash
74
+ music-disc-maker --config music_disc_maker.toml
75
+ ```
76
+
77
+ If `--config` is omitted, the tool checks the current directory for common config names such as `music_disc_maker.toml`, `music-disc-maker.toml`, `.music-disc-maker.toml`, JSON equivalents, `discs.json`, and `[tool.music-disc-maker]` / `[tool.music_disc_maker]` in `pyproject.toml`.
78
+
79
+ CLI arguments override config-file values where applicable. Config-file paths are resolved relative to the config file, not wherever your shell happens to be yelling from.
80
+
81
+
82
+ ## Procedural icons
83
+
84
+ Generated item icons now use bundled layered 16x16 disc assets instead of the old one-color fallback puck. The generator derives a deterministic icon from the disc namespace, ID, and title, so rebuilding the same pack keeps the same icon.
85
+
86
+ To use your own layer set, provide either a directory or zip containing files named like:
87
+
88
+ ```text
89
+ layer1_outer.png
90
+ layer2_surface.png
91
+ layer2_surface_alt.png
92
+ layer3_accent.png
93
+ layer3_accent_alt.png
94
+ layer4_edge.png
95
+ layer4_edge_alt.png
96
+ layer5_inner_a.png
97
+ layer5_inner_a_alt.png
98
+ layer6_inner_b.png
99
+ layer6_inner_b_alt.png
100
+ layer7_center.png
101
+ ```
102
+
103
+ Then set it in config:
104
+
105
+ ```toml
106
+ icon_layer_source = "assets/disc_layers.zip"
107
+ ```
108
+
109
+ Or pass it on the CLI:
110
+
111
+ ```bash
112
+ music-disc-maker --config music_disc_maker.toml --icon-layer-source assets/disc_layers.zip
113
+ ```
114
+
115
+ ## Loot tables
116
+
117
+ By default, the behavior pack writes chest loot tables for:
118
+
119
+ - `chests/simple_dungeon`
120
+ - `chests/abandoned_mineshaft`
121
+ - `chests/stronghold_corridor`
122
+ - `chests/ancient_city`
123
+
124
+ The generated tables preserve the bundled vanilla entries for those four targets and append a small extra custom-disc pool. Disable this with:
125
+
126
+ ```toml
127
+ loot_enabled = false
128
+ ```
129
+
130
+ Or from the CLI:
131
+
132
+ ```bash
133
+ music-disc-maker --config music_disc_maker.toml --disable-loot
134
+ ```
135
+
136
+
137
+ ## Generate a config from audio files
138
+
139
+ Scan the current directory and create `music_disc_maker.toml`:
140
+
141
+ ```bash
142
+ music-disc-maker-config
143
+ ```
144
+
145
+ The config generator uses `ffprobe` metadata when available. The generated disc `id` comes from the normalized song title, while the display `title` becomes `Artist - Title` when artist metadata is present. If metadata is missing, filenames like `01 - DJ Stomp - Whiplash! (Official Audio).mp3` are parsed as a fallback, because manually typing that crap is how souls leave bodies.
146
+
147
+ The metadata scan shows a `tqdm` progress bar by default. Disable it with `--no-progress` when piping logs or being aggressively boring.
148
+
149
+ Useful options:
150
+
151
+ ```bash
152
+ music-disc-maker-config --recursive --overwrite --pack-title "DJ Stomp Discs" --namespace dj
153
+ ```
154
+
155
+ Preview without writing:
156
+
157
+ ```bash
158
+ music-disc-maker-config --stdout
159
+ ```
160
+
161
+ If your files use `Title - Artist.ext` instead of `Artist - Title.ext`:
162
+
163
+ ```bash
164
+ music-disc-maker-config --filename-order title-artist --overwrite
165
+ ```
166
+
167
+ For a big messy library, use MusicBrainz Picard or beets to fix the tags first, then regenerate the TOML. This tool reads metadata; it does not rewrite your files.
168
+
169
+ ## Testing
170
+
171
+ ```bash
172
+ python -m pytest
173
+ ```
174
+
175
+ ## License
176
+
177
+ MIT License. See the [LICENSE](LICENSE) file for details.
178
+
@@ -0,0 +1,159 @@
1
+ # music-disc-maker
2
+
3
+ Build scripted Minecraft Bedrock custom music disc add-ons without globally replacing vanilla sound effects.
4
+
5
+ ## Single-disc mode
6
+
7
+ ```bash
8
+ music-disc-maker song.mp3 --id whiplash --title "Whiplash!"
9
+ ```
10
+
11
+ The CLI also works as a module:
12
+
13
+ ```bash
14
+ python -m music_disc_maker song.mp3 --id whiplash --title "Whiplash!"
15
+ ```
16
+
17
+ ## Config mode
18
+
19
+ `music_disc_maker.toml`:
20
+
21
+ ```toml
22
+ pack_id = "custom_discs"
23
+ pack_title = "Custom Music Discs"
24
+ namespace = "custom"
25
+ output_root = "dist"
26
+ dummy_sound_event = "pre_ram.screamer"
27
+ server_module_version = "2.8.0-beta"
28
+ item_format_version = "1.21.70"
29
+ sound_definitions_format_version = "1.20.20"
30
+ min_engine_version = [1, 21, 70]
31
+ default_comparator_signal = 13
32
+ comparator_signal_min = 1
33
+ comparator_signal_max = 13
34
+ pack_icon_size = 256
35
+ loot_enabled = true
36
+ # Optional: point at a custom layer directory or zip matching the bundled layer names.
37
+ # icon_layer_source = "disc_layers"
38
+
39
+ [[discs]]
40
+ input = "audio/whiplash.mp3"
41
+ id = "whiplash"
42
+ title = "Whiplash!"
43
+ comparator_signal = 13
44
+
45
+ [[discs]]
46
+ input = "audio/doom_banjo.mp3"
47
+ id = "doom_banjo"
48
+ title = "Doom Banjo"
49
+ sound_id = "record.doom_banjo"
50
+ comparator_signal = 11
51
+ ```
52
+
53
+ Run it:
54
+
55
+ ```bash
56
+ music-disc-maker --config music_disc_maker.toml
57
+ ```
58
+
59
+ If `--config` is omitted, the tool checks the current directory for common config names such as `music_disc_maker.toml`, `music-disc-maker.toml`, `.music-disc-maker.toml`, JSON equivalents, `discs.json`, and `[tool.music-disc-maker]` / `[tool.music_disc_maker]` in `pyproject.toml`.
60
+
61
+ CLI arguments override config-file values where applicable. Config-file paths are resolved relative to the config file, not wherever your shell happens to be yelling from.
62
+
63
+
64
+ ## Procedural icons
65
+
66
+ Generated item icons now use bundled layered 16x16 disc assets instead of the old one-color fallback puck. The generator derives a deterministic icon from the disc namespace, ID, and title, so rebuilding the same pack keeps the same icon.
67
+
68
+ To use your own layer set, provide either a directory or zip containing files named like:
69
+
70
+ ```text
71
+ layer1_outer.png
72
+ layer2_surface.png
73
+ layer2_surface_alt.png
74
+ layer3_accent.png
75
+ layer3_accent_alt.png
76
+ layer4_edge.png
77
+ layer4_edge_alt.png
78
+ layer5_inner_a.png
79
+ layer5_inner_a_alt.png
80
+ layer6_inner_b.png
81
+ layer6_inner_b_alt.png
82
+ layer7_center.png
83
+ ```
84
+
85
+ Then set it in config:
86
+
87
+ ```toml
88
+ icon_layer_source = "assets/disc_layers.zip"
89
+ ```
90
+
91
+ Or pass it on the CLI:
92
+
93
+ ```bash
94
+ music-disc-maker --config music_disc_maker.toml --icon-layer-source assets/disc_layers.zip
95
+ ```
96
+
97
+ ## Loot tables
98
+
99
+ By default, the behavior pack writes chest loot tables for:
100
+
101
+ - `chests/simple_dungeon`
102
+ - `chests/abandoned_mineshaft`
103
+ - `chests/stronghold_corridor`
104
+ - `chests/ancient_city`
105
+
106
+ The generated tables preserve the bundled vanilla entries for those four targets and append a small extra custom-disc pool. Disable this with:
107
+
108
+ ```toml
109
+ loot_enabled = false
110
+ ```
111
+
112
+ Or from the CLI:
113
+
114
+ ```bash
115
+ music-disc-maker --config music_disc_maker.toml --disable-loot
116
+ ```
117
+
118
+
119
+ ## Generate a config from audio files
120
+
121
+ Scan the current directory and create `music_disc_maker.toml`:
122
+
123
+ ```bash
124
+ music-disc-maker-config
125
+ ```
126
+
127
+ The config generator uses `ffprobe` metadata when available. The generated disc `id` comes from the normalized song title, while the display `title` becomes `Artist - Title` when artist metadata is present. If metadata is missing, filenames like `01 - DJ Stomp - Whiplash! (Official Audio).mp3` are parsed as a fallback, because manually typing that crap is how souls leave bodies.
128
+
129
+ The metadata scan shows a `tqdm` progress bar by default. Disable it with `--no-progress` when piping logs or being aggressively boring.
130
+
131
+ Useful options:
132
+
133
+ ```bash
134
+ music-disc-maker-config --recursive --overwrite --pack-title "DJ Stomp Discs" --namespace dj
135
+ ```
136
+
137
+ Preview without writing:
138
+
139
+ ```bash
140
+ music-disc-maker-config --stdout
141
+ ```
142
+
143
+ If your files use `Title - Artist.ext` instead of `Artist - Title.ext`:
144
+
145
+ ```bash
146
+ music-disc-maker-config --filename-order title-artist --overwrite
147
+ ```
148
+
149
+ For a big messy library, use MusicBrainz Picard or beets to fix the tags first, then regenerate the TOML. This tool reads metadata; it does not rewrite your files.
150
+
151
+ ## Testing
152
+
153
+ ```bash
154
+ python -m pytest
155
+ ```
156
+
157
+ ## License
158
+
159
+ MIT License. See the [LICENSE](LICENSE) file for details.
@@ -0,0 +1,12 @@
1
+ from __future__ import annotations
2
+
3
+ from music_disc_maker.models import BuildConfig, BuiltDisc, DiscInput, PackPaths
4
+ from music_disc_maker.pack_builder import ScriptedDiscPackBuilder
5
+
6
+ __all__ = [
7
+ "BuildConfig",
8
+ "BuiltDisc",
9
+ "DiscInput",
10
+ "PackPaths",
11
+ "ScriptedDiscPackBuilder",
12
+ ]
@@ -0,0 +1,18 @@
1
+ from __future__ import annotations
2
+
3
+ from music_disc_maker.loader import load_build_config
4
+ from music_disc_maker.pack_builder import ScriptedDiscPackBuilder
5
+ from music_disc_maker.parser import parse_args
6
+
7
+
8
+ def main() -> int:
9
+ """Run the pack generator."""
10
+ args = parse_args()
11
+ config = load_build_config(args)
12
+ builder = ScriptedDiscPackBuilder(config)
13
+ builder.build()
14
+ return 0
15
+
16
+
17
+ if __name__ == "__main__":
18
+ raise SystemExit(main())
@@ -0,0 +1,43 @@
1
+ from __future__ import annotations
2
+
3
+ from pathlib import Path
4
+
5
+ from music_disc_maker.io_utils import run_command
6
+
7
+
8
+ def convert_audio(input_file: Path, output_file: Path) -> float:
9
+ """Convert an input audio file to a mono streaming OGG and return duration in seconds."""
10
+ output_file.parent.mkdir(parents=True, exist_ok=True)
11
+
12
+ run_command([
13
+ "ffmpeg",
14
+ "-y",
15
+ "-i",
16
+ str(input_file),
17
+ "-vn",
18
+ "-ac",
19
+ "1",
20
+ "-ar",
21
+ "44100",
22
+ "-c:a",
23
+ "libvorbis",
24
+ "-q:a",
25
+ "4",
26
+ str(output_file),
27
+ ])
28
+
29
+ probe = run_command([
30
+ "ffprobe",
31
+ "-v",
32
+ "error",
33
+ "-show_entries",
34
+ "format=duration",
35
+ "-of",
36
+ "default=noprint_wrappers=1:nokey=1",
37
+ str(output_file),
38
+ ])
39
+
40
+ try:
41
+ return round(float(probe.stdout.strip()), 3)
42
+ except ValueError as exc:
43
+ raise RuntimeError(f"Unable to read duration from ffprobe output: {probe.stdout!r}") from exc
@@ -0,0 +1,10 @@
1
+ from __future__ import annotations
2
+
3
+ from music_disc_maker.models import BuildConfig, BuiltDisc, DiscInput, PackPaths
4
+
5
+ __all__ = [
6
+ "BuildConfig",
7
+ "BuiltDisc",
8
+ "DiscInput",
9
+ "PackPaths",
10
+ ]
@@ -0,0 +1,3 @@
1
+ from __future__ import annotations
2
+
3
+ from music_disc_maker.defaults import *