1919import urllib .request
2020from pathlib import Path
2121
22- from flask import Flask , redirect , render_template_string , request , send_from_directory
22+ from flask import Flask , redirect , render_template_string , request , send_from_directory , session
2323
2424app = Flask (__name__ )
2525app .secret_key = secrets .token_hex (32 )
@@ -285,6 +285,47 @@ def upsert_env_value(key: str, value: str) -> None:
285285"""
286286)
287287
288+ _PIXIV_CONTINUE_HTML = (
289+ _BASE_STYLE
290+ + """
291+ <div class="card shadow-sm">
292+ <div class="card-body p-4">
293+ <h5 class="card-title mb-3">Pixiv 認証 — ステップ 2/2</h5>
294+
295+ <div class="alert alert-info small mb-3">
296+ ログインは完了しています。<br>
297+ 下のボタンで<strong>認証の続き</strong>を新しいタブで開いてください。<br>
298+ ページが表示されたら、アドレスバーの URL をコピーして下のフォームに貼り付けてください。<br>
299+ <span class="text-muted">(ページが真っ白やエラーでも OK。URL に <code>?code=</code> が入っていれば成功)</span>
300+ </div>
301+
302+ <a href="{{ return_to_url }}" target="_blank" class="btn btn-danger w-100 mb-4">
303+ 認証を続ける(新しいタブで開く)
304+ </a>
305+
306+ <p class="small text-muted mb-1">
307+ コピーする URL の例:<br>
308+ <code>https://app-api.pixiv.net/web/v1/users/auth/pixiv/callback?code=XXXXX…</code>
309+ </p>
310+
311+ <form method="post" action="/pixiv-oauth/exchange">
312+ <div class="input-group">
313+ <input type="text" class="form-control form-control-sm font-monospace"
314+ name="callback_url" required
315+ placeholder="https://app-api.pixiv.net/…/callback?code=...">
316+ <button type="submit" class="btn btn-primary btn-sm">取得して保存</button>
317+ </div>
318+ </form>
319+
320+ <div class="mt-3">
321+ <a href="/" class="small text-muted">← セットアップに戻る</a>
322+ </div>
323+ </div>
324+ </div>
325+ </body></html>
326+ """
327+ )
328+
288329_GALLERY_INDEX_HTML = (
289330 _BASE_STYLE
290331 + """
@@ -438,8 +479,6 @@ def save_pixiv_token():
438479@app .route ("/pixiv-oauth/start" )
439480def pixiv_oauth_start ():
440481 """PKCE コードを生成して Pixiv 認証 URL を返す。"""
441- from flask import session
442-
443482 # gallery-dl と同じ方法で生成 (hex 文字列)
444483 code_verifier = os .urandom (32 ).hex ()
445484 digest = hashlib .sha256 (code_verifier .encode ()).digest ()
@@ -459,23 +498,30 @@ def pixiv_oauth_start():
459498@app .route ("/pixiv-oauth/exchange" , methods = ["POST" ])
460499def pixiv_oauth_exchange ():
461500 """コールバック URL からコードを取り出してリフレッシュトークンに交換する。"""
462- from flask import session
463-
464501 callback_url = request .form .get ("callback_url" , "" ).strip ()
465- code_verifier = session .pop ("pixiv_code_verifier" , None )
502+ code_verifier = session .get ("pixiv_code_verifier" )
466503
467504 if not code_verifier :
468505 return redirect ("/?pixiv_error=セッションが切れました。もう一度やり直してください。" )
469506
470- params = urllib .parse .parse_qs (urllib .parse .urlparse (callback_url ).query )
507+ parsed = urllib .parse .urlparse (callback_url )
508+ params = urllib .parse .parse_qs (parsed .query )
471509 codes = params .get ("code" , [])
510+
511+ # post-redirect URL が貼られた場合は return_to を取り出して中継ページへ
512+ if not codes and ("post-redirect" in callback_url or "return_to" in params ):
513+ return_to = params .get ("return_to" , ["" ])[0 ]
514+ if return_to :
515+ return render_template_string (_PIXIV_CONTINUE_HTML , return_to_url = return_to )
516+ msg = "URLを解析できませんでした。ページをリロードして最初からやり直してください。"
517+ return redirect (f"/?pixiv_error={ urllib .parse .quote (msg )} " )
518+
472519 if not codes :
473- if "post-redirect" in callback_url or "return_to" in callback_url :
474- msg = "リダイレクト途中のURLが貼られています。ブラウザがapp-api.pixiv.net/.../callback?code=...に到達してからコピーしてください。"
475- else :
476- msg = "URLにcodeが含まれていません。アドレスバーのURLをそのままコピーしてください。"
520+ msg = "URLにcodeが含まれていません。アドレスバーのURLをそのままコピーしてください。"
477521 return redirect (f"/?pixiv_error={ urllib .parse .quote (msg )} " )
478522
523+ session .pop ("pixiv_code_verifier" , None )
524+
479525 data = urllib .parse .urlencode ({
480526 "client_id" : _PIXIV_CLIENT_ID ,
481527 "client_secret" : _PIXIV_CLIENT_SECRET ,
0 commit comments