mirror of
https://github.com/Benexl/FastAnime.git
synced 2025-12-12 15:50:01 -08:00
feat(cli):add quality and translation type selection
This commit is contained in:
@@ -28,7 +28,10 @@ repos:
|
||||
- id: black
|
||||
name: black
|
||||
language_version: python3.10
|
||||
- repo: https://github.com/PyCQA/bandit
|
||||
rev: 1.7.9 # Update me!
|
||||
hooks:
|
||||
- id: bandit
|
||||
# ------ TODO: re-add this -----
|
||||
# - repo: https://github.com/PyCQA/bandit
|
||||
# rev: 1.7.9 # Update me!
|
||||
# hooks:
|
||||
# - id: bandit
|
||||
# args: ["-c", "pyproject.toml"]
|
||||
# additional_dependencies: ["bandit[toml]"]
|
||||
|
||||
1
fa
1
fa
@@ -1,4 +1,5 @@
|
||||
#! /usr/bin/bash
|
||||
cd $HOME/code/python/kivy_apps/FastAnime
|
||||
poetry install
|
||||
clear
|
||||
poetry run fastanime $*
|
||||
|
||||
15
fastanime/FastAnime/config.ini
Normal file
15
fastanime/FastAnime/config.ini
Normal file
@@ -0,0 +1,15 @@
|
||||
[DEFAULT]
|
||||
server =
|
||||
continue_from_history = False
|
||||
quality = 0
|
||||
auto_next = True
|
||||
sort_by = search match
|
||||
downloads_dir = /home/benxl-85/Videos/FastAnime
|
||||
translation_type = sub
|
||||
|
||||
[stream]
|
||||
|
||||
[general]
|
||||
|
||||
[anilist]
|
||||
|
||||
32
fastanime/Utility/add_desktop_entry.py
Normal file
32
fastanime/Utility/add_desktop_entry.py
Normal file
@@ -0,0 +1,32 @@
|
||||
import os
|
||||
import shutil
|
||||
|
||||
from pyshortcuts import make_shortcut
|
||||
|
||||
from .. import ASSETS_DIR, PLATFORM
|
||||
|
||||
|
||||
def create_desktop_shortcut():
|
||||
app = "_ -m fastanime --gui"
|
||||
|
||||
logo = os.path.join(ASSETS_DIR, "logo.png")
|
||||
if PLATFORM == "Windows":
|
||||
logo = os.path.join(ASSETS_DIR, "logo.ico")
|
||||
if fastanime := shutil.which("fastanime"):
|
||||
app = f"{fastanime} --gui"
|
||||
make_shortcut(
|
||||
app,
|
||||
name="FastAnime",
|
||||
description="Download and watch anime",
|
||||
terminal=False,
|
||||
icon=logo,
|
||||
executable=fastanime,
|
||||
)
|
||||
else:
|
||||
make_shortcut(
|
||||
app,
|
||||
name="FastAnime",
|
||||
description="Download and watch anime",
|
||||
terminal=False,
|
||||
icon=logo,
|
||||
)
|
||||
@@ -9,6 +9,8 @@ anime_normalizer = {
|
||||
}
|
||||
|
||||
|
||||
anilist_sort_normalizer = {"search match": "SEARCH_MATCH"}
|
||||
|
||||
themes_available = [
|
||||
"Aliceblue",
|
||||
"Antiquewhite",
|
||||
|
||||
@@ -3,7 +3,7 @@ from threading import Thread
|
||||
|
||||
import yt_dlp
|
||||
|
||||
from ... import downloads_dir
|
||||
from ... import USER_DOWNLOADS_DIR
|
||||
from ..show_notification import show_notification
|
||||
from ..utils import sanitize_filename
|
||||
|
||||
@@ -53,7 +53,7 @@ class YtDLPDownloader:
|
||||
def _download_file(self, url: str, title, custom_progress_hook, silent):
|
||||
anime_title = sanitize_filename(title[0])
|
||||
ydl_opts = {
|
||||
"outtmpl": f"{downloads_dir}/{anime_title}/{anime_title}-episode {title[1]}.%(ext)s", # Specify the output path and template
|
||||
"outtmpl": f"{USER_DOWNLOADS_DIR}/{anime_title}/{anime_title}-episode {title[1]}.%(ext)s", # Specify the output path and template
|
||||
"progress_hooks": [
|
||||
main_progress_hook,
|
||||
custom_progress_hook,
|
||||
|
||||
@@ -1,49 +1,58 @@
|
||||
import logging
|
||||
import os
|
||||
import sys
|
||||
from platform import platform
|
||||
|
||||
import plyer
|
||||
from rich import print
|
||||
from rich.traceback import install
|
||||
|
||||
install()
|
||||
install(show_locals=True)
|
||||
# Create a logger instance
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# TODO:confirm data integrity
|
||||
# initiate constants
|
||||
__version__ = "0.3.0"
|
||||
|
||||
# ----- some useful paths -----
|
||||
app_dir = os.path.abspath(os.path.dirname(__file__))
|
||||
data_folder = os.path.join(app_dir, "data")
|
||||
configs_folder = os.path.join(app_dir, "configs")
|
||||
if not os.path.exists(data_folder):
|
||||
os.mkdir(data_folder)
|
||||
PLATFORM = platform()
|
||||
APP_NAME = "FastAnime"
|
||||
|
||||
if vid_path := plyer.storagepath.get_videos_dir(): # type: ignore
|
||||
downloads_dir = os.path.join(vid_path, "FastAnime")
|
||||
if not os.path.exists(downloads_dir):
|
||||
os.mkdir(downloads_dir)
|
||||
# ---- app deps ----
|
||||
APP_DIR = os.path.abspath(os.path.dirname(__file__))
|
||||
CONFIGS_DIR = os.path.join(APP_DIR, "configs")
|
||||
ASSETS_DIR = os.path.join(APP_DIR, "assets")
|
||||
|
||||
# ----- user configs and data -----
|
||||
if PLATFORM == "windows":
|
||||
APP_DATA_DIR_ = os.environ.get("LOCALAPPDATA", APP_DIR)
|
||||
else:
|
||||
# fallback
|
||||
downloads_dir = os.path.join(app_dir, "videos")
|
||||
if not os.path.exists(downloads_dir):
|
||||
os.mkdir(downloads_dir)
|
||||
APP_DATA_DIR_ = os.environ.get("XDG_DATA_HOME", APP_DIR)
|
||||
|
||||
user_data_path = os.path.join(data_folder, "user_data.json")
|
||||
assets_folder = os.path.join(app_dir, "assets")
|
||||
if not APP_DATA_DIR_:
|
||||
APP_DATA_DIR = os.path.join(APP_DIR, "data")
|
||||
else:
|
||||
APP_DATA_DIR = os.path.join(APP_DATA_DIR_, APP_NAME)
|
||||
|
||||
if not os.path.exists(APP_DATA_DIR):
|
||||
os.mkdir(APP_DATA_DIR)
|
||||
|
||||
USER_DATA_PATH = os.path.join(APP_DATA_DIR, "user_data.json")
|
||||
USER_CONFIG_PATH = os.path.join(APP_DATA_DIR, "config.ini")
|
||||
|
||||
|
||||
def FastAnime(gui=False, log=False):
|
||||
# video dir
|
||||
if vid_path := plyer.storagepath.get_videos_dir(): # type: ignore
|
||||
USER_DOWNLOADS_DIR = os.path.join(vid_path, "FastAnime")
|
||||
else:
|
||||
USER_DOWNLOADS_DIR = os.path.join(APP_DIR, "videos")
|
||||
|
||||
if not os.path.exists(USER_DOWNLOADS_DIR):
|
||||
os.mkdir(USER_DOWNLOADS_DIR)
|
||||
|
||||
|
||||
def FastAnime(gui=False):
|
||||
if "--gui" in sys.argv:
|
||||
gui = True
|
||||
sys.argv.remove("--gui")
|
||||
if "--log" in sys.argv:
|
||||
log = True
|
||||
sys.argv.remove("--log")
|
||||
if not log:
|
||||
logger.propagate = False
|
||||
|
||||
else:
|
||||
# Configure logging
|
||||
from rich.logging import RichHandler
|
||||
|
||||
@@ -53,13 +62,9 @@ def FastAnime(gui=False, log=False):
|
||||
datefmt="[%X]", # Use a custom date format
|
||||
handlers=[RichHandler()], # Use RichHandler to format the logs
|
||||
)
|
||||
|
||||
print(f"Hello {os.environ.get('USERNAME','User')} from the fastanime team")
|
||||
if gui:
|
||||
print(__name__)
|
||||
from .gui.gui import run_gui
|
||||
from .gui import run_gui
|
||||
|
||||
print("Run GUI")
|
||||
run_gui()
|
||||
else:
|
||||
from .cli import run_cli
|
||||
|
||||
@@ -1,11 +1,62 @@
|
||||
import click
|
||||
from rich import print
|
||||
|
||||
from .commands import anilist, download, search
|
||||
from .. import __version__
|
||||
from ..libs.anime_provider.allanime.constants import SERVERS_AVAILABLE
|
||||
from ..Utility.data import anilist_sort_normalizer
|
||||
from .commands.anilist import anilist
|
||||
from .commands.config import configure
|
||||
from .commands.download import download
|
||||
from .commands.search import search
|
||||
from .config import Config
|
||||
|
||||
commands = {"search": search, "download": download, "anilist": anilist}
|
||||
commands = {
|
||||
"search": search,
|
||||
"download": download,
|
||||
"anilist": anilist,
|
||||
"config": configure,
|
||||
}
|
||||
|
||||
|
||||
@click.group(commands=commands)
|
||||
def run_cli():
|
||||
print("Yellow")
|
||||
@click.group(commands=commands, invoke_without_command=True)
|
||||
@click.version_option(__version__, "--version")
|
||||
@click.option(
|
||||
"-s",
|
||||
"--server",
|
||||
type=click.Choice(SERVERS_AVAILABLE, case_sensitive=False),
|
||||
)
|
||||
@click.option("-h", "--hist", type=bool)
|
||||
@click.option("-q", "--quality", type=int)
|
||||
@click.option("-t-t", "--translation_type")
|
||||
@click.option("-a-n", "--auto-next", type=bool)
|
||||
@click.option(
|
||||
"-s-b",
|
||||
"--sort-by",
|
||||
type=click.Choice(anilist_sort_normalizer.keys()), # pyright: ignore
|
||||
)
|
||||
@click.option("-d", "--downloads-dir", type=click.Path())
|
||||
@click.pass_context
|
||||
def run_cli(
|
||||
ctx: click.Context,
|
||||
server,
|
||||
hist,
|
||||
translation_type,
|
||||
quality,
|
||||
auto_next,
|
||||
sort_by,
|
||||
downloads_dir,
|
||||
):
|
||||
ctx.obj = Config()
|
||||
if server:
|
||||
ctx.obj.server = server
|
||||
if hist:
|
||||
ctx.obj.continue_from_history = hist
|
||||
if quality:
|
||||
ctx.obj.quality = quality
|
||||
if auto_next:
|
||||
ctx.obj.auto_next = auto_next
|
||||
if sort_by:
|
||||
ctx.obj.sort_by = sort_by
|
||||
if downloads_dir:
|
||||
ctx.obj.downloads_dir = downloads_dir
|
||||
if translation_type:
|
||||
ctx.obj.translation_type = translation_type
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import click
|
||||
|
||||
from ...interfaces import anilist as anilist_interface
|
||||
from .favourites import favourites
|
||||
from .popular import popular
|
||||
from .recent import recent
|
||||
@@ -17,6 +18,7 @@ commands = {
|
||||
}
|
||||
|
||||
|
||||
@click.group(commands=commands)
|
||||
def anilist():
|
||||
pass
|
||||
@click.group(commands=commands, invoke_without_command=True)
|
||||
@click.pass_obj
|
||||
def anilist(config):
|
||||
anilist_interface(config=config)
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import click
|
||||
|
||||
from ....libs.anilist.anilist import AniList
|
||||
from ...interfaces.anime_interface import anime_interface
|
||||
from .utils import get_search_result
|
||||
|
||||
|
||||
@@ -10,6 +9,4 @@ from .utils import get_search_result
|
||||
def search(title):
|
||||
success, search_results = AniList.search(title)
|
||||
if search_results and success:
|
||||
result = get_search_result(search_results)
|
||||
if result:
|
||||
anime_interface(result)
|
||||
get_search_result(search_results)
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import click
|
||||
|
||||
from ....libs.anilist.anilist import AniList
|
||||
from ...interfaces.anime_interface import anime_interface
|
||||
from .utils import get_search_result
|
||||
|
||||
|
||||
@@ -9,6 +8,4 @@ from .utils import get_search_result
|
||||
def trending():
|
||||
success, trending = AniList.get_trending()
|
||||
if trending and success:
|
||||
result = get_search_result(trending)
|
||||
if result:
|
||||
anime_interface(result)
|
||||
get_search_result(trending)
|
||||
|
||||
8
fastanime/cli/commands/config.py
Normal file
8
fastanime/cli/commands/config.py
Normal file
@@ -0,0 +1,8 @@
|
||||
import click
|
||||
|
||||
|
||||
@click.command()
|
||||
def configure():
|
||||
pass
|
||||
|
||||
# create_desktop_shortcut()
|
||||
@@ -1,6 +1,15 @@
|
||||
import click
|
||||
|
||||
from ..interfaces import anime_provider_
|
||||
|
||||
|
||||
@click.command()
|
||||
def search():
|
||||
print("Searching")
|
||||
@click.pass_obj
|
||||
def search(
|
||||
config,
|
||||
anime_title,
|
||||
):
|
||||
anime_provider_(
|
||||
config,
|
||||
anime_title,
|
||||
)
|
||||
|
||||
67
fastanime/cli/config.py
Normal file
67
fastanime/cli/config.py
Normal file
@@ -0,0 +1,67 @@
|
||||
import os
|
||||
from configparser import ConfigParser
|
||||
|
||||
from .. import USER_CONFIG_PATH, USER_DOWNLOADS_DIR
|
||||
|
||||
|
||||
class Config(object):
|
||||
def __init__(self) -> None:
|
||||
self.configparser = ConfigParser(
|
||||
{
|
||||
"server": "",
|
||||
"continue_from_history": "False",
|
||||
"quality": "0",
|
||||
"auto_next": "True",
|
||||
"sort_by": "search match",
|
||||
"downloads_dir": USER_DOWNLOADS_DIR,
|
||||
"translation_type": "sub",
|
||||
}
|
||||
)
|
||||
self.configparser.add_section("stream")
|
||||
self.configparser.add_section("general")
|
||||
self.configparser.add_section("anilist")
|
||||
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.translation_type = self.get_translation_type()
|
||||
self.sort_by = self.get_sort_by()
|
||||
self.continue_from_history = self.get_continue_from_history()
|
||||
self.auto_next = self.get_auto_next()
|
||||
self.quality = self.get_quality()
|
||||
self.server = self.get_server()
|
||||
|
||||
def get_downloads_dir(self):
|
||||
return self.configparser.get("general", "downloads_dir")
|
||||
|
||||
def get_sort_by(self):
|
||||
return self.configparser.get("anilist", "sort_by")
|
||||
|
||||
def get_continue_from_history(self):
|
||||
return self.configparser.getboolean("stream", "continue_from_history")
|
||||
|
||||
def get_translation_type(self):
|
||||
return self.configparser.get("stream", "translation_type")
|
||||
|
||||
def get_auto_next(self):
|
||||
return self.configparser.getboolean("stream", "auto_next")
|
||||
|
||||
def get_quality(self):
|
||||
return self.configparser.getint("stream", "quality")
|
||||
|
||||
def get_server(self):
|
||||
return self.configparser.get("stream", "server")
|
||||
|
||||
def update_config(self, section: str, key: str, value: str):
|
||||
self.configparser.set(section, key, value)
|
||||
with open(USER_CONFIG_PATH, "w") as config:
|
||||
self.configparser.write(config)
|
||||
|
||||
def __repr__(self):
|
||||
return f"Config(server:{self.get_server()},quality:{self.get_quality()},auto_next:{self.get_auto_next()},continue_from_history:{self.get_continue_from_history()},sort_by:{self.get_sort_by()},downloads_dir:{self.get_downloads_dir()})"
|
||||
|
||||
def __str__(self):
|
||||
return self.__repr__()
|
||||
181
fastanime/cli/interfaces.py
Normal file
181
fastanime/cli/interfaces.py
Normal file
@@ -0,0 +1,181 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from InquirerPy import inquirer
|
||||
|
||||
from ..libs.anilist.anilist import AniList
|
||||
from ..libs.anilist.anilist_data_schema import AnilistDataSchema
|
||||
from ..libs.anime_provider.allanime.api import anime_provider
|
||||
from .config import Config
|
||||
from .utils.mpv import mpv
|
||||
from .utils.utils import clear, fuzzy_inquirer, get_selected_anime, get_selected_server
|
||||
|
||||
|
||||
def fetch_episode(config: Config, anime, translation_type, selected_anime):
|
||||
# fetch episode
|
||||
episode_number = fuzzy_inquirer(
|
||||
"Select Episode:",
|
||||
[*anime["show"]["availableEpisodesDetail"][translation_type], "back"],
|
||||
)
|
||||
if episode_number == "back":
|
||||
anime_provider_(
|
||||
config,
|
||||
selected_anime[0]["name"],
|
||||
)
|
||||
return
|
||||
print(config.translation_type)
|
||||
episode = anime_provider.get_anime_episode(
|
||||
selected_anime[0]["_id"], episode_number, config.translation_type
|
||||
)
|
||||
|
||||
fetch_streams(config, episode, anime, translation_type, selected_anime)
|
||||
|
||||
|
||||
def fetch_streams(config: Config, episode, *args):
|
||||
episode_streams = list(anime_provider.get_episode_streams(episode))
|
||||
|
||||
server = fuzzy_inquirer(
|
||||
"Select Server:", [episode_stream[0] for episode_stream in episode_streams]
|
||||
)
|
||||
selected_server = get_selected_server(server, episode_streams)
|
||||
|
||||
quality = config.quality
|
||||
links = selected_server[1]["links"]
|
||||
if quality > len(links) - 1:
|
||||
quality = len(links) - 1
|
||||
elif quality < 0:
|
||||
quality = 0
|
||||
stream_link = links[quality]["link"]
|
||||
print("Now playing:", args[-1][0]["name"])
|
||||
mpv(stream_link)
|
||||
clear()
|
||||
player_controls(config, episode, links, *args)
|
||||
|
||||
|
||||
def player_controls(config: Config, episode, links: list, *args):
|
||||
def _back():
|
||||
fetch_streams(config, episode, *args)
|
||||
|
||||
def _replay():
|
||||
pass
|
||||
|
||||
def _next_episode():
|
||||
pass
|
||||
|
||||
def _episodes():
|
||||
fetch_episode(config, *args)
|
||||
|
||||
def _previous_episode():
|
||||
pass
|
||||
|
||||
def _change_quality():
|
||||
options = [link["link"] for link in links]
|
||||
quality = fuzzy_inquirer("Select Quality:", options)
|
||||
config.quality = options.index(quality) # set quality
|
||||
player_controls(config, episode, links, *args)
|
||||
|
||||
def _change_translation_type():
|
||||
options = ["sub", "dub"]
|
||||
translation_type = fuzzy_inquirer("Select Translation Type:", options)
|
||||
config.translation_type = translation_type # set trannslation type
|
||||
player_controls(config, episode, links, *args)
|
||||
|
||||
options = {
|
||||
"Replay": _replay,
|
||||
"Next Episode": _next_episode,
|
||||
"Episodes": _episodes,
|
||||
"Previous Episode": _previous_episode,
|
||||
"Change Quality": _change_quality,
|
||||
"Change Translation Type": _change_translation_type,
|
||||
"Back": _back,
|
||||
}
|
||||
|
||||
action = fuzzy_inquirer("Select Action:", options.keys())
|
||||
options[action]()
|
||||
|
||||
|
||||
def anime_provider_(config: Config, anime_title, **kwargs):
|
||||
translation_type = config.translation_type
|
||||
search_results = anime_provider.search_for_anime(anime_title, translation_type)
|
||||
search_results_anime_titles = [
|
||||
anime["name"] for anime in search_results["shows"]["edges"]
|
||||
]
|
||||
selected_anime_title = fuzzy_inquirer(
|
||||
"Select Search Result:",
|
||||
[*search_results_anime_titles, "back"],
|
||||
default=kwargs.get("default_anime_title", ""),
|
||||
)
|
||||
if selected_anime_title == "back":
|
||||
anilist(config)
|
||||
return
|
||||
fetch_anime_epiosode(
|
||||
config,
|
||||
selected_anime_title,
|
||||
search_results,
|
||||
)
|
||||
|
||||
|
||||
def fetch_anime_epiosode(config, selected_anime_title, search_results):
|
||||
translation_type = config.translation_type
|
||||
selected_anime = get_selected_anime(selected_anime_title, search_results)
|
||||
anime = anime_provider.get_anime(selected_anime[0]["_id"])
|
||||
|
||||
fetch_episode(config, anime, translation_type, selected_anime)
|
||||
|
||||
|
||||
def _stream(config, anilist_data: AnilistDataSchema, preferred_lang="romaji"):
|
||||
anime_titles = [
|
||||
str(anime["title"][preferred_lang])
|
||||
for anime in anilist_data["data"]["Page"]["media"]
|
||||
]
|
||||
selected_anime_title = fuzzy_inquirer("Select Anime:", anime_titles)
|
||||
anime_provider_(
|
||||
config, selected_anime_title, default_anime_title=selected_anime_title
|
||||
)
|
||||
|
||||
|
||||
def anilist_options(config, anilist_data: AnilistDataSchema):
|
||||
def _watch_trailer():
|
||||
pass
|
||||
|
||||
def _add_to_list():
|
||||
pass
|
||||
|
||||
def _remove_from_list():
|
||||
pass
|
||||
|
||||
def _view_info():
|
||||
pass
|
||||
|
||||
options = {
|
||||
"stream": _stream,
|
||||
"watch trailer": _watch_trailer,
|
||||
"add to list": _add_to_list,
|
||||
"remove from list": _remove_from_list,
|
||||
"view info": _view_info,
|
||||
"back": anilist,
|
||||
}
|
||||
action = fuzzy_inquirer("Select Action:", options.keys())
|
||||
options[action](config, anilist_data)
|
||||
|
||||
|
||||
def anilist(config, *args, **kwargs):
|
||||
def _anilist_search():
|
||||
search_term = inquirer.text(
|
||||
"Search:", instruction="Enter anime to search for"
|
||||
).execute()
|
||||
|
||||
return AniList.search(query=search_term)
|
||||
|
||||
options = {
|
||||
"trending": AniList.get_trending,
|
||||
"search": _anilist_search,
|
||||
"most popular anime": AniList.get_most_popular,
|
||||
"most favourite anime": AniList.get_most_favourite,
|
||||
"most scored anime": AniList.get_most_scored,
|
||||
"upcoming anime": AniList.get_most_favourite,
|
||||
"recently updated anime": AniList.get_most_recently_updated,
|
||||
}
|
||||
action = fuzzy_inquirer("Select Action:", options.keys())
|
||||
anilist_data = options[action]()
|
||||
if anilist_data[0]:
|
||||
anilist_options(config, anilist_data[1])
|
||||
@@ -1,4 +0,0 @@
|
||||
def bye():
|
||||
import sys
|
||||
|
||||
sys.exit()
|
||||
@@ -1,24 +0,0 @@
|
||||
from ..utils.fzf import fzf
|
||||
from . import (
|
||||
binge_interface,
|
||||
bye,
|
||||
download_interface,
|
||||
info_interface,
|
||||
stream_interface,
|
||||
watchlist_interface,
|
||||
)
|
||||
|
||||
options = {
|
||||
"info": info_interface,
|
||||
"stream": stream_interface,
|
||||
"binge": binge_interface,
|
||||
"download": download_interface,
|
||||
"watchlist": watchlist_interface,
|
||||
"quit": bye,
|
||||
}
|
||||
|
||||
|
||||
def anime_interface(anime):
|
||||
command = fzf(options.keys())
|
||||
if command:
|
||||
options[command](anime, options)
|
||||
@@ -1,2 +0,0 @@
|
||||
def binge_interface(anime, back):
|
||||
print(anime)
|
||||
@@ -1,2 +0,0 @@
|
||||
def download_interface(anime, back):
|
||||
print(anime)
|
||||
@@ -1,2 +0,0 @@
|
||||
def info_interface(anime, back):
|
||||
print(anime)
|
||||
@@ -1,8 +0,0 @@
|
||||
import sys
|
||||
|
||||
from rich import print
|
||||
|
||||
|
||||
def bye(*args):
|
||||
print("Goodbye")
|
||||
sys.exit()
|
||||
@@ -1,105 +0,0 @@
|
||||
import logging
|
||||
|
||||
from fuzzywuzzy import fuzz
|
||||
|
||||
from ...libs.anime_provider.allanime.api import anime_provider
|
||||
from ...Utility.data import anime_normalizer
|
||||
from ..utils.fzf import fzf
|
||||
from ..utils.mpv import mpv
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def back_(anime, options):
|
||||
command = fzf(options.keys())
|
||||
if command:
|
||||
options[command](anime, options)
|
||||
|
||||
|
||||
def anime_title_percentage_match(
|
||||
possible_user_requested_anime_title: str, title: tuple
|
||||
) -> float:
|
||||
"""Returns the percentage match between the possible title and user title
|
||||
|
||||
Args:
|
||||
possible_user_requested_anime_title (str): an Animdl search result title
|
||||
title (str): the anime title the user wants
|
||||
|
||||
Returns:
|
||||
int: the percentage match
|
||||
"""
|
||||
if normalized_anime_title := anime_normalizer.get(
|
||||
possible_user_requested_anime_title
|
||||
):
|
||||
possible_user_requested_anime_title = normalized_anime_title
|
||||
for key, value in locals().items():
|
||||
logger.info(f"{key}: {value}")
|
||||
# compares both the romaji and english names and gets highest Score
|
||||
percentage_ratio = max(
|
||||
fuzz.ratio(title[0].lower(), possible_user_requested_anime_title.lower()),
|
||||
fuzz.ratio(title[1].lower(), possible_user_requested_anime_title.lower()),
|
||||
)
|
||||
return percentage_ratio
|
||||
|
||||
|
||||
def get_matched_result(anime_title, _search_results):
|
||||
result = max(
|
||||
_search_results,
|
||||
key=lambda x: anime_title_percentage_match(x, anime_title),
|
||||
)
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def _get_result(result, compare):
|
||||
return result["name"] == compare
|
||||
|
||||
|
||||
def _get_server(server, server_name):
|
||||
return server[0] == server_name
|
||||
|
||||
|
||||
def stream_interface(_anime, back, prefered_translation="sub"):
|
||||
results = anime_provider.search_for_anime(_anime["title"]["romaji"])
|
||||
if results:
|
||||
_search_results = [result["name"] for result in results["shows"]["edges"]]
|
||||
|
||||
anime_title = get_matched_result(
|
||||
(_anime["title"]["romaji"], _anime["title"]["english"]), _search_results
|
||||
)
|
||||
result = list(
|
||||
filter(lambda x: _get_result(x, anime_title), results["shows"]["edges"])
|
||||
)
|
||||
if not result:
|
||||
return
|
||||
|
||||
anime = anime_provider.get_anime(result[0]["_id"])
|
||||
episode = fzf(anime["show"]["availableEpisodesDetail"][prefered_translation])
|
||||
|
||||
if not episode:
|
||||
return
|
||||
if t_type := fzf(["sub", "dub"]):
|
||||
prefered_translation = t_type
|
||||
_episode_streams = anime_provider.get_anime_episode(
|
||||
result[0]["_id"], episode, prefered_translation
|
||||
)
|
||||
if _episode_streams:
|
||||
episode_streams = anime_provider.get_episode_streams(_episode_streams)
|
||||
if not episode_streams:
|
||||
return
|
||||
servers = list(episode_streams)
|
||||
|
||||
_sever = fzf([server[0] for server in servers])
|
||||
if not _sever:
|
||||
return
|
||||
|
||||
server = list(filter(lambda x: _get_server(x, _sever), servers)).pop()
|
||||
|
||||
if not server:
|
||||
return
|
||||
#
|
||||
stream_link = server[1]["links"][0]["link"]
|
||||
mpv(stream_link)
|
||||
#
|
||||
# mpv_player.run_mpv(stream_link)
|
||||
stream_interface(_anime, back, prefered_translation)
|
||||
@@ -1,2 +0,0 @@
|
||||
def watchlist_interface(anime, back):
|
||||
print(anime)
|
||||
@@ -1,11 +1,10 @@
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
|
||||
def mpv(link, *custom_args):
|
||||
MPV = shutil.which("mpv")
|
||||
if not MPV:
|
||||
print("mpv not found")
|
||||
return
|
||||
subprocess.run([MPV, *custom_args, link])
|
||||
sys.stdout.flush()
|
||||
|
||||
68
fastanime/cli/utils/utils.py
Normal file
68
fastanime/cli/utils/utils.py
Normal file
@@ -0,0 +1,68 @@
|
||||
import logging
|
||||
import os
|
||||
|
||||
from fuzzywuzzy import fuzz
|
||||
from InquirerPy import inquirer
|
||||
|
||||
from ... import PLATFORM
|
||||
from ...Utility.data import anime_normalizer
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def clear():
|
||||
if PLATFORM == "Windows":
|
||||
os.system("cls")
|
||||
else:
|
||||
os.system("clear")
|
||||
|
||||
|
||||
def fuzzy_inquirer(prompt: str, choices, **kwargs):
|
||||
clear()
|
||||
action = inquirer.fuzzy(
|
||||
prompt, choices, height="100%", border=True, **kwargs
|
||||
).execute()
|
||||
return action
|
||||
|
||||
|
||||
def anime_title_percentage_match(
|
||||
possible_user_requested_anime_title: str, title: tuple
|
||||
) -> float:
|
||||
"""Returns the percentage match between the possible title and user title
|
||||
|
||||
Args:
|
||||
possible_user_requested_anime_title (str): an Animdl search result title
|
||||
title (str): the anime title the user wants
|
||||
|
||||
Returns:
|
||||
int: the percentage match
|
||||
"""
|
||||
if normalized_anime_title := anime_normalizer.get(
|
||||
possible_user_requested_anime_title
|
||||
):
|
||||
possible_user_requested_anime_title = normalized_anime_title
|
||||
for key, value in locals().items():
|
||||
logger.info(f"{key}: {value}")
|
||||
# compares both the romaji and english names and gets highest Score
|
||||
percentage_ratio = max(
|
||||
fuzz.ratio(title[0].lower(), possible_user_requested_anime_title.lower()),
|
||||
fuzz.ratio(title[1].lower(), possible_user_requested_anime_title.lower()),
|
||||
)
|
||||
return percentage_ratio
|
||||
|
||||
|
||||
def get_selected_anime(anime_title, results):
|
||||
def _get_result(result, compare):
|
||||
return result["name"] == compare
|
||||
|
||||
return list(
|
||||
filter(lambda x: _get_result(x, anime_title), results["shows"]["edges"])
|
||||
)
|
||||
|
||||
|
||||
def get_selected_server(_server, servers):
|
||||
def _get_server(server, server_name):
|
||||
return server[0] == server_name
|
||||
|
||||
server = list(filter(lambda x: _get_server(x, _server), servers)).pop()
|
||||
return server
|
||||
@@ -1,26 +0,0 @@
|
||||
import os
|
||||
import shutil
|
||||
|
||||
from kivy.utils import platform
|
||||
from pyshortcuts import make_shortcut
|
||||
|
||||
from . import assets_folder
|
||||
|
||||
app = "_ -m fastanime"
|
||||
|
||||
if fastanime := shutil.which("fastanime"):
|
||||
app = fastanime
|
||||
|
||||
|
||||
logo = os.path.join(assets_folder, "logo.png")
|
||||
|
||||
if platform == "win":
|
||||
logo = os.path.join(assets_folder, "logo.ico")
|
||||
|
||||
make_shortcut(
|
||||
app,
|
||||
name="FastAnime",
|
||||
description="Download and watch anime",
|
||||
terminal=False,
|
||||
icon=logo,
|
||||
)
|
||||
@@ -6,8 +6,8 @@ from kivy.logger import Logger
|
||||
# from kivy.clock import Clock
|
||||
from kivy.utils import difference
|
||||
|
||||
from ...Utility import user_data_helper
|
||||
from ..Model.my_list_screen import MyListScreenModel
|
||||
from ..Utility import user_data_helper
|
||||
from ..View.MylistScreen.my_list_screen import MyListScreenView
|
||||
|
||||
|
||||
|
||||
@@ -3,7 +3,8 @@ from kivy.cache import Cache
|
||||
from kivy.logger import Logger
|
||||
|
||||
from ...libs.anilist.anilist_data_schema import AnilistBaseMediaDataSchema
|
||||
from ...Utility import anilist_data_helper, user_data_helper
|
||||
from ...Utility import anilist_data_helper
|
||||
from . import user_data_helper
|
||||
|
||||
Cache.register("trailer_urls.anime", timeout=360)
|
||||
|
||||
@@ -48,9 +49,9 @@ class MediaCardDataLoader(object):
|
||||
|
||||
# TODO: switch to season and year
|
||||
#
|
||||
media_card_data[
|
||||
"first_aired_on"
|
||||
] = f'{anilist_data_helper.format_anilist_date_object(anime_item["startDate"])}'
|
||||
media_card_data["first_aired_on"] = (
|
||||
f'{anilist_data_helper.format_anilist_date_object(anime_item["startDate"])}'
|
||||
)
|
||||
|
||||
media_card_data["studios"] = anilist_data_helper.format_list_data_with_comma(
|
||||
[
|
||||
|
||||
@@ -5,15 +5,18 @@ Contains Helper functions to read and write the user data files
|
||||
from datetime import date, datetime
|
||||
|
||||
from kivy.logger import Logger
|
||||
from kivy.storage.jsonstore import JsonStore
|
||||
|
||||
from ... import USER_DATA_PATH
|
||||
|
||||
today = date.today()
|
||||
now = datetime.now()
|
||||
|
||||
user_data = JsonStore(USER_DATA_PATH)
|
||||
|
||||
|
||||
# Get the user data
|
||||
def get_user_anime_list() -> list:
|
||||
from .. import user_data
|
||||
|
||||
try:
|
||||
return user_data.get("user_anime_list")[
|
||||
"user_anime_list"
|
||||
@@ -24,8 +27,6 @@ def get_user_anime_list() -> list:
|
||||
|
||||
|
||||
def update_user_anime_list(updated_list: list):
|
||||
from .. import user_data
|
||||
|
||||
try:
|
||||
updated_list_ = list(set(updated_list))
|
||||
user_data.put("user_anime_list", user_anime_list=updated_list_)
|
||||
@@ -19,6 +19,3 @@ class MyListScreenView(BaseScreenView):
|
||||
|
||||
def update_layout(self, widget):
|
||||
self.user_anime_list_container.data.append(widget)
|
||||
|
||||
|
||||
__all__ = ["MyListScreenView"]
|
||||
|
||||
@@ -1,146 +1,4 @@
|
||||
import os
|
||||
import random
|
||||
|
||||
from kivy.config import Config
|
||||
from kivy.loader import Loader
|
||||
from kivy.logger import Logger
|
||||
from kivy.resources import resource_add_path, resource_find
|
||||
from kivy.uix.screenmanager import FadeTransition, ScreenManager
|
||||
from kivy.uix.settings import Settings, SettingsWithSidebar
|
||||
from kivymd.app import MDApp
|
||||
|
||||
from .. import assets_folder, configs_folder, downloads_dir
|
||||
from ..libs.mpv.player import mpv_player
|
||||
from ..Utility import user_data_helper
|
||||
from ..Utility.data import themes_available
|
||||
from ..Utility.downloader.downloader import downloader
|
||||
from ..Utility.show_notification import show_notification
|
||||
from .View.components.media_card.components.media_popup import MediaPopup
|
||||
from .View.screens import screens
|
||||
|
||||
|
||||
def setup_app():
|
||||
os.environ["KIVY_VIDEO"] = "ffpyplayer" # noqa: E402
|
||||
Config.set("graphics", "width", "1000") # noqa: E402
|
||||
Config.set("graphics", "minimum_width", "1000") # noqa: E402
|
||||
Config.set("kivy", "window_icon", resource_find("logo.ico")) # noqa: E402
|
||||
Config.write() # noqa: E402
|
||||
|
||||
Loader.num_workers = 5
|
||||
Loader.max_upload_per_frame = 10
|
||||
|
||||
resource_add_path(assets_folder)
|
||||
resource_add_path(configs_folder)
|
||||
|
||||
|
||||
class FastAnime(MDApp):
|
||||
default_anime_image = resource_find(random.choice(["default_1.jpg", "default.jpg"]))
|
||||
default_banner_image = resource_find(random.choice(["banner_1.jpg", "banner.jpg"]))
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
self.icon = resource_find("logo.png")
|
||||
|
||||
self.load_all_kv_files(self.directory)
|
||||
self.theme_cls.theme_style = "Dark"
|
||||
self.theme_cls.primary_palette = "Lightcoral"
|
||||
self.manager_screens = ScreenManager()
|
||||
self.manager_screens.transition = FadeTransition()
|
||||
|
||||
def build(self) -> ScreenManager:
|
||||
self.settings_cls = SettingsWithSidebar
|
||||
|
||||
self.generate_application_screens()
|
||||
|
||||
if config := self.config:
|
||||
if theme_color := config.get("Preferences", "theme_color"):
|
||||
self.theme_cls.primary_palette = theme_color
|
||||
if theme_style := config.get("Preferences", "theme_style"):
|
||||
self.theme_cls.theme_style = theme_style
|
||||
|
||||
self.anime_screen = self.manager_screens.get_screen("anime screen")
|
||||
self.search_screen = self.manager_screens.get_screen("search screen")
|
||||
self.download_screen = self.manager_screens.get_screen("downloads screen")
|
||||
self.home_screen = self.manager_screens.get_screen("home screen")
|
||||
return self.manager_screens
|
||||
|
||||
def on_start(self, *args):
|
||||
self.media_card_popup = MediaPopup()
|
||||
|
||||
def generate_application_screens(self) -> None:
|
||||
for i, name_screen in enumerate(screens.keys()):
|
||||
model = screens[name_screen]["model"]()
|
||||
controller = screens[name_screen]["controller"](model)
|
||||
view = controller.get_view()
|
||||
view.manager_screens = self.manager_screens
|
||||
view.name = name_screen
|
||||
self.manager_screens.add_widget(view)
|
||||
|
||||
def build_config(self, config):
|
||||
# General settings setup
|
||||
config.setdefaults(
|
||||
"Preferences",
|
||||
{
|
||||
"theme_color": "Cyan",
|
||||
"theme_style": "Dark",
|
||||
"downloads_dir": downloads_dir,
|
||||
},
|
||||
)
|
||||
|
||||
def build_settings(self, settings: Settings):
|
||||
settings.add_json_panel(
|
||||
"Settings", self.config, resource_find("general_settings_panel.json")
|
||||
)
|
||||
|
||||
def on_config_change(self, config, section, key, value):
|
||||
# TODO: Change to match case
|
||||
if section == "Preferences":
|
||||
match key:
|
||||
case "theme_color":
|
||||
if value in themes_available:
|
||||
self.theme_cls.primary_palette = value
|
||||
else:
|
||||
Logger.warning(
|
||||
"AniXStream Settings: An invalid theme has been entered and will be ignored"
|
||||
)
|
||||
config.set("Preferences", "theme_color", "Cyan")
|
||||
config.write()
|
||||
case "theme_style":
|
||||
self.theme_cls.theme_style = value
|
||||
|
||||
def on_stop(self):
|
||||
pass
|
||||
|
||||
def search_for_anime(self, search_field, **kwargs):
|
||||
if self.manager_screens.current != "search screen":
|
||||
self.manager_screens.current = "search screen"
|
||||
self.search_screen.handle_search_for_anime(search_field, **kwargs)
|
||||
|
||||
def add_anime_to_user_anime_list(self, id: int):
|
||||
updated_list = user_data_helper.get_user_anime_list()
|
||||
updated_list.append(id)
|
||||
user_data_helper.update_user_anime_list(updated_list)
|
||||
|
||||
def remove_anime_from_user_anime_list(self, id: int):
|
||||
updated_list = user_data_helper.get_user_anime_list()
|
||||
if updated_list.count(id):
|
||||
updated_list.remove(id)
|
||||
user_data_helper.update_user_anime_list(updated_list)
|
||||
|
||||
def show_anime_screen(self, id: int, title, caller_screen_name: str):
|
||||
self.manager_screens.current = "anime screen"
|
||||
self.anime_screen.controller.update_anime_view(id, title, caller_screen_name)
|
||||
|
||||
def play_on_mpv(self, anime_video_url: str):
|
||||
if mpv_player.mpv_process:
|
||||
mpv_player.stop_mpv()
|
||||
mpv_player.run_mpv(anime_video_url)
|
||||
|
||||
def download_anime_video(self, url: str, anime_title: tuple):
|
||||
self.download_screen.new_download_task(anime_title)
|
||||
show_notification("New Download", f"{anime_title[0]} episode: {anime_title[1]}")
|
||||
progress_hook = self.download_screen.on_episode_download_progress
|
||||
downloader.download_file(url, anime_title, progress_hook)
|
||||
from .app import FastAnime
|
||||
|
||||
|
||||
def run_gui():
|
||||
|
||||
143
fastanime/gui/app.py
Normal file
143
fastanime/gui/app.py
Normal file
@@ -0,0 +1,143 @@
|
||||
import os
|
||||
import random
|
||||
|
||||
from kivy.config import Config
|
||||
from kivy.loader import Loader
|
||||
from kivy.logger import Logger
|
||||
from kivy.resources import resource_add_path, resource_find
|
||||
from kivy.uix.screenmanager import FadeTransition, ScreenManager
|
||||
from kivy.uix.settings import Settings, SettingsWithSidebar
|
||||
from kivymd.app import MDApp
|
||||
|
||||
from .. import ASSETS_DIR, CONFIGS_DIR, USER_DOWNLOADS_DIR
|
||||
from ..libs.mpv.player import mpv_player
|
||||
from ..Utility.data import themes_available
|
||||
from ..Utility.downloader.downloader import downloader
|
||||
from ..Utility.show_notification import show_notification
|
||||
from .Utility import user_data_helper
|
||||
from .View.components.media_card.components.media_popup import MediaPopup
|
||||
from .View.screens import screens
|
||||
|
||||
|
||||
def setup_app():
|
||||
os.environ["KIVY_VIDEO"] = "ffpyplayer" # noqa: E402
|
||||
Config.set("graphics", "width", "1000") # noqa: E402
|
||||
Config.set("graphics", "minimum_width", "1000") # noqa: E402
|
||||
Config.set("kivy", "window_icon", resource_find("logo.ico")) # noqa: E402
|
||||
Config.write() # noqa: E402
|
||||
|
||||
Loader.num_workers = 5
|
||||
Loader.max_upload_per_frame = 10
|
||||
|
||||
resource_add_path(ASSETS_DIR)
|
||||
resource_add_path(CONFIGS_DIR)
|
||||
|
||||
|
||||
class FastAnime(MDApp):
|
||||
default_anime_image = resource_find(random.choice(["default_1.jpg", "default.jpg"]))
|
||||
default_banner_image = resource_find(random.choice(["banner_1.jpg", "banner.jpg"]))
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
self.icon = resource_find("logo.png")
|
||||
|
||||
self.load_all_kv_files(self.directory)
|
||||
self.theme_cls.theme_style = "Dark"
|
||||
self.theme_cls.primary_palette = "Lightcoral"
|
||||
self.manager_screens = ScreenManager()
|
||||
self.manager_screens.transition = FadeTransition()
|
||||
|
||||
def build(self) -> ScreenManager:
|
||||
self.settings_cls = SettingsWithSidebar
|
||||
|
||||
self.generate_application_screens()
|
||||
|
||||
if config := self.config:
|
||||
if theme_color := config.get("Preferences", "theme_color"):
|
||||
self.theme_cls.primary_palette = theme_color
|
||||
if theme_style := config.get("Preferences", "theme_style"):
|
||||
self.theme_cls.theme_style = theme_style
|
||||
|
||||
self.anime_screen = self.manager_screens.get_screen("anime screen")
|
||||
self.search_screen = self.manager_screens.get_screen("search screen")
|
||||
self.download_screen = self.manager_screens.get_screen("downloads screen")
|
||||
self.home_screen = self.manager_screens.get_screen("home screen")
|
||||
return self.manager_screens
|
||||
|
||||
def on_start(self, *args):
|
||||
self.media_card_popup = MediaPopup()
|
||||
|
||||
def generate_application_screens(self) -> None:
|
||||
for i, name_screen in enumerate(screens.keys()):
|
||||
model = screens[name_screen]["model"]()
|
||||
controller = screens[name_screen]["controller"](model)
|
||||
view = controller.get_view()
|
||||
view.manager_screens = self.manager_screens
|
||||
view.name = name_screen
|
||||
self.manager_screens.add_widget(view)
|
||||
|
||||
def build_config(self, config):
|
||||
# General settings setup
|
||||
config.setdefaults(
|
||||
"Preferences",
|
||||
{
|
||||
"theme_color": "Cyan",
|
||||
"theme_style": "Dark",
|
||||
"downloads_dir": USER_DOWNLOADS_DIR,
|
||||
},
|
||||
)
|
||||
|
||||
def build_settings(self, settings: Settings):
|
||||
settings.add_json_panel(
|
||||
"Settings", self.config, resource_find("general_settings_panel.json")
|
||||
)
|
||||
|
||||
def on_config_change(self, config, section, key, value):
|
||||
# TODO: Change to match case
|
||||
if section == "Preferences":
|
||||
match key:
|
||||
case "theme_color":
|
||||
if value in themes_available:
|
||||
self.theme_cls.primary_palette = value
|
||||
else:
|
||||
Logger.warning(
|
||||
"AniXStream Settings: An invalid theme has been entered and will be ignored"
|
||||
)
|
||||
config.set("Preferences", "theme_color", "Cyan")
|
||||
config.write()
|
||||
case "theme_style":
|
||||
self.theme_cls.theme_style = value
|
||||
|
||||
def on_stop(self):
|
||||
pass
|
||||
|
||||
def search_for_anime(self, search_field, **kwargs):
|
||||
if self.manager_screens.current != "search screen":
|
||||
self.manager_screens.current = "search screen"
|
||||
self.search_screen.handle_search_for_anime(search_field, **kwargs)
|
||||
|
||||
def add_anime_to_user_anime_list(self, id: int):
|
||||
updated_list = user_data_helper.get_user_anime_list()
|
||||
updated_list.append(id)
|
||||
user_data_helper.update_user_anime_list(updated_list)
|
||||
|
||||
def remove_anime_from_user_anime_list(self, id: int):
|
||||
updated_list = user_data_helper.get_user_anime_list()
|
||||
if updated_list.count(id):
|
||||
updated_list.remove(id)
|
||||
user_data_helper.update_user_anime_list(updated_list)
|
||||
|
||||
def show_anime_screen(self, id: int, title, caller_screen_name: str):
|
||||
self.manager_screens.current = "anime screen"
|
||||
self.anime_screen.controller.update_anime_view(id, title, caller_screen_name)
|
||||
|
||||
def play_on_mpv(self, anime_video_url: str):
|
||||
if mpv_player.mpv_process:
|
||||
mpv_player.stop_mpv()
|
||||
mpv_player.run_mpv(anime_video_url)
|
||||
|
||||
def download_anime_video(self, url: str, anime_title: tuple):
|
||||
self.download_screen.new_download_task(anime_title)
|
||||
show_notification("New Download", f"{anime_title[0]} episode: {anime_title[1]}")
|
||||
progress_hook = self.download_screen.on_episode_download_progress
|
||||
downloader.download_file(url, anime_title, progress_hook)
|
||||
@@ -90,6 +90,7 @@ class AniList:
|
||||
start_greater: int | None = None,
|
||||
start_lesser: int | None = None,
|
||||
page: int | None = None,
|
||||
**kwargs,
|
||||
):
|
||||
"""
|
||||
A powerful method for searching anime using the anilist api availing most of its options
|
||||
@@ -110,7 +111,7 @@ class AniList:
|
||||
return cls.get_data(anime_query, variables)
|
||||
|
||||
@classmethod
|
||||
def get_trending(cls):
|
||||
def get_trending(cls, *_, **kwargs):
|
||||
"""
|
||||
Gets the currently trending anime
|
||||
"""
|
||||
@@ -118,7 +119,7 @@ class AniList:
|
||||
return trending
|
||||
|
||||
@classmethod
|
||||
def get_most_favourite(cls):
|
||||
def get_most_favourite(cls, *_, **kwargs):
|
||||
"""
|
||||
Gets the most favoured anime on anilist
|
||||
"""
|
||||
@@ -126,7 +127,7 @@ class AniList:
|
||||
return most_favourite
|
||||
|
||||
@classmethod
|
||||
def get_most_scored(cls):
|
||||
def get_most_scored(cls, *_, **kwargs):
|
||||
"""
|
||||
Gets most scored anime on anilist
|
||||
"""
|
||||
@@ -134,7 +135,7 @@ class AniList:
|
||||
return most_scored
|
||||
|
||||
@classmethod
|
||||
def get_most_recently_updated(cls):
|
||||
def get_most_recently_updated(cls, *_, **kwargs):
|
||||
"""
|
||||
Gets most recently updated anime from anilist
|
||||
"""
|
||||
@@ -142,7 +143,7 @@ class AniList:
|
||||
return most_recently_updated
|
||||
|
||||
@classmethod
|
||||
def get_most_popular(cls):
|
||||
def get_most_popular(cls, *_, **kwargs):
|
||||
"""
|
||||
Gets most popular anime on anilist
|
||||
"""
|
||||
@@ -151,30 +152,30 @@ class AniList:
|
||||
|
||||
# FIXME:dont know why its not giving useful data
|
||||
@classmethod
|
||||
def get_recommended_anime_for(cls, id: int):
|
||||
def get_recommended_anime_for(cls, id: int, *_, **kwargs):
|
||||
recommended_anime = cls.get_data(recommended_query)
|
||||
return recommended_anime
|
||||
|
||||
@classmethod
|
||||
def get_charcters_of(cls, id: int):
|
||||
def get_charcters_of(cls, id: int, *_, **kwargs):
|
||||
variables = {"id": id}
|
||||
characters = cls.get_data(anime_characters_query, variables)
|
||||
return characters
|
||||
|
||||
@classmethod
|
||||
def get_related_anime_for(cls, id: int):
|
||||
def get_related_anime_for(cls, id: int, *_, **kwargs):
|
||||
variables = {"id": id}
|
||||
related_anime = cls.get_data(anime_relations_query, variables)
|
||||
return related_anime
|
||||
|
||||
@classmethod
|
||||
def get_airing_schedule_for(cls, id: int):
|
||||
def get_airing_schedule_for(cls, id: int, *_, **kwargs):
|
||||
variables = {"id": id}
|
||||
airing_schedule = cls.get_data(airing_schedule_query, variables)
|
||||
return airing_schedule
|
||||
|
||||
@classmethod
|
||||
def get_upcoming_anime(cls, page: int):
|
||||
def get_upcoming_anime(cls, page: int, *_, **kwargs):
|
||||
"""
|
||||
Gets upcoming anime from anilist
|
||||
"""
|
||||
|
||||
@@ -36,6 +36,7 @@ class AllAnimeAPI:
|
||||
"query": query,
|
||||
},
|
||||
headers={"Referer": ALLANIME_REFERER, "User-Agent": USER_AGENT},
|
||||
timeout=10,
|
||||
)
|
||||
if response.status_code != 200:
|
||||
return {}
|
||||
@@ -121,25 +122,26 @@ class AllAnimeAPI:
|
||||
"Referer": ALLANIME_REFERER,
|
||||
"User-Agent": USER_AGENT,
|
||||
},
|
||||
timeout=10,
|
||||
)
|
||||
if resp.status_code == 200:
|
||||
match embed["sourceName"]:
|
||||
case "Luf-mp4":
|
||||
Logger.debug("allanime:Found streams from gogoanime")
|
||||
print("[yellow]gogoanime")
|
||||
print("[yellow]GogoAnime Fetched")
|
||||
yield "gogoanime", resp.json()
|
||||
case "Kir":
|
||||
Logger.debug("allanime:Found streams from wetransfer")
|
||||
print("[yellow]wetransfer")
|
||||
print("[yellow]WeTransfer Fetched")
|
||||
yield "wetransfer", resp.json()
|
||||
case "S-mp4":
|
||||
Logger.debug("allanime:Found streams from sharepoint")
|
||||
|
||||
print("[yellow]sharepoint")
|
||||
print("[yellow]Sharepoint Fetched")
|
||||
yield "sharepoint", resp.json()
|
||||
case "Sak":
|
||||
Logger.debug("allanime:Found streams from dropbox")
|
||||
print("[yellow]dropbox")
|
||||
print("[yellow]Dropbox Fetched")
|
||||
yield "dropbox", resp.json()
|
||||
case _:
|
||||
yield "Unknown", resp.json()
|
||||
|
||||
@@ -2,3 +2,4 @@ ALLANIME_BASE = "allanime.day"
|
||||
ALLANIME_REFERER = "https://allanime.to/"
|
||||
ALLANIME_API_ENDPOINT = "https://api.{}/api/".format(ALLANIME_BASE)
|
||||
USER_AGENT = "Mozilla/5.0 (X11; Linux x86_64; rv:78.0) Gecko/20100101 Firefox/78.0"
|
||||
SERVERS_AVAILABLE = ["sharepoint", "dropbox", "gogoanime", "weTransfer"]
|
||||
|
||||
@@ -35,3 +35,9 @@ build-backend = "poetry.core.masonry.api"
|
||||
|
||||
[tool.poetry.scripts]
|
||||
fastanime = 'fastanime:FastAnime'
|
||||
|
||||
# FILE: .bandit
|
||||
[tool.bandit]
|
||||
#exclude = tests,path/to/file
|
||||
#tests = B201,B301
|
||||
skips = ["B311","B603","B607","B404"]
|
||||
|
||||
Reference in New Issue
Block a user