feat: add service-specific configuration overrides

Implement comprehensive per-service config override system that allows any configuration section (dl, n_m3u8dl_re, aria2c, subtitle, etc.) to be customized on a per-service basis.

Fixes #13
This commit is contained in:
Andy
2025-11-03 16:56:58 +00:00
parent f979e94235
commit f00790f31b
2 changed files with 70 additions and 23 deletions

View File

@@ -318,6 +318,38 @@ class dl:
self.log = logging.getLogger("download")
self.service = Services.get_tag(ctx.invoked_subcommand)
service_dl_config = config.services.get(self.service, {}).get("dl", {})
if service_dl_config:
param_types = {param.name: param.type for param in ctx.command.params if param.name}
for param_name, service_value in service_dl_config.items():
if param_name not in ctx.params:
continue
current_value = ctx.params[param_name]
global_default = config.dl.get(param_name)
param_type = param_types.get(param_name)
try:
if param_type and global_default is not None:
global_default = param_type.convert(global_default, None, ctx)
except Exception as e:
self.log.debug(f"Failed to convert global default for '{param_name}': {e}")
if current_value == global_default or (current_value is None and global_default is None):
try:
converted_value = service_value
if param_type and service_value is not None:
converted_value = param_type.convert(service_value, None, ctx)
ctx.params[param_name] = converted_value
self.log.debug(f"Applied service-specific '{param_name}' override: {converted_value}")
except Exception as e:
self.log.warning(
f"Failed to apply service-specific '{param_name}' override: {e}. "
f"Check that the value '{service_value}' is valid for this parameter."
)
self.profile = profile
self.tmdb_id = tmdb_id
self.tmdb_name = tmdb_name
@@ -383,7 +415,7 @@ class dl:
config.decryption = config.decryption_map.get(self.service, config.decryption)
service_config = config.services.get(self.service, {})
if service_config:
reserved_keys = {
"profiles",
"api_key",
@@ -393,16 +425,19 @@ class dl:
"device",
"endpoints",
"client",
"dl",
}
for config_key, override_value in service_config.items():
if config_key in reserved_keys:
if config_key in reserved_keys or not isinstance(override_value, dict):
continue
if isinstance(override_value, dict) and hasattr(config, config_key):
if hasattr(config, config_key):
current_config = getattr(config, config_key, {})
if isinstance(current_config, dict):
merged_config = {**current_config, **override_value}
merged_config = deepcopy(current_config)
merge_dict(override_value, merged_config)
setattr(config, config_key, merged_config)
self.log.debug(

View File

@@ -450,12 +450,24 @@ services:
region: "GB"
api_endpoint: "https://api.uk.service.com"
# Example: Rate-limited service
RATE_LIMITED_SERVICE:
dl:
downloads: 2 # Limit concurrent downloads
workers: 4 # Reduce workers to avoid rate limits
n_m3u8dl_re:
thread_count: 4 # Very low thread count
retry_count: 20 # More retries for flaky service
aria2c:
max_concurrent_downloads: 1 # Download tracks one at a time
max_connection_per_server: 1 # Single connection only
# Notes on service-specific overrides:
# - Overrides are merged with global config, not replaced
# - Only specified keys are overridden, others use global defaults
# - Reserved keys (profiles, api_key, certificate, etc.) are NOT treated as overrides
# - Any dict-type config option can be overridden (dl, aria2c, n_m3u8dl_re, etc.)
# - Use --debug flag to see which overrides are applied during downloads
# - Any dict-type config option can be overridden (dl, aria2c, n_m3u8dl_re, subtitle, etc.)
# - CLI arguments always take priority over service-specific config
# External proxy provider services
proxy_providers: