This commit is contained in:
Michel Roux 2023-01-04 16:57:16 +01:00
parent cbf978c9ea
commit 8ceebb80ae
14 changed files with 69 additions and 29 deletions

View File

@ -1,11 +1,14 @@
import asyncio
from datetime import datetime from datetime import datetime
from secrets import token_hex from secrets import token_hex
from flask import Flask, render_template from flask import Flask, redirect, render_template, request, url_for
from pynyaata.bridge import search_all
from pynyaata.forms import SearchForm from pynyaata.forms import SearchForm
from pynyaata.translations import current_lang, i18n from pynyaata.translations import current_lang, i18n
app = Flask(__name__) app = Flask(__name__)
app.config["SECRET_KEY"] = token_hex() app.config["SECRET_KEY"] = token_hex()
@ -33,7 +36,13 @@ def index():
@app.route("/search") @app.route("/search")
def search(): def search():
return render_template("search.html.j2") query = request.args.get("q")
if not query:
return redirect(url_for("index"))
torrents = asyncio.run(search_all(query))
return render_template("search.html.j2", torrents=torrents)
def run(): def run():

View File

@ -1,6 +1,25 @@
from asyncio import create_task, gather
from typing import List
from pynyaata.bridge.animeultime import AnimeUltime from pynyaata.bridge.animeultime import AnimeUltime
from pynyaata.bridge.nyaa import EraiRaws, Nyaa from pynyaata.bridge.nyaa import EraiRaws, Nyaa
from pynyaata.bridge.yggtorrent import YggAnimation, YggTorrent from pynyaata.bridge.yggtorrent import YggAnimation, YggTorrent
from pynyaata.types import Bridge, RemoteFile
BRIDGES = [Nyaa(), EraiRaws(), YggTorrent(), YggAnimation(), AnimeUltime()] BRIDGES: List[Bridge] = [
Nyaa(),
EraiRaws(),
YggTorrent(),
YggAnimation(),
AnimeUltime(),
]
async def search_all(query: str = "", page: int = 1) -> List[RemoteFile]:
tasks = []
for bridge in BRIDGES:
tasks.append(create_task(bridge.search(query, page)))
return await gather(*tasks)

View File

