DuoSubs / ui /events.py
CK-Explorer
feat: add merging modes to web UI
39b0aa8
"""
Event handlers and UI logic for subtitle merging in DuoSubs Hugging Face Web UI.
This module contains functions to handle merging of subtitles, and update UI elements
based on user interactions.
"""
from pathlib import Path
import gradio as gr
from duosubs import (
LoadSubsError,
MergeArgs,
MergeSubsError,
MergingMode,
OmitFile,
SaveSubsError,
SubtitleFormat,
load_subtitles,
merge_subtitles,
save_subtitles_in_zip,
)
from sentence_transformers import SentenceTransformer
def start_merging(
model_pool: dict[str, SentenceTransformer],
primary_subtitles: str,
secondary_subtitles: str,
model_name: str,
batch_size: int,
merging_mode: str,
retain_newline: bool,
secondary_above_primary: bool,
omit_subtitles: list[str],
combined_format: str,
primary_format:str,
secondary_format: str,
cancel_state: list[bool],
progress: gr.Progress | None = None
) -> str | None:
"""
The main function to handle the merging process of subtitles, which starts from
loading subtitles, merging subtitles, and saving the output in a ZIP file.
Args:
model_pool (dict[str, SentenceTransformer]): Mapping of model names to shared
SentenceTransformer instances.
primary_subtitles (str): Path to primary subtitle file.
secondary_subtitles (str): Path to secondary subtitle file.
model_name (str): Name of the model to use.
batch_size (int): Batch size for inference.
merging_mode (str): Subttitle merging mode (based on the value of MergingMode).
retain_newline (bool): Whether to retain newlines in output.
secondary_above_primary (bool): Whether to place secondary subtitle above
primary.
omit_subtitles (list[str]): List of subtitle types to omit from output (based
on the value of OmitFile).
combined_format (str): Format for combined subtitles (based on the value of
SubtitleFormat).
primary_format (str): Format for primary subtitles (based on the value of
SubtitleFormat).
secondary_format (str): Format for secondary subtitles (based on the value of
SubtitleFormat).
cancel_state (list[bool]): List tracking cancellation state.
progress (gradio.Progress) : Gradio progress object (optional).
Defaults to None.
Returns:
str | None: Path to the output ZIP file, or None if cancelled.
Raises:
gradio.Error: If any error occurs during loading, merging, or saving subtitles.
"""
if progress is None:
progress = gr.Progress()
args = MergeArgs(
primary=primary_subtitles,
secondary=secondary_subtitles,
batch_size=int(batch_size),
merging_mode=MergingMode(merging_mode.lower()),
retain_newline=retain_newline,
secondary_above=secondary_above_primary,
omit=[OmitFile.EDIT],
format_combined=SubtitleFormat(combined_format),
format_primary=SubtitleFormat(primary_format),
format_secondary=SubtitleFormat(secondary_format)
)
if "Combined" in omit_subtitles:
args.omit.append(OmitFile.COMBINED)
if "Primary" in omit_subtitles:
args.omit.append(OmitFile.PRIMARY)
if "Secondary" in omit_subtitles:
args.omit.append(OmitFile.SECONDARY)
zip_name_with_path: str | None = None
if len(args.omit) == 4:
gr.Warning(
(
"Nothing to merge β€” Please adjust "
"<strong><em>Excluded Subtitle Files</em></strong> options "
"in <strong><em>File Exports</em></strong>"
),
duration=7
)
return zip_name_with_path
try:
if not cancel_state[0]:
progress(progress=0, desc= "Stage 1 β†’ Loading subtitles", total=1)
primary_subs_data, secondary_subs_data = load_subtitles(args)
progress(progress=1, desc= "Stage 1 β†’ Loading subtitles", total=1)
if not cancel_state[0]:
def update_progress(current: int) -> None:
progress(
progress=current/100,
desc= (
f"Stage 2 β†’ Merging subtitles "
f"({args.merging_mode.value.capitalize()} mode, "
f"using {model_name})"
),
total=100
)
merged_subs = merge_subtitles(
args,
model_pool[model_name],
primary_subs_data,
secondary_subs_data,
cancel_state,
progress_callback=update_progress
)
if not cancel_state[0]:
full_zip_path_without_ext = str(Path(args.primary).with_suffix(""))
zip_name_with_path = f"{full_zip_path_without_ext}.zip"
zip_name = Path(zip_name_with_path).name
progress(
progress=0,
desc= f"Stage 3 β†’ Compressing files into {zip_name}",
total=1
)
save_subtitles_in_zip(
args,
merged_subs,
primary_subs_data.styles,
secondary_subs_data.styles
)
progress(
progress=1,
desc= f"Stage 3 β†’ Compressing files into {zip_name}",
total=1
)
if cancel_state[0]:
gr.Info("The merging process is stopped.", duration=7)
except LoadSubsError as e1:
raise gr.Error(str(e1)) from e1
except MergeSubsError as e2:
raise gr.Error(str(e2)) from e2
except SaveSubsError as e3:
raise gr.Error(str(e3)) from e3
return zip_name_with_path
def cancel_merging(cancel_state: list[bool]) -> gr.Button:
"""
Cancels the merging process and updates the UI state.
Args:
cancel_state (list[bool]): List tracking cancellation state.
Returns:
gradio.Button: Cancel button with updated interactivity.
"""
cancel_state[0] = True
gr.Info("Cancelling merge process...", duration=7)
return gr.Button("Cancel", interactive=False)
def states_during_merging(cancel_state: list[bool]) -> tuple[gr.Button, gr.Button]:
"""
Sets UI state for buttons during the merging process, which disables the Merge
button and enables the Cancel button.
Args:
cancel_state (list[bool]): List tracking cancellation state.
Returns:
tuple[gradio.Button, gradio.Button]: Updated Merge and Cancel buttons.
"""
cancel_state[0] = False
return gr.Button("Merge", interactive=False), gr.Button("Cancel", interactive=True)
def states_after_merging(cancel_state: list[bool]) -> tuple[gr.Button, gr.Button]:
"""
Sets UI state for buttons after the merging process, which enables the Merge button
and disables the Cancel button.
Args:
cancel_state (list[bool]): List tracking cancellation state.
Returns:
tuple[gradio.Button, gradio.Button]: Updated Merge and Cancel buttons.
"""
cancel_state[0] = False
return gr.Button("Merge", interactive=True), gr.Button("Cancel", interactive=False)
def validate_excluded_subtitle_file(selected: list[str]) -> None:
"""
Validates the selected options for excluded subtitle files.
If all options are selected, it shows a warning message.
Args:
selected (list[str]): List of selected options.
"""
if len(selected) == 3:
gr.Warning(
(
"Nothing to merge β€” Please adjust "
"<strong><em>Excluded Subtitle Files</em></strong> options "
"in <strong><em>File Exports</em></strong>"
),
duration=7
)