Compare commits

..

9 Commits

Author SHA1 Message Date
Benex254
6c1f8d09e6 chore: update package info 2024-07-26 14:13:50 +03:00
Benex254
6bb2c89a8c feat(mpv): improve streaming on mobile 2024-07-26 14:10:49 +03:00
Benex254
9f56b74ff0 feat(utils): add logging 2024-07-26 14:10:12 +03:00
Benex254
4d03b86498 chore(anime_provider): remove print statements from provider and switch to logging 2024-07-26 14:09:44 +03:00
Benex254
fab86090a3 chore: remove legacy code 2024-07-26 14:07:57 +03:00
Benex254
71d258385c chore(constants): create constants module to store useful constants 2024-07-26 14:07:37 +03:00
Benex254
bc55ed6e81 chore(updater): update updater info 2024-07-26 14:04:53 +03:00
Benex254
197bfa9f8a chore: update pyproject.toml 2024-07-26 09:27:56 +03:00
Benex254
f84c60e6bc chore: update dependencies 2024-07-26 09:24:15 +03:00
18 changed files with 303 additions and 243 deletions

View File

@@ -8,7 +8,7 @@ from subprocess import PIPE, Popen
import requests
from rich import print
from .. import APP_NAME, AUTHOR, GIT_REPO, REPO, __version__
from .. import APP_NAME, AUTHOR, GIT_REPO, __version__
API_URL = f"https://api.{GIT_REPO}/repos/{AUTHOR}/{APP_NAME}/releases/latest"
@@ -91,13 +91,12 @@ def update_app():
else:
executable = sys.executable
app_package_url = f"https://{REPO}/releases/download/{tag_name}/fastanime-{tag_name.replace("v","")}.tar.gz"
args = [
executable,
"-m",
"pip",
"install",
app_package_url,
APP_NAME,
"--user",
"--no-warn-script-location",
]

View File

@@ -2,7 +2,7 @@ import json
import logging
import os
from .. import USER_DATA_PATH
from ..constants import USER_DATA_PATH
logger = logging.getLogger(__name__)

View File

@@ -1,3 +1,4 @@
import logging
import os
import re
import shutil
@@ -10,6 +11,7 @@ from fastanime.libs.anilist.anilist_data_schema import AnilistBaseMediaDataSchem
from .data import anime_normalizer
logger = logging.getLogger(__name__)
# TODO: make it use color_text instead of fixed vals
# from .kivy_markup_helper import color_text
@@ -127,6 +129,7 @@ def anime_title_percentage_match(
fuzz.ratio(title_a.lower(), possible_user_requested_anime_title.lower()),
fuzz.ratio(title_b.lower(), possible_user_requested_anime_title.lower()),
)
logger.info(f"{locals()}")
return percentage_ratio

View File

@@ -1,10 +1,8 @@
import logging
import os
import sys
from platform import platform
from dotenv import load_dotenv
from platformdirs import PlatformDirs
load_dotenv()
@@ -15,43 +13,12 @@ if os.environ.get("FA_RICH_TRACEBACK", False):
# initiate constants
__version__ = "v0.30.0"
__version__ = "v0.32.0"
PLATFORM = platform()
APP_NAME = "FastAnime"
AUTHOR = "Benex254"
GIT_REPO = "github.com"
REPO = f"{GIT_REPO}/{AUTHOR}/{APP_NAME}"
USER_NAME = os.environ.get("USERNAME", f"{APP_NAME} user")
dirs = PlatformDirs(appname=APP_NAME, appauthor=AUTHOR, ensure_exists=True)
# ---- 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 -----
APP_DATA_DIR = dirs.user_config_dir
if not APP_DATA_DIR:
APP_DATA_DIR = dirs.user_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")
# cache dir
APP_CACHE_DIR = dirs.user_cache_dir
# video dir
USER_VIDEOS_DIR = os.path.join(dirs.user_videos_dir, APP_NAME)
# web dirs
WEB_DIR = os.path.join(APP_DIR, "web")
FRONTEND_DIR = os.path.join(WEB_DIR, "frontend")
BACKEND_DIR = os.path.join(WEB_DIR, "backend")
def FastAnime():

View File

@@ -4,7 +4,9 @@ import subprocess
import click
from rich import print
from ... import USER_CONFIG_PATH
from fastanime.cli.config import Config
from ...constants import USER_CONFIG_PATH
from ..utils.tools import exit_app
@@ -13,7 +15,8 @@ from ..utils.tools import exit_app
short_help="Edit your config",
)
@click.option("--path", "-p", help="Print the config location and exit", is_flag=True)
def configure(path):
@click.pass_obj
def configure(config: Config, path):
if path:
print(USER_CONFIG_PATH)
else:

