Skip to content

Commit

Permalink
Implement subsource as a provider (#697)
Browse files Browse the repository at this point in the history
  • Loading branch information
vagabondHustler authored Jul 22, 2024
2 parents 5dfb04b + 90775d0 commit bd55739
Show file tree
Hide file tree
Showing 29 changed files with 1,074 additions and 436 deletions.
25 changes: 8 additions & 17 deletions src/subsearch/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,36 +16,27 @@ class Subsearch:
def __init__(self) -> None:
self.subsearch_core = core.SubsearchCore(PREF_COUNTER)

def search_for_subtitles(self) -> None:
def start_app(self) -> None:
self.subsearch_core.init_search(
self.provider_opensubtitles,
self.provider_yifysubtitles,
self.subsearch_core.opensubtitles,
self.subsearch_core.yifysubtitles,
self.subsearch_core.subsource,
)

def provider_opensubtitles(self) -> None:
self.subsearch_core.opensubtitles()


def provider_yifysubtitles(self) -> None:
self.subsearch_core.yifysubtitles()

def process_files(self) -> None:
self.subsearch_core.download_files()
self.subsearch_core.download_manager()
self.subsearch_core.extract_files()
self.subsearch_core.subtitle_post_processing()
self.subsearch_core.clean_up()

def on_exit(self) -> None:
def exit_app(self) -> None:
self.subsearch_core.core_on_exit()


@decorators.apply_mutex
def main() -> None:
app = Subsearch()
app.search_for_subtitles()
app.process_files()
app.on_exit()
subsearch = Subsearch()
subsearch.start_app()
subsearch.exit_app()


if __name__ == "__main__":
Expand Down
211 changes: 170 additions & 41 deletions src/subsearch/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,34 @@
from subsearch.globals.dataclasses import Subtitle
from subsearch.gui import screen_manager, system_tray
from subsearch.gui.screens import download_manager
from subsearch.providers import opensubtitles, yifysubtitles
from subsearch.utils import io_file_system, io_toml, string_parser
from subsearch.providers import opensubtitles, subsource, yifysubtitles
from subsearch.utils import imdb_lookup, io_file_system, io_toml, string_parser


class Initializer:
def __init__(self, pref_counter: float) -> None:
log.brackets("Initializing")
log.stdout(f"Loading components...", level="info", end_new_line=True)
self.file_exist = True if VIDEO_FILE else False
self.setup_file_system()
self.start = pref_counter
log.brackets("Initializing")

self.api_calls_made: dict[str, int] = {}
self.downloaded_subtitles = 0
self.ran_download_tab = False
self.accepted_subtitles: list[Subtitle] = []
self.rejected_subtitles: list[Subtitle] = []
self.manually_accepted_subtitles: list[Subtitle] = []
self.release_data = string_parser.no_release_data()
self.provider_urls = string_parser.CreateProviderUrls.no_urls()
self.file_exist = VIDEO_FILE.file_exist

log.stdout("Verifing files and paths", level="debug")
self.setup_file_system()
self.language_data = io_toml.load_toml_data(FILE_PATHS.language_data)
self.app_config = io_toml.get_app_config(FILE_PATHS.config)

log.dataclass(DEVICE_INFO, level="debug", print_allowed=False)
log.dataclass(self.app_config, level="debug", print_allowed=False)

log.stdout("Initializing system tray icon", level="debug")
decorators.enable_system_tray = self.app_config.system_tray
self.system_tray = system_tray.SystemTray()
self.system_tray.start()
Expand All @@ -31,16 +44,8 @@ def __init__(self, pref_counter: float) -> None:
VIDEO_FILE.file_hash = io_file_system.get_file_hash(VIDEO_FILE.file_path)
log.dataclass(VIDEO_FILE, level="debug", print_allowed=False)
io_file_system.create_directory(VIDEO_FILE.file_directory)

self.downloaded_subtitles = 0
self.ran_download_tab = False
self.accepted_subtitles: list[Subtitle] = []
self.rejected_subtitles: list[Subtitle] = []
self.manually_accepted_subtitles: list[Subtitle] = []
self.language_data = io_toml.load_toml_data(FILE_PATHS.language_data)

if self.file_exist:
self.release_data = string_parser.get_release_data(VIDEO_FILE.filename)
self.update_imdb_id()
log.dataclass(self.release_data, level="debug", print_allowed=False)
provider_urls = string_parser.CreateProviderUrls(self.app_config, self.release_data, self.language_data)
self.provider_urls = provider_urls.retrieve_urls()
Expand All @@ -51,10 +56,22 @@ def __init__(self, pref_counter: float) -> None:
provider_urls=self.provider_urls,
language_data=self.language_data,
)

self.call_conditions = CallConditions(self)
log.task_completed()

