diff --git a/fastanime/cli/__init__.py b/fastanime/cli/__init__.py index ae4cc62..4d3ba58 100644 --- a/fastanime/cli/__init__.py +++ b/fastanime/cli/__init__.py @@ -98,6 +98,11 @@ signal.signal(signal.SIGINT, handle_exit) type=click.Choice(["dub", "sub"]), help="Anime language[dub/sub]", ) +@click.option( + "-sl", + "--sub-lang", + help="Set the preferred language for subs", +) @click.option( "-A/-no-A", "--auto-next/--no-auto-next", @@ -156,6 +161,7 @@ def run_cli( local_history, skip, translation_type, + sub_lang, quality, auto_next, auto_select, @@ -216,6 +222,8 @@ def run_cli( ctx.obj.server = server if format: ctx.obj.format = format + if sub_lang: + ctx.obj.sub_lang = sub_lang if ctx.get_parameter_source("continue_") == click.core.ParameterSource.COMMANDLINE: ctx.obj.continue_from_history = continue_ if ctx.get_parameter_source("skip") == click.core.ParameterSource.COMMANDLINE: diff --git a/fastanime/cli/commands/download.py b/fastanime/cli/commands/download.py index 6648a78..e003330 100644 --- a/fastanime/cli/commands/download.py +++ b/fastanime/cli/commands/download.py @@ -59,7 +59,11 @@ def download( from ...libs.fzf import fzf from ...Utility.downloader.downloader import downloader from ..utils.tools import exit_app - from ..utils.utils import filter_by_quality, fuzzy_inquirer + from ..utils.utils import ( + filter_by_quality, + fuzzy_inquirer, + move_preferred_subtitle_lang_to_top, + ) anime_provider = AnimeProvider(config.provider) @@ -168,37 +172,12 @@ def download( if config.server == "top": with Progress() as progress: progress.add_task("Fetching top server...", total=None) - server = next(streams, None) - if not server: + server_name = next(streams, None) + if not server_name: print("Sth went wrong when fetching the server") continue - stream_link = filter_by_quality(config.quality, server["links"]) - if not stream_link: - print("[yellow bold]WARNING:[/] No streams found") - time.sleep(1) - print("Continuing...") - continue - link = stream_link["link"] - provider_headers = server["headers"] - episode_title = server["episode_title"] - else: - with Progress() as progress: - progress.add_task("Fetching servers", total=None) - # prompt for server selection - servers = {server["server"]: server for server in streams} - servers_names = list(servers.keys()) - if config.server in servers_names: - server = config.server - else: - if config.use_fzf: - server = fzf.run(servers_names, "Select an link: ") - else: - server = fuzzy_inquirer( - servers_names, - "Select link", - ) stream_link = filter_by_quality( - config.quality, servers[server]["links"] + config.quality, server_name["links"] ) if not stream_link: print("[yellow bold]WARNING:[/] No streams found") @@ -206,11 +185,42 @@ def download( print("Continuing...") continue link = stream_link["link"] - provider_headers = servers[server]["headers"] + provider_headers = server_name["headers"] + episode_title = server_name["episode_title"] + subtitles = server_name["subtitles"] + else: + with Progress() as progress: + progress.add_task("Fetching servers", total=None) + # prompt for server selection + servers = {server["server"]: server for server in streams} + servers_names = list(servers.keys()) + if config.server in servers_names: + server_name = config.server + else: + if config.use_fzf: + server_name = fzf.run(servers_names, "Select an link: ") + else: + server_name = fuzzy_inquirer( + servers_names, + "Select link", + ) + stream_link = filter_by_quality( + config.quality, servers[server_name]["links"] + ) + if not stream_link: + print("[yellow bold]WARNING:[/] No streams found") + time.sleep(1) + print("Continuing...") + continue + link = stream_link["link"] + provider_headers = servers[server_name]["headers"] - episode_title = servers[server]["episode_title"] + subtitles = servers[server_name]["subtitles"] + episode_title = servers[server_name]["episode_title"] print(f"[purple]Now Downloading:[/] {search_result} Episode {episode}") - + subtitles = move_preferred_subtitle_lang_to_top( + subtitles, config.sub_lang + ) downloader._download_file( link, anime["title"], @@ -221,6 +231,7 @@ def download( force_unknown_ext, verbose, headers=provider_headers, + sub=subtitles[0]["url"] if subtitles else "", ) except Exception as e: print(e) diff --git a/fastanime/cli/commands/search.py b/fastanime/cli/commands/search.py index a90fc64..67dc58b 100644 --- a/fastanime/cli/commands/search.py +++ b/fastanime/cli/commands/search.py @@ -35,7 +35,11 @@ def search(config: Config, anime_titles: str, episode_range: str): from ...libs.rofi import Rofi from ..utils.mpv import run_mpv from ..utils.tools import exit_app - from ..utils.utils import filter_by_quality, fuzzy_inquirer + from ..utils.utils import ( + filter_by_quality, + fuzzy_inquirer, + move_preferred_subtitle_lang_to_top, + ) anime_provider = AnimeProvider(config.provider) @@ -177,6 +181,7 @@ def search(config: Config, anime_titles: str, episode_range: str): stream_anime() return link = stream_link["link"] + subtitles = server["subtitles"] stream_headers = server["headers"] episode_title = server["episode_title"] else: @@ -207,15 +212,23 @@ def search(config: Config, anime_titles: str, episode_range: str): return link = stream_link["link"] stream_headers = servers[server]["headers"] + subtitles = servers[server]["subtitles"] episode_title = servers[server]["episode_title"] print(f"[purple]Now Playing:[/] {search_result} Episode {episode}") + subtitles = move_preferred_subtitle_lang_to_top( + subtitles, config.sub_lang + ) if config.sync_play: from ..utils.syncplay import SyncPlayer - SyncPlayer(link, episode_title, headers=stream_headers) + SyncPlayer( + link, episode_title, headers=stream_headers, subtitles=subtitles + ) else: - run_mpv(link, episode_title, headers=stream_headers) + run_mpv( + link, episode_title, headers=stream_headers, subtitles=subtitles + ) except IndexError as e: print(e) input("Enter to continue") diff --git a/fastanime/cli/config.py b/fastanime/cli/config.py index 3055495..0c03440 100644 --- a/fastanime/cli/config.py +++ b/fastanime/cli/config.py @@ -96,6 +96,7 @@ class Config(object): "rofi_theme_input": "", "rofi_theme_confirm": "", "ffmpegthumnailer_seek_time": "-1", + "sub_lang": "eng", } ) self.configparser.add_section("stream") @@ -109,6 +110,7 @@ class Config(object): # --- set config values from file or using defaults --- self.downloads_dir = self.get_downloads_dir() + self.sub_lang = self.get_sub_lang() self.provider = self.get_provider() self.use_fzf = self.get_use_fzf() self.use_rofi = self.get_use_rofi() @@ -187,6 +189,9 @@ class Config(object): def get_preferred_language(self): return self.configparser.get("general", "preferred_language") + def get_sub_lang(self): + return self.configparser.get("general", "sub_lang") + def get_downloads_dir(self): return self.configparser.get("general", "downloads_dir") diff --git a/fastanime/cli/utils/mpv.py b/fastanime/cli/utils/mpv.py index 11f8053..620675f 100644 --- a/fastanime/cli/utils/mpv.py +++ b/fastanime/cli/utils/mpv.py @@ -55,6 +55,7 @@ def run_mpv( ytdl_format="", custom_args=[], headers={}, + subtitles=[], ): # Determine if mpv is available MPV = shutil.which("mpv") @@ -108,6 +109,8 @@ def run_mpv( for header_name, header_value in headers.items(): mpv_headers += f"{header_name}:{header_value}," mpv_args.append(mpv_headers) + for subtitle in subtitles: + mpv_args.append(f"--sub-file={subtitle['url']}") if start_time != "0": mpv_args.append(f"--start={start_time}") if title: diff --git a/fastanime/cli/utils/syncplay.py b/fastanime/cli/utils/syncplay.py index cd51cc6..c633836 100644 --- a/fastanime/cli/utils/syncplay.py +++ b/fastanime/cli/utils/syncplay.py @@ -4,7 +4,7 @@ import subprocess from .tools import exit_app -def SyncPlayer(url: str, anime_title=None, headers={}, *args): +def SyncPlayer(url: str, anime_title=None, headers={}, subtitles=[], *args): # TODO: handle m3u8 multi quality streams # # check for SyncPlay @@ -20,6 +20,8 @@ def SyncPlayer(url: str, anime_title=None, headers={}, *args): for header_name, header_value in headers.items(): mpv_headers += f"{header_name}:{header_value}," mpv_args.append(mpv_headers) + for subtitle in subtitles: + mpv_args.append(f"--sub-file={subtitle['url']}") if not anime_title: subprocess.run( [ diff --git a/fastanime/cli/utils/utils.py b/fastanime/cli/utils/utils.py index b671e12..bb6a694 100644 --- a/fastanime/cli/utils/utils.py +++ b/fastanime/cli/utils/utils.py @@ -19,6 +19,25 @@ BG_GREEN = "\033[48;2;120;233;12;m" GREEN = "\033[38;2;45;24;45;m" +def move_preferred_subtitle_lang_to_top(sub_list, lang_str): + """Moves the dictionary with the given ID to the front of the list. + + Args: + sub_list: list of subs + lang_str: the sub lang pref + + Returns: + The modified list. + """ + import re + + for i, d in enumerate(sub_list): + if re.search(lang_str, d["language"], re.IGNORECASE): + sub_list.insert(0, sub_list.pop(i)) + break + return sub_list + + def filter_by_quality(quality: str, stream_links: "list[EpisodeStream]", default=True): """Helper function used to filter a list of EpisodeStream objects to one that has a corresponding quality diff --git a/fastanime/libs/anime_provider/allanime/api.py b/fastanime/libs/anime_provider/allanime/api.py index b71b631..390ef2a 100644 --- a/fastanime/libs/anime_provider/allanime/api.py +++ b/fastanime/libs/anime_provider/allanime/api.py @@ -231,6 +231,7 @@ class AllAnimeAPI(AnimeProvider): "server": "Yt", "episode_title": f'{anime["title"]}; Episode {episode_number}', "headers": {"Referer": f"https://{ALLANIME_BASE}/"}, + "subtitles": [], "links": [ { "link": url, @@ -260,6 +261,7 @@ class AllAnimeAPI(AnimeProvider): yield { "server": "gogoanime", "headers": {}, + "subtitles": [], "episode_title": ( allanime_episode["notes"] or f'{anime["title"]}' ) @@ -271,6 +273,7 @@ class AllAnimeAPI(AnimeProvider): yield { "server": "wetransfer", "headers": {}, + "subtitles": [], "episode_title": ( allanime_episode["notes"] or f'{anime["title"]}' ) @@ -282,6 +285,7 @@ class AllAnimeAPI(AnimeProvider): yield { "server": "sharepoint", "headers": {}, + "subtitles": [], "episode_title": ( allanime_episode["notes"] or f'{anime["title"]}' ) @@ -293,6 +297,7 @@ class AllAnimeAPI(AnimeProvider): yield { "server": "dropbox", "headers": {}, + "subtitles": [], "episode_title": ( allanime_episode["notes"] or f'{anime["title"]}' ) @@ -304,6 +309,7 @@ class AllAnimeAPI(AnimeProvider): yield { "server": "wixmp", "headers": {}, + "subtitles": [], "episode_title": ( allanime_episode["notes"] or f'{anime["title"]}' ) diff --git a/fastanime/libs/anime_provider/allanime/constants.py b/fastanime/libs/anime_provider/allanime/constants.py index f5ce60d..59b85af 100644 --- a/fastanime/libs/anime_provider/allanime/constants.py +++ b/fastanime/libs/anime_provider/allanime/constants.py @@ -4,4 +4,4 @@ ALLANIME_BASE = "allanime.day" ALLANIME_REFERER = "https://allanime.to/" ALLANIME_API_ENDPOINT = "https://api.{}/api/".format(ALLANIME_BASE) USER_AGENT = random_user_agent() -SERVERS_AVAILABLE = ["sharepoint", "dropbox", "gogoanime", "weTransfer", "wixmp"] +SERVERS_AVAILABLE = ["sharepoint", "dropbox", "gogoanime", "weTransfer", "wixmp", "Yt"] diff --git a/fastanime/libs/anime_provider/animepahe/api.py b/fastanime/libs/anime_provider/animepahe/api.py index c6e647d..542439c 100644 --- a/fastanime/libs/anime_provider/animepahe/api.py +++ b/fastanime/libs/anime_provider/animepahe/api.py @@ -136,7 +136,7 @@ class AnimePaheApi(AnimeProvider): }, "episodesInfo": [ { - "title": episode["title"] or f"{title};{episode['episode']}", + "title": f"{episode['title'] or title};{episode['episode']}", "episode": episode["episode"], "id": episode["session"], "translation_type": episode["audio"], @@ -190,6 +190,7 @@ class AnimePaheApi(AnimeProvider): "server": "kwik", "links": [], "episode_title": episode_title, + "subtitles": [], "headers": {}, } for res_dict in res_dicts: diff --git a/fastanime/libs/anime_provider/animepahe/constants.py b/fastanime/libs/anime_provider/animepahe/constants.py index 2806239..54cdd42 100644 --- a/fastanime/libs/anime_provider/animepahe/constants.py +++ b/fastanime/libs/anime_provider/animepahe/constants.py @@ -1,5 +1,6 @@ from yt_dlp.utils.networking import random_user_agent +SERVERS_AVAILABLE = ["kwik"] USER_AGENT = random_user_agent() ANIMEPAHE = "animepahe.ru" ANIMEPAHE_BASE = f"https://{ANIMEPAHE}"