chore: clean up

This commit is contained in:
Benexl
2025-07-14 23:53:25 +03:00
parent ecdd1b5f20
commit 26f9c3b8de
3 changed files with 0 additions and 302 deletions

View File

@@ -1,43 +0,0 @@
import re
from datetime import datetime
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from ..libs.anilist.types import AnilistDateObject, AnilistMediaNextAiringEpisode
COMMA_REGEX = re.compile(r"([0-9]{3})(?=\d)")
# TODO: Add formating options for the final date
def format_anilist_date_object(anilist_date_object: "AnilistDateObject"):
if anilist_date_object and anilist_date_object["day"]:
return f"{anilist_date_object['day']}/{anilist_date_object['month']}/{anilist_date_object['year']}"
else:
return "Unknown"
def format_anilist_timestamp(anilist_timestamp: int | None):
if anilist_timestamp:
return datetime.fromtimestamp(anilist_timestamp).strftime("%d/%m/%Y %H:%M:%S")
else:
return "Unknown"
def format_list_data_with_comma(data: list | None):
if data:
return ", ".join(data)
else:
return "None"
def format_number_with_commas(number: int | None):
if not number:
return "0"
return COMMA_REGEX.sub(lambda match: f"{match.group(1)},", str(number)[::-1])[::-1]
def extract_next_airing_episode(airing_episode: "AnilistMediaNextAiringEpisode"):
if airing_episode:
return f"{airing_episode['episode']} on {format_anilist_timestamp(airing_episode['airingAt'])}"
else:
return "Completed"

View File

@@ -1,59 +0,0 @@
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from collections.abc import Callable
from typing import Any
from ...libs.anilist.types import AnilistBaseMediaDataSchema
from ...libs.anime_provider.types import Anime, EpisodeStream, SearchResult, Server
class FastAnimeRuntimeState:
"""A class that manages fastanime runtime during anilist command runtime"""
provider_current_episode_stream_link: str
provider_current_server: "Server"
provider_current_server_name: str
provider_available_episodes: list[str]
provider_current_episode_number: str
provider_server_episode_streams: list["EpisodeStream"]
provider_anime_title: str
provider_anime: "Anime"
provider_anime_search_result: "SearchResult"
progress_tracking: str = ""
selected_anime_anilist: "AnilistBaseMediaDataSchema"
selected_anime_id_anilist: int
selected_anime_title_anilist: str
# current_anilist_data: "AnilistDataSchema | AnilistMediaList"
anilist_results_data: "Any"
current_page: int
current_data_loader: "Callable"
def exit_app(exit_code=0, *args, **kwargs):
import sys
from rich.console import Console
from ...constants import APP_NAME, ICON_PATH, USER_NAME
console = Console()
if not console.is_terminal:
try:
from plyer import notification
except ImportError:
print(
"Plyer is not installed; install it for desktop notifications to be enabled"
)
exit(1)
notification.notify(
app_name=APP_NAME,
app_icon=ICON_PATH,
message=f"Have a good day {USER_NAME}",
title="Shutting down",
) # pyright:ignore
else:
console.clear()
console.print("Have a good day :smile:", USER_NAME)
sys.exit(exit_code)

View File

