mirror of
https://github.com/unshackle-dl/unshackle.git
synced 2026-03-10 08:29:00 +00:00
style: fix ruff E721, E701, and E722 lint errors
This commit is contained in:
@@ -195,12 +195,7 @@ class dl:
|
|||||||
sdh_suffix = ".sdh" if (subtitle.sdh or subtitle.cc) else ""
|
sdh_suffix = ".sdh" if (subtitle.sdh or subtitle.cc) else ""
|
||||||
|
|
||||||
extension = (target_codec or subtitle.codec or Subtitle.Codec.SubRip).extension
|
extension = (target_codec or subtitle.codec or Subtitle.Codec.SubRip).extension
|
||||||
if (
|
if not target_codec and not subtitle.codec and source_path and source_path.suffix:
|
||||||
not target_codec
|
|
||||||
and not subtitle.codec
|
|
||||||
and source_path
|
|
||||||
and source_path.suffix
|
|
||||||
):
|
|
||||||
extension = source_path.suffix.lstrip(".")
|
extension = source_path.suffix.lstrip(".")
|
||||||
|
|
||||||
filename = f"{base_filename}.{lang_suffix}{forced_suffix}{sdh_suffix}.{extension}"
|
filename = f"{base_filename}.{lang_suffix}{forced_suffix}{sdh_suffix}.{extension}"
|
||||||
@@ -1056,8 +1051,8 @@ class dl:
|
|||||||
return
|
return
|
||||||
|
|
||||||
# Enables manual selection for Series when --select-titles is set
|
# Enables manual selection for Series when --select-titles is set
|
||||||
if select_titles and type(titles) == Series:
|
if select_titles and isinstance(titles, Series):
|
||||||
console.print(Padding(Rule(f"[rule.text]Select Titles"), (1, 2)))
|
console.print(Padding(Rule("[rule.text]Select Titles"), (1, 2)))
|
||||||
|
|
||||||
selection_titles = []
|
selection_titles = []
|
||||||
dependencies = {}
|
dependencies = {}
|
||||||
@@ -1085,9 +1080,7 @@ class dl:
|
|||||||
|
|
||||||
# Apply indentation only for multiple seasons
|
# Apply indentation only for multiple seasons
|
||||||
prefix = " " if multiple_seasons else ""
|
prefix = " " if multiple_seasons else ""
|
||||||
option_text = (
|
option_text = f"{prefix}{t.number}" + (f". {display_name}" if t.name else "")
|
||||||
f"{prefix}{t.number}" + (f". {display_name}" if t.name else "")
|
|
||||||
)
|
|
||||||
|
|
||||||
selection_titles.append(option_text)
|
selection_titles.append(option_text)
|
||||||
current_ui_idx = len(selection_titles) - 1
|
current_ui_idx = len(selection_titles) - 1
|
||||||
@@ -1103,15 +1096,11 @@ class dl:
|
|||||||
|
|
||||||
# Execute selector with dependencies (headers select all children)
|
# Execute selector with dependencies (headers select all children)
|
||||||
selected_ui_idx = select_multiple(
|
selected_ui_idx = select_multiple(
|
||||||
selection_titles,
|
selection_titles, minimal_count=1, page_size=8, return_indices=True, dependencies=dependencies
|
||||||
minimal_count=1,
|
|
||||||
page_size=8,
|
|
||||||
return_indices=True,
|
|
||||||
dependencies=dependencies
|
|
||||||
)
|
)
|
||||||
|
|
||||||
selection_end = time.time()
|
selection_end = time.time()
|
||||||
start_time += (selection_end - selection_start)
|
start_time += selection_end - selection_start
|
||||||
|
|
||||||
# Map UI indices back to title indices (excluding headers)
|
# Map UI indices back to title indices (excluding headers)
|
||||||
selected_idx = []
|
selected_idx = []
|
||||||
@@ -1604,7 +1593,10 @@ class dl:
|
|||||||
if audio_description:
|
if audio_description:
|
||||||
standard_audio = [a for a in title.tracks.audio if not a.descriptive]
|
standard_audio = [a for a in title.tracks.audio if not a.descriptive]
|
||||||
selected_standards = title.tracks.by_language(
|
selected_standards = title.tracks.by_language(
|
||||||
standard_audio, processed_lang, per_language=per_language, exact_match=exact_lang
|
standard_audio,
|
||||||
|
processed_lang,
|
||||||
|
per_language=per_language,
|
||||||
|
exact_match=exact_lang,
|
||||||
)
|
)
|
||||||
desc_audio = [a for a in title.tracks.audio if a.descriptive]
|
desc_audio = [a for a in title.tracks.audio if a.descriptive]
|
||||||
# Include all descriptive tracks for the requested languages.
|
# Include all descriptive tracks for the requested languages.
|
||||||
@@ -1728,9 +1720,7 @@ class dl:
|
|||||||
),
|
),
|
||||||
licence=partial(
|
licence=partial(
|
||||||
service.get_playready_license
|
service.get_playready_license
|
||||||
if (
|
if (is_playready_cdm(self.cdm))
|
||||||
is_playready_cdm(self.cdm)
|
|
||||||
)
|
|
||||||
and hasattr(service, "get_playready_license")
|
and hasattr(service, "get_playready_license")
|
||||||
else service.get_widevine_license,
|
else service.get_widevine_license,
|
||||||
title=title,
|
title=title,
|
||||||
@@ -1848,9 +1838,7 @@ class dl:
|
|||||||
# Subtitle output mode configuration (for sidecar originals)
|
# Subtitle output mode configuration (for sidecar originals)
|
||||||
subtitle_output_mode = config.subtitle.get("output_mode", "mux")
|
subtitle_output_mode = config.subtitle.get("output_mode", "mux")
|
||||||
sidecar_format = config.subtitle.get("sidecar_format", "srt")
|
sidecar_format = config.subtitle.get("sidecar_format", "srt")
|
||||||
skip_subtitle_mux = (
|
skip_subtitle_mux = subtitle_output_mode == "sidecar" and (title.tracks.videos or title.tracks.audio)
|
||||||
subtitle_output_mode == "sidecar" and (title.tracks.videos or title.tracks.audio)
|
|
||||||
)
|
|
||||||
sidecar_subtitles: list[Subtitle] = []
|
sidecar_subtitles: list[Subtitle] = []
|
||||||
sidecar_original_paths: dict[str, Path] = {}
|
sidecar_original_paths: dict[str, Path] = {}
|
||||||
if subtitle_output_mode in ("sidecar", "both") and not no_mux:
|
if subtitle_output_mode in ("sidecar", "both") and not no_mux:
|
||||||
@@ -2101,7 +2089,9 @@ class dl:
|
|||||||
|
|
||||||
sidecar_dir = config.directories.downloads
|
sidecar_dir = config.directories.downloads
|
||||||
if not no_folder and isinstance(title, (Episode, Song)) and media_info:
|
if not no_folder and isinstance(title, (Episode, Song)) and media_info:
|
||||||
sidecar_dir /= title.get_filename(media_info, show_service=not no_source, folder=True)
|
sidecar_dir /= title.get_filename(
|
||||||
|
media_info, show_service=not no_source, folder=True
|
||||||
|
)
|
||||||
sidecar_dir.mkdir(parents=True, exist_ok=True)
|
sidecar_dir.mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
with console.status("Saving subtitle sidecar files..."):
|
with console.status("Saving subtitle sidecar files..."):
|
||||||
|
|||||||
@@ -1,21 +1,25 @@
|
|||||||
import click
|
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
import click
|
||||||
from rich.console import Group
|
from rich.console import Group
|
||||||
from rich.live import Live
|
from rich.live import Live
|
||||||
from rich.padding import Padding
|
from rich.padding import Padding
|
||||||
from rich.table import Table
|
from rich.table import Table
|
||||||
from rich.text import Text
|
from rich.text import Text
|
||||||
|
|
||||||
from unshackle.core.console import console
|
from unshackle.core.console import console
|
||||||
|
|
||||||
IS_WINDOWS = sys.platform == "win32"
|
IS_WINDOWS = sys.platform == "win32"
|
||||||
if IS_WINDOWS:
|
if IS_WINDOWS:
|
||||||
import msvcrt
|
import msvcrt
|
||||||
|
|
||||||
|
|
||||||
class Selector:
|
class Selector:
|
||||||
"""
|
"""
|
||||||
A custom interactive selector class using the Rich library.
|
A custom interactive selector class using the Rich library.
|
||||||
Allows for multi-selection of items with pagination.
|
Allows for multi-selection of items with pagination.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
options: list[str],
|
options: list[str],
|
||||||
@@ -24,7 +28,7 @@ class Selector:
|
|||||||
page_size: int = 8,
|
page_size: int = 8,
|
||||||
minimal_count: int = 0,
|
minimal_count: int = 0,
|
||||||
dependencies: dict[int, list[int]] = None,
|
dependencies: dict[int, list[int]] = None,
|
||||||
prefixes: list[str] = None
|
prefixes: list[str] = None,
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
Initialize the Selector.
|
Initialize the Selector.
|
||||||
@@ -61,8 +65,8 @@ class Selector:
|
|||||||
|
|
||||||
if idx < len(self.options):
|
if idx < len(self.options):
|
||||||
option = self.options[idx]
|
option = self.options[idx]
|
||||||
is_cursor = (idx == self.cursor_index)
|
is_cursor = idx == self.cursor_index
|
||||||
is_selected = (idx in self.selected_indices)
|
is_selected = idx in self.selected_indices
|
||||||
|
|
||||||
symbol = "[X]" if is_selected else "[ ]"
|
symbol = "[X]" if is_selected else "[ ]"
|
||||||
style = self.cursor_style if is_cursor else self.text_style
|
style = self.cursor_style if is_cursor else self.text_style
|
||||||
@@ -80,7 +84,7 @@ class Selector:
|
|||||||
|
|
||||||
info_text = Text(
|
info_text = Text(
|
||||||
f"\n[Space]: Toggle [a]: All [←/→]: Page [Enter]: Confirm (Page {current_page}/{total_pages})",
|
f"\n[Space]: Toggle [a]: All [←/→]: Page [Enter]: Confirm (Page {current_page}/{total_pages})",
|
||||||
style="gray"
|
style="gray",
|
||||||
)
|
)
|
||||||
|
|
||||||
return Padding(Group(table, info_text), (0, 5))
|
return Padding(Group(table, info_text), (0, 5))
|
||||||
@@ -144,28 +148,43 @@ class Selector:
|
|||||||
Returns command strings like 'UP', 'DOWN', 'ENTER', etc.
|
Returns command strings like 'UP', 'DOWN', 'ENTER', etc.
|
||||||
"""
|
"""
|
||||||
key = msvcrt.getch()
|
key = msvcrt.getch()
|
||||||
if key == b'\x03' or key == b'\x1b':
|
if key == b"\x03" or key == b"\x1b":
|
||||||
return 'CANCEL'
|
return "CANCEL"
|
||||||
if key == b'\xe0' or key == b'\x00':
|
if key == b"\xe0" or key == b"\x00":
|
||||||
try:
|
try:
|
||||||
key = msvcrt.getch()
|
key = msvcrt.getch()
|
||||||
if key == b'H': return 'UP'
|
if key == b"H":
|
||||||
if key == b'P': return 'DOWN'
|
return "UP"
|
||||||
if key == b'K': return 'LEFT'
|
if key == b"P":
|
||||||
if key == b'M': return 'RIGHT'
|
return "DOWN"
|
||||||
except: pass
|
if key == b"K":
|
||||||
|
return "LEFT"
|
||||||
|
if key == b"M":
|
||||||
|
return "RIGHT"
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
try: char = key.decode('utf-8', errors='ignore')
|
try:
|
||||||
except: return None
|
char = key.decode("utf-8", errors="ignore")
|
||||||
|
except Exception:
|
||||||
|
return None
|
||||||
|
|
||||||
if char in ('\r', '\n'): return 'ENTER'
|
if char in ("\r", "\n"):
|
||||||
if char == ' ': return 'SPACE'
|
return "ENTER"
|
||||||
if char in ('q', 'Q'): return 'QUIT'
|
if char == " ":
|
||||||
if char in ('a', 'A'): return 'ALL'
|
return "SPACE"
|
||||||
if char in ('w', 'W', 'k', 'K'): return 'UP'
|
if char in ("q", "Q"):
|
||||||
if char in ('s', 'S', 'j', 'J'): return 'DOWN'
|
return "QUIT"
|
||||||
if char in ('h', 'H'): return 'LEFT'
|
if char in ("a", "A"):
|
||||||
if char in ('d', 'D', 'l', 'L'): return 'RIGHT'
|
return "ALL"
|
||||||
|
if char in ("w", "W", "k", "K"):
|
||||||
|
return "UP"
|
||||||
|
if char in ("s", "S", "j", "J"):
|
||||||
|
return "DOWN"
|
||||||
|
if char in ("h", "H"):
|
||||||
|
return "LEFT"
|
||||||
|
if char in ("d", "D", "l", "L"):
|
||||||
|
return "RIGHT"
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def get_input_unix(self):
|
def get_input_unix(self):
|
||||||
@@ -174,37 +193,49 @@ class Selector:
|
|||||||
Returns command strings like 'UP', 'DOWN', 'ENTER', etc.
|
Returns command strings like 'UP', 'DOWN', 'ENTER', etc.
|
||||||
"""
|
"""
|
||||||
char = click.getchar()
|
char = click.getchar()
|
||||||
if char == '\x03':
|
if char == "\x03":
|
||||||
return 'CANCEL'
|
return "CANCEL"
|
||||||
mapping = {
|
mapping = {
|
||||||
'\x1b[A': 'UP',
|
"\x1b[A": "UP",
|
||||||
'\x1b[B': 'DOWN',
|
"\x1b[B": "DOWN",
|
||||||
'\x1b[C': 'RIGHT',
|
"\x1b[C": "RIGHT",
|
||||||
'\x1b[D': 'LEFT',
|
"\x1b[D": "LEFT",
|
||||||
}
|
}
|
||||||
if char in mapping:
|
if char in mapping:
|
||||||
return mapping[char]
|
return mapping[char]
|
||||||
if char == '\x1b':
|
if char == "\x1b":
|
||||||
try:
|
try:
|
||||||
next1 = click.getchar()
|
next1 = click.getchar()
|
||||||
if next1 in ('[', 'O'):
|
if next1 in ("[", "O"):
|
||||||
next2 = click.getchar()
|
next2 = click.getchar()
|
||||||
if next2 == 'A': return 'UP'
|
if next2 == "A":
|
||||||
if next2 == 'B': return 'DOWN'
|
return "UP"
|
||||||
if next2 == 'C': return 'RIGHT'
|
if next2 == "B":
|
||||||
if next2 == 'D': return 'LEFT'
|
return "DOWN"
|
||||||
return 'CANCEL'
|
if next2 == "C":
|
||||||
except:
|
return "RIGHT"
|
||||||
return 'CANCEL'
|
if next2 == "D":
|
||||||
|
return "LEFT"
|
||||||
|
return "CANCEL"
|
||||||
|
except Exception:
|
||||||
|
return "CANCEL"
|
||||||
|
|
||||||
if char in ('\r', '\n'): return 'ENTER'
|
if char in ("\r", "\n"):
|
||||||
if char == ' ': return 'SPACE'
|
return "ENTER"
|
||||||
if char in ('q', 'Q'): return 'QUIT'
|
if char == " ":
|
||||||
if char in ('a', 'A'): return 'ALL'
|
return "SPACE"
|
||||||
if char in ('w', 'W', 'k', 'K'): return 'UP'
|
if char in ("q", "Q"):
|
||||||
if char in ('s', 'S', 'j', 'J'): return 'DOWN'
|
return "QUIT"
|
||||||
if char in ('h', 'H'): return 'LEFT'
|
if char in ("a", "A"):
|
||||||
if char in ('d', 'D', 'l', 'L'): return 'RIGHT'
|
return "ALL"
|
||||||
|
if char in ("w", "W", "k", "K"):
|
||||||
|
return "UP"
|
||||||
|
if char in ("s", "S", "j", "J"):
|
||||||
|
return "DOWN"
|
||||||
|
if char in ("h", "H"):
|
||||||
|
return "LEFT"
|
||||||
|
if char in ("d", "D", "l", "L"):
|
||||||
|
return "RIGHT"
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def run(self) -> list[int]:
|
def run(self) -> list[int]:
|
||||||
@@ -219,29 +250,39 @@ class Selector:
|
|||||||
with Live(self.get_renderable(), console=console, auto_refresh=False, transient=True) as live:
|
with Live(self.get_renderable(), console=console, auto_refresh=False, transient=True) as live:
|
||||||
while True:
|
while True:
|
||||||
live.update(self.get_renderable(), refresh=True)
|
live.update(self.get_renderable(), refresh=True)
|
||||||
if IS_WINDOWS: action = self.get_input_windows()
|
if IS_WINDOWS:
|
||||||
else: action = self.get_input_unix()
|
action = self.get_input_windows()
|
||||||
|
else:
|
||||||
|
action = self.get_input_unix()
|
||||||
|
|
||||||
if action == 'UP': self.move_cursor(-1)
|
if action == "UP":
|
||||||
elif action == 'DOWN': self.move_cursor(1)
|
self.move_cursor(-1)
|
||||||
elif action == 'LEFT': self.change_page(-1)
|
elif action == "DOWN":
|
||||||
elif action == 'RIGHT': self.change_page(1)
|
self.move_cursor(1)
|
||||||
elif action == 'SPACE': self.toggle_selection()
|
elif action == "LEFT":
|
||||||
elif action == 'ALL': self.toggle_all()
|
self.change_page(-1)
|
||||||
elif action in ('ENTER', 'QUIT'):
|
elif action == "RIGHT":
|
||||||
|
self.change_page(1)
|
||||||
|
elif action == "SPACE":
|
||||||
|
self.toggle_selection()
|
||||||
|
elif action == "ALL":
|
||||||
|
self.toggle_all()
|
||||||
|
elif action in ("ENTER", "QUIT"):
|
||||||
if len(self.selected_indices) >= self.minimal_count:
|
if len(self.selected_indices) >= self.minimal_count:
|
||||||
return sorted(list(self.selected_indices))
|
return sorted(list(self.selected_indices))
|
||||||
elif action == 'CANCEL': raise KeyboardInterrupt
|
elif action == "CANCEL":
|
||||||
|
raise KeyboardInterrupt
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
return []
|
return []
|
||||||
|
|
||||||
|
|
||||||
def select_multiple(
|
def select_multiple(
|
||||||
options: list[str],
|
options: list[str],
|
||||||
minimal_count: int = 1,
|
minimal_count: int = 1,
|
||||||
page_size: int = 8,
|
page_size: int = 8,
|
||||||
return_indices: bool = True,
|
return_indices: bool = True,
|
||||||
cursor_style: str = "pink",
|
cursor_style: str = "pink",
|
||||||
**kwargs
|
**kwargs,
|
||||||
) -> list[int]:
|
) -> list[int]:
|
||||||
"""
|
"""
|
||||||
Drop-in replacement using custom Selector with global console.
|
Drop-in replacement using custom Selector with global console.
|
||||||
@@ -259,7 +300,7 @@ def select_multiple(
|
|||||||
text_style="text",
|
text_style="text",
|
||||||
page_size=page_size,
|
page_size=page_size,
|
||||||
minimal_count=minimal_count,
|
minimal_count=minimal_count,
|
||||||
**kwargs
|
**kwargs,
|
||||||
)
|
)
|
||||||
|
|
||||||
selected_indices = selector.run()
|
selected_indices = selector.run()
|
||||||
|
|||||||
Reference in New Issue
Block a user