mirror of
https://github.com/unshackle-dl/unshackle.git
synced 2026-06-22 17:07:23 +00:00
feat(music): native music core - shared helpers, album folder template, display cleanup (#125)
* Add native Music core workflow
* feat(music): add shared music core helpers, album folder template, and UX cleanup
Consolidate duplicated music-service logic into core and extend the native music workflow.
- add core/music/extract.py: shared stateless helpers (first_text, first_number, year/duration/name formatting, classify_release_kind, dedupe_track_options, build_music_from_songs) so services stop carrying their own copies
- add core/music/display.py: shared rich rendering (render_track_panel, render_album_header, render_artwork_preview) with TrackRow / MusicHeaderInfo data holders
- export the new helpers from core/music/__init__.py
- add dedicated `albums` folder template kind (output_template.folder.albums) resolving albums -> songs -> "{artist} - {album} ({year})"; whitelist music template variables (album_artist, track_total, disc_total, release_type, genre, explicit, isrc, upc, label)
- fix song filename crash: config.get_output_template(...) did not exist; use config.output_template.get("songs") with a sane default
- strip emojis from music output (renderer, dl.py music branch) to match unshackle UX; remove dead MusicSongPlan import and music_icon logic
- document the albums folder key in unshackle-example.yaml
- add tests for extract, display, and the folder template
---------
Co-authored-by: MrMovies-Dev <MrMovies-Dev@users.noreply.github.com>
This commit is contained in:
22
uv.lock
generated
22
uv.lock
generated
@@ -660,6 +660,15 @@ wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/7f/ed/e3705d6d02b4f7aea715a353c8ce193efd0b5db13e204df895d38734c244/isort-7.0.0-py3-none-any.whl", hash = "sha256:1bcabac8bc3c36c7fb7b98a76c8abb18e0f841a3ba81decac7691008592499c1", size = 94672, upload-time = "2025-10-11T13:30:57.665Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jsonpath-ng"
|
||||
version = "1.8.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/32/58/250751940d75c8019659e15482d548a4aa3b6ce122c515102a4bfdac50e3/jsonpath_ng-1.8.0.tar.gz", hash = "sha256:54252968134b5e549ea5b872f1df1168bd7defe1a52fed5a358c194e1943ddc3", size = 74513, upload-time = "2026-02-24T14:42:06.182Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/03/99/33c7d78a3fb70d545fd5411ac67a651c81602cc09c9cf0df383733f068c5/jsonpath_ng-1.8.0-py3-none-any.whl", hash = "sha256:b8dde192f8af58d646fc031fac9c99fe4d00326afc4148f1f043c601a8cfe138", size = 67844, upload-time = "2026-02-28T00:53:19.637Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jsonpickle"
|
||||
version = "4.1.1"
|
||||
@@ -934,6 +943,15 @@ wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/81/08/7036c080d7117f28a4af526d794aab6a84463126db031b007717c1a6676e/multidict-6.7.1-py3-none-any.whl", hash = "sha256:55d97cc6dae627efa6a6e548885712d4864b81110ac76fa4e534c03819fa4a56", size = 12319, upload-time = "2026-01-26T02:46:44.004Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mutagen"
|
||||
version = "1.47.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/81/e6/64bc71b74eef4b68e61eb921dcf72dabd9e4ec4af1e11891bbd312ccbb77/mutagen-1.47.0.tar.gz", hash = "sha256:719fadef0a978c31b4cf3c956261b3c58b6948b32023078a2117b1de09f0fc99", size = 1274186, upload-time = "2023-09-03T16:33:33.411Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/b0/7a/620f945b96be1f6ee357d211d5bf74ab1b7fe72a9f1525aafbfe3aee6875/mutagen-1.47.0-py3-none-any.whl", hash = "sha256:edd96f50c5907a9539d8e5bba7245f62c9f520aef333d13392a79a4f70aca719", size = 194391, upload-time = "2023-09-03T16:33:29.955Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mypy"
|
||||
version = "1.19.1"
|
||||
@@ -1778,10 +1796,12 @@ dependencies = [
|
||||
{ name = "defusedxml" },
|
||||
{ name = "filelock" },
|
||||
{ name = "fonttools" },
|
||||
{ name = "jsonpath-ng" },
|
||||
{ name = "jsonpickle" },
|
||||
{ name = "langcodes" },
|
||||
{ name = "language-data" },
|
||||
{ name = "lxml" },
|
||||
{ name = "mutagen" },
|
||||
{ name = "protobuf" },
|
||||
{ name = "pycaption" },
|
||||
{ name = "pycountry" },
|
||||
@@ -1844,10 +1864,12 @@ requires-dist = [
|
||||
{ name = "defusedxml", specifier = ">=0.7.1" },
|
||||
{ name = "filelock", specifier = ">=3.20.3,<4" },
|
||||
{ name = "fonttools", specifier = ">=4.60.2,<5" },
|
||||
{ name = "jsonpath-ng", specifier = ">=1.8.0" },
|
||||
{ name = "jsonpickle", specifier = ">=3.0.4,<5" },
|
||||
{ name = "langcodes", specifier = ">=3.4.0,<4" },
|
||||
{ name = "language-data", specifier = ">=1.4.0" },
|
||||
{ name = "lxml", specifier = ">=5.2.1,<7" },
|
||||
{ name = "mutagen", specifier = ">=1.47.0,<2" },
|
||||
{ name = "protobuf", specifier = ">=4.25.3,<7" },
|
||||
{ name = "pycaption", specifier = ">=2.2.6,<3" },
|
||||
{ name = "pycountry", specifier = ">=24.6.1" },
|
||||
|
||||
Reference in New Issue
Block a user