async ok
This commit is contained in:
parent
cbf978c9ea
commit
8ceebb80ae
@ -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():
|
||||||
|
@ -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)
|
||||||
|
@ -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
|
||||||
|
@ -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:
|
||||||
|
@ -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:
|
||||||
|
9
pynyaata/cache/__init__.py
vendored
9
pynyaata/cache/__init__.py
vendored
@ -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
|
||||||
|
5
pynyaata/cache/redis.py
vendored
5
pynyaata/cache/redis.py
vendored
@ -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}")
|
||||||
|
|
||||||
|
3
pynyaata/cache/simple.py
vendored
3
pynyaata/cache/simple.py
vendored
@ -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]] = {}
|
||||||
|
|
||||||
|
|
||||||
|
@ -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)
|
||||||
|
@ -1,3 +1,7 @@
|
|||||||
.title {
|
.title {
|
||||||
letter-spacing: 0.5rem;
|
letter-spacing: 0.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.navbar-menu {
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
@ -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", "")) }}
|
||||||
|
@ -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 %}
|
||||||
|
@ -3,6 +3,7 @@ from os import path
|
|||||||
|
|
||||||
from flask import request
|
from flask import request
|
||||||
|
|
||||||
|
|
||||||
CATALOG_CACHE = {}
|
CATALOG_CACHE = {}
|
||||||
|
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user