refactor: remove unnecessary underscore prefixes from function names

This commit is contained in:
Andy
2025-11-08 22:53:47 +00:00
parent 5d20bf9d52
commit 55db8da125
7 changed files with 62 additions and 44 deletions

View File

@@ -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"):

View File

@@ -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

View File

@@ -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:

View File

@@ -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

View File

@@ -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

View File

@@ -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):

View File

@@ -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] = []