mirror of
https://github.com/Benexl/FastAnime.git
synced 2026-06-29 09:48:23 -07:00
feat:create cli subpackage
This commit is contained in:
+23
-166
@@ -1,191 +1,48 @@
|
||||
import os
|
||||
import random
|
||||
import sys
|
||||
|
||||
from rich import print
|
||||
from rich.traceback import install
|
||||
|
||||
import plyer
|
||||
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.storage.jsonstore import JsonStore
|
||||
from kivy.uix.screenmanager import FadeTransition, ScreenManager
|
||||
from kivy.uix.settings import Settings, SettingsWithSidebar
|
||||
from kivymd.app import MDApp
|
||||
|
||||
from .libs.mpv.player import mpv_player
|
||||
from .Utility import (
|
||||
themes_available,
|
||||
)
|
||||
from .Utility.show_notification import show_notification
|
||||
from .View.components.media_card.components.media_popup import MediaPopup
|
||||
from .View.screens import screens
|
||||
install()
|
||||
|
||||
os.environ["KIVY_VIDEO"] = "ffpyplayer" # noqa: E402
|
||||
# TODO:confirm data integrity
|
||||
|
||||
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
|
||||
|
||||
|
||||
# print(plyer.storagepath.get_application_dir(), plyer.storagepath.get_home_dir())
|
||||
# ----- 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)
|
||||
|
||||
|
||||
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)
|
||||
else:
|
||||
# fallback
|
||||
downloads_dir = os.path.join(app_dir, "videos")
|
||||
if not os.path.exists(downloads_dir):
|
||||
os.mkdir(downloads_dir)
|
||||
|
||||
|
||||
# TODO:confirm data integrity
|
||||
if os.path.exists(os.path.join(data_folder, "user_data.json")):
|
||||
user_data = JsonStore(os.path.join(data_folder, "user_data.json"))
|
||||
else:
|
||||
user_data_path = os.path.join(data_folder, "user_data.json")
|
||||
user_data = JsonStore(user_data_path)
|
||||
|
||||
|
||||
user_data_path = os.path.join(data_folder, "user_data.json")
|
||||
assets_folder = os.path.join(app_dir, "assets")
|
||||
resource_add_path(assets_folder)
|
||||
conigs_folder = os.path.join(app_dir, "configs")
|
||||
resource_add_path(conigs_folder)
|
||||
|
||||
|
||||
from .Utility import user_data_helper
|
||||
def FastAnime(gui=False):
|
||||
if "--gui" in sys.argv:
|
||||
gui = True
|
||||
sys.argv.remove("--gui")
|
||||
print(f"Hello {os.environ.get("USERNAME")} from the fastanime team")
|
||||
if gui:
|
||||
print(__name__)
|
||||
from .gui.gui import run_gui
|
||||
|
||||
print("Run GUI")
|
||||
run_gui()
|
||||
else:
|
||||
from .cli import run_cli
|
||||
|
||||
from .Utility.downloader.downloader import downloader
|
||||
|
||||
|
||||
class FastAnime(MDApp):
|
||||
# Ensure the user data fields exist
|
||||
if not (user_data.exists("user_anime_list")):
|
||||
user_data_helper.update_user_anime_list([])
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
self.default_banner_image = resource_find(
|
||||
random.choice(["banner_1.jpg", "banner.jpg"])
|
||||
)
|
||||
self.default_anime_image = resource_find(
|
||||
random.choice(["default_1.jpg", "default.jpg"])
|
||||
)
|
||||
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)
|
||||
|
||||
|
||||
def main():
|
||||
FastAnime().run()
|
||||
run_cli()
|
||||
|
||||
@@ -11,13 +11,13 @@ if __package__ is None and not getattr(sys, "frozen", False):
|
||||
|
||||
if __name__ == "__main__":
|
||||
in_development = bool(os.environ.get("IN_DEVELOPMENT", False))
|
||||
import fastanime
|
||||
from . import FastAnime
|
||||
|
||||
if in_development:
|
||||
fastanime.main()
|
||||
FastAnime()
|
||||
else:
|
||||
try:
|
||||
fastanime.main()
|
||||
FastAnime()
|
||||
except Exception as e:
|
||||
from .Utility.utils import write_crash
|
||||
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
import click
|
||||
from rich import print
|
||||
from .commands import search, download, anilist
|
||||
|
||||
commands = {"search": search, "download": download, "anilist": anilist}
|
||||
|
||||
|
||||
@click.group(commands=commands)
|
||||
def run_cli():
|
||||
print("Yellow")
|
||||
@@ -0,0 +1,3 @@
|
||||
from .anilist import anilist
|
||||
from .download import download
|
||||
from .search import search
|
||||
@@ -0,0 +1,23 @@
|
||||
import click
|
||||
|
||||
from .favourites import favourites
|
||||
from .recent import recent
|
||||
from .search import search
|
||||
from .popular import popular
|
||||
from .trending import trending
|
||||
from .upcoming import upcoming
|
||||
|
||||
|
||||
commands = {
|
||||
"favourites": favourites,
|
||||
"recent": recent,
|
||||
"search": search,
|
||||
"popular": popular,
|
||||
"trending": trending,
|
||||
"upcoming": upcoming,
|
||||
}
|
||||
|
||||
|
||||
@click.group(commands=commands)
|
||||
def anilist():
|
||||
pass
|
||||
@@ -0,0 +1,6 @@
|
||||
import click
|
||||
|
||||
|
||||
@click.command()
|
||||
def favourites():
|
||||
print("favourites")
|
||||
@@ -0,0 +1,6 @@
|
||||
import click
|
||||
|
||||
|
||||
@click.command()
|
||||
def popular():
|
||||
print("popular")
|
||||
@@ -0,0 +1,6 @@
|
||||
import click
|
||||
|
||||
|
||||
@click.command()
|
||||
def recent():
|
||||
print("recent")
|
||||
@@ -0,0 +1,6 @@
|
||||
import click
|
||||
|
||||
|
||||
@click.command()
|
||||
def search():
|
||||
print("search")
|
||||
@@ -0,0 +1,6 @@
|
||||
import click
|
||||
|
||||
|
||||
@click.command()
|
||||
def trending():
|
||||
print("trending")
|
||||
@@ -0,0 +1,6 @@
|
||||
import click
|
||||
|
||||
|
||||
@click.command()
|
||||
def upcoming():
|
||||
print("upcoming")
|
||||
@@ -0,0 +1,6 @@
|
||||
import click
|
||||
|
||||
|
||||
@click.command()
|
||||
def download():
|
||||
print("download")
|
||||
@@ -0,0 +1,6 @@
|
||||
import click
|
||||
|
||||
|
||||
@click.command()
|
||||
def search():
|
||||
print("Searching")
|
||||
@@ -0,0 +1,31 @@
|
||||
import subprocess
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def run_fzf(options: tuple[str], *custom_commands):
|
||||
"""
|
||||
Run fzf with a list of options and return the selected option.
|
||||
"""
|
||||
# Join the list of options into a single string with newlines
|
||||
options_str = "\n".join(options)
|
||||
|
||||
# Run fzf as a subprocess
|
||||
result = subprocess.run(
|
||||
["fzf", *custom_commands],
|
||||
input=options_str,
|
||||
text=True,
|
||||
stdout=subprocess.PIPE,
|
||||
)
|
||||
|
||||
# Check if fzf was successful
|
||||
if result.returncode == 0:
|
||||
# Return the selected option
|
||||
selection = result.stdout.strip()
|
||||
logger.info(f"fzf: selected {selection}")
|
||||
return selection
|
||||
else:
|
||||
# Handle the case where fzf fails or is canceled
|
||||
logger.error("fzf was canceled or failed")
|
||||
return None
|
||||
@@ -4,39 +4,37 @@ import random
|
||||
from kivy.config import Config
|
||||
from kivy.loader import Loader
|
||||
from kivy.logger import Logger
|
||||
from kivy.resources import resource_find
|
||||
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 fastanime.Utility.show_notification import show_notification
|
||||
from ..Utility.show_notification import show_notification
|
||||
|
||||
from . import downloads_dir
|
||||
from .libs.mpv.player import mpv_player
|
||||
from .Utility import (
|
||||
from .. import downloads_dir, assets_folder, configs_folder
|
||||
from ..libs.mpv.player import mpv_player
|
||||
from ..Utility import (
|
||||
themes_available,
|
||||
user_data_helper,
|
||||
)
|
||||
from .Utility.downloader.downloader import downloader
|
||||
from .Utility.utils import write_crash
|
||||
from ..Utility.downloader.downloader import downloader
|
||||
from .View.components.media_card.components.media_popup import MediaPopup
|
||||
from .View.screens import screens
|
||||
|
||||
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
|
||||
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
|
||||
|
||||
Loader.num_workers = 5
|
||||
Loader.max_upload_per_frame = 10
|
||||
|
||||
|
||||
# Ensure the user data fields exist
|
||||
if not (user_data_helper.user_data.exists("user_anime_list")):
|
||||
user_data_helper.update_user_anime_list([])
|
||||
resource_add_path(assets_folder)
|
||||
resource_add_path(configs_folder)
|
||||
|
||||
|
||||
class FastAnime(MDApp):
|
||||
@@ -149,5 +147,5 @@ class FastAnime(MDApp):
|
||||
downloader.download_file(url, anime_title, progress_hook)
|
||||
|
||||
|
||||
def run_app():
|
||||
def run_gui():
|
||||
FastAnime().run()
|
||||
@@ -1,23 +0,0 @@
|
||||
All this instructions should be done from the folder you chose to install
|
||||
aniXstream but incase you have never installed python should work any where
|
||||
|
||||
1. First install pyenv with the following command:
|
||||
Invoke-WebRequest -UseBasicParsing -Uri
|
||||
"https://raw.githubusercontent.com/pyenv-win/pyenv-win/master/pyenv-win/install-pyenv-win.ps1"
|
||||
-OutFile "./install-pyenv-win.ps1"; &"./install-pyenv-win.ps1"
|
||||
2. run the following command:
|
||||
pyenv --version to check whether installation was a success
|
||||
3. run pyenv install 3.10 and confirm success by running pyenv -l and check
|
||||
for 3.10
|
||||
4. run pyenv local 3.10 (if in anixstream directory) or pyenv global 3.10 (if
|
||||
in another directory to set python version 3.10 as global interpreter)
|
||||
5. check if success by running python --version and checking if output is 3.10
|
||||
6. run python -m pip install animdl
|
||||
7. check if success by running python -m animdl and if no error then you are
|
||||
ready to use anixstream to stream anime
|
||||
8. additionally you can use animdl independently by running python -m animdl
|
||||
and any arguments specified in the animdl documentation eg python -m animdl
|
||||
stream naruto
|
||||
-----------------------------
|
||||
Now enjoy :)
|
||||
------------------------------
|
||||
@@ -5,3 +5,5 @@ plyer
|
||||
https://github.com/kivymd/KivyMD/archive/master.zip
|
||||
fuzzywuzzy
|
||||
python-Levenshtein
|
||||
rich
|
||||
click
|
||||
|
||||
Reference in New Issue
Block a user