From ae60ca65234d9bd739655b857ff8d760fe5c8af7 Mon Sep 17 00:00:00 2001 From: Benex254 Date: Mon, 5 Aug 2024 09:47:05 +0300 Subject: [PATCH] feat(anilist interface): add rofi as tertiary option for the interface --- fastanime/cli/__init__.py | 12 ++++ fastanime/cli/config.py | 13 +++++ .../cli/interfaces/anilist_interfaces.py | 54 ++++++++++++++++- fastanime/libs/rofi/__init__.py | 58 +++++++++++++++++++ 4 files changed, 135 insertions(+), 2 deletions(-) create mode 100644 fastanime/libs/rofi/__init__.py diff --git a/fastanime/cli/__init__.py b/fastanime/cli/__init__.py index d9e4877..bfcac23 100644 --- a/fastanime/cli/__init__.py +++ b/fastanime/cli/__init__.py @@ -112,6 +112,8 @@ signal.signal(signal.SIGINT, handle_exit) ) @click.option("--dub", help="Set the translation type to dub", is_flag=True) @click.option("--sub", help="Set the translation type to sub", is_flag=True) +@click.option("--rofi", help="Use rofi for the ui", is_flag=True) +@click.option("--rofi-theme", help="Rofi theme to use", type=click.Path()) @click.pass_context def run_cli( ctx: click.Context, @@ -133,6 +135,8 @@ def run_cli( icons, dub, sub, + rofi, + rofi_theme, ): ctx.obj = Config() if provider: @@ -176,3 +180,11 @@ def run_cli( ctx.obj.translation_type = "dub" if sub: ctx.obj.translation_type = "sub" + if rofi: + ctx.obj.use_fzf = False + ctx.obj.use_rofi = True + if rofi_theme: + ctx.obj.rofi_theme = rofi_theme + from ..libs.rofi import Rofi + + Rofi.rofi_theme = rofi_theme diff --git a/fastanime/cli/config.py b/fastanime/cli/config.py index 4592762..c0808fb 100644 --- a/fastanime/cli/config.py +++ b/fastanime/cli/config.py @@ -5,6 +5,7 @@ from rich import print from ..AnimeProvider import AnimeProvider from ..constants import USER_CONFIG_PATH, USER_VIDEOS_DIR +from ..libs.rofi import Rofi from ..Utility.user_data_helper import user_data_helper @@ -38,6 +39,8 @@ class Config(object): "icons": "false", "notification_duration": "2", "skip": "false", + "use_rofi": "false", + "rofi_theme": "", } ) self.configparser.add_section("stream") @@ -46,12 +49,14 @@ class Config(object): if not os.path.exists(USER_CONFIG_PATH): with open(USER_CONFIG_PATH, "w") as config: self.configparser.write(config) + self.configparser.read(USER_CONFIG_PATH) # --- set defaults --- self.downloads_dir = self.get_downloads_dir() self.provider = self.get_provider() self.use_fzf = self.get_use_fzf() + self.use_rofi = self.get_use_rofi() self.skip = self.get_skip() self.icons = self.get_icons() self.preview = self.get_preview() @@ -66,6 +71,8 @@ class Config(object): self.server = self.get_server() self.format = self.get_format() self.preferred_language = self.get_preferred_language() + self.rofi_theme = self.get_rofi_theme() + Rofi.rofi_theme = self.rofi_theme # ---- setup user data ------ self.watch_history: dict = user_data_helper.user_data.get("watch_history", {}) @@ -108,12 +115,18 @@ class Config(object): def get_provider(self): return self.configparser.get("general", "provider") + def get_rofi_theme(self): + return self.configparser.get("general", "rofi_theme") + def get_downloads_dir(self): return self.configparser.get("general", "downloads_dir") def get_use_fzf(self): return self.configparser.getboolean("general", "use_fzf") + def get_use_rofi(self): + return self.configparser.getboolean("general", "use_rofi") + def get_skip(self): return self.configparser.getboolean("stream", "skip") diff --git a/fastanime/cli/interfaces/anilist_interfaces.py b/fastanime/cli/interfaces/anilist_interfaces.py index 0e982e6..a66c99c 100644 --- a/fastanime/cli/interfaces/anilist_interfaces.py +++ b/fastanime/cli/interfaces/anilist_interfaces.py @@ -15,6 +15,7 @@ from ...constants import USER_CONFIG_PATH from ...libs.anilist.anilist_data_schema import AnilistBaseMediaDataSchema from ...libs.anime_provider.types import Anime, SearchResult, Server from ...libs.fzf import fzf +from ...libs.rofi import Rofi from ...Utility.data import anime_normalizer from ...Utility.utils import anime_title_percentage_match, sanitize_filename from ..config import Config @@ -113,7 +114,7 @@ def player_controls(config: Config, anilist_config: QueryDict): ): anilist_options(config, anilist_config) return - else: + elif not config.use_rofi: if not Confirm.ask( "Are you sure you wish to continue to the next episode, your progress for the current episodes will be erased?", default=True, @@ -164,6 +165,8 @@ def player_controls(config: Config, anilist_config: QueryDict): quality = fzf.run( options, prompt="Select Quality:", header="Quality Options" ) + elif config.use_rofi: + quality = Rofi.run(options, "Select Quality") else: quality = fuzzy_inquirer("Select Quality", options) config.quality = options.index(quality) # set quality @@ -176,6 +179,8 @@ def player_controls(config: Config, anilist_config: QueryDict): translation_type = fzf.run( options, prompt="Select Translation Type: ", header="Lang Options" ).lower() + elif config.use_rofi: + translation_type = Rofi.run(options, "Select Translation Type") else: translation_type = fuzzy_inquirer( "Select Translation Type", options @@ -214,6 +219,8 @@ def player_controls(config: Config, anilist_config: QueryDict): action = fzf.run( list(options.keys()), prompt="Select Action:", header="Player Controls" ) + elif config.use_rofi: + action = Rofi.run(list(options.keys()), "Select Action") else: action = fuzzy_inquirer("Select Action", options.keys()) options[action]() @@ -261,6 +268,8 @@ def fetch_streams(config: Config, anilist_config: QueryDict): prompt="Select Server: ", header="Servers", ) + elif config.use_rofi: + server = Rofi.run(choices, "Select Server") else: server = fuzzy_inquirer("Select Server", choices) if server == "Back": @@ -370,6 +379,8 @@ def fetch_episode(config: Config, anilist_config: QueryDict): prompt="Select Episode:", header=anime_title, ) + elif config.use_rofi: + episode_number = Rofi.run(choices, "Select Episode") else: episode_number = fuzzy_inquirer("Select Episode", choices) @@ -457,6 +468,8 @@ def provide_anime(config: Config, anilist_config: QueryDict): header="Anime Search Results", ) + elif config.use_rofi: + anime_title = Rofi.run(choices, "Select Search Result") else: anime_title = fuzzy_inquirer("Select Search Result", choices) if anime_title == "Back": @@ -501,6 +514,10 @@ def anilist_options(config, anilist_config: QueryDict): "Choose the list you want to add to", "Add your animelist", ) + elif config.use_rofi: + anime_list = Rofi.run( + list(anime_lists.keys()), "Choose list you want to add to" + ) else: anime_list = fuzzy_inquirer( "Choose the list you want to add to", list(anime_lists.keys()) @@ -559,6 +576,8 @@ def anilist_options(config, anilist_config: QueryDict): translation_type = fzf.run( options, prompt="Select Translation Type:", header="Language Options" ) + elif config.use_rofi: + translation_type = Rofi.run(options, "Select Translation Type") else: translation_type = fuzzy_inquirer("Select translation type", options) @@ -636,6 +655,8 @@ def anilist_options(config, anilist_config: QueryDict): action = fzf.run( list(options.keys()), prompt="Select Action:", header="Anime Menu" ) + elif config.use_rofi: + action = Rofi.run(list(options.keys()), "Select Action") else: action = fuzzy_inquirer("Select Action", options.keys()) options[action](config, anilist_config) @@ -668,6 +689,27 @@ def select_anime(config: Config, anilist_config: QueryDict): prompt="Select Anime: ", header="Search Results", ) + elif config.use_rofi: + # TODO: Make this faster + if config.preview and False: + from .utils import SEARCH_RESULTS_CACHE, get_preview + + get_preview(search_results, config, wait=True) + choices = [] + for anime in search_results: + title = sanitize_filename( + str( + anime["title"][config.preferred_language] + or anime["title"]["romaji"] + ) + ) + anime_cache = os.path.join(SEARCH_RESULTS_CACHE, title) + icon_path = f"{anime_cache}/image" + choices.append(f"{title}\0icon\x1f{icon_path}") + choices.append("Back") + selected_anime_title = Rofi.run_with_icons(choices, "Select Anime") + else: + selected_anime_title = Rofi.run(choices, "Select Anime") else: selected_anime_title = fuzzy_inquirer("Select Anime", choices) # "bat %s/{}" % SEARCH_RESULTS_CACHE @@ -749,7 +791,12 @@ def anilist(config: Config, anilist_config: QueryDict): import subprocess subprocess.run([os.environ.get("EDITOR", "open"), USER_CONFIG_PATH]) - config.load_config() + if config.use_rofi: + config.load_config() + config.use_rofi = True + config.use_fzf = False + else: + config.load_config() anilist(config, anilist_config) @@ -793,6 +840,9 @@ def anilist(config: Config, anilist_config: QueryDict): prompt="Select Action: ", header="Anilist Menu", ) + elif config.use_rofi: + + action = Rofi.run(list(options.keys()), "Select Action") else: action = fuzzy_inquirer("Select Action", options.keys()) anilist_data = options[action]() diff --git a/fastanime/libs/rofi/__init__.py b/fastanime/libs/rofi/__init__.py new file mode 100644 index 0000000..8064f98 --- /dev/null +++ b/fastanime/libs/rofi/__init__.py @@ -0,0 +1,58 @@ +import subprocess +from shutil import which +from sys import exit + + +class RofiApi: + ROFI_EXECUTABLE = which("rofi") + + rofi_theme = "" + + def run_with_icons(self, options: list[str], prompt_text: str) -> str: + rofi_input = "\n".join(options) + + if not self.ROFI_EXECUTABLE: + raise Exception("Rofi not found") + + args = [self.ROFI_EXECUTABLE] + if self.rofi_theme: + args.extend(["-no-config", "-theme", self.rofi_theme]) + args.extend(["-p", prompt_text, "-i", "-show-icons", "-dmenu"]) + result = subprocess.run( + args, + input=rofi_input, + stdout=subprocess.PIPE, + text=True, + ) + + choice = result.stdout.strip() + if not choice: + exit(1) + + return choice + + def run(self, options: list[str], prompt_text: str) -> str: + rofi_input = "\n".join(options) + + if not self.ROFI_EXECUTABLE: + raise Exception("Rofi not found") + + args = [self.ROFI_EXECUTABLE] + if self.rofi_theme: + args.extend(["-no-config", "-theme", self.rofi_theme]) + args.extend(["-p", prompt_text, "-i", "-dmenu"]) + result = subprocess.run( + args, + input=rofi_input, + stdout=subprocess.PIPE, + text=True, + ) + + choice = result.stdout.strip() + if not choice or choice not in options: + exit(1) + + return choice + + +Rofi = RofiApi()