@@ -1,200 +0,0 @@
import logging
import shutil
from typing import TYPE_CHECKING
from InquirerPy import inquirer
from fastanime.constants import S_PLATFORM
logger = logging.getLogger(__name__)
if TYPE_CHECKING:
from ...libs.anime_provider.types import EpisodeStream
# Define ANSI escape codes as constants
RESET = "\033[0m"
BOLD = "\033[1m"
INVISIBLE_CURSOR = "\033[?25l"
VISIBLE_CURSOR = "\033[?25h"
UNDERLINE = "\033[4m"
# ESC[38;2;{r};{g};{b}m
BG_GREEN = "\033[48;2;120;233;12;m"
GREEN = "\033[38;2;45;24;45;m"
def get_requested_quality_or_default_to_first(url, quality):
import yt_dlp
with yt_dlp.YoutubeDL({"quiet": True, "silent": True, "no_warnings": True}) as ydl:
m3u8_info = ydl.extract_info(url, False)
if not m3u8_info:
return
m3u8_formats = m3u8_info["formats"]
quality = int(quality)
quality_u = quality - 80
quality_l = quality + 80
for m3u8_format in m3u8_formats:
if m3u8_format["height"] == quality or (
m3u8_format["height"] < quality_u and m3u8_format["height"] > quality_l
):
return m3u8_format["url"]
return m3u8_formats[0]["url"]
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
Args:
quality: the quality to use
stream_links: a list of EpisodeStream objects
Returns:
an EpisodeStream object or None incase the quality was not found
"""
for stream_link in stream_links:
q = float(quality)
Q = float(stream_link["quality"])
# some providers have inaccurate/weird/non-standard eg qualities 718 instead of 720
if Q <= q + 80 and Q >= q - 80:
return stream_link
if stream_links and default:
from rich import print
try:
print("[yellow bold]WARNING Qualities were:[/] ", stream_links)
print(
"[cyan bold]Using default of quality:[/] ",
stream_links[0]["quality"],
)
return stream_links[0]
except Exception as e:
print(e)
return
def format_bytes_to_human(num_of_bytes: float, suffix: str = "B"):
"""Helper function used to format bytes to human
Args:
num_of_bytes: the number of bytes to format
suffix: the suffix to use
Returns:
formated bytes
"""
for unit in ("", "K", "M", "G", "T", "P", "E", "Z"):
if abs(num_of_bytes) < 1024.0:
return f"{num_of_bytes:3.1f}{unit}{suffix}"
num_of_bytes /= 1024.0
return f"{num_of_bytes:.1f}Yi{suffix}"
def get_true_fg(string: str, r, g, b, bold: bool = True) -> str:
"""Custom helper function that enables colored text in the terminal
Args:
bold: whether to bolden the text
string: string to color
r: red
g: green
b: blue
Returns:
colored string
"""
# NOTE: Currently only supports terminals that support true color
if bold:
return f"{BOLD}\033[38;2;{r};{g};{b};m{string}{RESET}"
else:
return f"\033[38;2;{r};{g};{b};m{string}{RESET}"
def get_true_bg(string, r: int, g: int, b: int) -> str:
return f"\033[48;2;{r};{g};{b};m{string}{RESET}"
def fuzzy_inquirer(choices: list, prompt: str, **kwargs):
"""helper function that enables easier interaction with InquirerPy lib
Args:
choices: the choices to prompt
prompt: the prompt string to use
**kwargs: other options to pass to fuzzy_inquirer
Returns:
a choice
"""
from click import clear
clear()
action = inquirer.fuzzy( # pyright:ignore
prompt,
choices,
height="100%",
border=True,
validate=lambda result: result in choices,
**kwargs,
).execute()
return action
def which_win32_gitbash():
"""Helper function that returns absolute path to the git bash executable
(came with Git for Windows) on Windows
Returns:
the path to the git bash executable or None if not found
"""
from os import path
gb_path = shutil.which("bash")
# Windows came with its own bash.exe but it's just an entry point for WSL not Git Bash
if gb_path and not path.dirname(gb_path).lower().endswith("windows\\system32"):
return gb_path
git_path = shutil.which("git")
if git_path:
if path.dirname(git_path).endswith("cmd"):
gb_path = path.abspath(
path.join(path.dirname(git_path), "..", "bin", "bash.exe")
)
else:
gb_path = path.join(path.dirname(git_path), "bash.exe")
if path.exists(gb_path):
return gb_path
def which_bashlike():
"""Helper function that returns absolute path to the bash executable for the current platform
Returns:
the path to the bash executable or None if not found
"""
return (
(shutil.which("bash") or "bash")
if S_PLATFORM != "win32"
else which_win32_gitbash()
)