View File

@@ -1,5 +1,6 @@
import click
from rich import print
from rich.progress import Progress
from thefuzz import fuzz
from ...libs.anime_provider.types import Anime
@@ -28,9 +29,11 @@ def download(config: Config, anime_title, episode_range):
anime_provider = config.anime_provider
translation_type = config.translation_type
download_dir = config.downloads_dir
search_results = anime_provider.search_for_anime(
anime_title, translation_type=translation_type
)
with Progress() as progress:
progress.add_task("Fetching Search Results...", total=None)
search_results = anime_provider.search_for_anime(
anime_title, translation_type=translation_type
)
if not search_results:
print("Search results failed")
input("Enter to retry")
@@ -51,7 +54,11 @@ def download(config: Config, anime_title, episode_range):
list(search_results_.keys()), "Please Select title: ", "FastAnime"
)
anime: Anime | None = anime_provider.get_anime(search_results_[search_result]["id"])
with Progress() as progress:
progress.add_task("Fetching Anime...", total=None)
anime: Anime | None = anime_provider.get_anime(
search_results_[search_result]["id"]
)
if not anime:
print("Sth went wring anime no found")
input("Enter to continue...")
@@ -70,20 +77,24 @@ def download(config: Config, anime_title, episode_range):
if episode not in episodes:
print(f"[cyan]Warning[/]: Episode {episode} not found, skipping")
continue
streams = anime_provider.get_episode_streams(
anime, episode, config.translation_type
)
if not streams:
print("No streams skipping")
continue
with Progress() as progress:
progress.add_task("Fetching Episode Streams...", total=None)
streams = anime_provider.get_episode_streams(
anime, episode, config.translation_type
)
if not streams:
print("No streams skipping")
continue
streams = list(streams)
links = [
(link.get("priority", 0), link["link"])
for server in streams
for link in server["links"]
]
link = max(links, key=lambda x: x[0])[1]
print(f"[purple]Now Downloading:[/] {search_result} Episode {episode}")
streams = list(streams)
links = [
(link.get("priority", 0), link["link"])
for server in streams
for link in server["links"]
]
link = max(links, key=lambda x: x[0])[1]
downloader._download_file(
link,
download_dir,

View File

@@ -1,5 +1,6 @@
import click
from rich import print
from rich.progress import Progress
from thefuzz import fuzz
from ...cli.config import Config
@@ -23,9 +24,11 @@ from ..utils.utils import clear
@click.pass_obj
def search(config: Config, anime_title: str, episode_range: str):
anime_provider = config.anime_provider
search_results = anime_provider.search_for_anime(
anime_title, config.translation_type
)
with Progress() as progress:
progress.add_task("Fetching Search Results...", total=None)
search_results = anime_provider.search_for_anime(
anime_title, config.translation_type
)
if not search_results:
print("Search results not found")
input("Enter to retry")
@@ -50,7 +53,12 @@ def search(config: Config, anime_title: str, episode_range: str):
list(search_results_.keys()), "Please Select title: ", "FastAnime"
)
anime: Anime | None = anime_provider.get_anime(search_results_[search_result]["id"])
with Progress() as progress:
progress.add_task("Fetching Anime...", total=None)
anime: Anime | None = anime_provider.get_anime(
search_results_[search_result]["id"]
)
if not anime:
print("Sth went wring anime no found")
input("Enter to continue...")
@@ -82,17 +90,20 @@ def search(config: Config, anime_title: str, episode_range: str):
if not episode or episode not in episodes:
episode = fzf.run(episodes, "Select an episode: ", header=search_result)
streams = anime_provider.get_episode_streams(
anime, episode, config.translation_type
)
if not streams:
print("Failed to get streams")
return
links = [link["link"] for server in streams for link in server["links"]]
with Progress() as progress:
progress.add_task("Fetching Episode Streams...", total=None)
streams = anime_provider.get_episode_streams(
anime, episode, config.translation_type
)
if not streams:
print("Failed to get streams")
return
links = [link["link"] for server in streams for link in server["links"]]
# TODO: Come up with way to know quality and better server interface
link = links[config.quality]
# TODO: Come up with way to know quality and better server interface
link = links[config.quality]
# link = fzf.run(links, "Select stream", "Streams")
print(f"[purple]Now Playing:[/] {search_result} Episode {episode}")
mpv(link, search_result)
stream_anime()

