unidl 2.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.
- unidl-2.0.0/MANIFEST.in +16 -0
- unidl-2.0.0/PKG-INFO +271 -0
- unidl-2.0.0/README.md +243 -0
- unidl-2.0.0/docs/CONTRIBUTING.md +105 -0
- unidl-2.0.0/docs/README.md +53 -0
- unidl-2.0.0/docs/SECURITY.md +61 -0
- unidl-2.0.0/docs/architecture.md +315 -0
- unidl-2.0.0/docs/audio.md +111 -0
- unidl-2.0.0/docs/availability.md +71 -0
- unidl-2.0.0/docs/batch.md +107 -0
- unidl-2.0.0/docs/cancelling.md +90 -0
- unidl-2.0.0/docs/chapters.md +104 -0
- unidl-2.0.0/docs/configuration.md +108 -0
- unidl-2.0.0/docs/downloader/audio-vivid.md +72 -0
- unidl-2.0.0/docs/downloader/ism-smooth-streaming.md +43 -0
- unidl-2.0.0/docs/downloader/json-manifest-format.md +243 -0
- unidl-2.0.0/docs/downloader/live-pipe-mux.md +26 -0
- unidl-2.0.0/docs/downloader/mp3-audio-format.md +379 -0
- unidl-2.0.0/docs/downloader-integration.md +100 -0
- unidl-2.0.0/docs/drm.md +542 -0
- unidl-2.0.0/docs/external-helpers.md +33 -0
- unidl-2.0.0/docs/i18n.md +105 -0
- unidl-2.0.0/docs/interface.md +210 -0
- unidl-2.0.0/docs/key-vault.md +371 -0
- unidl-2.0.0/docs/live.md +104 -0
- unidl-2.0.0/docs/partner-authorization.md +333 -0
- unidl-2.0.0/docs/playback-lifecycle.md +27 -0
- unidl-2.0.0/docs/publishing.md +83 -0
- unidl-2.0.0/docs/requirements.md +108 -0
- unidl-2.0.0/docs/settings.md +336 -0
- unidl-2.0.0/docs/testing.md +92 -0
- unidl-2.0.0/docs/troubleshooting.md +160 -0
- unidl-2.0.0/docs/ui-design.md +408 -0
- unidl-2.0.0/docs/unidl.example.yaml +21 -0
- unidl-2.0.0/docs/writing-a-service.md +401 -0
- unidl-2.0.0/pyproject.toml +71 -0
- unidl-2.0.0/requirements-dev.txt +7 -0
- unidl-2.0.0/requirements.txt +17 -0
- unidl-2.0.0/setup.cfg +4 -0
- unidl-2.0.0/src/unidl/__init__.py +3 -0
- unidl-2.0.0/src/unidl/__main__.py +180 -0
- unidl-2.0.0/src/unidl/core/__init__.py +70 -0
- unidl-2.0.0/src/unidl/core/appearance.py +199 -0
- unidl-2.0.0/src/unidl/core/brands.py +400 -0
- unidl-2.0.0/src/unidl/core/cache.py +231 -0
- unidl-2.0.0/src/unidl/core/cdm.py +123 -0
- unidl-2.0.0/src/unidl/core/cdmrules.py +354 -0
- unidl-2.0.0/src/unidl/core/chapters.py +207 -0
- unidl-2.0.0/src/unidl/core/config.py +1001 -0
- unidl-2.0.0/src/unidl/core/cookies.py +494 -0
- unidl-2.0.0/src/unidl/core/credentials.py +92 -0
- unidl-2.0.0/src/unidl/core/delivery.py +455 -0
- unidl-2.0.0/src/unidl/core/devreload.py +279 -0
- unidl-2.0.0/src/unidl/core/drm.py +928 -0
- unidl-2.0.0/src/unidl/core/engine.py +2971 -0
- unidl-2.0.0/src/unidl/core/exports.py +578 -0
- unidl-2.0.0/src/unidl/core/flow.py +677 -0
- unidl-2.0.0/src/unidl/core/helpers.py +562 -0
- unidl-2.0.0/src/unidl/core/i18n.py +475 -0
- unidl-2.0.0/src/unidl/core/justwatch.py +699 -0
- unidl-2.0.0/src/unidl/core/lyrics.py +310 -0
- unidl-2.0.0/src/unidl/core/monalisa.py +160 -0
- unidl-2.0.0/src/unidl/core/naming.py +564 -0
- unidl-2.0.0/src/unidl/core/partner.py +180 -0
- unidl-2.0.0/src/unidl/core/playback.py +323 -0
- unidl-2.0.0/src/unidl/core/playready.py +335 -0
- unidl-2.0.0/src/unidl/core/proxy.py +393 -0
- unidl-2.0.0/src/unidl/core/proxy_express.py +496 -0
- unidl-2.0.0/src/unidl/core/pssh.py +328 -0
- unidl-2.0.0/src/unidl/core/qr.py +438 -0
- unidl-2.0.0/src/unidl/core/ranges.py +277 -0
- unidl-2.0.0/src/unidl/core/readiness.py +242 -0
- unidl-2.0.0/src/unidl/core/redact.py +112 -0
- unidl-2.0.0/src/unidl/core/remotecdm.py +425 -0
- unidl-2.0.0/src/unidl/core/secureio.py +219 -0
- unidl-2.0.0/src/unidl/core/service.py +1623 -0
- unidl-2.0.0/src/unidl/core/settings.py +1409 -0
- unidl-2.0.0/src/unidl/core/template.py +136 -0
- unidl-2.0.0/src/unidl/core/titles.py +125 -0
- unidl-2.0.0/src/unidl/core/vault.py +693 -0
- unidl-2.0.0/src/unidl/core/vaults.py +1178 -0
- unidl-2.0.0/src/unidl/downloader/__init__.py +20 -0
- unidl-2.0.0/src/unidl/downloader/api.py +454 -0
- unidl-2.0.0/src/unidl/downloader/applemusic_decrypt.py +217 -0
- unidl-2.0.0/src/unidl/downloader/audio.py +294 -0
- unidl-2.0.0/src/unidl/downloader/avs3.py +965 -0
- unidl-2.0.0/src/unidl/downloader/backend.py +827 -0
- unidl-2.0.0/src/unidl/downloader/bbts.py +498 -0
- unidl-2.0.0/src/unidl/downloader/cenc_fragment.py +1349 -0
- unidl-2.0.0/src/unidl/downloader/chapters.py +89 -0
- unidl-2.0.0/src/unidl/downloader/cli.py +9008 -0
- unidl-2.0.0/src/unidl/downloader/console.py +202 -0
- unidl-2.0.0/src/unidl/downloader/deezer.py +202 -0
- unidl-2.0.0/src/unidl/downloader/detect.py +45 -0
- unidl-2.0.0/src/unidl/downloader/display.py +168 -0
- unidl-2.0.0/src/unidl/downloader/downloader.py +3982 -0
- unidl-2.0.0/src/unidl/downloader/embedding.py +336 -0
- unidl-2.0.0/src/unidl/downloader/http_client.py +875 -0
- unidl-2.0.0/src/unidl/downloader/ism_live.py +29 -0
- unidl-2.0.0/src/unidl/downloader/live.py +2356 -0
- unidl-2.0.0/src/unidl/downloader/live_rules.py +1325 -0
- unidl-2.0.0/src/unidl/downloader/loader.py +306 -0
- unidl-2.0.0/src/unidl/downloader/models.py +219 -0
- unidl-2.0.0/src/unidl/downloader/parser.py +170 -0
- unidl-2.0.0/src/unidl/downloader/parsers/__init__.py +7 -0
- unidl-2.0.0/src/unidl/downloader/parsers/dash.py +1224 -0
- unidl-2.0.0/src/unidl/downloader/parsers/direct.py +157 -0
- unidl-2.0.0/src/unidl/downloader/parsers/hls.py +1081 -0
- unidl-2.0.0/src/unidl/downloader/parsers/ism.py +560 -0
- unidl-2.0.0/src/unidl/downloader/parsers/ism_init.py +536 -0
- unidl-2.0.0/src/unidl/downloader/parsers/json_manifest.py +1153 -0
- unidl-2.0.0/src/unidl/downloader/parsers/sabr_ump.py +705 -0
- unidl-2.0.0/src/unidl/downloader/postprocess.py +1986 -0
- unidl-2.0.0/src/unidl/downloader/qobuz.py +143 -0
- unidl-2.0.0/src/unidl/downloader/sabr_ump.py +2604 -0
- unidl-2.0.0/src/unidl/downloader/selection.py +471 -0
- unidl-2.0.0/src/unidl/downloader/subtitles.py +721 -0
- unidl-2.0.0/src/unidl/downloader/utils.py +350 -0
- unidl-2.0.0/src/unidl/downloader/vgc.py +114 -0
- unidl-2.0.0/src/unidl/downloader/video_range.py +62 -0
- unidl-2.0.0/src/unidl/downloader/webm_decrypt.py +534 -0
- unidl-2.0.0/src/unidl/downloader/webm_live.py +527 -0
- unidl-2.0.0/src/unidl/downloader/youku.py +144 -0
- unidl-2.0.0/src/unidl/locales/en.json +998 -0
- unidl-2.0.0/src/unidl/locales/es.json +998 -0
- unidl-2.0.0/src/unidl/locales/fr.json +998 -0
- unidl-2.0.0/src/unidl/locales/pt.json +998 -0
- unidl-2.0.0/src/unidl/locales/zh-Hans.json +998 -0
- unidl-2.0.0/src/unidl/locales/zh-Hant.json +998 -0
- unidl-2.0.0/src/unidl/services/__init__.py +17 -0
- unidl-2.0.0/src/unidl/services/bbciplayer/__init__.py +402 -0
- unidl-2.0.0/src/unidl/services/bbciplayer/api.py +844 -0
- unidl-2.0.0/src/unidl/services/example/__init__.py +201 -0
- unidl-2.0.0/src/unidl/services/example/api.py +196 -0
- unidl-2.0.0/src/unidl/tui/__init__.py +1 -0
- unidl-2.0.0/src/unidl/tui/about_screen.py +98 -0
- unidl-2.0.0/src/unidl/tui/app.py +841 -0
- unidl-2.0.0/src/unidl/tui/askhost.py +1108 -0
- unidl-2.0.0/src/unidl/tui/asks.py +1004 -0
- unidl-2.0.0/src/unidl/tui/audio.py +494 -0
- unidl-2.0.0/src/unidl/tui/banner.py +366 -0
- unidl-2.0.0/src/unidl/tui/bidi.py +94 -0
- unidl-2.0.0/src/unidl/tui/cdm_rules_screen.py +283 -0
- unidl-2.0.0/src/unidl/tui/cdm_screen.py +421 -0
- unidl-2.0.0/src/unidl/tui/cells.py +46 -0
- unidl-2.0.0/src/unidl/tui/chapters_screen.py +111 -0
- unidl-2.0.0/src/unidl/tui/chrome.py +181 -0
- unidl-2.0.0/src/unidl/tui/download_screen.py +822 -0
- unidl-2.0.0/src/unidl/tui/filterbox.py +69 -0
- unidl-2.0.0/src/unidl/tui/flow_screen.py +106 -0
- unidl-2.0.0/src/unidl/tui/home.py +1036 -0
- unidl-2.0.0/src/unidl/tui/import_screen.py +226 -0
- unidl-2.0.0/src/unidl/tui/justwatch_screen.py +814 -0
- unidl-2.0.0/src/unidl/tui/justwatch_settings.py +112 -0
- unidl-2.0.0/src/unidl/tui/logline.py +201 -0
- unidl-2.0.0/src/unidl/tui/logpane.py +338 -0
- unidl-2.0.0/src/unidl/tui/lyrics_screen.py +96 -0
- unidl-2.0.0/src/unidl/tui/palette.py +69 -0
- unidl-2.0.0/src/unidl/tui/proxy_manager.py +764 -0
- unidl-2.0.0/src/unidl/tui/qr.py +389 -0
- unidl-2.0.0/src/unidl/tui/readiness_screen.py +179 -0
- unidl-2.0.0/src/unidl/tui/resource_manager.py +1360 -0
- unidl-2.0.0/src/unidl/tui/search.py +785 -0
- unidl-2.0.0/src/unidl/tui/service_screen.py +82 -0
- unidl-2.0.0/src/unidl/tui/session.py +2833 -0
- unidl-2.0.0/src/unidl/tui/settings_group.py +148 -0
- unidl-2.0.0/src/unidl/tui/settings_screen.py +740 -0
- unidl-2.0.0/src/unidl/tui/storage_manager.py +481 -0
- unidl-2.0.0/src/unidl/tui/theme.py +2245 -0
- unidl-2.0.0/src/unidl/tui/update_screen.py +67 -0
- unidl-2.0.0/src/unidl/tui/vault_screen.py +643 -0
- unidl-2.0.0/src/unidl/tui/vault_targets.py +349 -0
- unidl-2.0.0/src/unidl.egg-info/PKG-INFO +271 -0
- unidl-2.0.0/src/unidl.egg-info/SOURCES.txt +177 -0
- unidl-2.0.0/src/unidl.egg-info/dependency_links.txt +1 -0
- unidl-2.0.0/src/unidl.egg-info/entry_points.txt +2 -0
- unidl-2.0.0/src/unidl.egg-info/requires.txt +23 -0
- unidl-2.0.0/src/unidl.egg-info/top_level.txt +1 -0
- unidl-2.0.0/tests/test_framework.py +71 -0
unidl-2.0.0/MANIFEST.in
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# Public source archives include the user-facing documentation and install
|
|
2
|
+
# requirement lists, but never local runtime state or private media devices.
|
|
3
|
+
include README.md pyproject.toml requirements.txt requirements-dev.txt
|
|
4
|
+
recursive-include docs *.md *.yaml
|
|
5
|
+
recursive-exclude cdm *
|
|
6
|
+
recursive-exclude helpers *
|
|
7
|
+
recursive-exclude db *
|
|
8
|
+
recursive-exclude cookies *
|
|
9
|
+
recursive-exclude tokens *
|
|
10
|
+
recursive-exclude downloads *
|
|
11
|
+
recursive-exclude download_commands *
|
|
12
|
+
recursive-exclude exports *
|
|
13
|
+
recursive-exclude logs *
|
|
14
|
+
recursive-exclude cache *
|
|
15
|
+
global-exclude *.wvd *.prd *.mld *.sqlite *.sqlite3 *.db-shm *.db-wal *.db-journal
|
|
16
|
+
global-exclude *.pem
|
unidl-2.0.0/PKG-INFO
ADDED
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: unidl
|
|
3
|
+
Version: 2.0.0
|
|
4
|
+
Summary: Integrated TUI for browsing streaming services and downloading selected media.
|
|
5
|
+
Author: unidl contributors
|
|
6
|
+
Requires-Python: >=3.11
|
|
7
|
+
Description-Content-Type: text/markdown
|
|
8
|
+
Requires-Dist: textual>=0.80
|
|
9
|
+
Requires-Dist: pywidevine>=1.8
|
|
10
|
+
Requires-Dist: pyplayready>=0.8.5
|
|
11
|
+
Requires-Dist: wasmtime>=20
|
|
12
|
+
Requires-Dist: requests[socks]>=2.31
|
|
13
|
+
Requires-Dist: qrcode[pil]>=7.4
|
|
14
|
+
Requires-Dist: textual-image[textual]>=0.13.2; python_version >= "3.12"
|
|
15
|
+
Requires-Dist: httpx[http2]>=0.27
|
|
16
|
+
Requires-Dist: cryptography>=42
|
|
17
|
+
Requires-Dist: PyYAML>=6.0
|
|
18
|
+
Requires-Dist: geonamescache>=2.0
|
|
19
|
+
Requires-Dist: pycryptodome>=3.20
|
|
20
|
+
Requires-Dist: python-bidi>=0.6
|
|
21
|
+
Requires-Dist: arabic-reshaper>=3.0
|
|
22
|
+
Provides-Extra: dev
|
|
23
|
+
Requires-Dist: build>=1.2; extra == "dev"
|
|
24
|
+
Requires-Dist: pytest>=8.0; extra == "dev"
|
|
25
|
+
Requires-Dist: ruff>=0.6; extra == "dev"
|
|
26
|
+
Requires-Dist: setuptools>=68; extra == "dev"
|
|
27
|
+
Requires-Dist: wheel>=0.43; extra == "dev"
|
|
28
|
+
|
|
29
|
+
# UniDL
|
|
30
|
+
|
|
31
|
+
UniDL is a terminal-first media browser and native downloader. It connects
|
|
32
|
+
streaming services to one consistent workflow: find a title or channel, sign in
|
|
33
|
+
when needed, inspect the available media, choose the tracks you want, resolve
|
|
34
|
+
DRM keys through the service contract, and download or record the result.
|
|
35
|
+
|
|
36
|
+
The project is designed around three clear layers:
|
|
37
|
+
|
|
38
|
+
- **Services** handle login, catalogues, search, manifests, service settings and
|
|
39
|
+
service-owned licence requests.
|
|
40
|
+
- **Core/TUI** handles navigation, settings, credentials, CDM/vault selection,
|
|
41
|
+
track selection, progress, logs and the interactive workflow.
|
|
42
|
+
- **Native downloader** parses manifests, downloads segments, decrypts media,
|
|
43
|
+
writes subtitles and chapters, and muxes the final output in-process.
|
|
44
|
+
|
|
45
|
+
## Features
|
|
46
|
+
|
|
47
|
+
### Interactive TUI
|
|
48
|
+
|
|
49
|
+
- Keyboard and mouse navigation with predictable Back, Cancel and Quit behavior.
|
|
50
|
+
- Service home screens with URL, search, live, library and login entry points.
|
|
51
|
+
- Search results that continue through seasons and episodes without leaving the
|
|
52
|
+
service flow.
|
|
53
|
+
- JustWatch title and availability search with configurable regions and provider
|
|
54
|
+
mapping.
|
|
55
|
+
- Responsive log and progress panels, selectable text, copy actions, light and
|
|
56
|
+
dark themes, and localized interface strings.
|
|
57
|
+
- Explicit development reload for service packages without silently watching
|
|
58
|
+
files in the background.
|
|
59
|
+
|
|
60
|
+
### VOD
|
|
61
|
+
|
|
62
|
+
- DASH/MPD, HLS, ISM/Smooth Streaming, JSON manifests and direct media URLs.
|
|
63
|
+
- Multiple video, audio and subtitle tracks with independent output selection.
|
|
64
|
+
- Resolution, codec, dynamic-range, language, channel-layout and subtitle
|
|
65
|
+
controls, including HDR/Dolby Vision and audio codec labels where available.
|
|
66
|
+
- Multi-manifest playback plans for services that expose separate ladders.
|
|
67
|
+
- Optional chapter retrieval and chapter embedding into the final container.
|
|
68
|
+
- Safe output naming with title, season/episode, resolution, audio and codec
|
|
69
|
+
tags based on the tracks the user actually downloads.
|
|
70
|
+
- Resumable segment downloads, cache-aware retries, post-processing and muxing.
|
|
71
|
+
|
|
72
|
+
### Live recording
|
|
73
|
+
|
|
74
|
+
- Live HLS, DASH/fMP4 and other refreshable playlists.
|
|
75
|
+
- Track selection before recording, replay/DVR window inspection, recording
|
|
76
|
+
from the live edge or a chosen offset, and finite or unlimited duration.
|
|
77
|
+
- `00:00:00` means no duration limit; Stop, Back or Esc ends an active recording.
|
|
78
|
+
- Real-time merge and pipe-mux modes where the source and container support them.
|
|
79
|
+
- Rotating live keys with service-provided init data and an interactive fallback
|
|
80
|
+
for a genuinely new KID.
|
|
81
|
+
- Progress, replay-window information, segment counts, estimated size and
|
|
82
|
+
cancellation state in the TUI.
|
|
83
|
+
|
|
84
|
+
### DRM, vaults and credentials
|
|
85
|
+
|
|
86
|
+
- Local Widevine, PlayReady and MonaLisa device contracts with strict system
|
|
87
|
+
matching.
|
|
88
|
+
- Optional remote CDM endpoints for systems that support remote challenge and
|
|
89
|
+
licence parsing.
|
|
90
|
+
- Local SQLite key vaults and compatible remote key vaults, with multi-vault
|
|
91
|
+
read/write policies, service scoping and manual KID:key entry.
|
|
92
|
+
- Service-local licence transport: the shared DRM layer creates challenges and
|
|
93
|
+
parses responses, while each service owns its endpoint, headers and request
|
|
94
|
+
format.
|
|
95
|
+
- Independent credential slots, cookie profiles, token stores and refresh
|
|
96
|
+
lifecycles per service and login method.
|
|
97
|
+
|
|
98
|
+
### Audio and metadata
|
|
99
|
+
|
|
100
|
+
- Audio-only services and audio tracks use a dedicated presentation and naming
|
|
101
|
+
path.
|
|
102
|
+
- MP3 export with ID3v2 metadata, cover art, artist/album/title fields and
|
|
103
|
+
chapter-aware post-processing.
|
|
104
|
+
- Clear audio formats remain available when the source already matches the
|
|
105
|
+
requested container; other sources are converted through FFmpeg.
|
|
106
|
+
|
|
107
|
+
### Helpers, proxy and storage
|
|
108
|
+
|
|
109
|
+
- Declared service helpers resolved from configuration, `PATH`, project helper
|
|
110
|
+
folders or package resources; no arbitrary filesystem scan.
|
|
111
|
+
- HTTP/HTTPS and SOCKS proxy support plus provider-specific VPN integrations
|
|
112
|
+
when configured by the user.
|
|
113
|
+
- Project-relative paths for tokens, cookies, CDMs, vaults, caches, commands,
|
|
114
|
+
subtitles and finished media.
|
|
115
|
+
- JSON command/export artifacts for automation and reproducible downloads.
|
|
116
|
+
|
|
117
|
+
## Install
|
|
118
|
+
|
|
119
|
+
The minimum supported runtime is **Python 3.11** on Windows, macOS or Linux.
|
|
120
|
+
Use a 64-bit Python build and install FFmpeg (including `ffprobe`) for the full
|
|
121
|
+
download, conversion and muxing workflow. The Python dependency list is kept in
|
|
122
|
+
[`requirements.txt`](requirements.txt); development checks are in
|
|
123
|
+
[`requirements-dev.txt`](requirements-dev.txt).
|
|
124
|
+
|
|
125
|
+
From a published PyPI release:
|
|
126
|
+
|
|
127
|
+
```console
|
|
128
|
+
python3 -m venv .venv
|
|
129
|
+
source .venv/bin/activate # Windows: .venv\Scripts\activate
|
|
130
|
+
python -m pip install --upgrade pip
|
|
131
|
+
python -m pip install unidl
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
The project is also installable directly from a source checkout:
|
|
135
|
+
|
|
136
|
+
```console
|
|
137
|
+
python3 -m venv .venv
|
|
138
|
+
source .venv/bin/activate # Windows: .venv\Scripts\activate
|
|
139
|
+
python -m pip install --upgrade pip
|
|
140
|
+
python -m pip install .
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
For development and tests:
|
|
144
|
+
|
|
145
|
+
```console
|
|
146
|
+
python -m pip install -e '.[dev]'
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
The project also works with `uv`:
|
|
150
|
+
|
|
151
|
+
```console
|
|
152
|
+
uv sync --extra dev
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
`pip install unidl` is the shortest installation after a release has been
|
|
156
|
+
published to PyPI. Until then, use the source-checkout command above.
|
|
157
|
+
|
|
158
|
+
Place local CDM files under the configured `paths.cdm` tree and keep their
|
|
159
|
+
private material outside version control. Helpers, cookies, tokens and vault
|
|
160
|
+
databases are runtime data and should be stored in the configured project
|
|
161
|
+
directories.
|
|
162
|
+
|
|
163
|
+
See [Requirements and installation](docs/requirements.md) for external tools,
|
|
164
|
+
platform notes and a complete preflight checklist.
|
|
165
|
+
|
|
166
|
+
## Use UniDL
|
|
167
|
+
|
|
168
|
+
Launch the installed TUI:
|
|
169
|
+
|
|
170
|
+
```console
|
|
171
|
+
unidl
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
`python -m unidl` is equivalent. A packaged install uses `unidl.yaml` from the
|
|
175
|
+
current directory when it exists; otherwise it starts with the safe built-in
|
|
176
|
+
path defaults. Pass an explicit configuration whenever the file lives elsewhere:
|
|
177
|
+
|
|
178
|
+
```console
|
|
179
|
+
unidl --config ./unidl.yaml
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
Useful read-only diagnostics:
|
|
183
|
+
|
|
184
|
+
```console
|
|
185
|
+
unidl --config ./unidl.yaml --help
|
|
186
|
+
unidl --config ./unidl.yaml services
|
|
187
|
+
unidl --config ./unidl.yaml cdm --check
|
|
188
|
+
unidl --config ./unidl.yaml keys <kid> --service <service-id>
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
The native downloader can also consume an exported JSON manifest or a direct
|
|
192
|
+
source URL:
|
|
193
|
+
|
|
194
|
+
```console
|
|
195
|
+
unidl list <manifest-or-json>
|
|
196
|
+
unidl download <manifest-or-url> --save-name "Example.Title"
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
In the TUI, choose a service, search or open a URL, select the title and tracks,
|
|
200
|
+
then choose whether to download now or save a command/export. A service's own
|
|
201
|
+
settings control provider API/profile choices; the shared track settings control
|
|
202
|
+
the final output tracks only. See [docs/settings.md](docs/settings.md).
|
|
203
|
+
|
|
204
|
+
For live channels, choose the tracks first, then choose recording, replay/DVR
|
|
205
|
+
behavior and duration. Leave the duration at `00:00:00` for an unlimited
|
|
206
|
+
recording and use Stop/Back/Esc to finish it.
|
|
207
|
+
|
|
208
|
+
## Configuration and data
|
|
209
|
+
|
|
210
|
+
`unidl.yaml` is the static configuration surface. Relative paths are resolved
|
|
211
|
+
from the directory containing that file, so a checkout can be moved safely.
|
|
212
|
+
Interactive preferences are stored in `settings.json` under `paths.home`.
|
|
213
|
+
Credentials, cookies, tokens, CDMs, vaults, logs, command files and exports are
|
|
214
|
+
never required to be committed. Use a private override file for secrets:
|
|
215
|
+
|
|
216
|
+
```console
|
|
217
|
+
python -m unidl --config ./unidl.private.yaml
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
The application uses the explicitly selected configuration or the project-root
|
|
221
|
+
configuration when launched from a source checkout.
|
|
222
|
+
|
|
223
|
+
## Project layout
|
|
224
|
+
|
|
225
|
+
```text
|
|
226
|
+
src/unidl/core/ contracts, DRM, vaults, storage and flow engine
|
|
227
|
+
src/unidl/tui/ Textual interface and screens
|
|
228
|
+
src/unidl/downloader/ native parsers, transfer, decrypt and mux pipeline
|
|
229
|
+
src/unidl/services/ one package per service
|
|
230
|
+
helpers/ declared helper assets and modules
|
|
231
|
+
cdm/ local device files, kept private
|
|
232
|
+
docs/ architecture, service and downloader documentation
|
|
233
|
+
tests/ offline contract and integration tests
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
## Documentation
|
|
237
|
+
|
|
238
|
+
Start with [docs/README.md](docs/README.md). The most useful paths are:
|
|
239
|
+
|
|
240
|
+
- [Architecture](docs/architecture.md) — boundaries and data flow.
|
|
241
|
+
- [Requirements and installation](docs/requirements.md) — supported runtimes,
|
|
242
|
+
package installation and external tools.
|
|
243
|
+
- [Publishing](docs/publishing.md) — PyPI releases, token handling and GitHub
|
|
244
|
+
account switching.
|
|
245
|
+
- [Writing a service](docs/writing-a-service.md) — add a service and integrate
|
|
246
|
+
native Core capabilities.
|
|
247
|
+
- [Native downloader](docs/downloader-integration.md) — supported inputs,
|
|
248
|
+
delivery contracts and progress.
|
|
249
|
+
- [Configuration](docs/configuration.md) and [Settings](docs/settings.md) —
|
|
250
|
+
static configuration versus interactive preferences.
|
|
251
|
+
- [DRM](docs/drm.md) and [Key vault](docs/key-vault.md) — local/remote key
|
|
252
|
+
resolution and service-owned licensing.
|
|
253
|
+
- [Live channels](docs/live.md), [Audio](docs/audio.md) and
|
|
254
|
+
[Chapters](docs/chapters.md) — specialized playback paths.
|
|
255
|
+
- [Testing](docs/testing.md), [Troubleshooting](docs/troubleshooting.md) and
|
|
256
|
+
[Security](docs/SECURITY.md) — verification and safe operation.
|
|
257
|
+
|
|
258
|
+
## Development checks
|
|
259
|
+
|
|
260
|
+
```console
|
|
261
|
+
python -m pytest -q
|
|
262
|
+
python -m ruff check src tests
|
|
263
|
+
python -m compileall -q src
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
When changing a service, run its offline checks and a real playback check with
|
|
267
|
+
authorized account, region and device data. Never include credentials, cookies,
|
|
268
|
+
tokens, CDM private material, vault keys or signed URLs in commits or bug
|
|
269
|
+
reports.
|
|
270
|
+
|
|
271
|
+
Copyright © 2026 Chris20
|
unidl-2.0.0/README.md
ADDED
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
# UniDL
|
|
2
|
+
|
|
3
|
+
UniDL is a terminal-first media browser and native downloader. It connects
|
|
4
|
+
streaming services to one consistent workflow: find a title or channel, sign in
|
|
5
|
+
when needed, inspect the available media, choose the tracks you want, resolve
|
|
6
|
+
DRM keys through the service contract, and download or record the result.
|
|
7
|
+
|
|
8
|
+
The project is designed around three clear layers:
|
|
9
|
+
|
|
10
|
+
- **Services** handle login, catalogues, search, manifests, service settings and
|
|
11
|
+
service-owned licence requests.
|
|
12
|
+
- **Core/TUI** handles navigation, settings, credentials, CDM/vault selection,
|
|
13
|
+
track selection, progress, logs and the interactive workflow.
|
|
14
|
+
- **Native downloader** parses manifests, downloads segments, decrypts media,
|
|
15
|
+
writes subtitles and chapters, and muxes the final output in-process.
|
|
16
|
+
|
|
17
|
+
## Features
|
|
18
|
+
|
|
19
|
+
### Interactive TUI
|
|
20
|
+
|
|
21
|
+
- Keyboard and mouse navigation with predictable Back, Cancel and Quit behavior.
|
|
22
|
+
- Service home screens with URL, search, live, library and login entry points.
|
|
23
|
+
- Search results that continue through seasons and episodes without leaving the
|
|
24
|
+
service flow.
|
|
25
|
+
- JustWatch title and availability search with configurable regions and provider
|
|
26
|
+
mapping.
|
|
27
|
+
- Responsive log and progress panels, selectable text, copy actions, light and
|
|
28
|
+
dark themes, and localized interface strings.
|
|
29
|
+
- Explicit development reload for service packages without silently watching
|
|
30
|
+
files in the background.
|
|
31
|
+
|
|
32
|
+
### VOD
|
|
33
|
+
|
|
34
|
+
- DASH/MPD, HLS, ISM/Smooth Streaming, JSON manifests and direct media URLs.
|
|
35
|
+
- Multiple video, audio and subtitle tracks with independent output selection.
|
|
36
|
+
- Resolution, codec, dynamic-range, language, channel-layout and subtitle
|
|
37
|
+
controls, including HDR/Dolby Vision and audio codec labels where available.
|
|
38
|
+
- Multi-manifest playback plans for services that expose separate ladders.
|
|
39
|
+
- Optional chapter retrieval and chapter embedding into the final container.
|
|
40
|
+
- Safe output naming with title, season/episode, resolution, audio and codec
|
|
41
|
+
tags based on the tracks the user actually downloads.
|
|
42
|
+
- Resumable segment downloads, cache-aware retries, post-processing and muxing.
|
|
43
|
+
|
|
44
|
+
### Live recording
|
|
45
|
+
|
|
46
|
+
- Live HLS, DASH/fMP4 and other refreshable playlists.
|
|
47
|
+
- Track selection before recording, replay/DVR window inspection, recording
|
|
48
|
+
from the live edge or a chosen offset, and finite or unlimited duration.
|
|
49
|
+
- `00:00:00` means no duration limit; Stop, Back or Esc ends an active recording.
|
|
50
|
+
- Real-time merge and pipe-mux modes where the source and container support them.
|
|
51
|
+
- Rotating live keys with service-provided init data and an interactive fallback
|
|
52
|
+
for a genuinely new KID.
|
|
53
|
+
- Progress, replay-window information, segment counts, estimated size and
|
|
54
|
+
cancellation state in the TUI.
|
|
55
|
+
|
|
56
|
+
### DRM, vaults and credentials
|
|
57
|
+
|
|
58
|
+
- Local Widevine, PlayReady and MonaLisa device contracts with strict system
|
|
59
|
+
matching.
|
|
60
|
+
- Optional remote CDM endpoints for systems that support remote challenge and
|
|
61
|
+
licence parsing.
|
|
62
|
+
- Local SQLite key vaults and compatible remote key vaults, with multi-vault
|
|
63
|
+
read/write policies, service scoping and manual KID:key entry.
|
|
64
|
+
- Service-local licence transport: the shared DRM layer creates challenges and
|
|
65
|
+
parses responses, while each service owns its endpoint, headers and request
|
|
66
|
+
format.
|
|
67
|
+
- Independent credential slots, cookie profiles, token stores and refresh
|
|
68
|
+
lifecycles per service and login method.
|
|
69
|
+
|
|
70
|
+
### Audio and metadata
|
|
71
|
+
|
|
72
|
+
- Audio-only services and audio tracks use a dedicated presentation and naming
|
|
73
|
+
path.
|
|
74
|
+
- MP3 export with ID3v2 metadata, cover art, artist/album/title fields and
|
|
75
|
+
chapter-aware post-processing.
|
|
76
|
+
- Clear audio formats remain available when the source already matches the
|
|
77
|
+
requested container; other sources are converted through FFmpeg.
|
|
78
|
+
|
|
79
|
+
### Helpers, proxy and storage
|
|
80
|
+
|
|
81
|
+
- Declared service helpers resolved from configuration, `PATH`, project helper
|
|
82
|
+
folders or package resources; no arbitrary filesystem scan.
|
|
83
|
+
- HTTP/HTTPS and SOCKS proxy support plus provider-specific VPN integrations
|
|
84
|
+
when configured by the user.
|
|
85
|
+
- Project-relative paths for tokens, cookies, CDMs, vaults, caches, commands,
|
|
86
|
+
subtitles and finished media.
|
|
87
|
+
- JSON command/export artifacts for automation and reproducible downloads.
|
|
88
|
+
|
|
89
|
+
## Install
|
|
90
|
+
|
|
91
|
+
The minimum supported runtime is **Python 3.11** on Windows, macOS or Linux.
|
|
92
|
+
Use a 64-bit Python build and install FFmpeg (including `ffprobe`) for the full
|
|
93
|
+
download, conversion and muxing workflow. The Python dependency list is kept in
|
|
94
|
+
[`requirements.txt`](requirements.txt); development checks are in
|
|
95
|
+
[`requirements-dev.txt`](requirements-dev.txt).
|
|
96
|
+
|
|
97
|
+
From a published PyPI release:
|
|
98
|
+
|
|
99
|
+
```console
|
|
100
|
+
python3 -m venv .venv
|
|
101
|
+
source .venv/bin/activate # Windows: .venv\Scripts\activate
|
|
102
|
+
python -m pip install --upgrade pip
|
|
103
|
+
python -m pip install unidl
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
The project is also installable directly from a source checkout:
|
|
107
|
+
|
|
108
|
+
```console
|
|
109
|
+
python3 -m venv .venv
|
|
110
|
+
source .venv/bin/activate # Windows: .venv\Scripts\activate
|
|
111
|
+
python -m pip install --upgrade pip
|
|
112
|
+
python -m pip install .
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
For development and tests:
|
|
116
|
+
|
|
117
|
+
```console
|
|
118
|
+
python -m pip install -e '.[dev]'
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
The project also works with `uv`:
|
|
122
|
+
|
|
123
|
+
```console
|
|
124
|
+
uv sync --extra dev
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
`pip install unidl` is the shortest installation after a release has been
|
|
128
|
+
published to PyPI. Until then, use the source-checkout command above.
|
|
129
|
+
|
|
130
|
+
Place local CDM files under the configured `paths.cdm` tree and keep their
|
|
131
|
+
private material outside version control. Helpers, cookies, tokens and vault
|
|
132
|
+
databases are runtime data and should be stored in the configured project
|
|
133
|
+
directories.
|
|
134
|
+
|
|
135
|
+
See [Requirements and installation](docs/requirements.md) for external tools,
|
|
136
|
+
platform notes and a complete preflight checklist.
|
|
137
|
+
|
|
138
|
+
## Use UniDL
|
|
139
|
+
|
|
140
|
+
Launch the installed TUI:
|
|
141
|
+
|
|
142
|
+
```console
|
|
143
|
+
unidl
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
`python -m unidl` is equivalent. A packaged install uses `unidl.yaml` from the
|
|
147
|
+
current directory when it exists; otherwise it starts with the safe built-in
|
|
148
|
+
path defaults. Pass an explicit configuration whenever the file lives elsewhere:
|
|
149
|
+
|
|
150
|
+
```console
|
|
151
|
+
unidl --config ./unidl.yaml
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
Useful read-only diagnostics:
|
|
155
|
+
|
|
156
|
+
```console
|
|
157
|
+
unidl --config ./unidl.yaml --help
|
|
158
|
+
unidl --config ./unidl.yaml services
|
|
159
|
+
unidl --config ./unidl.yaml cdm --check
|
|
160
|
+
unidl --config ./unidl.yaml keys <kid> --service <service-id>
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
The native downloader can also consume an exported JSON manifest or a direct
|
|
164
|
+
source URL:
|
|
165
|
+
|
|
166
|
+
```console
|
|
167
|
+
unidl list <manifest-or-json>
|
|
168
|
+
unidl download <manifest-or-url> --save-name "Example.Title"
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
In the TUI, choose a service, search or open a URL, select the title and tracks,
|
|
172
|
+
then choose whether to download now or save a command/export. A service's own
|
|
173
|
+
settings control provider API/profile choices; the shared track settings control
|
|
174
|
+
the final output tracks only. See [docs/settings.md](docs/settings.md).
|
|
175
|
+
|
|
176
|
+
For live channels, choose the tracks first, then choose recording, replay/DVR
|
|
177
|
+
behavior and duration. Leave the duration at `00:00:00` for an unlimited
|
|
178
|
+
recording and use Stop/Back/Esc to finish it.
|
|
179
|
+
|
|
180
|
+
## Configuration and data
|
|
181
|
+
|
|
182
|
+
`unidl.yaml` is the static configuration surface. Relative paths are resolved
|
|
183
|
+
from the directory containing that file, so a checkout can be moved safely.
|
|
184
|
+
Interactive preferences are stored in `settings.json` under `paths.home`.
|
|
185
|
+
Credentials, cookies, tokens, CDMs, vaults, logs, command files and exports are
|
|
186
|
+
never required to be committed. Use a private override file for secrets:
|
|
187
|
+
|
|
188
|
+
```console
|
|
189
|
+
python -m unidl --config ./unidl.private.yaml
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
The application uses the explicitly selected configuration or the project-root
|
|
193
|
+
configuration when launched from a source checkout.
|
|
194
|
+
|
|
195
|
+
## Project layout
|
|
196
|
+
|
|
197
|
+
```text
|
|
198
|
+
src/unidl/core/ contracts, DRM, vaults, storage and flow engine
|
|
199
|
+
src/unidl/tui/ Textual interface and screens
|
|
200
|
+
src/unidl/downloader/ native parsers, transfer, decrypt and mux pipeline
|
|
201
|
+
src/unidl/services/ one package per service
|
|
202
|
+
helpers/ declared helper assets and modules
|
|
203
|
+
cdm/ local device files, kept private
|
|
204
|
+
docs/ architecture, service and downloader documentation
|
|
205
|
+
tests/ offline contract and integration tests
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
## Documentation
|
|
209
|
+
|
|
210
|
+
Start with [docs/README.md](docs/README.md). The most useful paths are:
|
|
211
|
+
|
|
212
|
+
- [Architecture](docs/architecture.md) — boundaries and data flow.
|
|
213
|
+
- [Requirements and installation](docs/requirements.md) — supported runtimes,
|
|
214
|
+
package installation and external tools.
|
|
215
|
+
- [Publishing](docs/publishing.md) — PyPI releases, token handling and GitHub
|
|
216
|
+
account switching.
|
|
217
|
+
- [Writing a service](docs/writing-a-service.md) — add a service and integrate
|
|
218
|
+
native Core capabilities.
|
|
219
|
+
- [Native downloader](docs/downloader-integration.md) — supported inputs,
|
|
220
|
+
delivery contracts and progress.
|
|
221
|
+
- [Configuration](docs/configuration.md) and [Settings](docs/settings.md) —
|
|
222
|
+
static configuration versus interactive preferences.
|
|
223
|
+
- [DRM](docs/drm.md) and [Key vault](docs/key-vault.md) — local/remote key
|
|
224
|
+
resolution and service-owned licensing.
|
|
225
|
+
- [Live channels](docs/live.md), [Audio](docs/audio.md) and
|
|
226
|
+
[Chapters](docs/chapters.md) — specialized playback paths.
|
|
227
|
+
- [Testing](docs/testing.md), [Troubleshooting](docs/troubleshooting.md) and
|
|
228
|
+
[Security](docs/SECURITY.md) — verification and safe operation.
|
|
229
|
+
|
|
230
|
+
## Development checks
|
|
231
|
+
|
|
232
|
+
```console
|
|
233
|
+
python -m pytest -q
|
|
234
|
+
python -m ruff check src tests
|
|
235
|
+
python -m compileall -q src
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
When changing a service, run its offline checks and a real playback check with
|
|
239
|
+
authorized account, region and device data. Never include credentials, cookies,
|
|
240
|
+
tokens, CDM private material, vault keys or signed URLs in commits or bug
|
|
241
|
+
reports.
|
|
242
|
+
|
|
243
|
+
Copyright © 2026 Chris20
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
# Contributing to unidl
|
|
2
|
+
|
|
3
|
+
UniDL services are the account, catalogue and key-acquisition layer; the native
|
|
4
|
+
delivery core is part of the same application. Keep that boundary intact:
|
|
5
|
+
services may log in, discover playback and acquire keys; the native core owns
|
|
6
|
+
manifest parsing, track selection, download, decrypt, subtitles and muxing.
|
|
7
|
+
|
|
8
|
+
## Before changing code
|
|
9
|
+
|
|
10
|
+
1. Create a virtual environment and install UniDL plus the development extras
|
|
11
|
+
as described in [docs/testing.md](testing.md).
|
|
12
|
+
2. Read [docs/architecture.md](architecture.md) and, for service work,
|
|
13
|
+
[docs/writing-a-service.md](writing-a-service.md).
|
|
14
|
+
3. Keep credentials, cookies, tokens, device files, content keys, command
|
|
15
|
+
exports and debug logs out of version control. The visible project-local
|
|
16
|
+
runtime layout is supported, but its paths must remain ignored.
|
|
17
|
+
|
|
18
|
+
## Project rules
|
|
19
|
+
|
|
20
|
+
- Service code never imports Textual, calls `print()` or calls `input()`. It
|
|
21
|
+
yields Flow asks and returns a `Playback`.
|
|
22
|
+
- Put HTTP clients and response parsing in the service's `api.py`; keep the flow
|
|
23
|
+
in `__init__.py`.
|
|
24
|
+
- Add each provider as one native package under `src/unidl/services/` and
|
|
25
|
+
register it in `src/unidl/services/__init__.py`; follow
|
|
26
|
+
[writing-a-service.md](writing-a-service.md).
|
|
27
|
+
- Do not duplicate manifest parsing, selection or download logic from the native delivery core.
|
|
28
|
+
- Do not hardcode credentials, local absolute paths or helper locations.
|
|
29
|
+
- Declare settings, credentials, helpers and `DRM_SYSTEMS`; do not make the UI
|
|
30
|
+
infer them from service internals.
|
|
31
|
+
- Shared Track output selection controls only what the native delivery core downloads and muxes.
|
|
32
|
+
Never reuse its quality/codec/range/audio/subtitle settings as licence-track
|
|
33
|
+
policy; configurable licence tracks/profiles/PSSH seeds require a separate
|
|
34
|
+
setting in that service's own section. The app-wide post-selection licence
|
|
35
|
+
compatibility mode is implemented by Core and is not permission for service
|
|
36
|
+
code to read those shared settings.
|
|
37
|
+
- Read and write session state only through `ctx.tokens`, which is rooted at this
|
|
38
|
+
service's own folder under `paths.tokens`. Name the file, never the directory:
|
|
39
|
+
path separators, absolute paths and `..` are rejected by `TokenStore`.
|
|
40
|
+
- If a service's file is renamed, move it rather than copy it: leaving the old
|
|
41
|
+
name behind leaves a session that signing out does not remove and the next read
|
|
42
|
+
adopts again.
|
|
43
|
+
- Keep narrative documentation free of fixed service totals. The porting record
|
|
44
|
+
may quote a measured snapshot; nothing else should.
|
|
45
|
+
|
|
46
|
+
## Documentation with code changes
|
|
47
|
+
|
|
48
|
+
Update the matching reference in the same change:
|
|
49
|
+
|
|
50
|
+
- a config key: `docs/configuration.md` and `unidl.example.yaml`
|
|
51
|
+
- a global or track setting: `docs/settings.md`
|
|
52
|
+
- a Flow ask or service hook: `docs/writing-a-service.md` and the reference
|
|
53
|
+
service comments
|
|
54
|
+
- a screen, binding or snapshot target: `docs/interface.md` and
|
|
55
|
+
`docs/ui-design.md`
|
|
56
|
+
- DRM or vault behaviour: `docs/drm.md` or `docs/key-vault.md`
|
|
57
|
+
- a new verification command or fixture: `docs/testing.md`
|
|
58
|
+
|
|
59
|
+
Link new user-facing documents from `README.md` and use relative Markdown links
|
|
60
|
+
inside the repository.
|
|
61
|
+
|
|
62
|
+
## Verification
|
|
63
|
+
|
|
64
|
+
Run `ruff` and `compileall`, then the smallest relevant offline checks. Run live
|
|
65
|
+
checks only when you have the required account, region, device and authority;
|
|
66
|
+
state exactly which commands ran and which were not run. Never paste live
|
|
67
|
+
credentials, full content keys, CDM secrets or unredacted debug logs into a bug
|
|
68
|
+
report or review.
|
|
69
|
+
|
|
70
|
+
For a service port, exercise every declared entry point against the real
|
|
71
|
+
service. Importing successfully is not proof that login, catalogue parsing,
|
|
72
|
+
licensing or the current third-party schema works.
|
|
73
|
+
|
|
74
|
+
## Reloading service code during development
|
|
75
|
+
|
|
76
|
+
unidl does not watch source files. To adopt an edit without quitting, turn on
|
|
77
|
+
global **Debug mode**, return to the bare Home screen, highlight one service (or
|
|
78
|
+
filter to exactly one), and press `ctrl+r`. The action compiles the selected
|
|
79
|
+
service's loaded source first, reloads its multi-file package in dependency
|
|
80
|
+
order, and also reloads native service packages that share those modules. Core,
|
|
81
|
+
TUI and unrelated service modules are outside the reload graph.
|
|
82
|
+
|
|
83
|
+
The registry receives new classes, so only the **next** service session uses the
|
|
84
|
+
new code. No active service instance, download, licence exchange, heartbeat or
|
|
85
|
+
playback-session cleanup is patched. Reload is deliberately unavailable while a
|
|
86
|
+
service or overlay is on the screen.
|
|
87
|
+
|
|
88
|
+
This is a development convenience, not a transactional production hot patch.
|
|
89
|
+
A syntax error is rejected before any module is touched and the old registry is
|
|
90
|
+
restored after an import error, but Python cannot fully undo module globals that
|
|
91
|
+
an already-started import changed. Restart unidl after a failed reload, or after
|
|
92
|
+
adding/removing/renaming modules or symbols whose old names may remain in a
|
|
93
|
+
module namespace. Changing a service id also requires a restart.
|
|
94
|
+
|
|
95
|
+
## Change description
|
|
96
|
+
|
|
97
|
+
Explain:
|
|
98
|
+
|
|
99
|
+
- what user-visible behaviour changed;
|
|
100
|
+
- which contract or bug motivated it;
|
|
101
|
+
- the checks run and their environment (offline, loopback or live);
|
|
102
|
+
- any account, region, helper, CDM or external-service limitation;
|
|
103
|
+
- any migration or configuration step users must take.
|
|
104
|
+
|
|
105
|
+
Use the software only with accounts and content you are authorised to access.
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# UniDL documentation
|
|
2
|
+
|
|
3
|
+
This directory documents the public UniDL contracts and the workflow for using
|
|
4
|
+
and extending the project.
|
|
5
|
+
|
|
6
|
+
## Start here
|
|
7
|
+
|
|
8
|
+
- [Architecture](architecture.md) — Core, TUI, services and native delivery.
|
|
9
|
+
- [Writing a service](writing-a-service.md) — package layout, registration,
|
|
10
|
+
Flow asks, playback, DRM, credentials and testing.
|
|
11
|
+
- [Configuration](configuration.md) — YAML, paths, devices and runtime state.
|
|
12
|
+
- [Settings](settings.md) — global, service and output-track preferences.
|
|
13
|
+
- [Requirements and installation](requirements.md) — supported Python versions,
|
|
14
|
+
external tools, package installs and runtime data.
|
|
15
|
+
- [Publishing](publishing.md) — PyPI tokens, trusted publishing and GitHub
|
|
16
|
+
account switching.
|
|
17
|
+
- [Native downloader](downloader-integration.md) — manifest inputs and delivery
|
|
18
|
+
integration.
|
|
19
|
+
- [Testing](testing.md) — offline checks, live checks and regression practice.
|
|
20
|
+
|
|
21
|
+
## Playback and delivery
|
|
22
|
+
|
|
23
|
+
- [DRM systems](drm.md) — local/remote CDMs, PlayReady PSSH handling and key
|
|
24
|
+
acquisition boundaries.
|
|
25
|
+
- [Key vault](key-vault.md) — local and remote vaults, policies and manual keys.
|
|
26
|
+
- [Live channels](live.md) — recording, DVR/replay, duration and rotation.
|
|
27
|
+
- [Audio-only services](audio.md) — audio presentation, metadata and export.
|
|
28
|
+
- [Chapters](chapters.md) — chapter retrieval and embedding.
|
|
29
|
+
- [Downloader audio formats](downloader/mp3-audio-format.md) and
|
|
30
|
+
[JSON manifests](downloader/json-manifest-format.md).
|
|
31
|
+
- [Live pipe mux](downloader/live-pipe-mux.md), [ISM](downloader/ism-smooth-streaming.md)
|
|
32
|
+
and [Audio Vivid](downloader/audio-vivid.md) for specialized delivery paths.
|
|
33
|
+
|
|
34
|
+
## Interface and integration
|
|
35
|
+
|
|
36
|
+
- [Interface](interface.md) and [UI design](ui-design.md) — navigation,
|
|
37
|
+
selection, logs, themes and accessibility.
|
|
38
|
+
- [Internationalization](i18n.md) — adding interface locales.
|
|
39
|
+
- [External helpers](external-helpers.md) — declaring and resolving helpers.
|
|
40
|
+
- [Partner authorization](partner-authorization.md) — service-to-service login
|
|
41
|
+
handoffs.
|
|
42
|
+
- [Playback lifecycle](playback-lifecycle.md) — session, heartbeat and cleanup
|
|
43
|
+
rules.
|
|
44
|
+
- [Availability](availability.md) — JustWatch search and regional offers.
|
|
45
|
+
- [Troubleshooting](troubleshooting.md) — common configuration and playback
|
|
46
|
+
issues.
|
|
47
|
+
|
|
48
|
+
## Contributing
|
|
49
|
+
|
|
50
|
+
Read [CONTRIBUTING.md](CONTRIBUTING.md) and [SECURITY.md](SECURITY.md) before
|
|
51
|
+
opening a change. Keep credentials and device/private material outside commits,
|
|
52
|
+
and update the matching documentation whenever a Core or service contract
|
|
53
|
+
changes.
|