mirror of
https://github.com/Benexl/FastAnime.git
synced 2025-12-26 04:41:34 -08:00
Compare commits
16 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6eb28cfa3d | ||
|
|
542d39fa6a | ||
|
|
e5e328148f | ||
|
|
cea1a67d64 | ||
|
|
97c6dc7968 | ||
|
|
d97072e298 | ||
|
|
7cd246478e | ||
|
|
8afe1df3a9 | ||
|
|
452c2a3569 | ||
|
|
f738069794 | ||
|
|
d178eb976e | ||
|
|
d58dae6d6b | ||
|
|
136cf841e1 | ||
|
|
748d321f36 | ||
|
|
3e71239981 | ||
|
|
571ab488f8 |
@@ -164,7 +164,8 @@ The only required external dependency, unless you won't be streaming, is [MPV](h
|
||||
|
||||
**Other external dependencies that will just make your experience better:**
|
||||
|
||||
- [fzf](https://github.com/junegunn/fzf) :fire: which is used as a better alternative to the ui.
|
||||
- [fzf](https://github.com/junegunn/fzf) 🔥 which is used as a better alternative to the ui.
|
||||
- [rofi](https://github.com/davatorium/rofi) 🔥 which is used as another alternative ui + the the desktop entry ui
|
||||
- [chafa](https://github.com/hpjansson/chafa) currently the best cross platform and cross terminal image viewer for the terminal.
|
||||
- [icat](https://sw.kovidgoyal.net/kitty/kittens/icat/) an image viewer that only works in [kitty terminal](https://sw.kovidgoyal.net/kitty/), which is currently the best terminal in my opinion, and by far the best image renderer for the terminal thanks to kitty's terminal graphics protocol. Its terminal graphics is so op that you can [run a browser on it](https://github.com/chase/awrit?tab=readme-ov-file)!!
|
||||
- [bash](https://www.gnu.org/software/bash/) is used as the preview script language.
|
||||
@@ -310,15 +311,15 @@ Powerful command mainly aimed at binging anime. Since it doesn't require interac
|
||||
**Syntax:**
|
||||
|
||||
```bash
|
||||
# basic form where you will still be promted for the episode number
|
||||
# basic form where you will still be prompted for the episode number
|
||||
fastanime search <anime-title>
|
||||
|
||||
# binge all episodes with this command
|
||||
fastanime search <anime-title> -
|
||||
fastanime search <anime-title> -r -
|
||||
|
||||
# binge a specific episode range with this command
|
||||
# be sure to observe the range Syntax
|
||||
fastanime search <anime-title> <episodes-start>-<episodes-end>
|
||||
fastanime search <anime-title> -r <episodes-start>-<episodes-end>
|
||||
```
|
||||
|
||||
#### downloads subcommand
|
||||
|
||||
@@ -6,7 +6,7 @@ if sys.version_info < (3, 10):
|
||||
) # noqa: F541
|
||||
|
||||
|
||||
__version__ = "v1.0.0"
|
||||
__version__ = "v1.1.6"
|
||||
|
||||
APP_NAME = "FastAnime"
|
||||
AUTHOR = "Benex254"
|
||||
|
||||
@@ -22,34 +22,71 @@ if TYPE_CHECKING:
|
||||
)
|
||||
@click.pass_obj
|
||||
def config(config: "Config", path, view, desktop_entry):
|
||||
from pyshortcuts import make_shortcut
|
||||
import sys
|
||||
|
||||
from rich import print
|
||||
|
||||
from ...constants import APP_NAME, ICON_PATH, USER_CONFIG_PATH
|
||||
from ... import __version__
|
||||
from ...constants import APP_NAME, ICON_PATH, S_PLATFORM, USER_CONFIG_PATH
|
||||
|
||||
if path:
|
||||
print(USER_CONFIG_PATH)
|
||||
elif view:
|
||||
print(config)
|
||||
elif desktop_entry:
|
||||
import os
|
||||
import shutil
|
||||
from pathlib import Path
|
||||
from textwrap import dedent
|
||||
|
||||
from rich import print
|
||||
from rich.prompt import Confirm
|
||||
|
||||
from ..utils.tools import exit_app
|
||||
|
||||
FASTANIME_EXECUTABLE = shutil.which("fastanime")
|
||||
if FASTANIME_EXECUTABLE:
|
||||
cmds = f"{FASTANIME_EXECUTABLE} --rofi anilist"
|
||||
else:
|
||||
cmds = "_ -m fastanime --rofi anilist"
|
||||
shortcut = make_shortcut(
|
||||
name=APP_NAME,
|
||||
description="Watch Anime from the terminal",
|
||||
icon=ICON_PATH,
|
||||
script=cmds,
|
||||
terminal=False,
|
||||
)
|
||||
if shortcut:
|
||||
print("Success", shortcut)
|
||||
cmds = f"{sys.executable} -m fastanime --rofi anilist"
|
||||
|
||||
# TODO: Get funs of the other platforms to complete this lol
|
||||
if S_PLATFORM == "win32":
|
||||
print(
|
||||
"Not implemented; the author thinks its not straight forward so welcomes lovers of windows to try and implement it themselves or to switch to a proper os like arch linux or pray the author gets bored 😜"
|
||||
)
|
||||
elif S_PLATFORM == "darwin":
|
||||
print(
|
||||
"Not implemented; the author thinks its not straight forward so welcomes lovers of mac to try and implement it themselves or to switch to a proper os like arch linux or pray the author gets bored 😜"
|
||||
)
|
||||
else:
|
||||
print("Failed")
|
||||
desktop_entry = dedent(
|
||||
f"""
|
||||
[Desktop Entry]
|
||||
Name={APP_NAME}
|
||||
Type=Application
|
||||
version={__version__}
|
||||
Path={Path().home()}
|
||||
Comment=Watch anime from your terminal
|
||||
Terminal=false
|
||||
Icon={ICON_PATH}
|
||||
Exec={cmds}
|
||||
Categories=Entertainment
|
||||
"""
|
||||
)
|
||||
base = os.path.expanduser("~/.local/share/applications")
|
||||
desktop_entry_path = os.path.join(base, f"{APP_NAME}.desktop")
|
||||
if os.path.exists(desktop_entry_path):
|
||||
if not Confirm.ask(
|
||||
f"The file already exists {desktop_entry_path}; or would you like to rewrite it",
|
||||
default=False,
|
||||
):
|
||||
exit_app(1)
|
||||
with open(desktop_entry_path, "w") as f:
|
||||
f.write(desktop_entry)
|
||||
with open(desktop_entry_path) as f:
|
||||
print(f"Successfully wrote \n{f.read()}")
|
||||
exit_app(0)
|
||||
else:
|
||||
import click
|
||||
|
||||
|
||||
@@ -112,7 +112,10 @@ def download(config: "Config", anime_title, episode_range, highest_priority):
|
||||
if config.server == "top":
|
||||
with Progress() as progress:
|
||||
progress.add_task("Fetching top server...", total=None)
|
||||
server = next(streams)
|
||||
server = next(streams, None)
|
||||
if not server:
|
||||
print("Sth went wrong when fetching the server")
|
||||
continue
|
||||
stream_link = filter_by_quality(config.quality, server["links"])
|
||||
if not stream_link:
|
||||
print("Quality not found")
|
||||
|
||||
@@ -130,7 +130,12 @@ def search(config: Config, anime_title: str, episode_range: str):
|
||||
if config.server == "top":
|
||||
with Progress() as progress:
|
||||
progress.add_task("Fetching top server...", total=None)
|
||||
server = next(streams)
|
||||
server = next(streams, None)
|
||||
if not server:
|
||||
print("Sth went wrong when fetching the episode")
|
||||
input("Enter to continue")
|
||||
stream_anime()
|
||||
return
|
||||
stream_link = filter_by_quality(config.quality, server["links"])
|
||||
if not stream_link:
|
||||
print("Quality not found")
|
||||
|
||||
@@ -20,7 +20,7 @@ from ...libs.rofi import Rofi
|
||||
from ...Utility.data import anime_normalizer
|
||||
from ...Utility.utils import anime_title_percentage_match
|
||||
from ..utils.mpv import run_mpv
|
||||
from ..utils.tools import FastAnimeRuntimeState, exit_app
|
||||
from ..utils.tools import exit_app
|
||||
from ..utils.utils import filter_by_quality, fuzzy_inquirer
|
||||
from .utils import aniskip
|
||||
|
||||
@@ -28,6 +28,7 @@ if TYPE_CHECKING:
|
||||
from ...libs.anilist.types import AnilistBaseMediaDataSchema
|
||||
from ...libs.anime_provider.types import Anime, SearchResult, Server
|
||||
from ..config import Config
|
||||
from ..utils.tools import FastAnimeRuntimeState
|
||||
|
||||
|
||||
def calculate_time_delta(start_time, end_time):
|
||||
@@ -316,7 +317,7 @@ def media_player_controls(
|
||||
|
||||
|
||||
def provider_anime_episode_servers_menu(
|
||||
config: "Config", fastanime_runtime_state: FastAnimeRuntimeState
|
||||
config: "Config", fastanime_runtime_state: "FastAnimeRuntimeState"
|
||||
):
|
||||
"""Menu that enables selection of a server either manually or automatically based on user config then plays the stream link of the quality the user prefers
|
||||
|
||||
@@ -365,7 +366,22 @@ def provider_anime_episode_servers_menu(
|
||||
with Progress() as progress:
|
||||
progress.add_task("Fetching top server...", total=None)
|
||||
try:
|
||||
selected_server = next(episode_streams_generator)
|
||||
selected_server = next(episode_streams_generator, None)
|
||||
if not selected_server:
|
||||
if config.use_rofi:
|
||||
if Rofi.confirm("Sth went wrong enter to continue"):
|
||||
provider_anime_episode_servers_menu(
|
||||
config, fastanime_runtime_state
|
||||
)
|
||||
else:
|
||||
exit_app(1)
|
||||
else:
|
||||
print("Sth went wrong")
|
||||
input("Enter to continue...")
|
||||
provider_anime_episode_servers_menu(
|
||||
config, fastanime_runtime_state
|
||||
)
|
||||
return
|
||||
server_name = "top"
|
||||
except Exception as e:
|
||||
print("Failed to get streams. Reason:", e)
|
||||
@@ -502,7 +518,7 @@ def provider_anime_episode_servers_menu(
|
||||
mpv.terminate()
|
||||
stop_time = player.last_stop_time
|
||||
total_time = player.last_total_time
|
||||
|
||||
current_episode_number = fastanime_runtime_state.provider_current_episode_number
|
||||
else:
|
||||
stop_time, total_time = run_mpv(
|
||||
current_stream_link,
|
||||
@@ -530,7 +546,10 @@ def provider_anime_episode_servers_menu(
|
||||
total_time = "0"
|
||||
|
||||
config.update_watch_history(
|
||||
anime_id_anilist, episode, start_time=stop_time, total_time=total_time
|
||||
anime_id_anilist,
|
||||
episode,
|
||||
start_time=stop_time,
|
||||
total_time=total_time,
|
||||
)
|
||||
|
||||
# switch to controls
|
||||
@@ -759,7 +778,7 @@ def anime_provider_search_results_menu(
|
||||
# ---- ANILIST MEDIA ACTIONS MENU ----
|
||||
#
|
||||
def media_actions_menu(
|
||||
config: "Config", fastanime_runtime_state: FastAnimeRuntimeState
|
||||
config: "Config", fastanime_runtime_state: "FastAnimeRuntimeState"
|
||||
):
|
||||
"""The menu responsible for handling all media actions such as watching a trailer or streaming it
|
||||
|
||||
@@ -781,7 +800,7 @@ def media_actions_menu(
|
||||
episodes_total = selected_anime_anilist["episodes"] or "Inf"
|
||||
|
||||
def _watch_trailer(
|
||||
config: "Config", fastanime_runtime_state: FastAnimeRuntimeState
|
||||
config: "Config", fastanime_runtime_state: "FastAnimeRuntimeState"
|
||||
):
|
||||
"""Helper function to watch trailers with
|
||||
|
||||
@@ -806,7 +825,9 @@ def media_actions_menu(
|
||||
exit(0)
|
||||
media_actions_menu(config, fastanime_runtime_state)
|
||||
|
||||
def _add_to_list(config: "Config", fastanime_runtime_state: FastAnimeRuntimeState):
|
||||
def _add_to_list(
|
||||
config: "Config", fastanime_runtime_state: "FastAnimeRuntimeState"
|
||||
):
|
||||
"""Helper function to update an anime's media_list_type
|
||||
|
||||
Args:
|
||||
@@ -848,7 +869,9 @@ def media_actions_menu(
|
||||
input("Enter to continue...")
|
||||
media_actions_menu(config, fastanime_runtime_state)
|
||||
|
||||
def _score_anime(config: "Config", fastanime_runtime_state: FastAnimeRuntimeState):
|
||||
def _score_anime(
|
||||
config: "Config", fastanime_runtime_state: "FastAnimeRuntimeState"
|
||||
):
|
||||
"""Helper function to score anime on anilist from terminal or rofi
|
||||
|
||||
Args:
|
||||
@@ -879,7 +902,7 @@ def media_actions_menu(
|
||||
|
||||
# FIX: For some reason this fails to delete
|
||||
def _remove_from_list(
|
||||
config: "Config", fastanime_runtime_state: FastAnimeRuntimeState
|
||||
config: "Config", fastanime_runtime_state: "FastAnimeRuntimeState"
|
||||
):
|
||||
"""Remove an anime from your media list
|
||||
|
||||
@@ -1121,7 +1144,7 @@ def media_actions_menu(
|
||||
# ---- ANILIST RESULTS MENU ----
|
||||
#
|
||||
def anilist_results_menu(
|
||||
config: "Config", fastanime_runtime_state: FastAnimeRuntimeState
|
||||
config: "Config", fastanime_runtime_state: "FastAnimeRuntimeState"
|
||||
):
|
||||
"""The menu that handles and displays the results of an anilist action enabling using to select anime of choice
|
||||
|
||||
@@ -1288,7 +1311,7 @@ def handle_animelist(
|
||||
|
||||
|
||||
def fastanime_main_menu(
|
||||
config: "Config", fastanime_runtime_state: FastAnimeRuntimeState
|
||||
config: "Config", fastanime_runtime_state: "FastAnimeRuntimeState"
|
||||
):
|
||||
"""The main entry point to the anilist command
|
||||
|
||||
|
||||
@@ -117,7 +117,10 @@ class MpvPlayer(object):
|
||||
|
||||
# always select the first
|
||||
if server == "top":
|
||||
selected_server = next(episode_streams)
|
||||
selected_server = next(episode_streams, None)
|
||||
if not selected_server:
|
||||
self.mpv_player.show_text("Sth went wrong when loading the episode")
|
||||
return
|
||||
else:
|
||||
episode_streams_dict = {
|
||||
episode_stream["server"]: episode_stream
|
||||
@@ -136,6 +139,7 @@ class MpvPlayer(object):
|
||||
if not stream_link_:
|
||||
self.mpv_player.show_text("Quality not found")
|
||||
return
|
||||
self.mpv_player._set_property("start", "0")
|
||||
stream_link = stream_link_["link"]
|
||||
return stream_link
|
||||
|
||||
@@ -230,6 +234,7 @@ class MpvPlayer(object):
|
||||
@mpv_player.on_key_press("shift+t")
|
||||
def _toggle_translation_type():
|
||||
translation_type = "sub" if config.translation_type == "dub" else "dub"
|
||||
mpv_player.show_text("Changing translation type...")
|
||||
anime = anime_provider.get_anime(
|
||||
fastanime_runtime_state.provider_anime_search_result["id"],
|
||||
fastanime_runtime_state.selected_anime_anilist,
|
||||
|
||||
@@ -14,7 +14,7 @@ class FastAnimeRuntimeState(dict):
|
||||
self.__setitem__(attr, value)
|
||||
|
||||
|
||||
def exit_app(*args):
|
||||
def exit_app(exit_code=0, *args):
|
||||
import os
|
||||
import shutil
|
||||
import sys
|
||||
@@ -46,4 +46,4 @@ def exit_app(*args):
|
||||
from rich import print
|
||||
|
||||
print("Have a good day :smile:", USER_NAME)
|
||||
sys.exit(0)
|
||||
sys.exit(exit_code)
|
||||
|
||||
@@ -19,7 +19,7 @@ BG_GREEN = "\033[48;2;120;233;12;m"
|
||||
GREEN = "\033[38;2;45;24;45;m"
|
||||
|
||||
|
||||
def filter_by_quality(quality: str, stream_links: "list[EpisodeStream]"):
|
||||
def filter_by_quality(quality: str, stream_links: "list[EpisodeStream]", default=True):
|
||||
"""Helper function used to filter a list of EpisodeStream objects to one that has a corresponding quality
|
||||
|
||||
Args:
|
||||
@@ -30,8 +30,20 @@ def filter_by_quality(quality: str, stream_links: "list[EpisodeStream]"):
|
||||
an EpisodeStream object or None incase the quality was not found
|
||||
"""
|
||||
for stream_link in stream_links:
|
||||
if stream_link["quality"] == quality:
|
||||
q = float(quality)
|
||||
Q = float(stream_link["quality"])
|
||||
# some providers have inaccurate eg qualities 718 instead of 720
|
||||
if Q < q + 80 and Q > q - 80:
|
||||
return stream_link
|
||||
else:
|
||||
if stream_links and default:
|
||||
try:
|
||||
print("Qualities were: ", stream_links)
|
||||
print("Using default of quality: ", stream_links[0]["quality"])
|
||||
return stream_links[0]
|
||||
except Exception as e:
|
||||
print(e)
|
||||
return
|
||||
|
||||
|
||||
def format_bytes_to_human(num_of_bytes: float, suffix: str = "B"):
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
import os
|
||||
import sys
|
||||
from pathlib import Path
|
||||
from platform import system
|
||||
|
||||
from platformdirs import PlatformDirs
|
||||
|
||||
from . import APP_NAME, AUTHOR
|
||||
from . import APP_NAME, AUTHOR, __version__
|
||||
|
||||
PLATFORM = system()
|
||||
dirs = PlatformDirs(appname=APP_NAME, appauthor=AUTHOR, ensure_exists=True)
|
||||
|
||||
|
||||
# ---- app deps ----
|
||||
APP_DIR = os.path.abspath(os.path.dirname(__file__))
|
||||
@@ -24,19 +22,63 @@ PREVIEW_IMAGE = os.path.join(ASSETS_DIR, "preview")
|
||||
|
||||
|
||||
# ----- user configs and data -----
|
||||
APP_DATA_DIR = dirs.user_config_dir
|
||||
if not APP_DATA_DIR:
|
||||
APP_DATA_DIR = dirs.user_data_dir
|
||||
|
||||
S_PLATFORM = sys.platform
|
||||
|
||||
if S_PLATFORM == "win32":
|
||||
# app data
|
||||
app_data_dir_base = os.getenv("LOCALAPPDATA")
|
||||
if not app_data_dir_base:
|
||||
raise RuntimeError("Could not determine app data dir please report to devs")
|
||||
APP_DATA_DIR = os.path.join(app_data_dir_base, AUTHOR, APP_NAME)
|
||||
|
||||
# cache dir
|
||||
APP_CACHE_DIR = os.path.join(APP_DATA_DIR, "cache")
|
||||
|
||||
# videos dir
|
||||
video_dir_base = os.path.expanduser("~/Videos")
|
||||
USER_VIDEOS_DIR = os.path.join(video_dir_base, APP_NAME)
|
||||
|
||||
elif S_PLATFORM == "darwin":
|
||||
# app data
|
||||
app_data_dir_base = os.path.expanduser("~/Library/Application Support")
|
||||
APP_DATA_DIR = os.path.join(app_data_dir_base, APP_NAME, __version__)
|
||||
|
||||
# cache dir
|
||||
cache_dir_base = os.path.expanduser("~/Library/Caches")
|
||||
APP_CACHE_DIR = os.path.join(cache_dir_base, APP_NAME, __version__)
|
||||
|
||||
# videos dir
|
||||
video_dir_base = os.path.expanduser("~/Movies")
|
||||
USER_VIDEOS_DIR = os.path.join(video_dir_base, APP_NAME)
|
||||
else:
|
||||
# app data
|
||||
app_data_dir_base = os.environ.get("XDG_CONFIG_HOME", "")
|
||||
if not app_data_dir_base.strip():
|
||||
app_data_dir_base = os.path.expanduser("~/.config")
|
||||
APP_DATA_DIR = os.path.join(app_data_dir_base, APP_NAME)
|
||||
|
||||
# cache dir
|
||||
cache_dir_base = os.environ.get("XDG_CACHE_HOME", "")
|
||||
if not cache_dir_base.strip():
|
||||
cache_dir_base = os.path.expanduser("~/.cache")
|
||||
APP_CACHE_DIR = os.path.join(cache_dir_base, APP_NAME)
|
||||
|
||||
# videos dir
|
||||
video_dir_base = os.environ.get("XDG_VIDEOS_DIR", "")
|
||||
if not video_dir_base.strip():
|
||||
video_dir_base = os.path.expanduser("~/Videos")
|
||||
USER_VIDEOS_DIR = os.path.join(video_dir_base, APP_NAME)
|
||||
|
||||
# ensure paths exist
|
||||
Path(APP_DATA_DIR).mkdir(parents=True, exist_ok=True)
|
||||
Path(APP_CACHE_DIR).mkdir(parents=True, exist_ok=True)
|
||||
Path(USER_VIDEOS_DIR).mkdir(parents=True, exist_ok=True)
|
||||
|
||||
# useful paths
|
||||
USER_DATA_PATH = os.path.join(APP_DATA_DIR, "user_data.json")
|
||||
USER_CONFIG_PATH = os.path.join(APP_DATA_DIR, "config.ini")
|
||||
NOTIFIER_LOG_FILE_PATH = os.path.join(APP_DATA_DIR, "notifier.log")
|
||||
|
||||
# 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", "Anime fun")
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import logging
|
||||
import random
|
||||
import re
|
||||
import shutil
|
||||
import subprocess
|
||||
import time
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from yt_dlp.utils import (
|
||||
@@ -68,20 +70,55 @@ class AnimePaheApi(AnimeProvider):
|
||||
return {}
|
||||
|
||||
def get_anime(self, session_id: str, *args):
|
||||
page = 1
|
||||
try:
|
||||
anime_result: "AnimeSearchResult" = [
|
||||
anime
|
||||
for anime in self.search_page["data"]
|
||||
if anime["session"] == session_id
|
||||
][0]
|
||||
url = (
|
||||
f"{ANIMEPAHE_ENDPOINT}m=release&id={session_id}&sort=episode_asc&page=1"
|
||||
data: "AnimePaheAnimePage" = {} # pyright:ignore
|
||||
|
||||
url = f"{ANIMEPAHE_ENDPOINT}m=release&id={session_id}&sort=episode_asc&page={page}"
|
||||
|
||||
def _pages_loader(
|
||||
url,
|
||||
page,
|
||||
):
|
||||
response = self.session.get(url, headers=REQUEST_HEADERS)
|
||||
if response.status_code == 200:
|
||||
if not data:
|
||||
data.update(response.json())
|
||||
if ep_data := response.json().get("data"):
|
||||
data["data"].extend(ep_data)
|
||||
if data["next_page_url"]:
|
||||
# TODO: Refine this
|
||||
time.sleep(
|
||||
random.choice(
|
||||
[
|
||||
0.25,
|
||||
0.1,
|
||||
0.5,
|
||||
0.75,
|
||||
1,
|
||||
]
|
||||
)
|
||||
)
|
||||
page += 1
|
||||
url = f"{ANIMEPAHE_ENDPOINT}m=release&id={session_id}&sort=episode_asc&page={page}"
|
||||
_pages_loader(
|
||||
url,
|
||||
page,
|
||||
)
|
||||
|
||||
_pages_loader(
|
||||
url,
|
||||
page,
|
||||
)
|
||||
response = self.session.get(url, headers=REQUEST_HEADERS)
|
||||
if not response.status_code == 200:
|
||||
|
||||
if not data:
|
||||
return {}
|
||||
data: "AnimePaheAnimePage" = response.json()
|
||||
self.anime = data
|
||||
self.anime = data # pyright:ignore
|
||||
episodes = list(map(str, range(data["total"])))
|
||||
title = ""
|
||||
return {
|
||||
|
||||
53
poetry.lock
generated
53
poetry.lock
generated
@@ -861,20 +861,6 @@ nodeenv = ">=1.6.0"
|
||||
all = ["twine (>=3.4.1)"]
|
||||
dev = ["twine (>=3.4.1)"]
|
||||
|
||||
[[package]]
|
||||
name = "pyshortcuts"
|
||||
version = "1.9.0"
|
||||
description = "Create desktop and Start Menu shortcuts for python scripts"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "pyshortcuts-1.9.0-py3-none-any.whl", hash = "sha256:54d12ed8cd29bf83ac15153ce882a77072f2032b5f979474c519a2bac5af849d"},
|
||||
{file = "pyshortcuts-1.9.0.tar.gz", hash = "sha256:016e89111337f74ce1ba3f4b79b295a643bc70b3e63ce4600247aa4bafa06877"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
pywin32 = {version = "*", markers = "platform_system == \"Windows\""}
|
||||
|
||||
[[package]]
|
||||
name = "pytest"
|
||||
version = "8.3.2"
|
||||
@@ -897,43 +883,6 @@ tomli = {version = ">=1", markers = "python_version < \"3.11\""}
|
||||
[package.extras]
|
||||
dev = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"]
|
||||
|
||||
[[package]]
|
||||
name = "python-dotenv"
|
||||
version = "1.0.1"
|
||||
description = "Read key-value pairs from a .env file and set them as environment variables"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "python-dotenv-1.0.1.tar.gz", hash = "sha256:e324ee90a023d808f1959c46bcbc04446a10ced277783dc6ee09987c37ec10ca"},
|
||||
{file = "python_dotenv-1.0.1-py3-none-any.whl", hash = "sha256:f7b63ef50f1b690dddf550d03497b66d609393b40b564ed0d674909a68ebf16a"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
cli = ["click (>=5.0)"]
|
||||
|
||||
[[package]]
|
||||
name = "pywin32"
|
||||
version = "306"
|
||||
description = "Python for Window Extensions"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
files = [
|
||||
{file = "pywin32-306-cp310-cp310-win32.whl", hash = "sha256:06d3420a5155ba65f0b72f2699b5bacf3109f36acbe8923765c22938a69dfc8d"},
|
||||
{file = "pywin32-306-cp310-cp310-win_amd64.whl", hash = "sha256:84f4471dbca1887ea3803d8848a1616429ac94a4a8d05f4bc9c5dcfd42ca99c8"},
|
||||
{file = "pywin32-306-cp311-cp311-win32.whl", hash = "sha256:e65028133d15b64d2ed8f06dd9fbc268352478d4f9289e69c190ecd6818b6407"},
|
||||
{file = "pywin32-306-cp311-cp311-win_amd64.whl", hash = "sha256:a7639f51c184c0272e93f244eb24dafca9b1855707d94c192d4a0b4c01e1100e"},
|
||||
{file = "pywin32-306-cp311-cp311-win_arm64.whl", hash = "sha256:70dba0c913d19f942a2db25217d9a1b726c278f483a919f1abfed79c9cf64d3a"},
|
||||
{file = "pywin32-306-cp312-cp312-win32.whl", hash = "sha256:383229d515657f4e3ed1343da8be101000562bf514591ff383ae940cad65458b"},
|
||||
{file = "pywin32-306-cp312-cp312-win_amd64.whl", hash = "sha256:37257794c1ad39ee9be652da0462dc2e394c8159dfd913a8a4e8eb6fd346da0e"},
|
||||
{file = "pywin32-306-cp312-cp312-win_arm64.whl", hash = "sha256:5821ec52f6d321aa59e2db7e0a35b997de60c201943557d108af9d4ae1ec7040"},
|
||||
{file = "pywin32-306-cp37-cp37m-win32.whl", hash = "sha256:1c73ea9a0d2283d889001998059f5eaaba3b6238f767c9cf2833b13e6a685f65"},
|
||||
{file = "pywin32-306-cp37-cp37m-win_amd64.whl", hash = "sha256:72c5f621542d7bdd4fdb716227be0dd3f8565c11b280be6315b06ace35487d36"},
|
||||
{file = "pywin32-306-cp38-cp38-win32.whl", hash = "sha256:e4c092e2589b5cf0d365849e73e02c391c1349958c5ac3e9d5ccb9a28e017b3a"},
|
||||
{file = "pywin32-306-cp38-cp38-win_amd64.whl", hash = "sha256:e8ac1ae3601bee6ca9f7cb4b5363bf1c0badb935ef243c4733ff9a393b1690c0"},
|
||||
{file = "pywin32-306-cp39-cp39-win32.whl", hash = "sha256:e25fd5b485b55ac9c057f67d94bc203f3f6595078d1fb3b458c9c28b7153a802"},
|
||||
{file = "pywin32-306-cp39-cp39-win_amd64.whl", hash = "sha256:39b61c15272833b5c329a2989999dcae836b1eed650252ab1b7bfbe1d59f30f4"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pyyaml"
|
||||
version = "6.0.2"
|
||||
@@ -1407,4 +1356,4 @@ test = ["pytest (>=8.1,<9.0)"]
|
||||
[metadata]
|
||||
lock-version = "2.0"
|
||||
python-versions = "^3.10"
|
||||
content-hash = "83ec7de7d9466dcd1fadef4b21eec2a879cc9a7d526992ed280b6af53b49d9f1"
|
||||
content-hash = "7d20e2d0c0c3c8f3a48d9160a2b4a11a5f353d23bb5d7a06ec527fe08e425b91"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[tool.poetry]
|
||||
name = "fastanime"
|
||||
version = "1.0.0"
|
||||
version = "1.1.6.dev1"
|
||||
description = "A browser anime site experience from the terminal"
|
||||
authors = ["Benextempest <benextempest@gmail.com>"]
|
||||
license = "UNLICENSE"
|
||||
@@ -12,12 +12,9 @@ yt-dlp = "^2024.5.27"
|
||||
rich = "^13.7.1"
|
||||
click = "^8.1.7"
|
||||
inquirerpy = "^0.3.4"
|
||||
platformdirs = "^4.2.2"
|
||||
python-dotenv = "^1.0.1"
|
||||
thefuzz = "^0.22.1"
|
||||
requests = "^2.32.3"
|
||||
plyer = "^2.1.0"
|
||||
pyshortcuts = "^1.9.0"
|
||||
|
||||
mpv = "^1.0.7"
|
||||
[tool.poetry.group.dev.dependencies]
|
||||
|
||||
Reference in New Issue
Block a user