Files

233 lines
9.8 KiB
Python

import traceback
try:
from .config import Config
from .pixiv_client import PixivClient
_config = Config()
_client_instance = PixivClient(_config)
from server import PromptServer
from aiohttp import web
import aiohttp
routes = PromptServer.instance.routes
# ── Auth ──────────────────────────────────────────────────────────────────
@routes.get("/pixiv/status")
async def pixiv_status(request):
# Consider logged-in if we have a saved token — actual auth happens lazily on first API call
logged_in = _client_instance._logged_in or bool(_config.get_refresh_token())
username = ""
if _client_instance._logged_in:
try:
username = str(_client_instance.api.user_id)
except Exception:
pass
return web.json_response({"logged_in": logged_in, "username": username})
# Temporary store for PKCE verifier during auth flow
_pending_verifier = {}
@routes.post("/pixiv/auth/login")
async def pixiv_auth_login(request):
verifier, challenge = _client_instance.generate_pkce()
auth_url = _client_instance.get_login_url(challenge)
_pending_verifier["current"] = verifier
return web.json_response({"auth_url": auth_url})
@routes.post("/pixiv/auth/callback")
async def pixiv_auth_callback(request):
data = await request.json()
redirect_url = data.get("redirect_url", "")
verifier = _pending_verifier.pop("current", None)
if not verifier:
return web.json_response({"error": "No pending auth"}, status=400)
try:
code = _client_instance.extract_code(redirect_url)
_client_instance.login_with_code(code, verifier)
return web.json_response({"ok": True})
except Exception as e:
return web.json_response({"error": str(e)}, status=400)
@routes.post("/pixiv/auth/set_token")
async def pixiv_set_token(request):
data = await request.json()
token = data.get("refresh_token", "").strip()
if not token:
return web.json_response({"error": "refresh_token 不能为空"}, status=400)
try:
import time
_client_instance.api.auth(refresh_token=token)
_client_instance._logged_in = True
_client_instance._auth_time = time.time()
_config.save_refresh_token(token)
return web.json_response({"ok": True})
except Exception as e:
return web.json_response({"error": str(e)}, status=400)
# ── Content ───────────────────────────────────────────────────────────────
@routes.get("/pixiv/recommended")
async def pixiv_recommended(request):
next_url = request.query.get("next_url")
try:
return web.json_response(_client_instance.get_recommended(next_url=next_url))
except RuntimeError as e:
return web.json_response({"error": str(e)}, status=401)
except Exception as e:
return web.json_response({"error": str(e)}, status=500)
@routes.get("/pixiv/ranking")
async def pixiv_ranking(request):
mode = request.query.get("mode", "day")
next_url = request.query.get("next_url")
try:
return web.json_response(_client_instance.get_ranking(mode=mode, next_url=next_url))
except RuntimeError as e:
return web.json_response({"error": str(e)}, status=401)
except Exception as e:
return web.json_response({"error": str(e)}, status=500)
@routes.get("/pixiv/bookmarks")
async def pixiv_bookmarks(request):
next_url = request.query.get("next_url")
try:
return web.json_response(_client_instance.get_bookmarks(next_url=next_url))
except RuntimeError as e:
return web.json_response({"error": str(e)}, status=401)
except Exception as e:
return web.json_response({"error": str(e)}, status=500)
@routes.get("/pixiv/bookmarked_artists")
async def pixiv_bookmarked_artists(request):
next_url = request.query.get("next_url")
try:
return web.json_response(_client_instance.get_bookmarked_artists(next_url=next_url))
except RuntimeError as e:
return web.json_response({"error": str(e)}, status=401)
except Exception as e:
return web.json_response({"error": str(e)}, status=500)
@routes.get("/pixiv/artist/{artist_id}/works")
async def pixiv_artist_works(request):
artist_id = int(request.match_info["artist_id"])
next_url = request.query.get("next_url")
try:
return web.json_response(
_client_instance.get_artist_works(artist_id=artist_id, next_url=next_url)
)
except RuntimeError as e:
return web.json_response({"error": str(e)}, status=401)
except Exception as e:
return web.json_response({"error": str(e)}, status=500)
@routes.post("/pixiv/bookmark")
async def pixiv_add_bookmark(request):
data = await request.json()
illust_id = data.get("illust_id")
if not illust_id:
return web.json_response({"error": "illust_id required"}, status=400)
try:
_client_instance.ensure_logged_in()
_client_instance.api.illust_bookmark_add(int(illust_id))
return web.json_response({"ok": True})
except Exception as e:
return web.json_response({"error": str(e)}, status=500)
@routes.post("/pixiv/bookmark_delete")
async def pixiv_del_bookmark(request):
data = await request.json()
illust_id = data.get("illust_id")
if not illust_id:
return web.json_response({"error": "illust_id required"}, status=400)
try:
_client_instance.ensure_logged_in()
_client_instance.api.illust_bookmark_delete(int(illust_id))
return web.json_response({"ok": True})
except Exception as e:
return web.json_response({"error": str(e)}, status=500)
@routes.get("/pixiv/search/illusts")
async def pixiv_search_illusts(request):
word = request.query.get("word", "")
next_url = request.query.get("next_url")
if not word and not next_url:
return web.json_response({"error": "word required"}, status=400)
try:
return web.json_response(_client_instance.search_illusts(word, next_url=next_url))
except RuntimeError as e:
return web.json_response({"error": str(e)}, status=401)
except Exception as e:
return web.json_response({"error": str(e)}, status=500)
@routes.get("/pixiv/search/users")
async def pixiv_search_users(request):
word = request.query.get("word", "")
next_url = request.query.get("next_url")
if not word and not next_url:
return web.json_response({"error": "word required"}, status=400)
try:
return web.json_response(_client_instance.search_users(word, next_url=next_url))
except RuntimeError as e:
return web.json_response({"error": str(e)}, status=401)
except Exception as e:
return web.json_response({"error": str(e)}, status=500)
@routes.post("/pixiv/follow")
async def pixiv_add_follow(request):
data = await request.json()
user_id = data.get("user_id")
if not user_id:
return web.json_response({"error": "user_id required"}, status=400)
try:
_client_instance.ensure_logged_in()
_client_instance.api.user_follow_add(int(user_id))
return web.json_response({"ok": True})
except Exception as e:
return web.json_response({"error": str(e)}, status=500)
# ── Image Proxy ───────────────────────────────────────────────────────────
@routes.get("/pixiv/image_proxy")
async def pixiv_image_proxy(request):
url = request.query.get("url", "")
if "pximg.net" not in url:
return web.Response(status=403, text="Only pximg.net URLs allowed")
try:
async with aiohttp.ClientSession() as session:
async with session.get(
url,
headers={"Referer": "https://www.pixiv.net/"},
timeout=aiohttp.ClientTimeout(total=30),
) as resp:
data = await resp.read()
ct = resp.headers.get("Content-Type", "image/jpeg")
return web.Response(body=data, content_type=ct)
except Exception as e:
return web.Response(status=502, text=str(e))
# ── Node registration ─────────────────────────────────────────────────────
from .pixiv_node import PixivBrowser
from . import pixiv_node as _pn_mod
_pn_mod._client = _client_instance # inject client — avoids circular import
NODE_CLASS_MAPPINGS = {"PixivBrowser": PixivBrowser}
NODE_DISPLAY_NAME_MAPPINGS = {"PixivBrowser": "Pixiv Browser"}
WEB_DIRECTORY = "./web"
print("[PixivBrowser] Loaded successfully")
except ImportError as e:
print(f"[PixivBrowser] ERROR: Missing dependency — {e}")
print("[PixivBrowser] Run: pip install pixivpy3 Pillow")
NODE_CLASS_MAPPINGS = {}
NODE_DISPLAY_NAME_MAPPINGS = {}
except Exception as e:
print(f"[PixivBrowser] ERROR during load: {e}")
traceback.print_exc()
NODE_CLASS_MAPPINGS = {}
NODE_DISPLAY_NAME_MAPPINGS = {}