mirror of
https://github.com/unshackle-dl/unshackle.git
synced 2026-03-12 01:19:02 +00:00
refactor: remove unnecessary underscore prefixes from function names
This commit is contained in:
@@ -12,7 +12,7 @@ from unshackle.core.vault import Vault
|
|||||||
from unshackle.core.vaults import Vaults
|
from unshackle.core.vaults import Vaults
|
||||||
|
|
||||||
|
|
||||||
def _load_vaults(vault_names: list[str]) -> Vaults:
|
def load_vaults(vault_names: list[str]) -> Vaults:
|
||||||
"""Load and validate vaults by name."""
|
"""Load and validate vaults by name."""
|
||||||
vaults = Vaults()
|
vaults = Vaults()
|
||||||
for vault_name in vault_names:
|
for vault_name in vault_names:
|
||||||
@@ -30,7 +30,7 @@ def _load_vaults(vault_names: list[str]) -> Vaults:
|
|||||||
return vaults
|
return vaults
|
||||||
|
|
||||||
|
|
||||||
def _process_service_keys(from_vault: Vault, service: str, log: logging.Logger) -> dict[str, str]:
|
def process_service_keys(from_vault: Vault, service: str, log: logging.Logger) -> dict[str, str]:
|
||||||
"""Get and validate keys from a vault for a specific service."""
|
"""Get and validate keys from a vault for a specific service."""
|
||||||
content_keys = list(from_vault.get_keys(service))
|
content_keys = list(from_vault.get_keys(service))
|
||||||
|
|
||||||
@@ -41,9 +41,9 @@ def _process_service_keys(from_vault: Vault, service: str, log: logging.Logger)
|
|||||||
return {kid: key for kid, key in content_keys if kid not in bad_keys}
|
return {kid: key for kid, key in content_keys if kid not in bad_keys}
|
||||||
|
|
||||||
|
|
||||||
def _copy_service_data(to_vault: Vault, from_vault: Vault, service: str, log: logging.Logger) -> int:
|
def copy_service_data(to_vault: Vault, from_vault: Vault, service: str, log: logging.Logger) -> int:
|
||||||
"""Copy data for a single service between vaults."""
|
"""Copy data for a single service between vaults."""
|
||||||
content_keys = _process_service_keys(from_vault, service, log)
|
content_keys = process_service_keys(from_vault, service, log)
|
||||||
total_count = len(content_keys)
|
total_count = len(content_keys)
|
||||||
|
|
||||||
if total_count == 0:
|
if total_count == 0:
|
||||||
@@ -95,7 +95,7 @@ def copy(to_vault_name: str, from_vault_names: list[str], service: Optional[str]
|
|||||||
log = logging.getLogger("kv")
|
log = logging.getLogger("kv")
|
||||||
|
|
||||||
all_vault_names = [to_vault_name] + list(from_vault_names)
|
all_vault_names = [to_vault_name] + list(from_vault_names)
|
||||||
vaults = _load_vaults(all_vault_names)
|
vaults = load_vaults(all_vault_names)
|
||||||
|
|
||||||
to_vault = vaults.vaults[0]
|
to_vault = vaults.vaults[0]
|
||||||
from_vaults = vaults.vaults[1:]
|
from_vaults = vaults.vaults[1:]
|
||||||
@@ -112,7 +112,7 @@ def copy(to_vault_name: str, from_vault_names: list[str], service: Optional[str]
|
|||||||
services_to_copy = [service] if service else from_vault.get_services()
|
services_to_copy = [service] if service else from_vault.get_services()
|
||||||
|
|
||||||
for service_tag in services_to_copy:
|
for service_tag in services_to_copy:
|
||||||
added = _copy_service_data(to_vault, from_vault, service_tag, log)
|
added = copy_service_data(to_vault, from_vault, service_tag, log)
|
||||||
total_added += added
|
total_added += added
|
||||||
|
|
||||||
if total_added > 0:
|
if total_added > 0:
|
||||||
@@ -164,7 +164,7 @@ def add(file: Path, service: str, vaults: list[str]) -> None:
|
|||||||
log = logging.getLogger("kv")
|
log = logging.getLogger("kv")
|
||||||
service = Services.get_tag(service)
|
service = Services.get_tag(service)
|
||||||
|
|
||||||
vaults_ = _load_vaults(list(vaults))
|
vaults_ = load_vaults(list(vaults))
|
||||||
|
|
||||||
data = file.read_text(encoding="utf8")
|
data = file.read_text(encoding="utf8")
|
||||||
kid_keys: dict[str, str] = {}
|
kid_keys: dict[str, str] = {}
|
||||||
@@ -194,7 +194,7 @@ def prepare(vaults: list[str]) -> None:
|
|||||||
"""Create Service Tables on Vaults if not yet created."""
|
"""Create Service Tables on Vaults if not yet created."""
|
||||||
log = logging.getLogger("kv")
|
log = logging.getLogger("kv")
|
||||||
|
|
||||||
vaults_ = _load_vaults(vaults)
|
vaults_ = load_vaults(vaults)
|
||||||
|
|
||||||
for vault in vaults_:
|
for vault in vaults_:
|
||||||
if hasattr(vault, "has_table") and hasattr(vault, "create_table"):
|
if hasattr(vault, "has_table") and hasattr(vault, "create_table"):
|
||||||
|
|||||||
@@ -91,7 +91,7 @@ class Cacher:
|
|||||||
except jwt.DecodeError:
|
except jwt.DecodeError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
self.expiration = self._resolve_datetime(expiration) if expiration else None
|
self.expiration = self.resolve_datetime(expiration) if expiration else None
|
||||||
|
|
||||||
payload = {"data": self.data, "expiration": self.expiration, "version": self.version}
|
payload = {"data": self.data, "expiration": self.expiration, "version": self.version}
|
||||||
payload["crc32"] = zlib.crc32(jsonpickle.dumps(payload).encode("utf8"))
|
payload["crc32"] = zlib.crc32(jsonpickle.dumps(payload).encode("utf8"))
|
||||||
@@ -109,7 +109,7 @@ class Cacher:
|
|||||||
return self.path.stat()
|
return self.path.stat()
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _resolve_datetime(timestamp: EXP_T) -> datetime:
|
def resolve_datetime(timestamp: EXP_T) -> datetime:
|
||||||
"""
|
"""
|
||||||
Resolve multiple formats of a Datetime or Timestamp to an absolute Datetime.
|
Resolve multiple formats of a Datetime or Timestamp to an absolute Datetime.
|
||||||
|
|
||||||
@@ -118,15 +118,15 @@ class Cacher:
|
|||||||
datetime.datetime(2022, 6, 27, 9, 49, 13, 657208)
|
datetime.datetime(2022, 6, 27, 9, 49, 13, 657208)
|
||||||
>>> iso8601 = now.isoformat()
|
>>> iso8601 = now.isoformat()
|
||||||
'2022-06-27T09:49:13.657208'
|
'2022-06-27T09:49:13.657208'
|
||||||
>>> Cacher._resolve_datetime(iso8601)
|
>>> Cacher.resolve_datetime(iso8601)
|
||||||
datetime.datetime(2022, 6, 27, 9, 49, 13, 657208)
|
datetime.datetime(2022, 6, 27, 9, 49, 13, 657208)
|
||||||
>>> Cacher._resolve_datetime(iso8601 + "Z")
|
>>> Cacher.resolve_datetime(iso8601 + "Z")
|
||||||
datetime.datetime(2022, 6, 27, 9, 49, 13, 657208)
|
datetime.datetime(2022, 6, 27, 9, 49, 13, 657208)
|
||||||
>>> Cacher._resolve_datetime(3600)
|
>>> Cacher.resolve_datetime(3600)
|
||||||
datetime.datetime(2022, 6, 27, 10, 52, 50, 657208)
|
datetime.datetime(2022, 6, 27, 10, 52, 50, 657208)
|
||||||
>>> Cacher._resolve_datetime('3600')
|
>>> Cacher.resolve_datetime('3600')
|
||||||
datetime.datetime(2022, 6, 27, 10, 52, 51, 657208)
|
datetime.datetime(2022, 6, 27, 10, 52, 51, 657208)
|
||||||
>>> Cacher._resolve_datetime(7800.113)
|
>>> Cacher.resolve_datetime(7800.113)
|
||||||
datetime.datetime(2022, 6, 27, 11, 59, 13, 770208)
|
datetime.datetime(2022, 6, 27, 11, 59, 13, 770208)
|
||||||
|
|
||||||
In the int/float examples you may notice that it did not return now + 3600 seconds
|
In the int/float examples you may notice that it did not return now + 3600 seconds
|
||||||
|
|||||||
@@ -79,7 +79,7 @@ class CurlSession(Session):
|
|||||||
)
|
)
|
||||||
self.log = logging.getLogger(self.__class__.__name__)
|
self.log = logging.getLogger(self.__class__.__name__)
|
||||||
|
|
||||||
def _get_sleep_time(self, response: Response | None, attempt: int) -> float | None:
|
def get_sleep_time(self, response: Response | None, attempt: int) -> float | None:
|
||||||
if response:
|
if response:
|
||||||
retry_after = response.headers.get("Retry-After")
|
retry_after = response.headers.get("Retry-After")
|
||||||
if retry_after:
|
if retry_after:
|
||||||
@@ -123,7 +123,7 @@ class CurlSession(Session):
|
|||||||
)
|
)
|
||||||
|
|
||||||
if attempt < self.max_retries:
|
if attempt < self.max_retries:
|
||||||
if sleep_duration := self._get_sleep_time(response, attempt + 1):
|
if sleep_duration := self.get_sleep_time(response, attempt + 1):
|
||||||
if sleep_duration > 0:
|
if sleep_duration > 0:
|
||||||
time.sleep(sleep_duration)
|
time.sleep(sleep_duration)
|
||||||
else:
|
else:
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ from unshackle.core.constants import DOWNLOAD_CANCELLED, DOWNLOAD_LICENCE_ONLY
|
|||||||
from unshackle.core.downloaders import aria2c, curl_impersonate, n_m3u8dl_re, requests
|
from unshackle.core.downloaders import aria2c, curl_impersonate, n_m3u8dl_re, requests
|
||||||
from unshackle.core.drm import DRM_T, PlayReady, Widevine
|
from unshackle.core.drm import DRM_T, PlayReady, Widevine
|
||||||
from unshackle.core.events import events
|
from unshackle.core.events import events
|
||||||
from unshackle.core.utilities import get_boxes, try_ensure_utf8, get_extension
|
from unshackle.core.utilities import get_boxes, get_extension, try_ensure_utf8
|
||||||
from unshackle.core.utils.subprocess import ffprobe
|
from unshackle.core.utils.subprocess import ffprobe
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -28,21 +28,21 @@ class UpdateChecker:
|
|||||||
DEFAULT_CHECK_INTERVAL = 24 * 60 * 60
|
DEFAULT_CHECK_INTERVAL = 24 * 60 * 60
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _get_cache_file(cls) -> Path:
|
def get_cache_file(cls) -> Path:
|
||||||
"""Get the path to the update check cache file."""
|
"""Get the path to the update check cache file."""
|
||||||
from unshackle.core.config import config
|
from unshackle.core.config import config
|
||||||
|
|
||||||
return config.directories.cache / "update_check.json"
|
return config.directories.cache / "update_check.json"
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _load_cache_data(cls) -> dict:
|
def load_cache_data(cls) -> dict:
|
||||||
"""
|
"""
|
||||||
Load cache data from file.
|
Load cache data from file.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Cache data dictionary or empty dict if loading fails
|
Cache data dictionary or empty dict if loading fails
|
||||||
"""
|
"""
|
||||||
cache_file = cls._get_cache_file()
|
cache_file = cls.get_cache_file()
|
||||||
|
|
||||||
if not cache_file.exists():
|
if not cache_file.exists():
|
||||||
return {}
|
return {}
|
||||||
@@ -54,7 +54,7 @@ class UpdateChecker:
|
|||||||
return {}
|
return {}
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _parse_version(version_string: str) -> str:
|
def parse_version(version_string: str) -> str:
|
||||||
"""
|
"""
|
||||||
Parse and normalize version string by removing 'v' prefix.
|
Parse and normalize version string by removing 'v' prefix.
|
||||||
|
|
||||||
@@ -107,7 +107,7 @@ class UpdateChecker:
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
data = response.json()
|
data = response.json()
|
||||||
latest_version = cls._parse_version(data.get("tag_name", ""))
|
latest_version = cls.parse_version(data.get("tag_name", ""))
|
||||||
|
|
||||||
return latest_version if cls._is_valid_version(latest_version) else None
|
return latest_version if cls._is_valid_version(latest_version) else None
|
||||||
|
|
||||||
@@ -125,7 +125,7 @@ class UpdateChecker:
|
|||||||
Returns:
|
Returns:
|
||||||
True if we should check for updates, False otherwise
|
True if we should check for updates, False otherwise
|
||||||
"""
|
"""
|
||||||
cache_data = cls._load_cache_data()
|
cache_data = cls.load_cache_data()
|
||||||
|
|
||||||
if not cache_data:
|
if not cache_data:
|
||||||
return True
|
return True
|
||||||
@@ -144,7 +144,7 @@ class UpdateChecker:
|
|||||||
latest_version: The latest version found, if any
|
latest_version: The latest version found, if any
|
||||||
current_version: The current version being used
|
current_version: The current version being used
|
||||||
"""
|
"""
|
||||||
cache_file = cls._get_cache_file()
|
cache_file = cls.get_cache_file()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
cache_file.parent.mkdir(parents=True, exist_ok=True)
|
cache_file.parent.mkdir(parents=True, exist_ok=True)
|
||||||
@@ -231,7 +231,7 @@ class UpdateChecker:
|
|||||||
Returns:
|
Returns:
|
||||||
The latest version string if an update is available from cache, None otherwise
|
The latest version string if an update is available from cache, None otherwise
|
||||||
"""
|
"""
|
||||||
cache_data = cls._load_cache_data()
|
cache_data = cls.load_cache_data()
|
||||||
|
|
||||||
if not cache_data:
|
if not cache_data:
|
||||||
return None
|
return None
|
||||||
|
|||||||
@@ -485,7 +485,7 @@ def extract_font_family(font_path: Path) -> Optional[str]:
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def _get_windows_fonts() -> dict[str, Path]:
|
def get_windows_fonts() -> dict[str, Path]:
|
||||||
"""
|
"""
|
||||||
Get fonts from Windows registry.
|
Get fonts from Windows registry.
|
||||||
|
|
||||||
@@ -504,7 +504,7 @@ def _get_windows_fonts() -> dict[str, Path]:
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def _scan_font_directory(font_dir: Path, fonts: dict[str, Path], log: logging.Logger) -> None:
|
def scan_font_directory(font_dir: Path, fonts: dict[str, Path], log: logging.Logger) -> None:
|
||||||
"""
|
"""
|
||||||
Scan a single directory for fonts.
|
Scan a single directory for fonts.
|
||||||
|
|
||||||
@@ -524,7 +524,7 @@ def _scan_font_directory(font_dir: Path, fonts: dict[str, Path], log: logging.Lo
|
|||||||
log.debug(f"Failed to process {font_file}: {e}")
|
log.debug(f"Failed to process {font_file}: {e}")
|
||||||
|
|
||||||
|
|
||||||
def _get_unix_fonts() -> dict[str, Path]:
|
def get_unix_fonts() -> dict[str, Path]:
|
||||||
"""
|
"""
|
||||||
Get fonts from Linux/macOS standard directories.
|
Get fonts from Linux/macOS standard directories.
|
||||||
|
|
||||||
@@ -546,11 +546,9 @@ def _get_unix_fonts() -> dict[str, Path]:
|
|||||||
continue
|
continue
|
||||||
|
|
||||||
try:
|
try:
|
||||||
_scan_font_directory(font_dir, fonts, log)
|
scan_font_directory(font_dir, fonts, log)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
log.warning(f"Failed to scan {font_dir}: {e}")
|
log.warning(f"Failed to scan {font_dir}: {e}")
|
||||||
|
|
||||||
log.debug(f"Discovered {len(fonts)} system font families")
|
|
||||||
return fonts
|
return fonts
|
||||||
|
|
||||||
|
|
||||||
@@ -565,8 +563,8 @@ def get_system_fonts() -> dict[str, Path]:
|
|||||||
Dictionary mapping font family names to their file paths
|
Dictionary mapping font family names to their file paths
|
||||||
"""
|
"""
|
||||||
if sys.platform == "win32":
|
if sys.platform == "win32":
|
||||||
return _get_windows_fonts()
|
return get_windows_fonts()
|
||||||
return _get_unix_fonts()
|
return get_unix_fonts()
|
||||||
|
|
||||||
|
|
||||||
# Common Windows font names mapped to their Linux equivalents
|
# Common Windows font names mapped to their Linux equivalents
|
||||||
@@ -754,9 +752,9 @@ class DebugLogger:
|
|||||||
if self.enabled:
|
if self.enabled:
|
||||||
self.log_path.parent.mkdir(parents=True, exist_ok=True)
|
self.log_path.parent.mkdir(parents=True, exist_ok=True)
|
||||||
self.file_handle = open(self.log_path, "a", encoding="utf-8")
|
self.file_handle = open(self.log_path, "a", encoding="utf-8")
|
||||||
self._log_session_start()
|
self.log_session_start()
|
||||||
|
|
||||||
def _log_session_start(self):
|
def log_session_start(self):
|
||||||
"""Log the start of a new session with environment information."""
|
"""Log the start of a new session with environment information."""
|
||||||
import platform
|
import platform
|
||||||
|
|
||||||
@@ -821,11 +819,11 @@ class DebugLogger:
|
|||||||
if service:
|
if service:
|
||||||
entry["service"] = service
|
entry["service"] = service
|
||||||
if context:
|
if context:
|
||||||
entry["context"] = self._sanitize_data(context)
|
entry["context"] = self.sanitize_data(context)
|
||||||
if request:
|
if request:
|
||||||
entry["request"] = self._sanitize_data(request)
|
entry["request"] = self.sanitize_data(request)
|
||||||
if response:
|
if response:
|
||||||
entry["response"] = self._sanitize_data(response)
|
entry["response"] = self.sanitize_data(response)
|
||||||
if duration_ms is not None:
|
if duration_ms is not None:
|
||||||
entry["duration_ms"] = duration_ms
|
entry["duration_ms"] = duration_ms
|
||||||
if success is not None:
|
if success is not None:
|
||||||
@@ -840,7 +838,7 @@ class DebugLogger:
|
|||||||
|
|
||||||
for key, value in kwargs.items():
|
for key, value in kwargs.items():
|
||||||
if key not in entry:
|
if key not in entry:
|
||||||
entry[key] = self._sanitize_data(value)
|
entry[key] = self.sanitize_data(value)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self.file_handle.write(json.dumps(entry, default=str) + "\n")
|
self.file_handle.write(json.dumps(entry, default=str) + "\n")
|
||||||
@@ -848,7 +846,7 @@ class DebugLogger:
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Failed to write debug log: {e}", file=sys.stderr)
|
print(f"Failed to write debug log: {e}", file=sys.stderr)
|
||||||
|
|
||||||
def _sanitize_data(self, data: Any) -> Any:
|
def sanitize_data(self, data: Any) -> Any:
|
||||||
"""
|
"""
|
||||||
Sanitize data for JSON serialization.
|
Sanitize data for JSON serialization.
|
||||||
Handles complex objects and removes sensitive information.
|
Handles complex objects and removes sensitive information.
|
||||||
@@ -860,7 +858,7 @@ class DebugLogger:
|
|||||||
return data
|
return data
|
||||||
|
|
||||||
if isinstance(data, (list, tuple)):
|
if isinstance(data, (list, tuple)):
|
||||||
return [self._sanitize_data(item) for item in data]
|
return [self.sanitize_data(item) for item in data]
|
||||||
|
|
||||||
if isinstance(data, dict):
|
if isinstance(data, dict):
|
||||||
sanitized = {}
|
sanitized = {}
|
||||||
@@ -883,7 +881,7 @@ class DebugLogger:
|
|||||||
if should_redact:
|
if should_redact:
|
||||||
sanitized[key] = "[REDACTED]"
|
sanitized[key] = "[REDACTED]"
|
||||||
else:
|
else:
|
||||||
sanitized[key] = self._sanitize_data(value)
|
sanitized[key] = self.sanitize_data(value)
|
||||||
return sanitized
|
return sanitized
|
||||||
|
|
||||||
if isinstance(data, bytes):
|
if isinstance(data, bytes):
|
||||||
|
|||||||
@@ -3,8 +3,11 @@ import sys
|
|||||||
import typing
|
import typing
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
|
import pysubs2
|
||||||
from pycaption import Caption, CaptionList, CaptionNode, CaptionReadError, WebVTTReader, WebVTTWriter
|
from pycaption import Caption, CaptionList, CaptionNode, CaptionReadError, WebVTTReader, WebVTTWriter
|
||||||
|
|
||||||
|
from unshackle.core.config import config
|
||||||
|
|
||||||
|
|
||||||
class CaptionListExt(CaptionList):
|
class CaptionListExt(CaptionList):
|
||||||
@typing.no_type_check
|
@typing.no_type_check
|
||||||
@@ -142,7 +145,24 @@ def merge_segmented_webvtt(vtt_raw: str, segment_durations: Optional[list[int]]
|
|||||||
"""
|
"""
|
||||||
MPEG_TIMESCALE = 90_000
|
MPEG_TIMESCALE = 90_000
|
||||||
|
|
||||||
vtt = WebVTTReaderExt().read(vtt_raw)
|
# Check config for conversion method preference
|
||||||
|
conversion_method = config.subtitle.get("conversion_method", "auto")
|
||||||
|
use_pysubs2 = conversion_method in ("pysubs2", "auto")
|
||||||
|
|
||||||
|
if use_pysubs2:
|
||||||
|
# Try using pysubs2 first for more lenient parsing
|
||||||
|
try:
|
||||||
|
# Use pysubs2 to parse and normalize the VTT
|
||||||
|
subs = pysubs2.SSAFile.from_string(vtt_raw)
|
||||||
|
# Convert back to WebVTT string for pycaption processing
|
||||||
|
normalized_vtt = subs.to_string("vtt")
|
||||||
|
vtt = WebVTTReaderExt().read(normalized_vtt)
|
||||||
|
except Exception:
|
||||||
|
# Fall back to direct pycaption parsing
|
||||||
|
vtt = WebVTTReaderExt().read(vtt_raw)
|
||||||
|
else:
|
||||||
|
# Use pycaption directly
|
||||||
|
vtt = WebVTTReaderExt().read(vtt_raw)
|
||||||
for lang in vtt.get_languages():
|
for lang in vtt.get_languages():
|
||||||
prev_caption = None
|
prev_caption = None
|
||||||
duplicate_index: list[int] = []
|
duplicate_index: list[int] = []
|
||||||
|
|||||||
Reference in New Issue
Block a user