mirror of
https://github.com/Benexl/FastAnime.git
synced 2025-12-05 20:40:09 -08:00
feat: improve performance
This commit is contained in:
@@ -1,12 +1,6 @@
|
||||
|
||||
import click
|
||||
|
||||
from .....core.config.model import AppConfig
|
||||
from .....core.constants import ANILIST_AUTH
|
||||
from .....libs.api.factory import create_api_client
|
||||
from .....libs.selectors.selector import create_selector
|
||||
from ....services.auth import AuthService
|
||||
from ....services.feedback import FeedbackService
|
||||
|
||||
|
||||
@click.command(help="Login to your AniList account to enable progress tracking.")
|
||||
@@ -15,6 +9,12 @@ from ....services.feedback import FeedbackService
|
||||
@click.pass_obj
|
||||
def auth(config: AppConfig, status: bool, logout: bool):
|
||||
"""Handles user authentication and credential management."""
|
||||
from .....core.constants import ANILIST_AUTH
|
||||
from .....libs.api.factory import create_api_client
|
||||
from .....libs.selectors.selector import create_selector
|
||||
from ....services.auth import AuthService
|
||||
from ....services.feedback import FeedbackService
|
||||
|
||||
auth_service = AuthService("anilist")
|
||||
feedback = FeedbackService(config.general.icons)
|
||||
selector = create_selector(config)
|
||||
|
||||
@@ -9,14 +9,9 @@ import click
|
||||
from ...core.config import AppConfig
|
||||
from ...core.constants import APP_DIR, USER_CONFIG_PATH
|
||||
from ...libs.api.base import BaseApiClient
|
||||
from ...libs.api.factory import create_api_client
|
||||
from ...libs.players import create_player
|
||||
from ...libs.players.base import BasePlayer
|
||||
from ...libs.providers.anime.base import BaseAnimeProvider
|
||||
from ...libs.providers.anime.provider import create_provider
|
||||
from ...libs.selectors import create_selector
|
||||
from ...libs.selectors.base import BaseSelector
|
||||
from ..config import ConfigLoader
|
||||
from ..services.auth import AuthService
|
||||
from ..services.feedback import FeedbackService
|
||||
from ..services.registry import MediaRegistryService
|
||||
@@ -66,6 +61,11 @@ class Session:
|
||||
|
||||
def _load_context(self, config: AppConfig):
|
||||
"""Initializes all shared services based on the provided configuration."""
|
||||
from ...libs.api.factory import create_api_client
|
||||
from ...libs.players import create_player
|
||||
from ...libs.providers.anime.provider import create_provider
|
||||
from ...libs.selectors import create_selector
|
||||
|
||||
media_registry = MediaRegistryService(
|
||||
media_api=config.general.media_api, config=config.media_registry
|
||||
)
|
||||
@@ -100,6 +100,8 @@ class Session:
|
||||
logger.info("Application context reloaded.")
|
||||
|
||||
def _edit_config(self):
|
||||
from ..config import ConfigLoader
|
||||
|
||||
click.edit(filename=str(USER_CONFIG_PATH))
|
||||
logger.debug("Config changed; Reloading context")
|
||||
loader = ConfigLoader()
|
||||
|
||||
@@ -2,8 +2,6 @@ import re
|
||||
from datetime import datetime
|
||||
from typing import List, Optional
|
||||
|
||||
from yt_dlp.utils import clean_html as ytdlp_clean_html
|
||||
|
||||
from ...libs.api.types import AiringSchedule
|
||||
|
||||
COMMA_REGEX = re.compile(r"([0-9]{3})(?=\d)")
|
||||
@@ -68,9 +66,71 @@ def format_date(dt: Optional[datetime], format_str: str = "%A, %d %B %Y") -> str
|
||||
return dt.strftime(format_str)
|
||||
|
||||
|
||||
def clean_html(raw_html: str) -> str:
|
||||
"""A wrapper around yt-dlp's clean_html to handle None inputs."""
|
||||
return ytdlp_clean_html(raw_html) if raw_html else ""
|
||||
def _htmlentity_transform(entity_with_semicolon):
|
||||
import contextlib
|
||||
import html.entities
|
||||
import html.parser
|
||||
|
||||
"""Transforms an HTML entity to a character."""
|
||||
entity = entity_with_semicolon[:-1]
|
||||
|
||||
# Known non-numeric HTML entity
|
||||
if entity in html.entities.name2codepoint:
|
||||
return chr(html.entities.name2codepoint[entity])
|
||||
|
||||
# TODO: HTML5 allows entities without a semicolon.
|
||||
# E.g. 'Éric' should be decoded as 'Éric'.
|
||||
if entity_with_semicolon in html.entities.html5:
|
||||
return html.entities.html5[entity_with_semicolon]
|
||||
|
||||
mobj = re.match(r"#(x[0-9a-fA-F]+|[0-9]+)", entity)
|
||||
if mobj is not None:
|
||||
numstr = mobj.group(1)
|
||||
if numstr.startswith("x"):
|
||||
base = 16
|
||||
numstr = f"0{numstr}"
|
||||
else:
|
||||
base = 10
|
||||
# See https://github.com/ytdl-org/youtube-dl/issues/7518
|
||||
with contextlib.suppress(ValueError):
|
||||
return chr(int(numstr, base))
|
||||
|
||||
# Unknown entity in name, return its literal representation
|
||||
return f"&{entity};"
|
||||
|
||||
|
||||
def unescapeHTML(s: str):
|
||||
if s is None:
|
||||
return None
|
||||
assert isinstance(s, str)
|
||||
|
||||
return re.sub(r"&([^&;]+;)", lambda m: _htmlentity_transform(m.group(1)), s)
|
||||
|
||||
|
||||
def escapeHTML(text):
|
||||
return (
|
||||
text.replace("&", "&")
|
||||
.replace("<", "<")
|
||||
.replace(">", ">")
|
||||
.replace('"', """)
|
||||
.replace("'", "'")
|
||||
)
|
||||
|
||||
|
||||
def clean_html(html: Optional[str]):
|
||||
"""Clean an HTML snippet into a readable string"""
|
||||
|
||||
if html is None: # Convenience for sanitizing descriptions etc.
|
||||
return html
|
||||
|
||||
html = re.sub(r"\s+", " ", html)
|
||||
html = re.sub(r"(?u)\s?<\s?br\s?/?\s?>\s?", "\n", html)
|
||||
html = re.sub(r"(?u)<\s?/\s?p\s?>\s?<\s?p[^>]*>", "\n", html)
|
||||
# Strip html tags
|
||||
html = re.sub("<.*?>", "", html)
|
||||
# Replace html entities
|
||||
html = unescapeHTML(html)
|
||||
return html.strip()
|
||||
|
||||
|
||||
def format_number_with_commas(number: Optional[int]) -> str:
|
||||
|
||||
@@ -1,10 +1,57 @@
|
||||
TIMEOUT = 10
|
||||
import os
|
||||
import random
|
||||
import re
|
||||
from urllib.parse import unquote, urlparse
|
||||
|
||||
import httpx
|
||||
|
||||
TIMEOUT = 10
|
||||
|
||||
|
||||
def random_user_agent():
|
||||
_USER_AGENT_TPL = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/%s Safari/537.36"
|
||||
_CHROME_VERSIONS = (
|
||||
"90.0.4430.212",
|
||||
"90.0.4430.24",
|
||||
"90.0.4430.70",
|
||||
"90.0.4430.72",
|
||||
"90.0.4430.85",
|
||||
"90.0.4430.93",
|
||||
"91.0.4472.101",
|
||||
"91.0.4472.106",
|
||||
"91.0.4472.114",
|
||||
"91.0.4472.124",
|
||||
"91.0.4472.164",
|
||||
"91.0.4472.19",
|
||||
"91.0.4472.77",
|
||||
"92.0.4515.107",
|
||||
"92.0.4515.115",
|
||||
"92.0.4515.131",
|
||||
"92.0.4515.159",
|
||||
"92.0.4515.43",
|
||||
"93.0.4556.0",
|
||||
"93.0.4577.15",
|
||||
"93.0.4577.63",
|
||||
"93.0.4577.82",
|
||||
"94.0.4606.41",
|
||||
"94.0.4606.54",
|
||||
"94.0.4606.61",
|
||||
"94.0.4606.71",
|
||||
"94.0.4606.81",
|
||||
"94.0.4606.85",
|
||||
"95.0.4638.17",
|
||||
"95.0.4638.50",
|
||||
"95.0.4638.54",
|
||||
"95.0.4638.69",
|
||||
"95.0.4638.74",
|
||||
"96.0.4664.18",
|
||||
"96.0.4664.45",
|
||||
"96.0.4664.55",
|
||||
"96.0.4664.93",
|
||||
"97.0.4692.20",
|
||||
)
|
||||
return _USER_AGENT_TPL % random.choice(_CHROME_VERSIONS)
|
||||
|
||||
|
||||
def get_remote_filename(response: httpx.Response) -> str | None:
|
||||
"""
|
||||
|
||||
@@ -5,7 +5,8 @@ import logging
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from httpx import Client
|
||||
from yt_dlp.utils.networking import random_user_agent
|
||||
|
||||
from ...core.utils.networking import random_user_agent
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from ...core.config import AppConfig
|
||||
|
||||
@@ -11,7 +11,6 @@ from .constants import (
|
||||
EPISODE_GQL,
|
||||
SEARCH_GQL,
|
||||
)
|
||||
from .extractors import extract_server
|
||||
from .parser import (
|
||||
map_to_anime_result,
|
||||
map_to_search_results,
|
||||
@@ -57,6 +56,8 @@ class AllAnime(BaseAnimeProvider):
|
||||
|
||||
@debug_provider
|
||||
def episode_streams(self, params):
|
||||
from .extractors import extract_server
|
||||
|
||||
episode_response = execute_graphql_query_with_get_request(
|
||||
API_GRAPHQL_ENDPOINT,
|
||||
self.client,
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
# from ..utils import int2base
|
||||
import re
|
||||
|
||||
from yt_dlp.utils import encode_base_n, get_element_text_and_html_by_tag
|
||||
|
||||
|
||||
def animepahe_key_creator(c: int, a: int):
|
||||
from yt_dlp.utils import encode_base_n
|
||||
|
||||
if c < a:
|
||||
val_a = ""
|
||||
else:
|
||||
@@ -38,6 +37,8 @@ ENCODE_JS_REGEX = re.compile(r"'(.*?);',(\d+),(\d+),'(.*)'\.split")
|
||||
|
||||
|
||||
def process_animepahe_embed_page(embed_page: str):
|
||||
from yt_dlp.utils import get_element_text_and_html_by_tag
|
||||
|
||||
encoded_js_string = ""
|
||||
embed_page_content = embed_page
|
||||
for _ in range(8):
|
||||
|
||||
@@ -2,12 +2,6 @@ import logging
|
||||
from functools import lru_cache
|
||||
from typing import Iterator, Optional
|
||||
|
||||
from yt_dlp.utils import (
|
||||
extract_attributes,
|
||||
get_element_by_id,
|
||||
get_elements_html_by_class,
|
||||
)
|
||||
|
||||
from ..base import BaseAnimeProvider
|
||||
from ..params import AnimeParams, EpisodeStreamsParams, SearchParams
|
||||
from ..types import Anime, AnimeEpisodeInfo, SearchResult, SearchResults, Server
|
||||
@@ -112,6 +106,13 @@ class AnimePahe(BaseAnimeProvider):
|
||||
|
||||
@debug_provider
|
||||
def episode_streams(self, params: EpisodeStreamsParams) -> Iterator[Server] | None:
|
||||
# TODO: replace with custom implementations using default html parser or lxml
|
||||
from yt_dlp.utils import (
|
||||
extract_attributes,
|
||||
get_element_by_id,
|
||||
get_elements_html_by_class,
|
||||
)
|
||||
|
||||
episode = self._get_episode_info(params)
|
||||
if not episode:
|
||||
logger.error(
|
||||
|
||||
@@ -2,7 +2,6 @@ import importlib
|
||||
import logging
|
||||
|
||||
from httpx import Client
|
||||
from yt_dlp.utils.networking import random_user_agent
|
||||
|
||||
from .base import BaseAnimeProvider
|
||||
from .types import ProviderName
|
||||
@@ -39,6 +38,7 @@ class AnimeProviderFactory:
|
||||
ValueError: If the provider_name is not supported.
|
||||
ImportError: If the provider module or class cannot be found.
|
||||
"""
|
||||
from ....core.utils.networking import random_user_agent
|
||||
|
||||
# Correctly determine module and class name from the map
|
||||
import_path = PROVIDERS_AVAILABLE[provider_name.value.lower()]
|
||||
|
||||
@@ -28,9 +28,9 @@ def test_anime_provider(AnimeProvider: Type[BaseAnimeProvider]):
|
||||
import subprocess
|
||||
|
||||
from httpx import Client
|
||||
from yt_dlp.utils.networking import random_user_agent
|
||||
|
||||
from .....core.constants import APP_ASCII_ART
|
||||
from .....core.utils.networking import random_user_agent
|
||||
from ..params import AnimeParams, EpisodeStreamsParams, SearchParams
|
||||
|
||||
anime_provider = AnimeProvider(
|
||||
|
||||
Reference in New Issue
Block a user