mirror of
https://github.com/Benexl/FastAnime.git
synced 2025-12-19 10:42:35 -08:00
feat:switch to poetry as build tool and package manager
This commit is contained in:
11
.pre-commit-config.yaml
Normal file
11
.pre-commit-config.yaml
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
repos:
|
||||||
|
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||||
|
rev: v2.3.0
|
||||||
|
hooks:
|
||||||
|
- id: check-yaml
|
||||||
|
- id: end-of-file-fixer
|
||||||
|
- id: trailing-whitespace
|
||||||
|
- repo: https://github.com/psf/black
|
||||||
|
rev: 22.10.0
|
||||||
|
hooks:
|
||||||
|
- id: black
|
||||||
5
fa
Executable file
5
fa
Executable file
@@ -0,0 +1,5 @@
|
|||||||
|
#! /usr/bin/bash
|
||||||
|
poetry install
|
||||||
|
clear
|
||||||
|
poetry run fastanime $*
|
||||||
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
from .data import themes_available
|
|
||||||
from .media_card_loader import media_card_loader
|
|
||||||
from .show_notification import show_notification
|
|
||||||
from .utils import write_crash
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
import logging
|
||||||
|
|
||||||
from rich import print
|
from rich import print
|
||||||
from rich.traceback import install
|
from rich.traceback import install
|
||||||
@@ -7,6 +8,8 @@ from rich.traceback import install
|
|||||||
import plyer
|
import plyer
|
||||||
|
|
||||||
install()
|
install()
|
||||||
|
# Create a logger instance
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
# TODO:confirm data integrity
|
# TODO:confirm data integrity
|
||||||
|
|
||||||
@@ -31,10 +34,27 @@ user_data_path = os.path.join(data_folder, "user_data.json")
|
|||||||
assets_folder = os.path.join(app_dir, "assets")
|
assets_folder = os.path.join(app_dir, "assets")
|
||||||
|
|
||||||
|
|
||||||
def FastAnime(gui=False):
|
def FastAnime(gui=False, log=False):
|
||||||
if "--gui" in sys.argv:
|
if "--gui" in sys.argv:
|
||||||
gui = True
|
gui = True
|
||||||
sys.argv.remove("--gui")
|
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
|
||||||
|
|
||||||
|
logging.basicConfig(
|
||||||
|
level=logging.DEBUG, # Set the logging level to DEBUG
|
||||||
|
format="%(message)s", # Use a simple message format
|
||||||
|
datefmt="[%X]", # Use a custom date format
|
||||||
|
handlers=[RichHandler()], # Use RichHandler to format the logs
|
||||||
|
)
|
||||||
|
|
||||||
print(f"Hello {os.environ.get("USERNAME")} from the fastanime team")
|
print(f"Hello {os.environ.get("USERNAME")} from the fastanime team")
|
||||||
if gui:
|
if gui:
|
||||||
print(__name__)
|
print(__name__)
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ if __package__ is None and not getattr(sys, "frozen", False):
|
|||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
in_development = bool(os.environ.get("IN_DEVELOPMENT", False))
|
in_development = bool(os.environ.get("IN_DEVELOPMENT", True))
|
||||||
from . import FastAnime
|
from . import FastAnime
|
||||||
|
|
||||||
if in_development:
|
if in_development:
|
||||||
|
|||||||
@@ -1,6 +1,14 @@
|
|||||||
import click
|
import click
|
||||||
|
from ....libs.anilist.anilist import AniList
|
||||||
|
from .utils import get_search_result
|
||||||
|
from ...interfaces.anime_interface import anime_interface
|
||||||
|
|
||||||
|
|
||||||
@click.command()
|
@click.command()
|
||||||
def search():
|
@click.option("--title", prompt="Enter anime title")
|
||||||
print("search")
|
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)
|
||||||
|
|||||||
@@ -1,6 +1,13 @@
|
|||||||
import click
|
import click
|
||||||
|
from ....libs.anilist.anilist import AniList
|
||||||
|
from .utils import get_search_result
|
||||||
|
from ...interfaces.anime_interface import anime_interface
|
||||||
|
|
||||||
|
|
||||||
@click.command()
|
@click.command()
|
||||||
def trending():
|
def trending():
|
||||||
print("trending")
|
success, trending = AniList.get_trending()
|
||||||
|
if trending and success:
|
||||||
|
result = get_search_result(trending)
|
||||||
|
if result:
|
||||||
|
anime_interface(result)
|
||||||
|
|||||||
25
fastanime/cli/commands/anilist/utils.py
Normal file
25
fastanime/cli/commands/anilist/utils.py
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
from ...utils.fzf import fzf
|
||||||
|
from ....libs.anilist.anilist_data_schema import (
|
||||||
|
AnilistDataSchema,
|
||||||
|
AnilistBaseMediaDataSchema,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def get_search_result(
|
||||||
|
anilist_data: AnilistDataSchema,
|
||||||
|
) -> AnilistBaseMediaDataSchema | None:
|
||||||
|
choices = []
|
||||||
|
data = anilist_data["data"]["Page"]["media"]
|
||||||
|
for choice in data:
|
||||||
|
choices.append(choice["title"]["romaji"])
|
||||||
|
_selected_anime = fzf(choices)
|
||||||
|
if not _selected_anime:
|
||||||
|
return None
|
||||||
|
|
||||||
|
def _get_result(x):
|
||||||
|
return x["title"]["romaji"] == _selected_anime
|
||||||
|
|
||||||
|
selected_anime = list(filter(_get_result, data))
|
||||||
|
if not selected_anime:
|
||||||
|
return None
|
||||||
|
return selected_anime[0]
|
||||||
6
fastanime/cli/interfaces/__init__.py
Normal file
6
fastanime/cli/interfaces/__init__.py
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
from .stream_interface import stream_interface
|
||||||
|
from .info_interface import info_interface
|
||||||
|
from .binge_interface import binge_interface
|
||||||
|
from .download_interface import download_interface
|
||||||
|
from .quit import bye
|
||||||
|
from .watchlist_interface import watchlist_interface
|
||||||
25
fastanime/cli/interfaces/anime_interface.py
Normal file
25
fastanime/cli/interfaces/anime_interface.py
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
import rich
|
||||||
|
from ..utils.fzf import fzf
|
||||||
|
from . import (
|
||||||
|
info_interface,
|
||||||
|
stream_interface,
|
||||||
|
binge_interface,
|
||||||
|
download_interface,
|
||||||
|
watchlist_interface,
|
||||||
|
bye,
|
||||||
|
)
|
||||||
|
|
||||||
|
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)
|
||||||
5
fastanime/cli/interfaces/binge_interface.py
Normal file
5
fastanime/cli/interfaces/binge_interface.py
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
from ..utils import fzf
|
||||||
|
|
||||||
|
|
||||||
|
def binge_interface(anime, back):
|
||||||
|
print(anime)
|
||||||
5
fastanime/cli/interfaces/download_interface.py
Normal file
5
fastanime/cli/interfaces/download_interface.py
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
from ..utils import fzf
|
||||||
|
|
||||||
|
|
||||||
|
def download_interface(anime, back):
|
||||||
|
print(anime)
|
||||||
5
fastanime/cli/interfaces/info_interface.py
Normal file
5
fastanime/cli/interfaces/info_interface.py
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
from ..utils import fzf
|
||||||
|
|
||||||
|
|
||||||
|
def info_interface(anime, back):
|
||||||
|
print(anime)
|
||||||
7
fastanime/cli/interfaces/quit.py
Normal file
7
fastanime/cli/interfaces/quit.py
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
import sys
|
||||||
|
from rich import print
|
||||||
|
|
||||||
|
|
||||||
|
def bye(*args):
|
||||||
|
print("Goodbye")
|
||||||
|
sys.exit()
|
||||||
103
fastanime/cli/interfaces/stream_interface.py
Normal file
103
fastanime/cli/interfaces/stream_interface.py
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
from ..utils.fzf import fzf
|
||||||
|
from ...libs.anime_provider.allanime.api import anime_provider
|
||||||
|
from ...Utility.data import anime_normalizer
|
||||||
|
from ..utils.mpv import mpv
|
||||||
|
from fuzzywuzzy import fuzz
|
||||||
|
import logging
|
||||||
|
|
||||||
|
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)
|
||||||
5
fastanime/cli/interfaces/watchlist_interface.py
Normal file
5
fastanime/cli/interfaces/watchlist_interface.py
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
from ..utils import fzf
|
||||||
|
|
||||||
|
|
||||||
|
def watchlist_interface(anime, back):
|
||||||
|
print(anime)
|
||||||
0
fastanime/cli/utils/__init__.py
Normal file
0
fastanime/cli/utils/__init__.py
Normal file
@@ -1,10 +1,11 @@
|
|||||||
import subprocess
|
import subprocess
|
||||||
import logging
|
import logging
|
||||||
|
import shutil
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
def run_fzf(options: tuple[str], *custom_commands):
|
def fzf(options, prompt="Select Anime: ", *custom_commands):
|
||||||
"""
|
"""
|
||||||
Run fzf with a list of options and return the selected option.
|
Run fzf with a list of options and return the selected option.
|
||||||
"""
|
"""
|
||||||
@@ -12,8 +13,21 @@ def run_fzf(options: tuple[str], *custom_commands):
|
|||||||
options_str = "\n".join(options)
|
options_str = "\n".join(options)
|
||||||
|
|
||||||
# Run fzf as a subprocess
|
# Run fzf as a subprocess
|
||||||
|
FZF = shutil.which("fzf")
|
||||||
|
if not FZF:
|
||||||
|
logger.error("fzf not found")
|
||||||
|
return None
|
||||||
|
|
||||||
result = subprocess.run(
|
result = subprocess.run(
|
||||||
["fzf", *custom_commands],
|
[
|
||||||
|
FZF,
|
||||||
|
"--reverse",
|
||||||
|
"--cycle",
|
||||||
|
"--prompt",
|
||||||
|
prompt,
|
||||||
|
]
|
||||||
|
if not custom_commands
|
||||||
|
else [FZF, *custom_commands],
|
||||||
input=options_str,
|
input=options_str,
|
||||||
text=True,
|
text=True,
|
||||||
stdout=subprocess.PIPE,
|
stdout=subprocess.PIPE,
|
||||||
|
|||||||
11
fastanime/cli/utils/mpv.py
Normal file
11
fastanime/cli/utils/mpv.py
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
import subprocess
|
||||||
|
import shutil
|
||||||
|
import sys
|
||||||
|
|
||||||
|
|
||||||
|
def mpv(link, *custom_args):
|
||||||
|
MPV = shutil.which("mpv")
|
||||||
|
if not MPV:
|
||||||
|
return
|
||||||
|
subprocess.run([MPV, *custom_args, link])
|
||||||
|
sys.stdout.flush()
|
||||||
@@ -2,7 +2,8 @@ import json
|
|||||||
import logging
|
import logging
|
||||||
|
|
||||||
import requests
|
import requests
|
||||||
|
from rich.progress import Progress
|
||||||
|
from rich import print
|
||||||
from .gql_queries import ALLANIME_SHOW_GQL, ALLANIME_SEARCH_GQL, ALLANIME_EPISODES_GQL
|
from .gql_queries import ALLANIME_SHOW_GQL, ALLANIME_SEARCH_GQL, ALLANIME_EPISODES_GQL
|
||||||
from .constants import (
|
from .constants import (
|
||||||
ALLANIME_BASE,
|
ALLANIME_BASE,
|
||||||
@@ -60,11 +61,18 @@ class AllAnimeAPI:
|
|||||||
"translationtype": translationtype,
|
"translationtype": translationtype,
|
||||||
"countryorigin": countryorigin,
|
"countryorigin": countryorigin,
|
||||||
}
|
}
|
||||||
return self._fetch_gql(ALLANIME_SEARCH_GQL, variables)
|
with Progress() as progress:
|
||||||
|
progress.add_task("[cyan]searching..", start=False, total=None)
|
||||||
|
|
||||||
|
search_results = self._fetch_gql(ALLANIME_SEARCH_GQL, variables)
|
||||||
|
return search_results
|
||||||
|
|
||||||
def get_anime(self, allanime_show_id: str):
|
def get_anime(self, allanime_show_id: str):
|
||||||
variables = {"showId": allanime_show_id}
|
variables = {"showId": allanime_show_id}
|
||||||
return anime_provider._fetch_gql(ALLANIME_SHOW_GQL, variables)
|
with Progress() as progress:
|
||||||
|
progress.add_task("[cyan]fetching anime..", start=False, total=None)
|
||||||
|
anime = self._fetch_gql(ALLANIME_SHOW_GQL, variables)
|
||||||
|
return anime
|
||||||
|
|
||||||
def get_anime_episode(
|
def get_anime_episode(
|
||||||
self, allanime_show_id: str, episode_string: str, translation_type: str = "sub"
|
self, allanime_show_id: str, episode_string: str, translation_type: str = "sub"
|
||||||
@@ -74,7 +82,10 @@ class AllAnimeAPI:
|
|||||||
"translationType": translation_type,
|
"translationType": translation_type,
|
||||||
"episodeString": episode_string,
|
"episodeString": episode_string,
|
||||||
}
|
}
|
||||||
return anime_provider._fetch_gql(ALLANIME_EPISODES_GQL, variables)
|
with Progress() as progress:
|
||||||
|
progress.add_task("[cyan]fetching episode..", start=False, total=None)
|
||||||
|
episode = self._fetch_gql(ALLANIME_EPISODES_GQL, variables)
|
||||||
|
return episode
|
||||||
|
|
||||||
def get_episode_streams(self, allanime_episode_embeds_data):
|
def get_episode_streams(self, allanime_episode_embeds_data):
|
||||||
if (
|
if (
|
||||||
@@ -83,47 +94,59 @@ class AllAnimeAPI:
|
|||||||
):
|
):
|
||||||
return {}
|
return {}
|
||||||
embeds = allanime_episode_embeds_data["episode"]["sourceUrls"]
|
embeds = allanime_episode_embeds_data["episode"]["sourceUrls"]
|
||||||
for embed in embeds:
|
with Progress() as progress:
|
||||||
# filter the working streams
|
progress.add_task("[cyan]fetching streams..", start=False, total=None)
|
||||||
if embed.get("sourceName", "") not in ("Sak", "Kir", "S-mp4", "Luf-mp4"):
|
for embed in embeds:
|
||||||
continue
|
# filter the working streams
|
||||||
url = embed.get("sourceUrl")
|
if embed.get("sourceName", "") not in (
|
||||||
|
"Sak",
|
||||||
|
"Kir",
|
||||||
|
"S-mp4",
|
||||||
|
"Luf-mp4",
|
||||||
|
):
|
||||||
|
continue
|
||||||
|
url = embed.get("sourceUrl")
|
||||||
|
|
||||||
if not url:
|
if not url:
|
||||||
continue
|
continue
|
||||||
if url.startswith("--"):
|
if url.startswith("--"):
|
||||||
url = url[2:]
|
url = url[2:]
|
||||||
|
|
||||||
# get the stream url for an episode of the defined source names
|
# get the stream url for an episode of the defined source names
|
||||||
parsed_url = decode_hex_string(url)
|
parsed_url = decode_hex_string(url)
|
||||||
embed_url = (
|
embed_url = (
|
||||||
f"https://{ALLANIME_BASE}{parsed_url.replace('clock','clock.json')}"
|
f"https://{ALLANIME_BASE}{parsed_url.replace('clock','clock.json')}"
|
||||||
)
|
)
|
||||||
resp = requests.get(
|
resp = requests.get(
|
||||||
embed_url,
|
embed_url,
|
||||||
headers={
|
headers={
|
||||||
"Referer": ALLANIME_REFERER,
|
"Referer": ALLANIME_REFERER,
|
||||||
"User-Agent": USER_AGENT,
|
"User-Agent": USER_AGENT,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
if resp.status_code == 200:
|
if resp.status_code == 200:
|
||||||
match embed["sourceName"]:
|
match embed["sourceName"]:
|
||||||
case "Luf-mp4":
|
case "Luf-mp4":
|
||||||
Logger.debug("allanime:Found streams from gogoanime")
|
Logger.debug("allanime:Found streams from gogoanime")
|
||||||
yield "gogoanime", resp.json()
|
print("[yellow]gogoanime")
|
||||||
case "Kir":
|
yield "gogoanime", resp.json()
|
||||||
Logger.debug("allanime:Found streams from wetransfer")
|
case "Kir":
|
||||||
yield "wetransfer", resp.json()
|
Logger.debug("allanime:Found streams from wetransfer")
|
||||||
case "S-mp4":
|
print("[yellow]wetransfer")
|
||||||
Logger.debug("allanime:Found streams from sharepoint")
|
yield "wetransfer", resp.json()
|
||||||
yield "sharepoint", resp.json()
|
case "S-mp4":
|
||||||
case "Sak":
|
Logger.debug("allanime:Found streams from sharepoint")
|
||||||
Logger.debug("allanime:Found streams from dropbox")
|
|
||||||
yield "dropbox", resp.json()
|
print("[yellow]sharepoint")
|
||||||
case _:
|
yield "sharepoint", resp.json()
|
||||||
yield "Unknown", resp.json()
|
case "Sak":
|
||||||
else:
|
Logger.debug("allanime:Found streams from dropbox")
|
||||||
return {}
|
print("[yellow]dropbox")
|
||||||
|
yield "dropbox", resp.json()
|
||||||
|
case _:
|
||||||
|
yield "Unknown", resp.json()
|
||||||
|
else:
|
||||||
|
return {}
|
||||||
|
|
||||||
|
|
||||||
anime_provider = AllAnimeAPI()
|
anime_provider = AllAnimeAPI()
|
||||||
|
|||||||
1643
poetry.lock
generated
Normal file
1643
poetry.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
33
pyproject.toml
Normal file
33
pyproject.toml
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
[tool.poetry]
|
||||||
|
name = "fastanime"
|
||||||
|
version = "0.3.0"
|
||||||
|
description = "A fast and efficient GUI and CLI anime scrapper"
|
||||||
|
authors = ["Benex254 <benedictx855@gmail.com>"]
|
||||||
|
license = "UNLICENSE"
|
||||||
|
readme = "README.md"
|
||||||
|
|
||||||
|
[tool.poetry.dependencies]
|
||||||
|
python = "^3.10"
|
||||||
|
kivy = "^2.3.0"
|
||||||
|
yt-dlp = "^2024.5.27"
|
||||||
|
ffpyplayer = "^4.5.1"
|
||||||
|
plyer = "^2.1.0"
|
||||||
|
fuzzywuzzy = "^0.18.0"
|
||||||
|
rich = "^13.7.1"
|
||||||
|
click = "^8.1.7"
|
||||||
|
python-levenshtein = "^0.25.1"
|
||||||
|
kivymd = {url = "https://github.com/kivymd/KivyMD/archive/master.zip"}
|
||||||
|
|
||||||
|
[tool.poetry.group.dev.dependencies]
|
||||||
|
black = "^24.4.2"
|
||||||
|
isort = "^5.13.2"
|
||||||
|
pytest = "^8.2.2"
|
||||||
|
ruff = "^0.4.10"
|
||||||
|
|
||||||
|
pre-commit = "^3.7.1"
|
||||||
|
[build-system]
|
||||||
|
requires = ["poetry-core"]
|
||||||
|
build-backend = "poetry.core.masonry.api"
|
||||||
|
|
||||||
|
[tool.poetry.scripts]
|
||||||
|
fastanime = 'fastanime:FastAnime'
|
||||||
Reference in New Issue
Block a user