mirror of
https://github.com/unshackle-dl/unshackle.git
synced 2026-11-14 13:05:09 +00:00
refactor(music)!: make Song an ordinary Title on the generic path
Delete the dead grouped-download block, the planner, and the music service hooks; Song now flows through the one download loop, gets tagged via tag_file, and answers -w with {disc}x{track} keys.
BREAKING CHANGE: GROUP_AUDIO_DOWNLOADS, get_music_track_options and get_music_collection_label are gone. A music service returns one Audio track per quality and lets the framework choose.
This commit is contained in:
@@ -112,7 +112,7 @@ The special language tokens `orig`, `all`, and `best` are honoured everywhere a
|
||||
|
||||
| Flag | Description |
|
||||
|---|---|
|
||||
| `-w`, `--wanted` | Wanted episodes, e.g. `S01-S05,S07`, `S01E01-S02E03`. Supports exclusions with a leading `-` (e.g. `-S03`). For a [split episode](downloading.md#split-episodes), `.N` picks one part (`S01E01.2`), a range must stay inside the episode (`S01E01.1-S01E01.3`), and `S01E01` on its own takes every part. For [dated content](downloading.md#daily-and-date-based-content), a token can also be an ISO air date (`2026-08-11`) or a date range with a colon (`2026-08-01:2026-08-31`). |
|
||||
| `-w`, `--wanted` | Wanted episodes, e.g. `S01-S05,S07`, `S01E01-S02E03`. Supports exclusions with a leading `-` (e.g. `-S03`). For a [split episode](downloading.md#split-episodes), `.N` picks one part (`S01E01.2`), a range must stay inside the episode (`S01E01.1-S01E01.3`), and `S01E01` on its own takes every part. For [dated content](downloading.md#daily-and-date-based-content), a token can also be an ISO air date (`2026-08-11`) or a date range with a colon (`2026-08-01:2026-08-31`). For a [music release](downloading.md#music-tracks), a token is a track number (`1-5`, `1,3,7`), or `{disc}x{track}` (`2x3`) when the release has more than one disc. |
|
||||
| `--select-titles` | Interactively select what to download: episodes of a series, or films when a title has more than one. **Cannot combine with `-w`.** |
|
||||
| `--latest-episode` | Download only the single most recent episode. |
|
||||
| `--list-titles` | List titles only; do not download. |
|
||||
|
||||
+80
-10
@@ -232,6 +232,27 @@ unshackle dl -a EC3,AAC EXAMPLE 81234567
|
||||
unshackle dl -c 5.1 --noatmos EXAMPLE 0ABC123
|
||||
```
|
||||
|
||||
### Music quality
|
||||
|
||||
A music service gives one `Audio` track for each codec and bitrate it offers for a song.
|
||||
The audio options above choose between them: `-a` picks the codec and `-ab` or `-ab-range`
|
||||
picks the bitrate. If you set neither, unshackle takes the best track.
|
||||
|
||||
`-q` / `--quality` is a video height. It has no effect on a music download.
|
||||
|
||||
```shell title="Take the lossless track"
|
||||
unshackle dl -a FLAC EXAMPLE 81234567
|
||||
```
|
||||
|
||||
```shell title="Take the lossy track at 320 kb/s"
|
||||
unshackle dl -a AAC -ab 320 EXAMPLE 81234567
|
||||
```
|
||||
|
||||
!!! tip "Two FLAC tracks in one release"
|
||||
A service can offer both a CD FLAC and a hi-res FLAC. The two have the same codec, so
|
||||
the bitrate is what separates them. Run `--list` to read the bitrates, then give `-ab`
|
||||
the one you want.
|
||||
|
||||
## Languages
|
||||
|
||||
### Video and audio language
|
||||
@@ -381,15 +402,16 @@ unshackle dl --sub-format srt EXAMPLE 81234567
|
||||
automatically. This behaviour is governed by the `subtitle.strip_sdh` config option
|
||||
(default on).
|
||||
|
||||
## Selecting episodes
|
||||
## Selecting episodes and tracks
|
||||
|
||||
For series, several flags control which episodes are downloaded. By default, **all**
|
||||
episodes are downloaded.
|
||||
For series, several flags control which episodes are downloaded. The same flags select the
|
||||
tracks of a music release. By default, **all** episodes and **all** tracks are downloaded.
|
||||
|
||||
### Wanted ranges
|
||||
|
||||
`-w` / `--wanted` accepts flexible season/episode ranges, comma-separated. Prefix a token
|
||||
with `-` to exclude it.
|
||||
`-w` / `--wanted` accepts season and episode ranges, comma-separated. Prefix a token
|
||||
with `-` to exclude it. For a music release, the same option takes track numbers. Read
|
||||
[music tracks](#music-tracks) below.
|
||||
|
||||
=== "Whole seasons"
|
||||
|
||||
@@ -440,6 +462,49 @@ with `-` to exclude it.
|
||||
unshackle dl -w 2026-08-01:2026-08-31,-2026-08-15 EXAMPLE 81234567
|
||||
```
|
||||
|
||||
### Music tracks
|
||||
|
||||
`-w` selects the tracks of an album, EP, single, or playlist. Give a track by its number.
|
||||
A release with more than one disc uses the `{disc}x{track}` form. A number on its own is a
|
||||
track on disc 1, which is the number the track list shows for a single-disc release.
|
||||
|
||||
=== "Tracks"
|
||||
|
||||
```shell
|
||||
# Track 3
|
||||
unshackle dl -w 3 EXAMPLE 81234567
|
||||
|
||||
# Tracks 1 through 5
|
||||
unshackle dl -w 1-5 EXAMPLE 81234567
|
||||
|
||||
# Tracks 1, 3 and 7
|
||||
unshackle dl -w 1,3,7 EXAMPLE 81234567
|
||||
```
|
||||
|
||||
=== "More than one disc"
|
||||
|
||||
```shell
|
||||
# Disc 2, track 3
|
||||
unshackle dl -w 2x3 EXAMPLE 81234567
|
||||
|
||||
# Disc 2, tracks 1 through 4
|
||||
unshackle dl -w 2x1-2x4 EXAMPLE 81234567
|
||||
|
||||
# Disc 1 track 3, through disc 2 track 2
|
||||
unshackle dl -w 1x3-2x2 EXAMPLE 81234567
|
||||
```
|
||||
|
||||
=== "Exclusions"
|
||||
|
||||
```shell
|
||||
# Tracks 1 through 8, but not track 4
|
||||
unshackle dl -w 1-8,-4 EXAMPLE 81234567
|
||||
```
|
||||
|
||||
!!! tip "Read the track list first"
|
||||
`--list-titles` prints the release with its disc and track numbers, so you can see
|
||||
which numbers to give `-w`.
|
||||
|
||||
### Daily and date-based content
|
||||
|
||||
Talk shows, news and sports have no official episode numbering, so unshackle names them
|
||||
@@ -570,8 +635,8 @@ unshackle dl -o ~/Videos/incoming EXAMPLE 81234567
|
||||
|
||||
### Muxing behaviour
|
||||
|
||||
By default, tracks are muxed into a single Matroska (`.mkv`) file with `mkvmerge`. These
|
||||
flags change how the output is assembled:
|
||||
By default, the tracks of a movie or an episode are muxed into a single Matroska (`.mkv`)
|
||||
file with `mkvmerge`. These flags change how the output is assembled:
|
||||
|
||||
| Flag | Behaviour | Default source |
|
||||
| --- | --- | --- |
|
||||
@@ -579,12 +644,17 @@ flags change how the output is assembled:
|
||||
| `--split-audio` | Write a separate output file per audio codec instead of merging all audio. | config `muxing.merge_audio` (on) |
|
||||
| `--merge-video` | Mux video tracks that share a height, range, and codec into one file, so only language varies inside a file. | config `muxing.merge_video` (off) |
|
||||
|
||||
!!! note "Music is never muxed"
|
||||
A music track skips the muxer. unshackle keeps the container that the service
|
||||
delivered, such as `.flac`, `.m4a`, or `.mp3`, and writes the metadata into that file.
|
||||
Read [Music output files](output-and-naming.md#music-output-files).
|
||||
|
||||
### After the download
|
||||
|
||||
`--postscript "<command>"` runs your own command once per output file, with unshackle's
|
||||
metadata substituted into `{variable}` placeholders. It is repeatable, and it replaces the
|
||||
`post_scripts` config for that run. Nothing runs under `--no-mux`, since no output is
|
||||
written.
|
||||
`post_scripts` config for that run. No `success` hook runs under `--no-mux`, because that
|
||||
run writes no muxed output. A `failure` hook still runs if the download itself fails.
|
||||
|
||||
```shell title="Hand each finished file to an uploader"
|
||||
unshackle dl --postscript "python /opt/upload.py {filepath} --service={service}" EXAMPLE 81234567
|
||||
@@ -820,7 +890,7 @@ authoritative list.
|
||||
| `--forced-subs` | `-fs` | Include forced subtitles. |
|
||||
| `--forced-s-lang` | `-fsl` | Forced subtitle language(s); implies `-fs`. `-` excludes. |
|
||||
| `--sub-format` | | Output subtitle format. |
|
||||
| `--wanted` | `-w` | Episode/season range, or an air date. |
|
||||
| `--wanted` | `-w` | Episode/season range, an air date, or a music track (`1-5`, `2x3`). |
|
||||
| `--daily` | | Fill missing air dates from TVDB during `--enrich`. |
|
||||
| `--select-titles` | | Interactively pick episodes or films. |
|
||||
| `--latest-episode` | | Only the newest episode. |
|
||||
|
||||
@@ -6,7 +6,7 @@ If you have not configured `unshackle.yaml` yet, read [Configuration File](../ge
|
||||
|
||||
## How an output path is assembled
|
||||
|
||||
When a download finishes muxing, unshackle builds the final path from three pieces:
|
||||
When a download finishes, unshackle builds the final path from three pieces:
|
||||
|
||||
```text
|
||||
<output directory> / <folder template> / <filename template><extension>
|
||||
@@ -15,7 +15,7 @@ When a download finishes muxing, unshackle builds the final path from three piec
|
||||
- **Output directory**: `directories.downloads` from your config, or whatever you pass to `-o/--output` on the command line for a single run.
|
||||
- **Folder template**: an optional per-title subfolder. TV episodes and music tracks are **always** placed in a folder; movies only get one if you define a `movies` folder template, or a single-string `folder` template that applies to all title kinds (see [Folder templates](#folder-templates)).
|
||||
- **Filename template**: the `output_template` for the title kind (movie, series, or song).
|
||||
- **Extension**: chosen by the muxer: `.mkv` for video, `.mka` for audio-only, `.mks` for subtitle-only.
|
||||
- **Extension**: chosen by the muxer for a movie or an episode: `.mkv` for video, `.mka` for audio-only, `.mks` for subtitle-only. A music track is not muxed. It keeps the container the service delivered, such as `.flac`, `.m4a`, or `.mp3`. Read [Music output files](#music-output-files).
|
||||
|
||||
!!! example "A typical episode path"
|
||||
```text
|
||||
@@ -218,14 +218,52 @@ The per-kind folder keys are `movies`, `series`, `songs`, and `albums`. Any othe
|
||||
**Fallback behavior:**
|
||||
|
||||
- A per-kind folder template wins if present; otherwise the single `folder` string is used; otherwise unshackle falls back to a built-in default.
|
||||
- Built-in defaults when no folder template is set: movies get no folder at all unless a `movies` folder template (or a single-string `folder` template) exists; series fall back to a folder *derived* from the `series` output template (stripping `{episode}`, `{episode_name}`, and collapsing `{season_episode}` down to `{season}`); music albums fall back to `{artist} - {album} ({year})`.
|
||||
- Built-in defaults when no folder template is set. Movies get no folder at all unless a `movies` folder template (or a single-string `folder` template) exists. Series fall back to a folder *derived* from the `series` output template (stripping `{episode}`, `{episode_name}`, and collapsing `{season_episode}` down to `{season}`). Music albums fall back to `{artist} - {album} ({year})`. If the song has no year, the folder name is only `{artist} - {album}`.
|
||||
|
||||
!!! note "Movies are flat by default"
|
||||
Episodes and songs are always foldered. Movies are written directly into the output directory *unless* you define a `movies` folder template (or a single-string `folder` template, which folders every kind). Set one if you want each movie in its own directory.
|
||||
|
||||
## Music output files
|
||||
|
||||
A music track does not go through the muxer. unshackle moves the downloaded audio file to
|
||||
its final path. It keeps the container that the service delivered. A lossless download
|
||||
arrives as a `.flac` file. An AAC download arrives as a `.m4a` file. unshackle writes no
|
||||
`.mkv` file for music, and the [muxing options](#muxing-options) below do not apply.
|
||||
|
||||
The `songs` output template names the file. The `albums` folder template names the folder
|
||||
around it.
|
||||
|
||||
```text
|
||||
/home/user/Downloads/
|
||||
└─ The Artist - The Album (2024)/
|
||||
├─ 01. First Track.flac
|
||||
└─ 02. Second Track.flac
|
||||
```
|
||||
|
||||
### Music metadata
|
||||
|
||||
After the file moves, unshackle writes the metadata into the audio file. It uses Vorbis
|
||||
comments for FLAC and Ogg, ID3 frames for MP3, and MP4 atoms for M4A. The tags hold the
|
||||
track title, artist, album artist, track and disc numbers, date, genre, ISRC, UPC,
|
||||
copyright, and record label. When `tag` and `tag_group_name` are set, unshackle also writes the group
|
||||
name into a `GROUP` tag.
|
||||
|
||||
Cover art is embedded when the service gives an artwork URL. unshackle downloads the image
|
||||
and puts it in the file.
|
||||
|
||||
Lyrics are written when the service supplies them: a `LYRICS` Vorbis comment for FLAC, a
|
||||
`USLT` frame for MP3, and a `©lyr` atom for M4A. Ogg uses the same `LYRICS` field as
|
||||
FLAC. unshackle does not write synchronized lyrics (`SYLT`).
|
||||
|
||||
A metadata fault does not stop the run. The file is already in place, so unshackle writes a
|
||||
warning and continues.
|
||||
|
||||
!!! warning "`--no-mux` leaves music files untagged"
|
||||
[`--no-mux`](cli-reference.md#output-muxing-files) moves each downloaded track file to the output path without the tagging step. A music file from such a run holds only the metadata that the service put in it.
|
||||
|
||||
## Muxing options
|
||||
|
||||
Muxing (combining video, audio, subtitle, chapter and attachment tracks into a single Matroska file with `mkvmerge`) is configured under the `muxing` key.
|
||||
Muxing (combining video, audio, subtitle, chapter and attachment tracks into a single Matroska file with `mkvmerge`) is configured under the `muxing` key. Only movies and episodes are muxed. Read [Music output files](#music-output-files) for what a music download does instead.
|
||||
|
||||
```yaml title="unshackle.yaml"
|
||||
muxing:
|
||||
|
||||
Reference in New Issue
Block a user