-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #63 from ieasybooks/feature/62/Integrate_the_UI_wi…
…th_Tafrigh
- Loading branch information
Showing
20 changed files
with
529 additions
and
149 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
"""Domain package.""" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
"""Backend that interacts with tafrigh.""" | ||
from platform import system | ||
from subprocess import Popen | ||
from typing import Any | ||
|
||
from PySide6.QtCore import Property, QObject, QThreadPool, Signal, Slot | ||
from tafrigh import Config, farrigh | ||
|
||
from domain.config import AppConfig, CaseSensitiveConfigParser | ||
from domain.progress import Progress | ||
from domain.threadpool import Worker, WorkerSignals | ||
|
||
|
||
# BACKEND | ||
class Backend(QObject): | ||
|
||
"""Backend object.""" | ||
|
||
result = Signal(dict) | ||
progress = Signal(int, int) | ||
error = Signal(tuple) | ||
finish = Signal() | ||
|
||
def __init__(self, parent: QObject | None = None) -> None: | ||
"""Initialize backend object.""" | ||
super().__init__(parent=parent) | ||
self.signals = WorkerSignals() | ||
self.threadpool = QThreadPool() | ||
self._is_running = False | ||
self._urls: list[str] = [] | ||
|
||
def on_error(self, error: tuple[str, int, str]) -> None: | ||
self.error.emit(error) | ||
self._is_running = False | ||
|
||
def on_result(self, result: dict[str, Any]) -> None: | ||
self.result.emit(result) | ||
|
||
def on_progress(self, progress: Progress) -> None: | ||
self.progress.emit(progress.value, progress.remaining_time) | ||
|
||
def on_finish(self) -> None: | ||
self.finish.emit() | ||
|
||
@Slot() | ||
def start(self) -> None: | ||
worker = Worker(func=self.run) | ||
worker.signals.finished.connect(self.on_finish) | ||
worker.signals.progress.connect(self.on_progress) | ||
worker.signals.error.connect(self.on_error) | ||
worker.signals.result.connect(self.on_result) | ||
self.threadpool.start(worker) | ||
|
||
@Property(list) | ||
def urls(self) -> list[str]: | ||
return self._urls | ||
|
||
@urls.setter # type: ignore[no-redef] | ||
def urls(self, value: list[str]): | ||
self._urls = [x.replace("file:///", "") for x in value] | ||
|
||
def run(self, *args: Any, **kwargs: Any) -> Any: | ||
app_config: AppConfig = CaseSensitiveConfigParser.read_config() | ||
|
||
config = Config( | ||
urls_or_paths=self.urls, | ||
playlist_items="", | ||
verbose=False, | ||
skip_if_output_exist=True, | ||
model_name_or_path=app_config.whisper_model, | ||
task="transcribe", | ||
language=app_config.convert_language, | ||
use_whisper_jax=False, | ||
use_faster_whisper=True, | ||
beam_size=5, | ||
ct2_compute_type="default", | ||
wit_client_access_token=app_config.wit_convert_key | ||
if app_config.is_wit_engine | ||
else None, | ||
max_cutting_duration=int(app_config.max_part_length), | ||
min_words_per_segment=app_config.word_count, | ||
save_files_before_compact=False, | ||
save_yt_dlp_responses=app_config.download_json, | ||
output_sample=0, | ||
output_formats=app_config.get_output_formats(), | ||
output_dir=app_config.save_location.replace("file:///", ""), | ||
) | ||
|
||
return farrigh(config) | ||
|
||
@Slot(str) | ||
@staticmethod | ||
def open_folder(path: str) -> None: | ||
if system() == "Windows": | ||
from os import startfile # type: ignore[attr-defined] | ||
|
||
startfile(path) # noqa: S606 | ||
elif system() == "Darwin": | ||
Popen(["open", path], shell=False) # noqa: S603, S607 | ||
else: | ||
Popen(["xdg-open", path], shell=False) # noqa: S603, S607 |
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
"""A module contains the configuration parser. | ||
It is used to read the settings.ini file and convert it to a pydantic model. | ||
""" | ||
import re | ||
from configparser import ConfigParser | ||
from typing import TypeVar, cast | ||
|
||
from pydantic import BaseModel | ||
|
||
T = TypeVar("T", bound=BaseModel) | ||
|
||
|
||
class AppConfig(BaseModel): | ||
|
||
"""App configuration model.""" | ||
|
||
download_json: bool | ||
convert_engine: str | ||
save_location: str | ||
word_count: int | ||
is_wit_engine: bool | ||
export_vtt: bool | ||
drop_empty_parts: bool | ||
max_part_length: float | ||
wit_convert_key: str | ||
whisper_model: str | ||
convert_language: str | ||
export_srt: bool | ||
export_txt: bool | ||
|
||
def get_output_formats(self) -> list[str]: | ||
formats = {"srt": self.export_srt, "vtt": self.export_vtt, "txt": self.export_txt} | ||
return [key for key, value in formats.items() if value] | ||
|
||
|
||
class CaseSensitiveConfigParser(ConfigParser): | ||
|
||
"""A case sensitive config parser.""" | ||
|
||
def optionxform(self, option_str: str) -> str: | ||
return option_str | ||
|
||
@staticmethod | ||
def camel_to_snake(camel_case: str) -> str: | ||
snake_case = re.sub(r"([a-z0-9])([A-Z])", r"\1_\2", camel_case) | ||
return snake_case.lower() | ||
|
||
@classmethod | ||
def read_config( | ||
cls, | ||
model: type[T] = AppConfig, | ||
filename: str = "settings.ini", | ||
default_section: str = "config", | ||
) -> T: | ||
parser = cls(default_section=default_section) | ||
parser.read(filename) | ||
|
||
data = {cls.camel_to_snake(key): value for key, value in parser.defaults().items()} | ||
|
||
return cast(T, model(**data)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
"""Progress domain model.""" | ||
from dataclasses import dataclass | ||
|
||
|
||
@dataclass | ||
class Progress: | ||
|
||
"""Progress data class.""" | ||
|
||
value: float = 0.0 | ||
remaining_time: float | None = None |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
"""Custom thread class and signals emitted by worker threads.""" | ||
import sys | ||
import traceback | ||
from collections.abc import Callable, Generator | ||
from typing import Any | ||
|
||
from PySide6.QtCore import QObject, QRunnable, Signal | ||
|
||
from domain.progress import Progress | ||
|
||
|
||
class WorkerSignals(QObject): | ||
|
||
"""Signals emitted by worker threads.""" | ||
|
||
finished = Signal() | ||
error = Signal(tuple) | ||
result = Signal(dict) | ||
progress = Signal(Progress) | ||
|
||
|
||
class Worker(QRunnable): | ||
|
||
"""Custom thread class.""" | ||
|
||
def __init__( | ||
self, func: Callable[..., Generator[dict[str, int], None, None]], *args: Any, **kwargs: Any | ||
) -> None: | ||
"""Initialize worker object.""" | ||
super().__init__() | ||
self.func = func | ||
self.args = args | ||
self.kwargs = kwargs | ||
self.signals = WorkerSignals() | ||
|
||
def run(self) -> None: | ||
try: | ||
results = self.func(args=self.args, kwargs=self.kwargs) | ||
for result in results: | ||
progress_value, remaining_time = result["progress"], result["remaining_time"] | ||
progress = Progress( | ||
value=progress_value, | ||
remaining_time=remaining_time, | ||
) | ||
self.signals.progress.emit(progress) | ||
self.signals.result.emit(result) | ||
except Exception: # noqa: BLE001 | ||
traceback.print_exc() | ||
exc_type, value = sys.exc_info()[:2] | ||
self.signals.error.emit((exc_type, value, traceback.format_exc())) | ||
finally: | ||
try: | ||
self.signals.finished.emit() | ||
except RuntimeError: | ||
return | ||
|
||
def stop(self) -> None: | ||
self.terminate() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.