Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

download in menu #54

Closed
wants to merge 10 commits into from
248 changes: 242 additions & 6 deletions fastanime/cli/interfaces/anilist_interfaces.py
Original file line number Diff line number Diff line change
Expand Up @@ -385,8 +385,6 @@ def provider_anime_episode_servers_menu(
current_episode_number: str = (
fastanime_runtime_state.provider_current_episode_number
)
provider_anime_title: str = fastanime_runtime_state.provider_anime_title
anime_id_anilist: int = fastanime_runtime_state.selected_anime_id_anilist
provider_anime: "Anime" = fastanime_runtime_state.provider_anime

server_name = ""
Expand Down Expand Up @@ -507,7 +505,29 @@ def provider_anime_episode_servers_menu(
fastanime_runtime_state.provider_current_server = selected_server
fastanime_runtime_state.provider_current_server_name = server_name

# play video
if fastanime_runtime_state.selected_anime_media_action == "Stream":
# play video
provider_anime_play_stream(config, fastanime_runtime_state)
elif fastanime_runtime_state.selected_anime_media_action == "Download":
provider_anime_download_stream(config, fastanime_runtime_state)


def provider_anime_play_stream(
config: Config, fastanime_runtime_state: FastAnimeRuntimeState
):

# user config
anime_provider = config.anime_provider

current_episode_number: str = (
fastanime_runtime_state.provider_current_episode_number
)
provider_anime_title: str = fastanime_runtime_state.provider_anime_title
anime_id_anilist: int = fastanime_runtime_state.selected_anime_id_anilist

current_stream_link = fastanime_runtime_state.provider_current_episode_stream_link
selected_server = fastanime_runtime_state.provider_current_server

print(
"[bold magenta]Now playing:[/]",
provider_anime_title,
Expand Down Expand Up @@ -831,9 +851,196 @@ def fetch_anime_episode(
return media_actions_menu(config, fastanime_runtime_state)

fastanime_runtime_state.provider_anime = provider_anime
provider_anime_episodes_menu(config, fastanime_runtime_state)
if fastanime_runtime_state.selected_anime_media_action == "Stream":
provider_anime_episodes_menu(config, fastanime_runtime_state)
elif fastanime_runtime_state.selected_anime_media_action == "Download":
download_options_menu(config, fastanime_runtime_state)


#
# ---- ANIME DOWNLOAD MENU ----
#


def download_options_menu(
config: "Config", fastanime_runtime_state: "FastAnimeRuntimeState"
):
options = ["Download all", "Download selected", "Back"]
download_option: str = ""
if config.use_fzf:
download_option = fzf.run(
options,
"Enter your preferred download option for the current anime",
)
elif config.use_rofi:
download_option = Rofi.run(
options,
"Enter your preferred download option for the current anime",
)
else:
download_option = fuzzy_inquirer(
options,
"Enter your preferred download option for the current anime",
)

selected_episodes: list[str] = []
if download_option == "Download all":

# User config
translation_type: str = config.translation_type.lower()

selected_episodes = sorted(
fastanime_runtime_state.provider_anime["availableEpisodesDetail"][
translation_type
],
key=float,
)

elif download_option == "Download selected":
selected_episodes = select_multiple_episodes(config, fastanime_runtime_state)

if selected_episodes == []:
download_options_menu(config, fastanime_runtime_state)
return

elif download_option == "Back":
media_actions_menu(config, fastanime_runtime_state)
return

else:
print("Invalid option")
download_options_menu(config, fastanime_runtime_state)
return

for episode in selected_episodes:
fastanime_runtime_state.provider_current_episode_number = episode

# Next interface
# Handles downloading from fastanime_runtime_state.selected_anime_media_action
provider_anime_episode_servers_menu(config, fastanime_runtime_state)


def select_multiple_episodes(
config: "Config", fastanime_runtime_state: "FastAnimeRuntimeState"
):
"""A menu that handles selection of episodes. Can be used to select multiple episodes

Args:
config: [TODO:description]
fastanime_runtime_state: [TODO:description]
"""
# user config
translation_type: str = config.translation_type.lower()

# runtime configuration
anime_title: str = fastanime_runtime_state.provider_anime_title
provider_anime: "Anime" = fastanime_runtime_state.provider_anime

available_episodes = sorted(
provider_anime["availableEpisodesDetail"][translation_type], key=float
)

selected_episodes: list[str] = (
[]
) # Use str instead of int to deal with special/recap episodes
selected_entry: str = ""

choices = [
"Select till top",
*list(map(lambda x: f"[ ] {x}", available_episodes)), # Convert to [ ] <num>
"Select till end",
"Select all in between",
"Download",
"Back",
]

preview = None
# if config.preview:
# from .utils import get_fzf_episode_preview
#
# e = fastanime_runtime_state.selected_anime_anilist["episodes"]
# if e:
# eps = range(0, e + 1)
# else:
# eps = available_episodes
#
# preview = get_fzf_episode_preview(
# fastanime_runtime_state.selected_anime_anilist, eps
# )
# # eps = [f"[ ] {ep}" for ep in eps]

preselect_index = 1

while selected_entry != "Download":

if config.use_fzf:
selected_entry = fzf.run(
choices,
prompt="Select Episode",
header=anime_title,
preview=preview,
preselect=preselect_index,
)
elif config.use_rofi:
selected_entry = Rofi.run(
choices, "Select Episode", preselect=preselect_index
)
else:
selected_entry = fuzzy_inquirer(
choices,
"Select Episode",
)

if selected_entry == "Back":
return []

elif selected_entry == "Select till top" and selected_episodes != []:
# Select all episodes from the top to the first selected episode
for i in range(1, int(choices.index(f"[*] {selected_episodes[0]}"))):
selected_episodes.append(choices[i][4:])
preselect_index = choices.index("Select till top")

elif selected_entry == "Select till end" and selected_episodes != []:
# Select all episodes from the last selected episode to the end
for i in range(
choices.index(f"[*] {selected_episodes[-1]}") + 1,
choices.index(selected_entry),
):
selected_episodes.append(choices[i][4:])
preselect_index = choices.index("Select till end")

elif selected_entry == "Select all in between" and selected_episodes != []:
# Select all episodes in between the first and last selected episodes
for i in range(
choices.index(f"[*] {selected_episodes[0]}") + 1,
choices.index(f"[*] {selected_episodes[-1]}"),
):
selected_episodes.append(choices[i][4:])
preselect_index = choices.index("Select all in between")
elif selected_entry.startswith("[ ] "):
selected_episodes.append(selected_entry[4:])
preselect_index = choices.index(selected_entry) + 1

elif selected_entry.startswith("[*] "):
selected_episodes.remove(selected_entry[4:])
preselect_index = choices.index(selected_entry) + 1

# Remake the choices list
selected_episodes = list(set(selected_episodes)) # Remove duplicates
selected_episodes.sort(key=float)
for i in range(1, len(available_episodes)):
if choices[i][4:] in selected_episodes:
choices[i] = f"[*] {choices[i][4:]}"
else:
choices[i] = f"[ ] {choices[i][4:]}"

return selected_episodes


def provider_anime_download_stream(
config: "Config", fastanime_runtime_state: "FastAnimeRuntimeState"
):
pass
#
# ---- ANIME PROVIDER SEARCH RESULTS MENU ----
#
Expand Down Expand Up @@ -961,8 +1168,19 @@ def anime_provider_search_results_menu(
fastanime_runtime_state.progress_tracking = config.watch_history.get(
str(fastanime_runtime_state.selected_anime_id_anilist), {}
).get("progress_tracking", "prompt")
set_prefered_progress_tracking(config, fastanime_runtime_state)
fetch_anime_episode(config, fastanime_runtime_state)
if fastanime_runtime_state.selected_anime_media_action == "Stream":
set_prefered_progress_tracking(config, fastanime_runtime_state)
fetch_anime_episode(config, fastanime_runtime_state)
elif fastanime_runtime_state.selected_anime_media_action == "Download":
fetch_anime_episode(config, fastanime_runtime_state)
else:
print("Unknown media action")
if not config.use_rofi:
input("Enter to continue...")
else:
if not Rofi.confirm("Unknown media action!!Enter to continue..."):
exit(1)
media_actions_menu(config, fastanime_runtime_state)


#
Expand Down Expand Up @@ -1337,6 +1555,8 @@ def _stream_anime(
config: [TODO:description]
fastanime_runtime_state: [TODO:description]
"""

fastanime_runtime_state.selected_anime_media_action = "Stream"
anime_provider_search_results_menu(config, fastanime_runtime_state)

def _select_episode_to_stream(
Expand All @@ -1349,6 +1569,7 @@ def _select_episode_to_stream(
fastanime_runtime_state: [TODO:description]
"""
config.continue_from_history = False
fastanime_runtime_state.selected_anime_media_action = "Stream"
anime_provider_search_results_menu(config, fastanime_runtime_state)

def _set_progress_tracking(
Expand Down Expand Up @@ -1409,10 +1630,25 @@ def _recommendations(
}
anilist_results_menu(config, fastanime_runtime_state)

def _download_anime(
config: "Config", fastanime_runtime_state: "FastAnimeRuntimeState"
):
"""helper function to go to the next menu containing download options respecting your config

Args:
config: [TODO:description]
fastanime_runtime_state: [TODO:description]
"""

fastanime_runtime_state.selected_anime_media_action = "Download"

anime_provider_search_results_menu(config, fastanime_runtime_state)

icons = config.icons
options = {
f"{'📽️ ' if icons else ''}Stream ({progress}/{episodes_total})": _stream_anime,
f"{'📽️ ' if icons else ''}Episodes": _select_episode_to_stream,
f"{' ' if icons else ''}Download": _download_anime,
f"{'📼 ' if icons else ''}Watch Trailer": _watch_trailer,
f"{'✨ ' if icons else ''}Score Anime": _score_anime,
f"{'✨ ' if icons else ''}Progress Tracking": _set_progress_tracking,
Expand Down
2 changes: 2 additions & 0 deletions fastanime/cli/utils/tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ class FastAnimeRuntimeState(object):
selected_anime_anilist: "AnilistBaseMediaDataSchema"
selected_anime_id_anilist: int
selected_anime_title_anilist: str
selected_anime_media_action: str = "Stream"
selected_anime_download_episodes: list[int]
# current_anilist_data: "AnilistDataSchema | AnilistMediaList"
anilist_results_data: "Any"
current_page: int
Expand Down
4 changes: 4 additions & 0 deletions fastanime/libs/fzf/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ def run(
preview: str | None = None,
expect: str | None = None,
validator: Callable | None = None,
preselect: int | None = None,
) -> str:
"""a helper method that wraps common use cases over the fzf utility

Expand Down Expand Up @@ -178,6 +179,9 @@ def run(
_commands.append(f"--preview={preview}")
if expect:
_commands.append(f"--expect={expect}")
if preselect:
_commands.append("--sync")
_commands.append(f"--bind=start:pos({preselect + 1})")

result = self._run_fzf(_commands, fzf_input) # pyright:ignore
if not result:
Expand Down
4 changes: 3 additions & 1 deletion fastanime/libs/rofi/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ def run_with_icons(self, options: list[str], prompt_text: str) -> str:

return choice

def run(self, options: list[str], prompt_text: str) -> str:
def run(self, options: list[str], prompt_text: str, preselect: int = 0) -> str:
rofi_input = "\n".join(options)

if not self.ROFI_EXECUTABLE:
Expand All @@ -60,6 +60,8 @@ def run(self, options: list[str], prompt_text: str) -> str:
args = [self.ROFI_EXECUTABLE]
if self.rofi_theme:
args.extend(["-no-config", "-theme", self.rofi_theme])
if preselect:
args.extend(["-selected-row", str(preselect)])
args.extend(["-p", prompt_text, "-i", "-dmenu"])
result = subprocess.run(
args,
Expand Down
Loading