def update_imdb_id(self) -> None:
timeout = self.app_config.request_connect_timeout, self.app_config.request_read_timeout
find_id = imdb_lookup.FindImdbID(
self.release_data.title,
self.release_data.year,
self.release_data.tvseries,
request_timeout=timeout,
)
self.release_data.imdb_id = find_id.imdb_id

def setup_file_system(self) -> None:
log.stdout("Verifing files and paths", level="debug")

io_file_system.create_directory(APP_PATHS.tmp_dir)
io_file_system.create_directory(APP_PATHS.appdata_subsearch)
io_toml.resolve_on_integrity_failure()
Expand All @@ -68,6 +85,7 @@ def all_providers_disabled(self) -> bool:
self.app_config.providers["opensubtitles_site"] is False
and self.app_config.providers["opensubtitles_hash"] is False
and self.app_config.providers["yifysubtitles_site"] is False
and self.app_config.providers["subsource_site"] is False
):
return True
return False
Expand All @@ -91,47 +109,59 @@ def __init__(self, pref_counter: float) -> None:

@decorators.call_func
def init_search(self, *providers: Callable[..., None]) -> None:
self._create_threads(*providers)
thread_handle._create_threads(*providers)
log.task_completed()

def _create_threads(self, *tasks) -> None:
for thread_count, target in enumerate(tasks, start=1):
func_name = str(target.__name__).split("_")[-1]
name = f"thread_{thread_count}_{func_name}"
task_thread = thread_handle.CreateThread(target=target, name=name)
task_thread.start()
task_thread.join()

def _start_search(self, provider, flag: str) -> None:
search_provider = provider(**self.search_kwargs)
search_provider.start_search(flag=flag)
self.accepted_subtitles.extend(search_provider.accepted_subtitles)
self.rejected_subtitles.extend(search_provider.rejected_subtitles)

@decorators.call_func
def opensubtitles(self) -> None:
self._start_search(provider=opensubtitles.OpenSubtitles, flag="hash")
self._start_search(provider=opensubtitles.OpenSubtitles, flag="site")
thread_handle._start_search(self, provider=opensubtitles.OpenSubtitles, flag="hash")
thread_handle._start_search(self, provider=opensubtitles.OpenSubtitles, flag="site")

@decorators.call_func
def yifysubtitles(self) -> None:
self._start_search(provider=yifysubtitles.YifiSubtitles, flag="site")
thread_handle._start_search(self, provider=yifysubtitles.YifiSubtitles, flag="site")

@decorators.call_func
def subsource(self) -> None:
thread_handle._start_search(self, provider=subsource.Subsource, flag="site")

@decorators.call_func
def download_files(self) -> None:
log.brackets(f"Downloading subtitles")
index_size = len(self.accepted_subtitles)
for enum, subtitle in enumerate(self.accepted_subtitles, 1):
io_file_system.download_subtitle(subtitle, enum, index_size)
self.downloaded_subtitles += 1
self.accepted_subtitles = sorted(self.accepted_subtitles, key=lambda i: i.precentage_result, reverse=True)
for index_position, subtitle in enumerate(self.accepted_subtitles):
if subtitle.provider_name not in self.api_calls_made:
self.api_calls_made[subtitle.provider_name] = 0
if not self.api_calls_made[subtitle.provider_name] == self.app_config.api_call_limit:
if subtitle.provider_name == "subsource":
self._handle_subsource_subtitle(index_position, subtitle)
sub_count = sum(self.api_calls_made.values(), 1)
io_file_system.download_subtitle(subtitle, sub_count, index_size)
self.downloaded_subtitles += 1
self.api_calls_made[subtitle.provider_name] += 1
else:
s = self.accepted_subtitles.pop(index_position)
self.rejected_subtitles.append(s)
log.task_completed()

def _handle_subsource_subtitle(self, index_position: int, subtitle: Subtitle) -> None:
if self.app_config.providers["subsource_site"]:
subsource_api = subsource.GetDownloadUrl()
download_url = subsource_api.get_url(subtitle)
if not download_url:
self.accepted_subtitles.pop(index_position)
log.stdout(f"{subtitle.provider_name} could not be reached. Removed {subtitle.subtitle_name}")
else:
self.accepted_subtitles[index_position].download_url = download_url
self.accepted_subtitles[index_position].request_data = {}

@decorators.call_func
def download_manager(self) -> None:
log.brackets(f"Download Manager")
subtitles = self.rejected_subtitles + self.accepted_subtitles
screen_manager.open_screen("download_manager", subtitles=subtitles)
self.manually_accepted_subtitles.extend(download_manager.DownloadManager.downloaded_subtitle)
self.manually_accepted_subtitles = download_manager.DownloadManager.downloaded_subtitle
log.task_completed()

