mirror of
https://github.com/unshackle-dl/unshackle.git
synced 2026-11-15 05:25:12 +00:00
feat(music): pick the song container from the codec in the downloaded file
FFprobe sets the codec; DTS goes to .mka, PCM to .flac or .wav, AC-4/MPEG-H/DTS-UHD to MP4Box. The remux also cuts --sample, --no-mux no longer applies to a Song, and the tagger adds cover fallback, WebP, ARTISTS and ReplayGain. Song tag data now reaches a --remote client.
This commit is contained in:
@@ -370,9 +370,9 @@ Common constructor fields:
|
||||
|
||||
From `get_tracks()`, give one `Audio` track for each codec and bitrate you offer
|
||||
for the song. The framework then selects one with its usual audio options.
|
||||
A `Song` skips the muxer, so restore the real container suffix on the track path
|
||||
in `on_track_downloaded`. The **MUSIC_EXAMPLE** service shows the full music
|
||||
surface.
|
||||
A `Song` skips the muxer: the framework reads the codec from the downloaded file
|
||||
and gives the file its container, so a service does not rename the track path.
|
||||
The **MUSIC_EXAMPLE** service shows the full music surface.
|
||||
|
||||
!!! note "The ID must be unique and stable"
|
||||
`id_` must be truthy and, if it has a length, at least 4 characters, to
|
||||
|
||||
@@ -202,7 +202,9 @@ Each subclass adds its own required fields on top of `id_` and `service`:
|
||||
|
||||
The tagger also falls back to `Song.data` for fields the constructor did not get, such
|
||||
as the composer or a full release date. It reads the top level of that dict and a
|
||||
nested `metadata` sub-dict, with the nested keys winning, so either shape works.
|
||||
nested `metadata` sub-dict, with the nested keys winning, so either shape works. The keys
|
||||
that a remote client gets back are `MUSIC_DATA_KEYS` in `unshackle/core/titles/music.py`,
|
||||
for example `artists` (a list) and `replaygain_track_gain`.
|
||||
|
||||
From `get_tracks()`, a music service gives **one `Audio` track for each codec and
|
||||
bitrate it offers for a `Song`**. The framework then selects one with its usual audio
|
||||
@@ -216,13 +218,9 @@ Each subclass adds its own required fields on top of `id_` and `service`:
|
||||
`GROUP_AUDIO_DOWNLOADS` flag, `get_music_track_options` and `get_music_collection_label`
|
||||
no longer exist, and a music service does not need them.
|
||||
|
||||
!!! warning "Restore the container in `on_track_downloaded`"
|
||||
Every track downloads to a temp file named `Audio_<id>.mp4` whatever it holds, and
|
||||
the final move keeps that suffix. A `Song` skips the muxer, so its download **is**
|
||||
the delivered file, and the tagger picks its metadata format from the suffix.
|
||||
Rename the track path to the true container in `on_track_downloaded`, or a FLAC
|
||||
lands as an untaggable `.mp4`. The event fires twice, once before decryption and
|
||||
once at the end, so wait until `track.drm` is clear before you rename.
|
||||
Core picks the container of a `Song` from the codec in the downloaded file, so a music
|
||||
service does not rename the track path. Read
|
||||
[Music output files](../guide/output-and-naming.md#music-output-files).
|
||||
|
||||
The **MUSIC_EXAMPLE** reference service, at `unshackle/services/MUSIC_EXAMPLE/`, shows
|
||||
the full music surface.
|
||||
|
||||
Reference in New Issue
Block a user