@ -35,7 +35,7 @@ class AnimeUltime(Bridge):
@cache_data @cache_data
@filter_data @filter_data
def search(self, query: str = "", page: int = 1) -> List[RemoteFile]: async def search(self, query: str = "", page: int = 1) -> List[RemoteFile]:
response = ( response = (
requests.post(self.search_url(query, page), {"search": query}) requests.post(self.search_url(query, page), {"search": query})
if query if query

View File

@ -39,7 +39,7 @@ class Nyaa(Bridge):
@cache_data @cache_data
@filter_data @filter_data
def search(self, query: str = "", page: int = 1) -> List[RemoteFile]: async def search(self, query: str = "", page: int = 1) -> List[RemoteFile]:
response = requests.get(self.search_url(query, page)) response = requests.get(self.search_url(query, page))
if response.status_code != 200: if response.status_code != 200:

View File

@ -34,7 +34,7 @@ class YggTorrent(Bridge):
@cache_data @cache_data
@filter_data @filter_data
def search(self, query: str = "", page: int = 1) -> List[RemoteFile]: async def search(self, query: str = "", page: int = 1) -> List[RemoteFile]:
response = FlareRequests().get(self.search_url(query, page)) response = FlareRequests().get(self.search_url(query, page))
if response.status_code != 200: if response.status_code != 200:

View File

@ -9,7 +9,6 @@ from pynyaata.types import Cache
from redis import RedisError from redis import RedisError
CACHE_TIMEOUT = int(getenv("CACHE_TIMEOUT", 60 * 60))
REDIS_URL: Optional[str] = getenv("REDIS_URL") REDIS_URL: Optional[str] = getenv("REDIS_URL")
client: Cache = SimpleCache() client: Cache = SimpleCache()
@ -25,15 +24,17 @@ if REDIS_URL:
def cache_data(f): def cache_data(f):
@wraps(f) @wraps(f)
def wrapper(*args, **kwds): async def wrapper(*args, **kwds):
bridge = args[0] bridge = args[0]
key = f"pynyaata.{bridge.__class__.__name__}.{f.__name__}.{bridge.query}.{bridge.page}" query = args[1]
page = args[2]
key = f"pynyaata.{bridge.__class__.__name__}.{f.__name__}.{query}.{page}"
ret = client.get(key) ret = client.get(key)
if ret: if ret:
return ret return ret
ret = f(*args, **kwds) ret = await f(*args, **kwds)
client.set(key, ret) client.set(key, ret)
return ret return ret

View File

@ -1,12 +1,15 @@
from json import dumps, loads from json import dumps, loads
from os import getenv
from typing import List, Optional from typing import List, Optional
from pynyaata.cache import CACHE_TIMEOUT, REDIS_URL
from pynyaata.types import Cache, RemoteFile from pynyaata.types import Cache, RemoteFile
from redis import ConnectionError, Redis from redis import ConnectionError, Redis
CACHE_TIMEOUT = int(getenv("CACHE_TIMEOUT", 60 * 60))
REDIS_URL: Optional[str] = getenv("REDIS_URL")
if not REDIS_URL: if not REDIS_URL:
raise ConnectionError(f"Invalid REDIS_URL: {REDIS_URL}") raise ConnectionError(f"Invalid REDIS_URL: {REDIS_URL}")

View File

@ -1,10 +1,11 @@
from datetime import datetime, timedelta from datetime import datetime, timedelta
from os import getenv
from typing import Dict, List, Optional, Tuple from typing import Dict, List, Optional, Tuple
from pynyaata.cache import CACHE_TIMEOUT
from pynyaata.types import Cache, RemoteFile from pynyaata.types import Cache, RemoteFile
CACHE_TIMEOUT = int(getenv("CACHE_TIMEOUT", 60 * 60))
CACHE_DATA: Dict[str, Tuple[List[RemoteFile], datetime]] = {} CACHE_DATA: Dict[str, Tuple[List[RemoteFile], datetime]] = {}

View File

@ -50,8 +50,8 @@ def danger(remotes: List[RemoteFile]) -> List[RemoteFile]:
def filter_data(f): def filter_data(f):
@wraps(f) @wraps(f)
def wrapper(*args, **kwds): async def wrapper(*args, **kwds):
ret = f(*args, **kwds) ret = await f(*args, **kwds)
ret = duplicate(ret) ret = duplicate(ret)
ret = inactive(ret) ret = inactive(ret)

View File

@ -1,3 +1,7 @@
.title { .title {
letter-spacing: 0.5rem; letter-spacing: 0.5rem;
} }
.navbar-menu {
box-shadow: none;
}

View File

@ -3,7 +3,7 @@
<section class="hero is-fullheight-with-navbar"> <section class="hero is-fullheight-with-navbar">
<div class="hero-body m-auto is-flex-direction-column is-justify-content-center"> <div class="hero-body m-auto is-flex-direction-column is-justify-content-center">
<p class="title mb-6 is-size-1">{{ _("𝚷😼た") }}</p> <p class="title mb-6 is-size-1">{{ _("𝚷😼た") }}</p>
<form action="{{ url_for('index') }}" class="subtitle"> <form action="{{ url_for('search') }}" class="subtitle">
<div class="field has-addons"> <div class="field has-addons">
<div class="control"> <div class="control">
{{ search_form.q(placeholder=_("Search animes ..."), class="input", value=request.args.get("q", "")) }} {{ search_form.q(placeholder=_("Search animes ..."), class="input", value=request.args.get("q", "")) }}

View File

@ -24,25 +24,27 @@
{% if request.endpoint != "index" %} {% if request.endpoint != "index" %}
<nav class="navbar" role="navigation" aria-label="main navigation"> <nav class="navbar" role="navigation" aria-label="main navigation">
<div class="navbar-brand"> <div class="navbar-brand">
<a class="navbar-item" href="{{ url_for('index') }}">{{ _("π😼た") }}</a> <a class="navbar-item" href="{{ url_for('index') }}">{{ _("𝚷😼た") }}</a>
</div> </div>
<div class="navbar-start"> <div class="navbar-start">
{% block links %} {% block links %}
{% endblock links %} {% endblock links %}
</div> </div>
<div class="navbar-end"> <div class="navbar-menu">
<form action="{{ url_for('index') }}" class="navbar-item"> <div class="navbar-end">
<div class="field has-addons"> <form action="{{ url_for('search') }}" class="navbar-item">
<div class="control"> <div class="field has-addons">
{{ search_form.q(placeholder=_("Search animes ..."), class="input", value=request.args.get("q", "")) }} <div class="control">
{{ search_form.q(placeholder=_("Search animes ..."), class="input", value=request.args.get("q", "")) }}
</div>
<div class="control">
<button type="submit" class="button">
<i class="fa fa-search"></i>
</button>
</div>
</div> </div>
<div class="control"> </form>
<button type="submit" class="button"> </div>
<i class="fa fa-search"></i>
</button>
</div>
</div>
</form>
</div> </div>
</nav> </nav>
{% endif %} {% endif %}

View File

@ -3,6 +3,7 @@ from os import path
from flask import request from flask import request
CATALOG_CACHE = {} CATALOG_CACHE = {}

View File

@ -50,7 +50,7 @@ class Bridge(BaseModel, ABC):
pass pass
@abstractmethod @abstractmethod
def search(self, query: str = "", page: int = 1) -> List[RemoteFile]: async def search(self, query: str = "", page: int = 1) -> List[RemoteFile]:
pass pass