View File

@@ -3,8 +3,8 @@ from configparser import ConfigParser
from rich import print
from .. import USER_CONFIG_PATH, USER_VIDEOS_DIR
from ..AnimeProvider import AnimeProvider
from ..constants import USER_CONFIG_PATH, USER_VIDEOS_DIR
from ..Utility.user_data_helper import user_data_helper

View File

@@ -4,10 +4,11 @@ import os
import random
from rich import print
from rich.progress import Progress
from rich.prompt import Prompt
from ... import USER_CONFIG_PATH
from ...anilist import AniList
from ...constants import USER_CONFIG_PATH
from ...libs.anilist.anilist_data_schema import AnilistBaseMediaDataSchema
from ...libs.anime_provider.types import Anime, SearchResult, Server
from ...libs.fzf import fzf
@@ -154,17 +155,20 @@ def fetch_streams(config: Config, anilist_config: QueryDict):
anime_provider = config.anime_provider
# get streams for episode from provider
episode_streams = anime_provider.get_episode_streams(
anime, episode_number, translation_type
)
if not episode_streams:
print("Failed to fetch :cry:")
input("Enter to retry...")
return fetch_streams(config, anilist_config)
with Progress() as progress:
progress.add_task("Fetching Episode Streams...", total=None)
episode_streams = anime_provider.get_episode_streams(
anime, episode_number, translation_type
)
if not episode_streams:
print("Failed to fetch :cry:")
input("Enter to retry...")
return fetch_streams(config, anilist_config)
episode_streams = {
episode_stream["server"]: episode_stream for episode_stream in episode_streams
}
episode_streams = {
episode_stream["server"]: episode_stream
for episode_stream in episode_streams
}
# prompt for preferred server
server = None
@@ -267,7 +271,9 @@ def fetch_episode(config: Config, anilist_config: QueryDict):
def fetch_anime_episode(config, anilist_config: QueryDict):
selected_anime: SearchResult = anilist_config._anime
anime_provider = config.anime_provider
anilist_config.anime = anime_provider.get_anime(selected_anime["id"])
with Progress() as progress:
progress.add_task("Fetching Anime Info...", total=None)
anilist_config.anime = anime_provider.get_anime(selected_anime["id"])
if not anilist_config.anime:
print(
@@ -291,9 +297,11 @@ def provide_anime(config: Config, anilist_config: QueryDict):
anime_provider = config.anime_provider
# search and get the requested title from provider
search_results = anime_provider.search_for_anime(
selected_anime_title, translation_type
)
with Progress() as progress:
progress.add_task("Fetching Search Results...", total=None)
search_results = anime_provider.search_for_anime(
selected_anime_title, translation_type
)
if not search_results:
print(
"Sth went wrong :cry: while fetching this could mean you have poor internet connection or the provider is down"

View File

@@ -5,7 +5,7 @@ from threading import Thread
import requests
from ... import APP_CACHE_DIR
from ...constants import APP_CACHE_DIR
from ...libs.anilist.anilist_data_schema import AnilistBaseMediaDataSchema
from ...Utility import anilist_data_helper
from ...Utility.utils import remove_html_tags, sanitize_filename

View File

@@ -1,23 +1,87 @@
import re
import shutil
import subprocess
from typing import Optional
def mpv(link, title: None | str = "anime", *custom_args):
# legacy
# def mpv(link, title: None | str = "anime", *custom_args):
# MPV = shutil.which("mpv")
# if not MPV:
# args = [
# "nohup",
# "am",
# "start",
# "--user",
# "0",
# "-a",
# "android.intent.action.VIEW",
# "-d",
# link,
# "-n",
# "is.xyz.mpv/.MPVActivity",
# ]
# subprocess.run(args)
# else:
# subprocess.run([MPV, *custom_args, f"--title={title}", link])
#
#
def mpv(link: str, title: Optional[str] = "anime", *custom_args):
# Determine if mpv is available
MPV = shutil.which("mpv")
# If title is None, set a default value
if title is None:
title = "anime"
# Regex to check if the link is a YouTube URL
youtube_regex = r"(https?://)?(www\.)?(youtube|youtu|youtube-nocookie)\.(com|be)/.+"
if not MPV:
args = [
"nohup",
"am",
"start",
"--user",
"0",
"-a",
"android.intent.action.VIEW",
"-d",
link,
"-n",
"is.xyz.mpv/.MPVActivity",
]
# Determine if the link is a YouTube URL
if re.match(youtube_regex, link):
# Android specific commands to launch mpv with a YouTube URL
args = [
"nohup",
"am",
"start",
"--user",
"0",
"-a",
"android.intent.action.VIEW",
"-d",
link,
"-n",
"com.google.android.youtube/.UrlActivity",
]
else:
# Android specific commands to launch mpv with a regular URL
args = [
"nohup",
"am",
"start",
"--user",
"0",
"-a",
"android.intent.action.VIEW",
"-d",
link,
"-n",
"is.xyz.mpv/.MPVActivity",
]
subprocess.run(args)
else:
subprocess.run([MPV, *custom_args, f"--title={title}", link])
# General mpv command with custom arguments
mpv_args = [MPV, *custom_args, f"--title={title}", link]
subprocess.run(mpv_args)
# Example usage
if __name__ == "__main__":
mpv(
"https://www.youtube.com/watch?v=dQw4w9WgXcQ",
"Example Video",
"--fullscreen",
"--volume=50",
)

View File

@@ -18,7 +18,7 @@ def exit_app(*args):
from rich import print
from ... import USER_NAME
from ...constants import USER_NAME
print("Have a good day :smile:", USER_NAME)
sys.exit(0)

View File

@@ -4,7 +4,7 @@ import os
from InquirerPy import inquirer
from thefuzz import fuzz
from ... import PLATFORM
from ...constants import PLATFORM
from ...Utility.data import anime_normalizer
logger = logging.getLogger(__name__)
@@ -54,20 +54,3 @@ def anime_title_percentage_match(
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

32
fastanime/constants.py Normal file
View File

@@ -0,0 +1,32 @@
import os
from platform import platform
from platformdirs import PlatformDirs
from . import APP_NAME, AUTHOR
PLATFORM = platform()
dirs = PlatformDirs(appname=APP_NAME, appauthor=AUTHOR, ensure_exists=True)
# ---- 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 -----
APP_DATA_DIR = dirs.user_config_dir
if not APP_DATA_DIR:
APP_DATA_DIR = dirs.user_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")
# cache dir
APP_CACHE_DIR = dirs.user_cache_dir
# video dir
USER_VIDEOS_DIR = os.path.join(dirs.user_videos_dir, APP_NAME)
USER_NAME = os.environ.get("USERNAME", f"{APP_NAME} user")

View File

@@ -4,8 +4,6 @@ from typing import Iterator
import requests
from requests.exceptions import Timeout
from rich import print
from rich.progress import Progress
from ....libs.anime_provider.allanime.types import AllAnimeEpisode
from ....libs.anime_provider.types import Anime, Server
@@ -43,14 +41,12 @@ class AllAnimeAPI:
timeout=10,
)
return response.json()["data"]
except Timeout as e:
print(
"Timeout has been exceeded :cry:. This could mean allanime is down or your internet is down"
except Timeout:
Logger.error(
"allanime(Error):Timeout exceeded this could mean allanime is down or you have lost internet connection"
)
Logger.error(f"allanime(Error): {e}")
return {}
except Exception as e:
print("sth went wrong :confused:")
Logger.error(f"allanime:Error: {e}")
return {}
@@ -75,22 +71,20 @@ class AllAnimeAPI:
"countryorigin": countryorigin,
}
try:
with Progress() as progress:
progress.add_task("[cyan]searching..", start=False, total=None)
search_results = self._fetch_gql(ALLANIME_SEARCH_GQL, variables)
return normalize_search_results(search_results) # pyright:ignore
except Exception:
search_results = self._fetch_gql(ALLANIME_SEARCH_GQL, variables)
return normalize_search_results(search_results) # pyright:ignore
except Exception as e:
Logger.error(f"FA(AllAnime): {e}")
return {}
def get_anime(self, allanime_show_id: str):
variables = {"showId": allanime_show_id}
try:
with Progress() as progress:
progress.add_task("[cyan]fetching anime..", start=False, total=None)
anime = self._fetch_gql(ALLANIME_SHOW_GQL, variables)
return normalize_anime(anime["show"])
except Exception:
anime = self._fetch_gql(ALLANIME_SHOW_GQL, variables)
return normalize_anime(anime["show"])
except Exception as e:
Logger.error(f"FA(AllAnime): {e}")
return None
def get_anime_episode(
@@ -102,11 +96,10 @@ class AllAnimeAPI:
"episodeString": episode_string,
}
try:
with Progress() as progress:
progress.add_task("[cyan]fetching episode..", start=False, total=None)
episode = self._fetch_gql(ALLANIME_EPISODES_GQL, variables)
return episode["episode"] # pyright: ignore
except Exception:
episode = self._fetch_gql(ALLANIME_EPISODES_GQL, variables)
return episode["episode"] # pyright: ignore
except Exception as e:
Logger.error(f"FA(AllAnime): {e}")
return {}
def get_episode_streams(
@@ -121,99 +114,86 @@ class AllAnimeAPI:
embeds = allanime_episode["sourceUrls"]
try:
with Progress() as progress:
progress.add_task("[cyan]fetching streams..", start=False, total=None)
for embed in embeds:
try:
# filter the working streams
if embed.get("sourceName", "") not in (
"Sak",
"Kir",
"S-mp4",
"Luf-mp4",
):
continue
url = embed.get("sourceUrl")
for embed in embeds:
try:
# filter the working streams
if embed.get("sourceName", "") not in (
"Sak",
"Kir",
"S-mp4",
"Luf-mp4",
):
continue
url = embed.get("sourceUrl")
if not url:
continue
if url.startswith("--"):
url = url[2:]
if not url:
continue
if url.startswith("--"):
url = url[2:]
# get the stream url for an episode of the defined source names
parsed_url = decode_hex_string(url)
embed_url = f"https://{ALLANIME_BASE}{parsed_url.replace('clock','clock.json')}"
resp = requests.get(
embed_url,
headers={
"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"
# get the stream url for an episode of the defined source names
parsed_url = decode_hex_string(url)
embed_url = f"https://{ALLANIME_BASE}{parsed_url.replace('clock','clock.json')}"
resp = requests.get(
embed_url,
headers={
"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")
yield {
"server": "gogoanime",
"episode_title": (
allanime_episode["notes"] or f'{anime["title"]}'
)
print("[yellow]GogoAnime Fetched")
yield {
"server": "gogoanime",
"episode_title": (
allanime_episode["notes"]
or f'{anime["title"]}'
)
+ f"; Episode {episode_number}",
"links": resp.json()["links"],
} # pyright:ignore
case "Kir":
Logger.debug(
"allanime:Found streams from wetransfer"
+ f"; Episode {episode_number}",
"links": resp.json()["links"],
} # pyright:ignore
case "Kir":
Logger.debug("allanime:Found streams from wetransfer")
yield {
"server": "wetransfer",
"episode_title": (
allanime_episode["notes"] or f'{anime["title"]}'
)
print("[yellow]WeTransfer Fetched")
yield {
"server": "wetransfer",
"episode_title": (
allanime_episode["notes"]
or f'{anime["title"]}'
)
+ f"; Episode {episode_number}",
"links": resp.json()["links"],
} # pyright:ignore
case "S-mp4":
Logger.debug(
"allanime:Found streams from sharepoint"
+ f"; Episode {episode_number}",
"links": resp.json()["links"],
} # pyright:ignore
case "S-mp4":
Logger.debug("allanime:Found streams from sharepoint")
yield {
"server": "sharepoint",
"episode_title": (
allanime_episode["notes"] or f'{anime["title"]}'
)
print("[yellow]Sharepoint Fetched")
yield {
"server": "sharepoint",
"episode_title": (
allanime_episode["notes"]
or f'{anime["title"]}'
)
+ f"; Episode {episode_number}",
"links": resp.json()["links"],
} # pyright:ignore
case "Sak":
Logger.debug("allanime:Found streams from dropbox")
print("[yellow]Dropbox Fetched")
yield {
"server": "dropbox",
"episode_title": (
allanime_episode["notes"]
or f'{anime["title"]}'
)
+ f"; Episode {episode_number}",
"links": resp.json()["links"],
} # pyright:ignore
except Timeout:
print(
"Timeout has been exceeded :cry: this could mean allanime is down or your internet connection is poor"
)
except Exception as e:
print("Sth went wrong :confused:", e)
except Exception:
+ f"; Episode {episode_number}",
"links": resp.json()["links"],
} # pyright:ignore
case "Sak":
Logger.debug("allanime:Found streams from dropbox")
yield {
"server": "dropbox",
"episode_title": (
allanime_episode["notes"] or f'{anime["title"]}'
)
+ f"; Episode {episode_number}",
"links": resp.json()["links"],
} # pyright:ignore
except Timeout:
Logger.error(
"Timeout has been exceeded this could mean allanime is down or you have lost internet connection"
)
return []
except Exception as e:
Logger.error(f"FA(Allanime): {e}")
return []
except Exception as e:
Logger.error(f"FA(Allanime): {e}")
return []

View File

@@ -8,7 +8,7 @@ from typing import Callable, List
from art import text2art
from rich import print
from ... import PLATFORM
from ...constants import PLATFORM
from .config import FZF_DEFAULT_OPTS, FzfOptions
logger = logging.getLogger(__name__)

16
poetry.lock generated
View File

@@ -771,13 +771,13 @@ windows-terminal = ["colorama (>=0.4.6)"]
[[package]]
name = "pytest"
version = "8.3.1"
version = "8.3.2"
description = "pytest: simple powerful testing with Python"
optional = false
python-versions = ">=3.8"
files = [
{file = "pytest-8.3.1-py3-none-any.whl", hash = "sha256:e9600ccf4f563976e2c99fa02c7624ab938296551f280835ee6516df8bc4ae8c"},
{file = "pytest-8.3.1.tar.gz", hash = "sha256:7e8e5c5abd6e93cb1cc151f23e57adc31fcf8cfd2a3ff2da63e23f732de35db6"},
{file = "pytest-8.3.2-py3-none-any.whl", hash = "sha256:4ba08f9ae7dcf84ded419494d229b48d0903ea6407b030eaec46df5e6a73bba5"},
{file = "pytest-8.3.2.tar.gz", hash = "sha256:c132345d12ce551242c87269de812483f5bcc87cdbb4722e48487ba194f9fdce"},
]
[package.dependencies]
@@ -1202,13 +1202,13 @@ files = [
[[package]]
name = "yt-dlp"
version = "2024.7.16"
version = "2024.7.25"
description = "A feature-rich command-line audio/video downloader"
optional = false
python-versions = ">=3.8"
files = [
{file = "yt_dlp-2024.7.16-py3-none-any.whl", hash = "sha256:424805a112e757b141e767bc938d49db56d13d6415a92fa4cd8acadd55790be0"},
{file = "yt_dlp-2024.7.16.tar.gz", hash = "sha256:c5bd517a49dea1923ec8e14f51858f10fd89dfece14cb701392b480b41b2f516"},
{file = "yt_dlp-2024.7.25-py3-none-any.whl", hash = "sha256:f44b5f33776b4f718900c670fe6e4698fb6fcd426455cd837cf25a1d6d4d9560"},
{file = "yt_dlp-2024.7.25.tar.gz", hash = "sha256:7587aa25e236cf7b14bdb9378bbffff51202d901b04202be0cf62cbb56d3b52c"},
]
[package.dependencies]
@@ -1222,7 +1222,7 @@ urllib3 = ">=1.26.17,<3"
websockets = ">=12.0"
[package.extras]
build = ["build", "hatchling", "pip", "setuptools", "wheel"]
build = ["build", "hatchling", "pip", "setuptools (>=71.0.2)", "wheel"]
curl-cffi = ["curl-cffi (==0.5.10)", "curl-cffi (>=0.5.10,<0.6.dev0 || ==0.7.*)"]
dev = ["autopep8 (>=2.0,<3.0)", "pre-commit", "pytest (>=8.1,<9.0)", "ruff (>=0.5.0,<0.6.0)"]
py2exe = ["py2exe (>=0.12)"]
@@ -1234,4 +1234,4 @@ test = ["pytest (>=8.1,<9.0)"]
[metadata]
lock-version = "2.0"
python-versions = "^3.10"
content-hash = "b6f2f120c8a562e8c8d98aae75f1e5fc4dd779d2da60fdcff6b98bf88008f23b"
content-hash = "38fed68d89077d348221af9eb8e2d0ea6c9585bd4c5de16d6e5974664c562f73"

View File

@@ -1,7 +1,7 @@
[tool.poetry]
name = "fastanime"
version = "0.31.2"
description = "A fast and efficient GUI and CLI anime scrapper"
version = "0.32.0"
description = "A fast and efficient anime scrapper and exploration tool"
authors = ["Benex254 <benedictx855@gmail.com>"]
license = "UNLICENSE"
readme = "README.md"
@@ -32,4 +32,3 @@ build-backend = "poetry.core.masonry.api"
[tool.poetry.scripts]
fastanime = 'fastanime:FastAnime'