diff --git a/src/app.py b/src/app.py
index 51efd62..d58b301 100644
--- a/src/app.py
+++ b/src/app.py
@@ -1,11 +1,17 @@
from quart import Quart, render_template, request, jsonify
import httpx
-from anilistapi.queries.manga import REQUESTS_QUERY, TAGS_QUERY, GENRES_QUERY
+from anilistapi.queries.manga import (
+ REQUESTS_QUERY,
+ TAGS_QUERY,
+ GENRES_QUERY,
+ REQUESTED_QUERY,
+)
from anilistapi.schemas.manga import Manga
from komconfig import KomConfig
from komcache import KomCache
from komgapi import komgapi as KOMGAPI
from typing import Any, Dict, List
+from limit import limit
app = Quart(__name__)
@@ -13,9 +19,6 @@ cache = KomCache()
cache.create_table(
"CREATE TABLE IF NOT EXISTS manga_requests (id INTEGER PRIMARY KEY, manga_id INTEGER, grabbed BOOLEAN DEFAULT 0)"
)
-cache.create_table(
- "CREATE TABLE IF NOT EXISTS manga_titles (id INTEGER PRIMARY KEY, anilist_id INTEGER DEFAULT 0, komga_title UNIQUE)"
-)
settings = KomConfig()
@@ -25,35 +28,20 @@ komga = KOMGAPI(
password=settings.komga.password,
)
komga_series = komga.seriesList()
-# store the entries in the database table manga_titles, komga_series is a list of strings of the series names
-for series in komga_series:
- # check if the series is already in the database
- existing_series = cache.fetch_one(
- query="SELECT komga_title FROM manga_titles WHERE komga_title = ?",
- args=(series,),
- )
- if existing_series:
- # series already exists, skip
- continue
- else:
- cache.insert(
- # insert into if not in database
- query="INSERT OR IGNORE INTO manga_titles (komga_title) VALUES (?)",
- args=(series,),
- )
-komga_series = [series.lower() for series in komga_series]
-# Update type annotations for fetch_data
-async def fetch_data(data: Dict[str, Any]) -> List[Dict[str, Any]]:
+@limit(90, 60)
+async def fetch_data(
+ data: Dict[str, Any], query: str = REQUESTS_QUERY
+) -> List[Dict[str, Any]]:
async with httpx.AsyncClient() as client:
try:
- variables: Dict[str, Any] = {"search": data["query"]}
- if len(data["genres"]) > 0:
+ variables: Dict[str, Any] = {"search": data["query"], "type": "MANGA"}
+ if data.get("genres"):
variables["genres"] = data["genres"]
- if len(data["tags"]) > 0:
+ if data.get("tags"):
variables["tags"] = data["tags"]
- print(data["query"], variables)
+ # print(data["query"], variables)
response = await client.post(
"https://graphql.anilist.co",
json={
@@ -62,6 +50,7 @@ async def fetch_data(data: Dict[str, Any]) -> List[Dict[str, Any]]:
},
)
response.raise_for_status()
+
data = response.json()
results: List[Dict[str, Any]] = []
@@ -74,9 +63,7 @@ async def fetch_data(data: Dict[str, Any]) -> List[Dict[str, Any]]:
query="SELECT manga_id, grabbed FROM manga_requests WHERE manga_id = ?",
args=(manga.id,),
)
- komga_request = False
- if requested:
- komga_request = True
+ komga_request = bool(requested)
results.append(
{
@@ -109,6 +96,73 @@ async def fetch_data(data: Dict[str, Any]) -> List[Dict[str, Any]]:
return []
+async def fetch_requested_data(data: list[int]) -> List[Dict[str, Any]]:
+ requested_data: list[dict[str, Any]] = []
+ for manga_id in data:
+ async with httpx.AsyncClient() as client:
+ try:
+ variables: Dict[str, Any] = {
+ "search": manga_id,
+ "type": "MANGA",
+ } # TODO: replace the type once the UI has been updated
+ # print(data, variables)
+ response = await client.post(
+ "https://graphql.anilist.co",
+ json={
+ "query": REQUESTED_QUERY,
+ "variables": variables,
+ },
+ )
+ response.raise_for_status()
+ data = response.json()
+
+ # print(data)
+ entry = data.get("data", {}).get("Media", {})
+ if entry:
+ manga = Manga(**entry)
+
+ in_komga = komga.getSeries(
+ manga.title.english
+ if manga.title.english
+ else manga.title.romaji
+ )
+ requested = cache.fetch_one(
+ query="SELECT manga_id, grabbed FROM manga_requests WHERE manga_id = ?",
+ args=(manga.id,),
+ )
+ komga_request = bool(requested)
+
+ requested_data.append(
+ {
+ "id": manga.id,
+ "title": manga.title.english
+ if manga.title.english
+ else manga.title.romaji,
+ "image": manga.coverImage.get("large")
+ if manga.coverImage
+ else "https://demofree.sirv.com/nope-not-here.jpg",
+ "status": manga.status,
+ "type": manga.format,
+ "genres": manga.genres or [],
+ "tags": [tag.name for tag in (manga.tags or [])],
+ "description": manga.description.replace("
", "\n")
+ if manga.description
+ else "No description available",
+ "isAdult": manga.isAdult,
+ "in_komga": in_komga,
+ "requested": komga_request,
+ }
+ )
+
+ except httpx.RequestError as e:
+ print(f"An error occurred while requesting data: {e}")
+ requested_data.append({"id": manga_id})
+ except Exception as e:
+ print(f"Unexpected error: {e}")
+ requested_data.append({"id": manga_id})
+ return requested_data
+
+
@app.route("/api/genres")
async def get_genres():
async with httpx.AsyncClient() as client:
@@ -147,6 +201,7 @@ async def get_tags():
@app.route("/search", methods=["POST"])
async def search():
data = await request.get_json()
+ print(data)
results = await fetch_data(data)
if not results:
return jsonify({"error": "No results found"}), 404
@@ -172,5 +227,21 @@ async def log_request():
return jsonify({"status": "failed"}), 400
+@app.route("/requests", methods=["GET"])
+async def requests_page():
+ requests = (
+ cache.fetch_all(query="SELECT manga_id, grabbed FROM manga_requests") or []
+ )
+ entries: List[Dict[str, Any]] = []
+ req_ids = [req[0] for req in requests]
+ if req_ids:
+ entries = await fetch_requested_data(req_ids)
+ else:
+ entries = []
+ print(entries)
+
+ return await render_template("requests.html", requests=entries)
+
+
if __name__ == "__main__":
app.run(debug=True, host="0.0.0.0", port=5001)
diff --git a/src/static/style.css b/src/static/style.css
index 7ce6d90..cc986aa 100644
--- a/src/static/style.css
+++ b/src/static/style.css
@@ -1,8 +1,9 @@
+/* other styles are in magic.css */
/* ========== GRID LAYOUT ========== */
.results {
display: grid;
- grid-template-columns: repeat(5, 1fr);
- gap: 20px;
+ grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
+ gap: 1em;
margin-top: 20px;
}
@@ -20,11 +21,16 @@
border: 1px solid #ccc;
background: #fafafa;
text-align: center;
- transition: box-shadow 0.2s;
+ transition: box-shadow 0.2s transform 0.2s;
+ border-radius: 10px;
}
.card:hover {
box-shadow: 0 0 10px #aaa;
+ transform: scale(1.1);
+ /* pop out by 10% */
+ z-index: 2;
+ /* ensure it appears above others */
}
.card img {
@@ -39,6 +45,32 @@
justify-content: space-around;
}
+.actions .info {
+ background-color: #007bff;
+ color: white;
+ border: none;
+ padding: 0.5em 1em;
+ cursor: pointer;
+ border-radius: 5px;
+ margin-right: 0.5em;
+}
+
+.actions .info:hover {
+ background-color: #0056b3;
+}
+
+.actions .request {
+ background-color: #28a745;
+ color: white;
+ border: none;
+ padding: 0.5em 1em;
+ cursor: pointer;
+ border-radius: 5px;
+}
+
+.actions .request:hover {
+ background-color: #1e7e34;
+}
/* ========== MODAL ========== */
.modal {
position: fixed;
@@ -84,12 +116,15 @@
/* ========== BLUR CONTROL VIA BODY CLASS ========== */
body.nsfw-disabled .image-container.nsfw img {
- filter: blur(8px);
+ filter: grayscale(100%) blur(5px) !important;
+ /* Ensure the blur is applied */
+ transition: filter 0.3s ease;
+ /* Add smooth transition */
}
body.nsfw-disabled .image-container.nsfw:hover img {
- filter: none;
- /* Remove blur on hover, set as important */
+ filter: none !important;
+ /* Remove blur on hover */
}
@@ -145,10 +180,23 @@ body.nsfw-disabled .image-container.nsfw:hover img {
.reset {
/* Implement design here */
+ background-color: #f44336;
+ /* round the edges of the button */
+ border-radius: 9px;
+
+ }
+
+ .selectors {
+ display: flex;
+ gap: 10px;
+ margin-bottom: 8px;
+ margin-top: 5px;
+ flex-wrap: wrap;
}
.info {
/* Implement design here */
+ background-color: #4CAF50;
}
.request {
@@ -183,4 +231,10 @@ body.nsfw-disabled .image-container.nsfw:hover img {
.card.komga .request {
pointer-events: none;
opacity: 0.5;
+}
+.card.komga:hover,
+.card.requested:hover {
+ transform: none !important;
+ box-shadow: none !important;
+ z-index: auto !important;
}
\ No newline at end of file
diff --git a/src/templates/index.html b/src/templates/index.html
index b850101..6b66161 100644
--- a/src/templates/index.html
+++ b/src/templates/index.html
@@ -4,7 +4,6 @@
{{ result.title }}
-