@decorators.call_func
Expand Down Expand Up @@ -173,12 +203,13 @@ def summary_notification(self, elapsed) -> None:
log.brackets("Summary toast")
elapsed_summary = f"Finished in {elapsed} seconds"
tot_num_of_subtitles = len(self.accepted_subtitles) + len(self.rejected_subtitles)
matches_downloaded = f"Downloaded: {self.downloaded_subtitles}/{tot_num_of_subtitles}"
if self.downloaded_subtitles > 0:
all_downloaded = self.downloaded_subtitles + len(self.manually_accepted_subtitles)
matches_downloaded = f"Downloaded: {all_downloaded}/{tot_num_of_subtitles}"
if all_downloaded > 0:
msg = "Search Succeeded", f"{matches_downloaded}\n{elapsed_summary}"
log.stdout(matches_downloaded, hex_color="#a6e3a1")
self.system_tray.display_toast(*msg)
elif self.downloaded_subtitles == 0:
elif all_downloaded == 0:
msg = "Search Failed", f"{matches_downloaded}\n{elapsed_summary}"
log.stdout(matches_downloaded, hex_color="#f38ba8")
self.system_tray.display_toast(*msg)
Expand Down Expand Up @@ -208,3 +239,101 @@ def core_on_exit(self) -> None:
input("Enter to exit")
except KeyboardInterrupt:
pass


class CallConditions:

def __init__(self, cls: Initializer) -> None:
self.app_config = cls.app_config
self.file_exist = cls.file_exist
self.release_data = cls.release_data
self.provider_urls = cls.provider_urls
self.language_data = cls.language_data
self.accepted_subtitles = cls.accepted_subtitles
self.rejected_subtitles = cls.rejected_subtitles
self.downloaded_subtitles = cls.downloaded_subtitles

def check_language_compatibility(self, provider: str) -> bool:
language = self.app_config.current_language
if provider in self.language_data[language]:
return False
return True

def all_conditions_true(self, conditions: list[bool]) -> bool:
if False in conditions:
return False
return True

def call_func(self, *args, **kwargs) -> bool:
func_name = kwargs["func_name"]
conditions: dict[str, list[bool]] = {
"init_search": [self.file_exist],
"opensubtitles": [
self.file_exist,
lambda: self.check_language_compatibility("opensubtitles"),
self.app_config.providers["opensubtitles_hash"] or self.app_config.providers["opensubtitles_site"],
],
"yifysubtitles": [
self.file_exist,
not self.app_config.only_foreign_parts,
lambda: self.check_language_compatibility("yifysubtitles"),
not self.release_data.tvseries,
not self.provider_urls.yifysubtitles == "",
self.app_config.providers["yifysubtitles_site"],
],
"subsource": [
self.file_exist,
not self.app_config.only_foreign_parts,
lambda: self.check_language_compatibility("subsource"),
self.app_config.providers["subsource_site"],
],
"download_files": [
len(self.accepted_subtitles) >= 1
and self.app_config.automatic_downloads
or (
len(self.accepted_subtitles) >= 1
and not self.app_config.automatic_downloads
and not self.app_config.always_open
and not self.app_config.open_on_no_matches
),
],
"download_manager": [
(
(
len(self.accepted_subtitles) == 0
and len(self.rejected_subtitles) >= 1
and self.app_config.open_on_no_matches
)
or (
(len(self.accepted_subtitles) >= 1 or len(self.rejected_subtitles) >= 1)
and self.app_config.always_open
)
),
],
"extract_files": [
len(self.accepted_subtitles) >= 1,
],
"subtitle_post_processing": [
self.file_exist,
],
"subtitle_rename": [
self.app_config.subtitle_post_processing["rename"],
self.downloaded_subtitles >= 1,
],
"subtitle_move_best": [
self.app_config.subtitle_post_processing["move_best"],
self.downloaded_subtitles >= 1,
not self.app_config.subtitle_post_processing["move_all"],
],
"subtitle_move_all": [
self.app_config.subtitle_post_processing["move_all"],
self.downloaded_subtitles > 1,
],
"summary_notification": [
self.file_exist,
self.app_config.summary_notification,
],
"clean_up": [self.file_exist],
}

return self.all_conditions_true(conditions[func_name])
2 changes: 1 addition & 1 deletion src/subsearch/globals/_logging.py
Original file line number Diff line number Diff line change
Expand Up @@ -165,4 +165,4 @@ def dataclass(self, instance: GenericDataClass, **kwargs) -> None:

@capture_call_info
def task_completed(self, **kwargs) -> None:
self("Task completed", level="info", hex_color="#89b4fa", **kwargs)
self("Tasks completed", level="info", hex_color="#89b4fa", **kwargs)
2 changes: 1 addition & 1 deletion src/subsearch/globals/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,4 @@
REGISTRY_PATHS = io_app.get_windows_registry_paths()
COMPUTER_NAME = io_app.get_computer_name()
VERSION = io_app.get_app_version()
GUID = io_app.get_guid()
GUID = io_app.get_guid()
Loading

0 comments on commit bd55739

Please sign in to comment.