mirror of
https://github.com/unshackle-dl/unshackle.git
synced 2026-11-13 12:35:05 +00:00
fix(api): show filename codec and range labels in codec_display and range_display
This commit is contained in:
@@ -333,10 +333,10 @@ When you give both `season` and `episode`, the server combines them into a `"{se
|
|||||||
"title": { "type": "movie", "name": "Example Movie", "id": "12345", "year": 2021 },
|
"title": { "type": "movie", "name": "Example Movie", "id": "12345", "year": 2021 },
|
||||||
"video": [
|
"video": [
|
||||||
{
|
{
|
||||||
"id": "v-1", "codec": "H265", "codec_display": "HEVC",
|
"id": "v-1", "codec": "HEVC", "codec_display": "H.265",
|
||||||
"bitrate": 8000, "bitrate_bps": 8000000, "width": 3840, "height": 2160,
|
"bitrate": 8000, "bitrate_bps": 8000000, "width": 3840, "height": 2160,
|
||||||
"resolution": "2160p", "fps": "24", "range": "HDR10",
|
"resolution": "2160p", "fps": "24", "range": "HDR10",
|
||||||
"range_display": "HDR10", "scan_type": null, "closed_captions": [],
|
"range_display": "HDR", "scan_type": null, "closed_captions": [],
|
||||||
"dv_compatible_bitstream": false, "hdr10plus": false, "hdr10_base": false, "language": "en",
|
"dv_compatible_bitstream": false, "hdr10plus": false, "hdr10_base": false, "language": "en",
|
||||||
"is_original_lang": true,
|
"is_original_lang": true,
|
||||||
"name": null, "track_name": "English", "needs_repack": false, "edition": [], "data": null,
|
"name": null, "track_name": "English", "needs_repack": false, "edition": [], "data": null,
|
||||||
@@ -345,7 +345,7 @@ When you give both `season` and `episode`, the server combines them into a `"{se
|
|||||||
],
|
],
|
||||||
"audio": [
|
"audio": [
|
||||||
{
|
{
|
||||||
"id": "a-1", "codec": "EC3", "codec_display": "DD+",
|
"id": "a-1", "codec": "EC3", "codec_display": "DDP",
|
||||||
"bitrate": 640, "bitrate_bps": 640000, "channels": "5.1", "language": "en",
|
"bitrate": 640, "bitrate_bps": 640000, "channels": "5.1", "language": "en",
|
||||||
"is_original": true, "is_original_lang": true, "atmos": false, "joc": 0,
|
"is_original": true, "is_original_lang": true, "atmos": false, "joc": 0,
|
||||||
"descriptive": false, "name": null, "track_name": "English", "needs_repack": false, "edition": [],
|
"descriptive": false, "name": null, "track_name": "English", "needs_repack": false, "edition": [],
|
||||||
|
|||||||
@@ -91,6 +91,9 @@ For `hdr`, unshackle renames each part of a Dolby Vision label separately, so `H
|
|||||||
changes `DV.HDR10P` to `DV.HDR10+`. When an audio name ends in a digit, `audio_full` puts a
|
changes `DV.HDR10P` to `DV.HDR10+`. When an audio name ends in a digit, `audio_full` puts a
|
||||||
separator before the channels: `EAC3.5.1`, not `EAC35.1`.
|
separator before the channels: `EAC3.5.1`, not `EAC35.1`.
|
||||||
|
|
||||||
|
The REST API fields `codec_display` and `range_display` use the same names and the same map.
|
||||||
|
The `dl --export` file name does not use `codec_names`.
|
||||||
|
|
||||||
!!! note "`tag_rules` see the new names"
|
!!! note "`tag_rules` see the new names"
|
||||||
unshackle evaluates [`tag_rules`](#tag_rules) after the rename. With the example above, a
|
unshackle evaluates [`tag_rules`](#tag_rules) after the rename. With the example above, a
|
||||||
rule must match `audio: EAC3`, not `audio: DDP`.
|
rule must match `audio: EAC3`, not `audio: DDP`.
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ from unshackle.core.api.handlers import (
|
|||||||
validate_download_parameters,
|
validate_download_parameters,
|
||||||
validate_service,
|
validate_service,
|
||||||
)
|
)
|
||||||
|
from unshackle.core.config import config
|
||||||
from unshackle.core.titles.episode import Episode
|
from unshackle.core.titles.episode import Episode
|
||||||
from unshackle.core.titles.movie import Movie
|
from unshackle.core.titles.movie import Movie
|
||||||
from unshackle.core.tracks import Audio, Subtitle, Video
|
from unshackle.core.tracks import Audio, Subtitle, Video
|
||||||
@@ -172,6 +173,22 @@ def test_serialize_video_track_basic() -> None:
|
|||||||
assert "url" not in d
|
assert "url" not in d
|
||||||
|
|
||||||
|
|
||||||
|
def test_display_labels_match_the_filename_labels(monkeypatch: pytest.MonkeyPatch) -> None:
|
||||||
|
"""codec_display and range_display use the filename names, after any codec_names override."""
|
||||||
|
hevc = video(codec=Video.Codec.HEVC, range_=Video.Range.DV)
|
||||||
|
hevc.hdr10_base = True
|
||||||
|
assert serialize_audio_track(audio(codec=Audio.Codec.EC3))["codec_display"] == "DDP"
|
||||||
|
assert (serialize_video_track(hevc)["codec_display"], serialize_video_track(hevc)["range_display"]) == (
|
||||||
|
"H.265",
|
||||||
|
"DV+HDR",
|
||||||
|
)
|
||||||
|
assert serialize_video_track(video(codec=Video.Codec.VC1))["codec_display"] == "VC-1"
|
||||||
|
|
||||||
|
monkeypatch.setattr(config, "codec_names", {"DDP": "EAC3", "H.265": "HEVC"})
|
||||||
|
assert serialize_audio_track(audio(codec=Audio.Codec.EC3))["codec_display"] == "EAC3"
|
||||||
|
assert serialize_video_track(hevc)["codec_display"] == "HEVC"
|
||||||
|
|
||||||
|
|
||||||
def test_serialize_video_track_include_url() -> None:
|
def test_serialize_video_track_include_url() -> None:
|
||||||
d = serialize_video_track(video(), include_url=True)
|
d = serialize_video_track(video(), include_url=True)
|
||||||
assert d["url"] == "https://example.com/v.mpd"
|
assert d["url"] == "https://example.com/v.mpd"
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ from unshackle.core.services import Services
|
|||||||
from unshackle.core.session import RnetSession, utf8_text
|
from unshackle.core.session import RnetSession, utf8_text
|
||||||
from unshackle.core.titles import Episode, Movie, Song, Title_T
|
from unshackle.core.titles import Episode, Movie, Song, Title_T
|
||||||
from unshackle.core.titles.music import SONG_FIELDS
|
from unshackle.core.titles.music import SONG_FIELDS
|
||||||
|
from unshackle.core.titles.title import rename
|
||||||
from unshackle.core.tracks import Audio, Subtitle, Tracks, Video
|
from unshackle.core.tracks import Audio, Subtitle, Tracks, Video
|
||||||
from unshackle.core.tunnel import HEARTBEAT, MAX_MESSAGE, MAX_TUNNELS, TUNNELS, Tunnel, tunnel_proxy
|
from unshackle.core.tunnel import HEARTBEAT, MAX_MESSAGE, MAX_TUNNELS, TUNNELS, Tunnel, tunnel_proxy
|
||||||
from unshackle.core.utilities import declared_kwargs, kind_only_conflict, original_tag
|
from unshackle.core.utilities import declared_kwargs, kind_only_conflict, original_tag
|
||||||
@@ -1734,12 +1735,13 @@ def serialize_track_common(track: Any) -> Dict[str, Any]:
|
|||||||
def serialize_video_track(track: Video, include_url: bool = False) -> Dict[str, Any]:
|
def serialize_video_track(track: Video, include_url: bool = False) -> Dict[str, Any]:
|
||||||
"""Convert video track to JSON-serializable dict."""
|
"""Convert video track to JSON-serializable dict."""
|
||||||
codec_name = enum_name(track.codec)
|
codec_name = enum_name(track.codec)
|
||||||
|
codec_value = track.codec.value if track.codec else codec_name
|
||||||
range_name = enum_name(track.range)
|
range_name = enum_name(track.range)
|
||||||
|
|
||||||
result = {
|
result = {
|
||||||
"id": str(track.id),
|
"id": str(track.id),
|
||||||
"codec": codec_name,
|
"codec": codec_name,
|
||||||
"codec_display": VIDEO_CODEC_MAP.get(codec_name, codec_name),
|
"codec_display": rename(VIDEO_CODEC_MAP.get(codec_name, codec_value)),
|
||||||
"bitrate": int(track.bitrate / 1000) if track.bitrate else None,
|
"bitrate": int(track.bitrate / 1000) if track.bitrate else None,
|
||||||
"bitrate_bps": track.bitrate or None,
|
"bitrate_bps": track.bitrate or None,
|
||||||
"width": track.width,
|
"width": track.width,
|
||||||
@@ -1747,7 +1749,7 @@ def serialize_video_track(track: Video, include_url: bool = False) -> Dict[str,
|
|||||||
"resolution": f"{track.width}x{track.height}" if track.width and track.height else None,
|
"resolution": f"{track.width}x{track.height}" if track.width and track.height else None,
|
||||||
"fps": track.fps if track.fps else None,
|
"fps": track.fps if track.fps else None,
|
||||||
"range": range_name,
|
"range": range_name,
|
||||||
"range_display": DYNAMIC_RANGE_MAP.get(track.range_label, track.range_label),
|
"range_display": "+".join(rename(DYNAMIC_RANGE_MAP.get(p, p)) for p in track.range_label.split("+")),
|
||||||
"scan_type": enum_name(track.scan_type) if track.scan_type else None,
|
"scan_type": enum_name(track.scan_type) if track.scan_type else None,
|
||||||
"closed_captions": list(getattr(track, "closed_captions", None) or []),
|
"closed_captions": list(getattr(track, "closed_captions", None) or []),
|
||||||
"dv_compatible_bitstream": bool(getattr(track, "dv_compatible_bitstream", False)),
|
"dv_compatible_bitstream": bool(getattr(track, "dv_compatible_bitstream", False)),
|
||||||
@@ -1779,11 +1781,12 @@ def serialize_audio_track(track: Audio, include_url: bool = False, is_original:
|
|||||||
track 'orig' would download.
|
track 'orig' would download.
|
||||||
"""
|
"""
|
||||||
codec_name = enum_name(track.codec)
|
codec_name = enum_name(track.codec)
|
||||||
|
codec_value = track.codec.value if track.codec else codec_name
|
||||||
|
|
||||||
result = {
|
result = {
|
||||||
"id": str(track.id),
|
"id": str(track.id),
|
||||||
"codec": codec_name,
|
"codec": codec_name,
|
||||||
"codec_display": AUDIO_CODEC_MAP.get(codec_name, codec_name),
|
"codec_display": rename(AUDIO_CODEC_MAP.get(codec_value, codec_value)),
|
||||||
"bitrate": int(track.bitrate / 1000) if track.bitrate else None,
|
"bitrate": int(track.bitrate / 1000) if track.bitrate else None,
|
||||||
"bitrate_bps": track.bitrate or None,
|
"bitrate_bps": track.bitrate or None,
|
||||||
"channels": track.channels if track.channels else None,
|
"channels": track.channels if track.channels else None,
|
||||||
|
|||||||
@@ -28,7 +28,14 @@ DYNAMIC_RANGE_MAP = {
|
|||||||
"HDR10 / HDR10+": "HDR10P",
|
"HDR10 / HDR10+": "HDR10P",
|
||||||
"HDR10 / HDR10": "HDR",
|
"HDR10 / HDR10": "HDR",
|
||||||
}
|
}
|
||||||
AUDIO_CODEC_MAP = {"E-AC-3": "DDP", "AC-3": "DD", "DTS-UHD": "DTS-X", "DTS LBR": "DTS-LBR", "MPEG-H 3D Audio": "MPEG-H"}
|
AUDIO_CODEC_MAP = {
|
||||||
|
"E-AC-3": "DDP",
|
||||||
|
"DD+": "DDP", # Audio.Codec.EC3's value, which the REST API names a track by
|
||||||
|
"AC-3": "DD",
|
||||||
|
"DTS-UHD": "DTS-X",
|
||||||
|
"DTS LBR": "DTS-LBR",
|
||||||
|
"MPEG-H 3D Audio": "MPEG-H",
|
||||||
|
}
|
||||||
|
|
||||||
SPACED_AUDIO_CODECS = {"DTS-X"}
|
SPACED_AUDIO_CODECS = {"DTS-X"}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user