mirror of
https://github.com/unshackle-dl/unshackle.git
synced 2025-10-23 15:11:08 +00:00
Compare commits
4 Commits
ed0f03eca3
...
5949931b56
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5949931b56 | ||
|
|
ddfc0555c9 | ||
|
|
3dda3290d3 | ||
|
|
19ff200617 |
26
CHANGELOG.md
26
CHANGELOG.md
@@ -5,6 +5,32 @@ All notable changes to this project will be documented in this file.
|
|||||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
||||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
|
## [1.4.3] - 2025-08-20
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- Cached IP info helper for region detection
|
||||||
|
- New `get_cached_ip_info()` with 24h cache and provider rotation (ipinfo/ipapi) with 429 handling.
|
||||||
|
- Reduces external calls and stabilizes non-proxy region lookups for caching/logging.
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- DRM decryption selection is fully configuration-driven
|
||||||
|
- Widevine and PlayReady now select the decrypter based solely on `decryption` in YAML (including per-service mapping).
|
||||||
|
- Shaka Packager remains the default decrypter when not specified.
|
||||||
|
- `dl.py` logs the chosen tool based on the resolved configuration.
|
||||||
|
- Geofencing and proxy verification improvements
|
||||||
|
- Safer geofence checks with error handling and clearer logs.
|
||||||
|
- Always verify proxy exit region via live IP lookup; fallback to proxy parsing on failure.
|
||||||
|
- Example config updated to default to Shaka
|
||||||
|
- `unshackle.yaml`/example now sets `decryption.default: shaka` (service overrides still supported).
|
||||||
|
|
||||||
|
### Removed
|
||||||
|
|
||||||
|
- Deprecated parameter `use_mp4decrypt`
|
||||||
|
- Removed from `Widevine.decrypt()` and `PlayReady.decrypt()` and all callsites.
|
||||||
|
- Internal naming switched from mp4decrypt-specific flags to generic `decrypter` selection.
|
||||||
|
|
||||||
## [1.4.2] - 2025-08-14
|
## [1.4.2] - 2025-08-14
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|||||||
110
CONFIG.md
110
CONFIG.md
@@ -141,6 +141,11 @@ The following directories are available and may be overridden,
|
|||||||
- `logs` - Logs.
|
- `logs` - Logs.
|
||||||
- `wvds` - Widevine Devices.
|
- `wvds` - Widevine Devices.
|
||||||
- `prds` - PlayReady Devices.
|
- `prds` - PlayReady Devices.
|
||||||
|
- `dcsl` - Device Certificate Status List.
|
||||||
|
|
||||||
|
Notes:
|
||||||
|
|
||||||
|
- `services` accepts either a single directory or a list of directories to search for service modules.
|
||||||
|
|
||||||
For example,
|
For example,
|
||||||
|
|
||||||
@@ -165,6 +170,14 @@ For example to set the default primary language to download to German,
|
|||||||
lang: de
|
lang: de
|
||||||
```
|
```
|
||||||
|
|
||||||
|
You can also set multiple preferred languages using a list, e.g.,
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
lang:
|
||||||
|
- en
|
||||||
|
- fr
|
||||||
|
```
|
||||||
|
|
||||||
to set how many tracks to download concurrently to 4 and download threads to 16,
|
to set how many tracks to download concurrently to 4 and download threads to 16,
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
@@ -302,6 +315,11 @@ Note: SQLite and MySQL vaults have to connect directly to the Host/IP. It cannot
|
|||||||
Beware that some Hosting Providers do not let you access the MySQL server outside their intranet and may not be
|
Beware that some Hosting Providers do not let you access the MySQL server outside their intranet and may not be
|
||||||
accessible outside their hosting platform.
|
accessible outside their hosting platform.
|
||||||
|
|
||||||
|
Additional behavior:
|
||||||
|
|
||||||
|
- `no_push` (bool): Optional per-vault flag. When `true`, the vault will not receive pushed keys (writes) but
|
||||||
|
will still be queried and can provide keys for lookups. Useful for read-only/backup vaults.
|
||||||
|
|
||||||
### Using an API Vault
|
### Using an API Vault
|
||||||
|
|
||||||
API vaults use a specific HTTP request format, therefore API or HTTP Key Vault APIs from other projects or services may
|
API vaults use a specific HTTP request format, therefore API or HTTP Key Vault APIs from other projects or services may
|
||||||
@@ -314,6 +332,7 @@ not work in unshackle. The API format can be seen in the [API Vault Code](unshac
|
|||||||
# uri: "127.0.0.1:80/key-vault"
|
# uri: "127.0.0.1:80/key-vault"
|
||||||
# uri: "https://api.example.com/key-vault"
|
# uri: "https://api.example.com/key-vault"
|
||||||
token: "random secret key" # authorization token
|
token: "random secret key" # authorization token
|
||||||
|
# no_push: true # optional; make this API vault read-only (lookups only)
|
||||||
```
|
```
|
||||||
|
|
||||||
### Using a MySQL Vault
|
### Using a MySQL Vault
|
||||||
@@ -329,6 +348,7 @@ A MySQL Vault can be on a local or remote network, but I recommend SQLite for lo
|
|||||||
database: vault # database used for unshackle
|
database: vault # database used for unshackle
|
||||||
username: jane11
|
username: jane11
|
||||||
password: Doe123
|
password: Doe123
|
||||||
|
# no_push: false # optional; defaults to false
|
||||||
```
|
```
|
||||||
|
|
||||||
I recommend giving only a trustable user (or yourself) CREATE permission and then use unshackle to cache at least one CEK
|
I recommend giving only a trustable user (or yourself) CREATE permission and then use unshackle to cache at least one CEK
|
||||||
@@ -352,6 +372,7 @@ case something happens to your MySQL Vault.
|
|||||||
- type: SQLite
|
- type: SQLite
|
||||||
name: "My Local Vault" # arbitrary vault name
|
name: "My Local Vault" # arbitrary vault name
|
||||||
path: "C:/Users/Jane11/Documents/unshackle/data/key_vault.db"
|
path: "C:/Users/Jane11/Documents/unshackle/data/key_vault.db"
|
||||||
|
# no_push: true # optional; commonly true for local backup vaults
|
||||||
```
|
```
|
||||||
|
|
||||||
**Note**: You do not need to create the file at the specified path.
|
**Note**: You do not need to create the file at the specified path.
|
||||||
@@ -394,7 +415,7 @@ n_m3u8dl_re:
|
|||||||
Set your NordVPN Service credentials with `username` and `password` keys to automate the use of NordVPN as a Proxy
|
Set your NordVPN Service credentials with `username` and `password` keys to automate the use of NordVPN as a Proxy
|
||||||
system where required.
|
system where required.
|
||||||
|
|
||||||
You can also specify specific servers to use per-region with the `servers` key.
|
You can also specify specific servers to use per-region with the `server_map` key.
|
||||||
Sometimes a specific server works best for a service than others, so hard-coding one for a day or two helps.
|
Sometimes a specific server works best for a service than others, so hard-coding one for a day or two helps.
|
||||||
|
|
||||||
For example,
|
For example,
|
||||||
@@ -403,8 +424,8 @@ For example,
|
|||||||
nordvpn:
|
nordvpn:
|
||||||
username: zxqsR7C5CyGwmGb6KSvk8qsZ # example of the login format
|
username: zxqsR7C5CyGwmGb6KSvk8qsZ # example of the login format
|
||||||
password: wXVHmht22hhRKUEQ32PQVjCZ
|
password: wXVHmht22hhRKUEQ32PQVjCZ
|
||||||
servers:
|
server_map:
|
||||||
- us: 12 # force US server #12 for US proxies
|
us: 12 # force US server #12 for US proxies
|
||||||
```
|
```
|
||||||
|
|
||||||
The username and password should NOT be your normal NordVPN Account Credentials.
|
The username and password should NOT be your normal NordVPN Account Credentials.
|
||||||
@@ -443,7 +464,7 @@ second proxy of the US list.
|
|||||||
Set your NordVPN Service credentials with `username` and `password` keys to automate the use of NordVPN as a Proxy
|
Set your NordVPN Service credentials with `username` and `password` keys to automate the use of NordVPN as a Proxy
|
||||||
system where required.
|
system where required.
|
||||||
|
|
||||||
You can also specify specific servers to use per-region with the `servers` key.
|
You can also specify specific servers to use per-region with the `server_map` key.
|
||||||
Sometimes a specific server works best for a service than others, so hard-coding one for a day or two helps.
|
Sometimes a specific server works best for a service than others, so hard-coding one for a day or two helps.
|
||||||
|
|
||||||
For example,
|
For example,
|
||||||
@@ -451,8 +472,8 @@ For example,
|
|||||||
```yaml
|
```yaml
|
||||||
username: zxqsR7C5CyGwmGb6KSvk8qsZ # example of the login format
|
username: zxqsR7C5CyGwmGb6KSvk8qsZ # example of the login format
|
||||||
password: wXVHmht22hhRKUEQ32PQVjCZ
|
password: wXVHmht22hhRKUEQ32PQVjCZ
|
||||||
servers:
|
server_map:
|
||||||
- us: 12 # force US server #12 for US proxies
|
us: 12 # force US server #12 for US proxies
|
||||||
```
|
```
|
||||||
|
|
||||||
The username and password should NOT be your normal NordVPN Account Credentials.
|
The username and password should NOT be your normal NordVPN Account Credentials.
|
||||||
@@ -463,6 +484,20 @@ You can even set a specific server number this way, e.g., `--proxy=gb2366`.
|
|||||||
|
|
||||||
Note that `gb` is used instead of `uk` to be more consistent across regional systems.
|
Note that `gb` is used instead of `uk` to be more consistent across regional systems.
|
||||||
|
|
||||||
|
### surfsharkvpn (dict)
|
||||||
|
|
||||||
|
Enable Surfshark VPN proxy service using Surfshark Service credentials (not your login password).
|
||||||
|
You may pin specific server IDs per region using `server_map`.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
username: your_surfshark_service_username # https://my.surfshark.com/vpn/manual-setup/main/openvpn
|
||||||
|
password: your_surfshark_service_password # service credentials, not account password
|
||||||
|
server_map:
|
||||||
|
us: 3844 # force US server #3844
|
||||||
|
gb: 2697 # force GB server #2697
|
||||||
|
au: 4621 # force AU server #4621
|
||||||
|
```
|
||||||
|
|
||||||
### hola (dict)
|
### hola (dict)
|
||||||
|
|
||||||
Enable Hola VPN proxy service. This is a simple provider that doesn't require configuration.
|
Enable Hola VPN proxy service. This is a simple provider that doesn't require configuration.
|
||||||
@@ -497,6 +532,15 @@ For example,
|
|||||||
|
|
||||||
[pywidevine]: https://github.com/rlaphoenix/pywidevine
|
[pywidevine]: https://github.com/rlaphoenix/pywidevine
|
||||||
|
|
||||||
|
## scene_naming (bool)
|
||||||
|
|
||||||
|
Set scene-style naming for titles. When `true` uses scene naming patterns (e.g., `Prime.Suspect.S07E01...`), when
|
||||||
|
`false` uses a more human-readable style (e.g., `Prime Suspect S07E01 ...`). Default: `true`.
|
||||||
|
|
||||||
|
## series_year (bool)
|
||||||
|
|
||||||
|
Whether to include the series year in series names for episodes and folders. Default: `true`.
|
||||||
|
|
||||||
## serve (dict)
|
## serve (dict)
|
||||||
|
|
||||||
Configuration data for pywidevine's serve functionality run through unshackle.
|
Configuration data for pywidevine's serve functionality run through unshackle.
|
||||||
@@ -561,6 +605,27 @@ set_terminal_bg: true
|
|||||||
Group or Username to postfix to the end of all download filenames following a dash.
|
Group or Username to postfix to the end of all download filenames following a dash.
|
||||||
For example, `tag: "J0HN"` will have `-J0HN` at the end of all download filenames.
|
For example, `tag: "J0HN"` will have `-J0HN` at the end of all download filenames.
|
||||||
|
|
||||||
|
## tag_group_name (bool)
|
||||||
|
|
||||||
|
Enable/disable tagging downloads with your group name when `tag` is set. Default: `true`.
|
||||||
|
|
||||||
|
## tag_imdb_tmdb (bool)
|
||||||
|
|
||||||
|
Enable/disable tagging downloaded files with IMDB/TMDB/TVDB identifiers (when available). Default: `true`.
|
||||||
|
|
||||||
|
## title_cache_enabled (bool)
|
||||||
|
|
||||||
|
Enable/disable caching of title metadata to reduce redundant API calls. Default: `true`.
|
||||||
|
|
||||||
|
## title_cache_time (int)
|
||||||
|
|
||||||
|
Cache duration in seconds for title metadata. Default: `1800` (30 minutes).
|
||||||
|
|
||||||
|
## title_cache_max_retention (int)
|
||||||
|
|
||||||
|
Maximum retention time in seconds for serving slightly stale cached title metadata when API calls fail.
|
||||||
|
Default: `86400` (24 hours). Effective retention is `min(title_cache_time + grace, title_cache_max_retention)`.
|
||||||
|
|
||||||
## tmdb_api_key (str)
|
## tmdb_api_key (str)
|
||||||
|
|
||||||
API key for The Movie Database (TMDB). This is used for tagging downloaded files with TMDB,
|
API key for The Movie Database (TMDB). This is used for tagging downloaded files with TMDB,
|
||||||
@@ -580,3 +645,36 @@ tmdb_api_key: cf66bf18956kca5311ada3bebb84eb9a # Not a real key
|
|||||||
```
|
```
|
||||||
|
|
||||||
**Note**: Keep your API key secure and do not share it publicly. This key is used by the core/utils/tags.py module to fetch metadata from TMDB for proper file tagging.
|
**Note**: Keep your API key secure and do not share it publicly. This key is used by the core/utils/tags.py module to fetch metadata from TMDB for proper file tagging.
|
||||||
|
|
||||||
|
## subtitle (dict)
|
||||||
|
|
||||||
|
Control subtitle conversion and SDH (hearing-impaired) stripping behavior.
|
||||||
|
|
||||||
|
- `conversion_method`: How to convert subtitles between formats. Default: `auto`.
|
||||||
|
|
||||||
|
- `auto`: Use subby for WebVTT/SAMI, standard for others.
|
||||||
|
- `subby`: Always use subby with CommonIssuesFixer.
|
||||||
|
- `subtitleedit`: Prefer SubtitleEdit when available; otherwise fallback to standard conversion.
|
||||||
|
- `pycaption`: Use only the pycaption library (no SubtitleEdit, no subby).
|
||||||
|
|
||||||
|
- `sdh_method`: How to strip SDH cues. Default: `auto`.
|
||||||
|
- `auto`: Try subby for SRT first, then SubtitleEdit, then filter-subs.
|
||||||
|
- `subby`: Use subby’s SDHStripper (SRT only).
|
||||||
|
- `subtitleedit`: Use SubtitleEdit’s RemoveTextForHI when available.
|
||||||
|
- `filter-subs`: Use the subtitle-filter library.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
subtitle:
|
||||||
|
conversion_method: auto
|
||||||
|
sdh_method: auto
|
||||||
|
```
|
||||||
|
|
||||||
|
## update_checks (bool)
|
||||||
|
|
||||||
|
Check for updates from the GitHub repository on startup. Default: `true`.
|
||||||
|
|
||||||
|
## update_check_interval (int)
|
||||||
|
|
||||||
|
How often to check for updates, in hours. Default: `24`.
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|||||||
|
|
||||||
[project]
|
[project]
|
||||||
name = "unshackle"
|
name = "unshackle"
|
||||||
version = "1.4.2"
|
version = "1.4.3"
|
||||||
description = "Modular Movie, TV, and Music Archival Software."
|
description = "Modular Movie, TV, and Music Archival Software."
|
||||||
authors = [{ name = "unshackle team" }]
|
authors = [{ name = "unshackle team" }]
|
||||||
requires-python = ">=3.10,<3.13"
|
requires-python = ">=3.10,<3.13"
|
||||||
|
|||||||
@@ -248,7 +248,9 @@ class dl:
|
|||||||
)
|
)
|
||||||
@click.option("--downloads", type=int, default=1, help="Amount of tracks to download concurrently.")
|
@click.option("--downloads", type=int, default=1, help="Amount of tracks to download concurrently.")
|
||||||
@click.option("--no-cache", "no_cache", is_flag=True, default=False, help="Bypass title cache for this download.")
|
@click.option("--no-cache", "no_cache", is_flag=True, default=False, help="Bypass title cache for this download.")
|
||||||
@click.option("--reset-cache", "reset_cache", is_flag=True, default=False, help="Clear title cache before fetching.")
|
@click.option(
|
||||||
|
"--reset-cache", "reset_cache", is_flag=True, default=False, help="Clear title cache before fetching."
|
||||||
|
)
|
||||||
@click.pass_context
|
@click.pass_context
|
||||||
def cli(ctx: click.Context, **kwargs: Any) -> dl:
|
def cli(ctx: click.Context, **kwargs: Any) -> dl:
|
||||||
return dl(ctx, **kwargs)
|
return dl(ctx, **kwargs)
|
||||||
@@ -294,6 +296,9 @@ class dl:
|
|||||||
if getattr(config, "downloader_map", None):
|
if getattr(config, "downloader_map", None):
|
||||||
config.downloader = config.downloader_map.get(self.service, config.downloader)
|
config.downloader = config.downloader_map.get(self.service, config.downloader)
|
||||||
|
|
||||||
|
if getattr(config, "decryption_map", None):
|
||||||
|
config.decryption = config.decryption_map.get(self.service, config.decryption)
|
||||||
|
|
||||||
with console.status("Loading DRM CDM...", spinner="dots"):
|
with console.status("Loading DRM CDM...", spinner="dots"):
|
||||||
try:
|
try:
|
||||||
self.cdm = self.get_cdm(self.service, self.profile)
|
self.cdm = self.get_cdm(self.service, self.profile)
|
||||||
@@ -531,7 +536,7 @@ class dl:
|
|||||||
else:
|
else:
|
||||||
console.print(Padding("Search -> [bright_black]No match found[/]", (0, 5)))
|
console.print(Padding("Search -> [bright_black]No match found[/]", (0, 5)))
|
||||||
|
|
||||||
if self.tmdb_id and getattr(self, 'search_source', None) != 'simkl':
|
if self.tmdb_id and getattr(self, "search_source", None) != "simkl":
|
||||||
kind = "tv" if isinstance(title, Episode) else "movie"
|
kind = "tv" if isinstance(title, Episode) else "movie"
|
||||||
tags.external_ids(self.tmdb_id, kind)
|
tags.external_ids(self.tmdb_id, kind)
|
||||||
if self.tmdb_year:
|
if self.tmdb_year:
|
||||||
@@ -1001,12 +1006,7 @@ class dl:
|
|||||||
# Handle DRM decryption BEFORE repacking (must decrypt first!)
|
# Handle DRM decryption BEFORE repacking (must decrypt first!)
|
||||||
service_name = service.__class__.__name__.upper()
|
service_name = service.__class__.__name__.upper()
|
||||||
decryption_method = config.decryption_map.get(service_name, config.decryption)
|
decryption_method = config.decryption_map.get(service_name, config.decryption)
|
||||||
use_mp4decrypt = decryption_method.lower() == "mp4decrypt"
|
decrypt_tool = "mp4decrypt" if decryption_method.lower() == "mp4decrypt" else "Shaka Packager"
|
||||||
|
|
||||||
if use_mp4decrypt:
|
|
||||||
decrypt_tool = "mp4decrypt"
|
|
||||||
else:
|
|
||||||
decrypt_tool = "Shaka Packager"
|
|
||||||
|
|
||||||
drm_tracks = [track for track in title.tracks if track.drm]
|
drm_tracks = [track for track in title.tracks if track.drm]
|
||||||
if drm_tracks:
|
if drm_tracks:
|
||||||
@@ -1015,7 +1015,7 @@ class dl:
|
|||||||
for track in drm_tracks:
|
for track in drm_tracks:
|
||||||
drm = track.get_drm_for_cdm(self.cdm)
|
drm = track.get_drm_for_cdm(self.cdm)
|
||||||
if drm and hasattr(drm, "decrypt"):
|
if drm and hasattr(drm, "decrypt"):
|
||||||
drm.decrypt(track.path, use_mp4decrypt=use_mp4decrypt)
|
drm.decrypt(track.path)
|
||||||
has_decrypted = True
|
has_decrypted = True
|
||||||
events.emit(events.Types.TRACK_REPACKED, track=track)
|
events.emit(events.Types.TRACK_REPACKED, track=track)
|
||||||
else:
|
else:
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
__version__ = "1.4.2"
|
__version__ = "1.4.3"
|
||||||
|
|||||||
@@ -253,12 +253,11 @@ class PlayReady:
|
|||||||
if not self.content_keys:
|
if not self.content_keys:
|
||||||
raise PlayReady.Exceptions.EmptyLicense("No Content Keys were within the License")
|
raise PlayReady.Exceptions.EmptyLicense("No Content Keys were within the License")
|
||||||
|
|
||||||
def decrypt(self, path: Path, use_mp4decrypt: bool = False) -> None:
|
def decrypt(self, path: Path) -> None:
|
||||||
"""
|
"""
|
||||||
Decrypt a Track with PlayReady DRM.
|
Decrypt a Track with PlayReady DRM.
|
||||||
Args:
|
Args:
|
||||||
path: Path to the encrypted file to decrypt
|
path: Path to the encrypted file to decrypt
|
||||||
use_mp4decrypt: If True, use mp4decrypt instead of Shaka Packager
|
|
||||||
Raises:
|
Raises:
|
||||||
EnvironmentError if the required decryption executable could not be found.
|
EnvironmentError if the required decryption executable could not be found.
|
||||||
ValueError if the track has not yet been downloaded.
|
ValueError if the track has not yet been downloaded.
|
||||||
@@ -270,7 +269,9 @@ class PlayReady:
|
|||||||
if not path or not path.exists():
|
if not path or not path.exists():
|
||||||
raise ValueError("Tried to decrypt a file that does not exist.")
|
raise ValueError("Tried to decrypt a file that does not exist.")
|
||||||
|
|
||||||
if use_mp4decrypt:
|
decrypter = str(getattr(config, "decryption", "")).lower()
|
||||||
|
|
||||||
|
if decrypter == "mp4decrypt":
|
||||||
return self._decrypt_with_mp4decrypt(path)
|
return self._decrypt_with_mp4decrypt(path)
|
||||||
else:
|
else:
|
||||||
return self._decrypt_with_shaka_packager(path)
|
return self._decrypt_with_shaka_packager(path)
|
||||||
|
|||||||
@@ -227,12 +227,11 @@ class Widevine:
|
|||||||
finally:
|
finally:
|
||||||
cdm.close(session_id)
|
cdm.close(session_id)
|
||||||
|
|
||||||
def decrypt(self, path: Path, use_mp4decrypt: bool = False) -> None:
|
def decrypt(self, path: Path) -> None:
|
||||||
"""
|
"""
|
||||||
Decrypt a Track with Widevine DRM.
|
Decrypt a Track with Widevine DRM.
|
||||||
Args:
|
Args:
|
||||||
path: Path to the encrypted file to decrypt
|
path: Path to the encrypted file to decrypt
|
||||||
use_mp4decrypt: If True, use mp4decrypt instead of Shaka Packager
|
|
||||||
Raises:
|
Raises:
|
||||||
EnvironmentError if the required decryption executable could not be found.
|
EnvironmentError if the required decryption executable could not be found.
|
||||||
ValueError if the track has not yet been downloaded.
|
ValueError if the track has not yet been downloaded.
|
||||||
@@ -244,7 +243,9 @@ class Widevine:
|
|||||||
if not path or not path.exists():
|
if not path or not path.exists():
|
||||||
raise ValueError("Tried to decrypt a file that does not exist.")
|
raise ValueError("Tried to decrypt a file that does not exist.")
|
||||||
|
|
||||||
if use_mp4decrypt:
|
decrypter = str(getattr(config, "decryption", "")).lower()
|
||||||
|
|
||||||
|
if decrypter == "mp4decrypt":
|
||||||
return self._decrypt_with_mp4decrypt(path)
|
return self._decrypt_with_mp4decrypt(path)
|
||||||
else:
|
else:
|
||||||
return self._decrypt_with_shaka_packager(path)
|
return self._decrypt_with_shaka_packager(path)
|
||||||
|
|||||||
@@ -28,9 +28,9 @@ update_check_interval: 24
|
|||||||
|
|
||||||
# Title caching configuration
|
# Title caching configuration
|
||||||
# Cache title metadata to reduce redundant API calls
|
# Cache title metadata to reduce redundant API calls
|
||||||
title_cache_enabled: true # Enable/disable title caching globally (default: true)
|
title_cache_enabled: true # Enable/disable title caching globally (default: true)
|
||||||
title_cache_time: 1800 # Cache duration in seconds (default: 1800 = 30 minutes)
|
title_cache_time: 1800 # Cache duration in seconds (default: 1800 = 30 minutes)
|
||||||
title_cache_max_retention: 86400 # Maximum cache retention for fallback when API fails (default: 86400 = 24 hours)
|
title_cache_max_retention: 86400 # Maximum cache retention for fallback when API fails (default: 86400 = 24 hours)
|
||||||
|
|
||||||
# Muxing configuration
|
# Muxing configuration
|
||||||
muxing:
|
muxing:
|
||||||
@@ -156,7 +156,6 @@ curl_impersonate:
|
|||||||
|
|
||||||
# Pre-define default options and switches of the dl command
|
# Pre-define default options and switches of the dl command
|
||||||
dl:
|
dl:
|
||||||
best: true
|
|
||||||
sub_format: srt
|
sub_format: srt
|
||||||
downloads: 4
|
downloads: 4
|
||||||
workers: 16
|
workers: 16
|
||||||
@@ -241,14 +240,14 @@ proxy_providers:
|
|||||||
username: username_from_service_credentials
|
username: username_from_service_credentials
|
||||||
password: password_from_service_credentials
|
password: password_from_service_credentials
|
||||||
server_map:
|
server_map:
|
||||||
- us: 12 # force US server #12 for US proxies
|
us: 12 # force US server #12 for US proxies
|
||||||
surfsharkvpn:
|
surfsharkvpn:
|
||||||
username: your_surfshark_service_username # Service credentials from https://my.surfshark.com/vpn/manual-setup/main/openvpn
|
username: your_surfshark_service_username # Service credentials from https://my.surfshark.com/vpn/manual-setup/main/openvpn
|
||||||
password: your_surfshark_service_password # Service credentials (not your login password)
|
password: your_surfshark_service_password # Service credentials (not your login password)
|
||||||
server_map:
|
server_map:
|
||||||
- us: 3844 # force US server #3844 for US proxies
|
us: 3844 # force US server #3844 for US proxies
|
||||||
- gb: 2697 # force GB server #2697 for GB proxies
|
gb: 2697 # force GB server #2697 for GB proxies
|
||||||
- au: 4621 # force AU server #4621 for AU proxies
|
au: 4621 # force AU server #4621 for AU proxies
|
||||||
basic:
|
basic:
|
||||||
GB:
|
GB:
|
||||||
- "socks5://username:password@bhx.socks.ipvanish.com:1080" # 1 (Birmingham)
|
- "socks5://username:password@bhx.socks.ipvanish.com:1080" # 1 (Birmingham)
|
||||||
|
|||||||
Reference in New Issue
Block a user