From 589d7e6e9eefc6123ad12916ce55cc04b365860f Mon Sep 17 00:00:00 2001 From: ALVES-Ethan <86202958+SHARKgamestudio@users.noreply.github.com> Date: Mon, 14 Sep 2026 13:37:50 +0200 Subject: [PATCH 01/14] feat(docs): add standalone token extractor (get_tokens.py + run_get_tokens.bat) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Guided browser wizard that pulls DeepSeek/Qwen auth tokens via a bookmarklet and a local 127.0.0.1-only server; .bat locates a Python 3.6+ interpreter and forwards extra args. 🤖 --- docs/get_tokens.py | 1068 +++++++++++++++++++++++++++++++++++++++ docs/run_get_tokens.bat | 37 ++ 2 files changed, 1105 insertions(+) create mode 100644 docs/get_tokens.py create mode 100644 docs/run_get_tokens.bat diff --git a/docs/get_tokens.py b/docs/get_tokens.py new file mode 100644 index 0000000..2bc31e7 --- /dev/null +++ b/docs/get_tokens.py @@ -0,0 +1,1068 @@ +#!/usr/bin/env python3 +""" +get_tokens.py — Extract DeepSeek & Qwen tokens for DanyAPI. + +Uses your DEFAULT browser (no automation, no dependencies). + + python get_tokens.py + +Flow: + 1. A tiny local server starts (127.0.0.1:8765) and a page opens in your + default browser. + 2. Step by step wizard: first drag the "🔍 Run DanyAPI token utility" button to + your bookmarks bar (one time only), click Next. + 3. The page guides you to DeepSeek: log in, click the grabber bookmark + there. The token is sent silently, the DeepSeek tab closes itself, + the wizard shows a success flash and automatically moves on to Qwen. + 4. Same for Qwen — and when both tokens are in, you land on a results + screen with your tokens ready to copy. + +Everything stays local: the server binds to 127.0.0.1 only. +""" + +from __future__ import annotations + +import argparse +import io +import json +import re +import sys +import webbrowser +from datetime import datetime +from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer +from typing import Any + +# Windows consoles often default to cp1252 which can't render emoji/box glyphs. +if sys.stdout.encoding and sys.stdout.encoding.lower() not in ("utf-8", "utf8"): + sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding="utf-8", errors="replace") + sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding="utf-8", errors="replace") + +RESULT_PORT = 8765 + +DEEPSEEK_URL = "https://chat.deepseek.com/" +QWEN_URL = "https://chat.qwen.ai/auth?action=signin" + +# ---------------------------------------------------------------------------- +# Visible text (edit here - no need to dig into the HTML below) +# +# Strings used inside the static HTML go through __KEY__ placeholders; strings +# used by the page's JavaScript are injected as JSON and read via t("key"). +# ---------------------------------------------------------------------------- + +TEXTS: dict[str, str] = { + # --- Wizard page ----------------------------------------------------- + "page_title": "DanyAPI - Token Utils", + "header_title": "Token Utilities", + "header_sub": "DanyAPI uses the internal APIs of DeepSeek and Qwen's free web clients, so it needs your auth tokens.
This tool simply helps you to retrieve them.", + # Step 0 - bookmarklet + "step0_heading": "One-time: add the token utility bookmarklet", + "step0_intro": "Drag this button onto your browser's bookmarks bar,
(press Ctrl+Shift+B if you don't see the bar):", + "bookmarklet_label": "🔍 Run DanyAPI token utility", + "bookmarklet_aria": "DanyAPI token utility - drag this button onto your bookmarks bar", + "step0_fineprint": "Why is this necessary? We know this looks weird and unfamiliar, but while other methods for extracting tokens exist, they are not browser-agnostic. This bookmarklet will execute JavaScript in the context of the provider's page (deepseek.com or qwen.ai), extract your token, and send it to this page.", + "step0_next": "I added the bookmarklet - Next →", + # Step 1 - DeepSeek + "step1_heading": "DeepSeek token", + "step1_p1": "1. Open DeepSeek by clicking the button below.", + "step1_p2": "2. Sign in to your account if needed.", + "step1_p3": "3. On the DeepSeek page, click your “🔍 Run DanyAPI token utility” bookmark.", + "step1_fineprint": "The tab closes automatically after the token is sent. If the token is valid, a green checkmark will appear on this page and you will be guided to the next step within a few seconds. Overwise a red cross will appear, and you can click the button below to try again.", + "step1_button": "Open DeepSeek →", + "step1_waiting": "Waiting for the DeepSeek token…", + # Step 2 - Qwen + "step2_heading": "Qwen token", + "step2_p1": "1. Open Qwen by clicking the button below.", + "step2_p2": "2. Sign in to your account if needed.", + "step2_p3": "3. On the Qwen page, click the “🔍 Run DanyAPI token utility” bookmark.", + "step2_fineprint": "The tab closes automatically after the token is sent. If the token is valid, a green checkmark will appear on this page and you will be guided to the next step within a few seconds. Overwise a red cross will appear, and you can click the button below to try again.", + "step2_button": "Open Qwen →", + "step2_waiting": "Waiting for the Qwen token…", + # Step 3 - done + "step3_heading": "Tokens successfully extracted!", + "step3_text": "Redirecting to your tokens…", + # Footer + "footer_public_instance": "Public Instance", + "footer_docs": "Docs", + "footer_github": "GitHub", + "footer_public_url": "https://danyapi.cloudpub.ru", + "footer_docs_url": "https://danyapi.cloudpub.ru/docs/", + "footer_github_url": "https://github.com/FANATFANATA/DanyAPI", + # --- Wizard page JS -------------------------------------------------- + "js_title_wizard": "🔑 DanyAPI token utilities", + "js_title_step1": "🤖 Step 1 of 2 - DeepSeek", + "js_title_step2": "🤖 Step 2 of 2 - Qwen", + "js_title_done": "🎉 All done!", + "js_alert_popup_blocked": "Popup blocked! Please allow popups for this page and try again.", + "js_ok_both": "✔ {provider} token received! Redirecting to your tokens shortly…", + "js_ok_deepseek": "✔ DeepSeek token received! Moving on to Qwen shortly…", + "js_ok_qwen": "✔ Qwen token received! Moving to your tokens shortly…", + "js_fail": "✖ No token found - you are probably not logged in. Log in on {provider}, then try again.", + # --- Results page ---------------------------------------------------- + "results_page_title": "DanyAPI - Your tokens", + "results_title": "Your Tokens", + "results_sub": "Tokens for DeepSeek & Qwen were successfully extracted. Use them in your .env when running the API locally.

To support us, you can also add them to the public API instance: {public_url}", + "results_public_instance": "Public instance", + "results_pane_ds": "DeepSeek token", + "results_pane_qw": "Qwen token", + "results_copy": "Copy", + "results_copied": "✓ Copied", + "results_no_token": "❌ No token received - complete the setup page first.", + "results_footer_again": "Run utility again", + "results_footer_docs": "Docs", + "results_footer_github": "GitHub", + # --- Popup page (shown in the provider tab after collection) -------- + "popup_title": "Token received", + "popup_message": "✔ Token received - you can close this tab and return to the DanyAPI page.", +} + +# ---------------------------------------------------------------------------- +# Shared state +# ---------------------------------------------------------------------------- + +STATE: dict[str, Any] = { + "deepseek": None, + "qwen": None, + "deepseek_failed": False, + "qwen_failed": False, +} + +# ---------------------------------------------------------------------------- +# Bookmarklet (runs on chat.deepseek.com / chat.qwen.ai, sends token to us) +# +# IMPORTANT: this source gets collapsed into ONE line by build_bookmarklet(), +# so it must contain NO '//' comments and every statement must end with ';' +# (automatic-semicolon-insertion disappears when newlines are removed). +# ---------------------------------------------------------------------------- + +BOOKMARKLET_SOURCE = r''' +(function () { + var host = location.hostname.toLowerCase(); + var isDeepSeek = host === "chat.deepseek.com" || host.endsWith(".deepseek.com"); + var isQwen = host === "chat.qwen.ai" || host.endsWith(".qwen.ai"); + if (!isDeepSeek && !isQwen) { + alert("Please run the DanyAPI token utility on DeepSeek or Qwen."); + return; + } + var p = isDeepSeek ? "deepseek" : "qwen"; + function pt(raw, depth) { + if (typeof raw !== "string") return null; + var v = raw.trim(); + if (!v) return null; + // Only accept values that actually look like auth tokens (JWT or hex), + // never random storage junk: a logged-out page must NOT produce a + // "success". Same rules are enforced server-side in register_token(). + if (/^eyJ[A-Za-z0-9._-]{20,}/.test(v) || /^[a-f0-9]{32,}$/i.test(v)) return v; + if (depth >= 4) return null; + try { + var j = JSON.parse(v); + if (typeof j === "string") return pt(j, depth + 1); + if (typeof j === "object" && j !== null) { + // Recursively unwrap ANY JSON shape ({"value":"..."}, + // {"token":{"value":"..."}}, ...) and return the first + // token-shaped string found. + for (var key in j) { + var t = pt(j[key], depth + 1); + if (t) return t; + } + } + } catch (e) {} + return null; + } + function scan(st) { + var ks = p === "deepseek" ? ["userToken", "token"] : ["token", "userToken"]; + for (var a = 0; a < ks.length; a++) { + var t = pt(st.getItem(ks[a]), 0); + if (t) return t; + } + // Fallback scan: only entries whose KEY name mentions "token". Without + // this guard, unrelated IDs (device ids, analytics ids...) that happen to + // be 32+ hex chars get grabbed on logged-out pages and fake a success. + for (var b = 0; b < st.length; b++) { + var k = st.key(b); + if (!/token/i.test(k)) continue; + var t2 = pt(st.getItem(k), 0); + if (t2) return t2; + } + return null; + } + // The providers store auth as a known key, but may wrap refreshed values + // several times (for example {"value":"{\\"token\\":\\"...\\"}"}). + // Unwrap only those known auth records; do not inspect unrelated storage. + function opaqueValue(raw, depth) { + if (typeof raw !== "string") return null; + var value = raw.trim(); + if (!value || depth > 5) return null; + if (value.length >= 16 && !/\s/.test(value) && value.charAt(0) !== "{" && value.charAt(0) !== "[" && value.charAt(0) !== "\"") return value; + try { + var obj = JSON.parse(value); + if (typeof obj === "string") return opaqueValue(obj, depth + 1); + if (!obj || typeof obj !== "object") return null; + var preferred = ["value", "token", "accessToken", "access_token", "userToken"]; + for (var i = 0; i < preferred.length; i++) { + var found = opaqueValue(obj[preferred[i]], depth + 1); + if (found) return found; + } + } catch (e) {} + return null; + } + function find() { + var t = scan(localStorage); + if (t) return t; + t = scan(sessionStorage); + if (t) return t; + var keys = p === "deepseek" ? ["userToken", "token"] : ["token", "userToken"]; + for (var i = 0; i < keys.length; i++) { + t = opaqueValue(localStorage.getItem(keys[i]), 0) || opaqueValue(sessionStorage.getItem(keys[i]), 0); + if (t) return t; + } + return null; + } + var token = find(); + // Always report back, even with no token: the local server marks the + // attempt as failed and the wizard shows a red hint instead of a green + // checkmark, so a logged-out click can never look like a success. + // Deliver via top-level navigation, NOT fetch/sendBeacon: browsers gate + // cross-site requests to 127.0.0.1 behind a "local network / device + // services" permission prompt, but plain navigations are always allowed. + location.href = "http://127.0.0.1:__PORT__/collect?p=" + encodeURIComponent(p) + + "&t=" + encodeURIComponent(token || ""); +})() +''' + + +def build_bookmarklet(port: int) -> str: + """Collapse the readable source into a one-line javascript: URL.""" + src = BOOKMARKLET_SOURCE.replace("__PORT__", str(port)) + lines = [ln.strip() for ln in src.strip().splitlines()] + lines = [ln for ln in lines if ln and not ln.startswith("//")] + one_line = "javascript:" + " ".join(lines) + # Safety net: a stray '//' would comment out everything after it once the + # code is on a single line ("http://" is the only legitimate use). + assert "http://" in one_line + assert "//" not in one_line.replace("http://", ""), \ + "bookmarklet source contains a // comment — it would break on one line" + return one_line + + +def html_escape(s: str) -> str: + return s.replace("&", "&").replace("<", "<").replace(">", ">").replace('"', """) + + +# ---------------------------------------------------------------------------- +# Guided wizard page (step by step) +# ---------------------------------------------------------------------------- + +SETUP_PAGE = r""" + + + + +__page_title__ + + + + + + + + + + + +
+
+ + + DanyAPI + +

__header_title__

+

__header_sub__

+
+
+ + +
+

0 __step0_heading__

+

__step0_intro__

+

+ __bookmarklet_label__ +

+

__step0_fineprint__

+ +
+ + + + + + + + + + + +
+ + + + +""" + +# ---------------------------------------------------------------------------- +# Results page +# ---------------------------------------------------------------------------- + +RESULTS_PAGE = r""" + + + + +__results_page_title__ + + + + + + + + + + + +
+
+ + + DanyAPI + +

__results_title__

+

__RESULTS_SUB__

+
+ +
+
+ +

DeepSeek

+
+
+
__results_pane_ds__
+
__DEEPSEEK_TOKEN__
+
+
+ +
+
+ +

Qwen

+
+
+
__results_pane_qw__
+
__QWEN_TOKEN__
+
+
+ + +
+ + + + +""" + + +def _apply_texts(template: str, extra: dict[str, str] | None = None) -> str: + """Fill __key__ placeholders with the TEXTS config (plus any extra values).""" + out = template + for key, value in TEXTS.items(): + out = out.replace(f"__{key}__", value) + if extra: + for key, value in extra.items(): + out = out.replace(f"__{key}__", value) + return out + + +def render_setup_page() -> str: + texts_json = json.dumps(TEXTS, ensure_ascii=False) + return ( + _apply_texts( + SETUP_PAGE, + { + "BOOKMARKLET": html_escape(build_bookmarklet(RESULT_PORT)), + "DEEPSEEK_URL": DEEPSEEK_URL, + "QWEN_URL": QWEN_URL, + "HAS_DEEPSEEK": "true" if STATE["deepseek"] else "false", + "HAS_QWEN": "true" if STATE["qwen"] else "false", + "TEXTS_JSON": texts_json, + }, + ) + ) + + +def render_results_page() -> str: + def show(tok: str | None) -> str: + return html_escape(tok) if tok else TEXTS["results_no_token"] + + public_url = TEXTS["footer_public_url"] + return _apply_texts( + RESULTS_PAGE, + { + "DEEPSEEK_TOKEN": show(STATE["deepseek"]), + "QWEN_TOKEN": show(STATE["qwen"]), + "RESULTS_SUB": TEXTS["results_sub"].replace("{public_url}", public_url), + }, + ) + + +# ---------------------------------------------------------------------------- +# Local HTTP server +# ---------------------------------------------------------------------------- + + +SUCCESS_PAGE = r""" +__popup_title__ + + + + + + +""" + + +def register_token(provider: str, token: str) -> bool: + """Validate and store a token. Returns True on success. + + Must stay in sync with the bookmarklet's client-side checks: only + token-shaped values from the provider's auth storage count, so a logged-out + provider page (or random localStorage junk) cannot be registered. An + empty/invalid token records a failed attempt instead (visible in /status). + """ + if provider not in ("deepseek", "qwen"): + return False + # The provider can rotate from JWT/hex to an opaque bearer value and may + # use characters outside the URL-safe subset. The bookmarklet only sends + # values from the provider's known auth record, so validate shape here + # without imposing a token alphabet. + if token and re.fullmatch(r"\S{16,4096}", token): + STATE[provider] = token + STATE[provider + "_failed"] = False + print(f" ✔ {provider} token received ({len(token)} chars)") + return True + STATE[provider + "_failed"] = True + print(f" ✖ {provider}: no valid token found (user probably not logged in)") + return False + + +class Handler(BaseHTTPRequestHandler): + def _send(self, body: bytes, status: int = 200, ctype: str = "text/html; charset=utf-8") -> None: + self.send_response(status) + self.send_header("Content-Type", ctype) + self.send_header("Content-Length", str(len(body))) + self.send_header("Cache-Control", "no-store") + # CORS + Private Network Access: requests arriving here come from + # https://chat.deepseek.com etc. Chrome requires these headers or it + # silently drops the request (PNA preflight). + self.send_header("Access-Control-Allow-Origin", "*") + self.send_header("Access-Control-Allow-Methods", "GET, POST, OPTIONS") + self.send_header("Access-Control-Allow-Headers", "*") + if self.headers.get("Access-Control-Request-Private-Network"): + self.send_header("Access-Control-Allow-Private-Network", "true") + self.end_headers() + self.wfile.write(body) + + def do_OPTIONS(self) -> None: + self.send_response(204) + self.send_header("Access-Control-Allow-Origin", "*") + self.send_header("Access-Control-Allow-Methods", "GET, POST, OPTIONS") + self.send_header("Access-Control-Allow-Headers", "*") + if self.headers.get("Access-Control-Request-Private-Network"): + self.send_header("Access-Control-Allow-Private-Network", "true") + self.send_header("Content-Length", "0") + self.end_headers() + + def do_GET(self) -> None: + from urllib.parse import parse_qs, urlsplit + parts = urlsplit(self.path) + path = parts.path + if path == "/status": + self._send(json.dumps({k: v for k, v in STATE.items() if not k.endswith("_failed") or v}).encode(), ctype="application/json") + elif path == "/results": + self._send(render_results_page().encode()) + elif path == "/collect": + # Top-level navigation fallback: /collect?p=deepseek&t=TOKEN + qs = parse_qs(parts.query) + provider = (qs.get("p") or [""])[0] + token = (qs.get("t") or [""])[0].strip() + if register_token(provider, token): + self._send(SUCCESS_PAGE.encode()) + else: + # Invalid/missing token: still close the tab like a success — + # the wizard itself shows the red "no token" hint via /status. + self._send(SUCCESS_PAGE.encode()) + else: # "/" and anything else -> setup page + self._send(render_setup_page().encode()) + + def do_POST(self) -> None: + if self.path.split("?")[0] != "/collect": + self._send(b"not found", 404) + return + try: + length = int(self.headers.get("Content-Length") or 0) + raw = self.rfile.read(length).decode("utf-8", errors="replace") + # sendBeacon may send text/plain; strip junk before parsing + data = json.loads(raw) + if register_token(data.get("provider") or "", (data.get("token") or "").strip()): + self._send(b'{"ok":true}', ctype="application/json") + else: + self._send(b'{"ok":false}', 400, ctype="application/json") + except Exception: + self._send(b'{"ok":false}', 400, ctype="application/json") + + def log_message(self, *args: Any) -> None: + pass + + +def serve() -> None: + server = ThreadingHTTPServer(("127.0.0.1", RESULT_PORT), Handler) + url = f"http://127.0.0.1:{RESULT_PORT}" + print(f" Local page: {url}") + print(" (Ctrl+C in this window to stop when you're done.)\n") + print(" Opening your default browser…") + webbrowser.open_new_tab(url) + try: + server.serve_forever() + except KeyboardInterrupt: + pass + finally: + server.server_close() + + +# ---------------------------------------------------------------------------- +# Main +# ---------------------------------------------------------------------------- + + +def main() -> None: + global RESULT_PORT + parser = argparse.ArgumentParser(description="Extract DeepSeek & Qwen tokens for DanyAPI (uses your default browser)") + parser.add_argument("--port", type=int, default=RESULT_PORT, help=f"local server port (default {RESULT_PORT})") + parser.add_argument("--no-browser", action="store_true", help="don't auto-open the browser") + args = parser.parse_args() + RESULT_PORT = args.port + + print("=" * 60) + print(" DanyAPI token extractor") + print(" DeepSeek + Qwen → DEEPSEEK_TOKENS / QWEN_TOKENS") + print("=" * 60) + print(" 1. Drag the grabber button to your bookmarks bar (once), click Next") + print(" 2. DeepSeek: log in, click the grabber bookmark — page auto-advances") + print(" 3. Qwen: same again — then both tokens are shown automatically\n") + + serve() + + +if __name__ == "__main__": + main() diff --git a/docs/run_get_tokens.bat b/docs/run_get_tokens.bat new file mode 100644 index 0000000..b7bf88c --- /dev/null +++ b/docs/run_get_tokens.bat @@ -0,0 +1,37 @@ +@echo off +setlocal +title DanyAPI Token Extractor +cd /d "%~dp0" + +rem Locate a Python interpreter (any version 3.6+, 32 or 64-bit - no deps needed) +set "PY=" + +where python >nul 2>nul && set "PY=python" +if not defined PY ( + where py >nul 2>nul && set "PY=py -3" +) +if not defined PY ( + if exist "%LocalAppData%\Programs\Python\Python310-32\python.exe" ( + set "PY=%LocalAppData%\Programs\Python\Python310-32\python.exe" + ) +) + +if not defined PY ( + echo [ERROR] Python not found. Install Python 3.6+ from https://python.org + echo and make sure "Add Python to PATH" is checked. + pause + exit /b 1 +) + +echo Using interpreter: %PY% +echo. + +%PY% get_tokens.py %* +if errorlevel 1 ( + echo. + echo [ERROR] Script exited with an error. + pause + exit /b 1 +) + +endlocal From bd427d7539e9a1645e6e13777d83f09a3a7e2316 Mon Sep 17 00:00:00 2001 From: ALVES-Ethan <86202958+SHARKgamestudio@users.noreply.github.com> Date: Mon, 14 Sep 2026 13:39:07 +0200 Subject: [PATCH 02/14] fix(docs): replace em-dashes in get_tokens.py to satisfy repo guards MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit check_repo_guards() bans U+2014/U+2013 in docs/ text files; the copied script had 8 of them. Replaced with ASCII hyphens, no content changes. 🤖 --- docs/get_tokens.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/docs/get_tokens.py b/docs/get_tokens.py index 2bc31e7..e6efcf6 100644 --- a/docs/get_tokens.py +++ b/docs/get_tokens.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 """ -get_tokens.py — Extract DeepSeek & Qwen tokens for DanyAPI. +get_tokens.py - Extract DeepSeek & Qwen tokens for DanyAPI. Uses your DEFAULT browser (no automation, no dependencies). @@ -14,7 +14,7 @@ 3. The page guides you to DeepSeek: log in, click the grabber bookmark there. The token is sent silently, the DeepSeek tab closes itself, the wizard shows a success flash and automatically moves on to Qwen. - 4. Same for Qwen — and when both tokens are in, you land on a results + 4. Same for Qwen - and when both tokens are in, you land on a results screen with your tokens ready to copy. Everything stays local: the server binds to 127.0.0.1 only. @@ -240,7 +240,7 @@ def build_bookmarklet(port: int) -> str: # code is on a single line ("http://" is the only legitimate use). assert "http://" in one_line assert "//" not in one_line.replace("http://", ""), \ - "bookmarklet source contains a // comment — it would break on one line" + "bookmarklet source contains a // comment - it would break on one line" return one_line @@ -558,7 +558,7 @@ def html_escape(s: str) -> str: function showToken(n, provider) { const wait = document.getElementById("wait" + n); if (!wait) return; - // Grey out the provider button — no need to open the tab again. + // Grey out the provider button - no need to open the tab again. const btn = document.getElementById("btn-open-" + provider); if (btn) { btn.classList.add("disabled"); btn.removeAttribute("onclick"); } // Green validation message also tells the user what happens next. @@ -918,7 +918,7 @@ def show(tok: str | None) -> str: SUCCESS_PAGE = r""" __popup_title__ - @@ -999,7 +999,7 @@ def do_GET(self) -> None: if register_token(provider, token): self._send(SUCCESS_PAGE.encode()) else: - # Invalid/missing token: still close the tab like a success — + # Invalid/missing token: still close the tab like a success - # the wizard itself shows the red "no token" hint via /status. self._send(SUCCESS_PAGE.encode()) else: # "/" and anything else -> setup page @@ -1058,8 +1058,8 @@ def main() -> None: print(" DeepSeek + Qwen → DEEPSEEK_TOKENS / QWEN_TOKENS") print("=" * 60) print(" 1. Drag the grabber button to your bookmarks bar (once), click Next") - print(" 2. DeepSeek: log in, click the grabber bookmark — page auto-advances") - print(" 3. Qwen: same again — then both tokens are shown automatically\n") + print(" 2. DeepSeek: log in, click the grabber bookmark - page auto-advances") + print(" 3. Qwen: same again - then both tokens are shown automatically\n") serve() From defaa2b20d2fbfa7dd34489d90cc2f06f5ef0da1 Mon Sep 17 00:00:00 2001 From: ALVES-Ethan <86202958+SHARKgamestudio@users.noreply.github.com> Date: Mon, 14 Sep 2026 13:39:34 +0200 Subject: [PATCH 03/14] fix(docs): drop unused datetime import in get_tokens.py (ruff F401) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 🤖 --- docs/get_tokens.py | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/get_tokens.py b/docs/get_tokens.py index e6efcf6..f49d687 100644 --- a/docs/get_tokens.py +++ b/docs/get_tokens.py @@ -28,7 +28,6 @@ import re import sys import webbrowser -from datetime import datetime from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer from typing import Any From 69fe01fc99e3175c46d49e96dc8c124580ed391d Mon Sep 17 00:00:00 2001 From: ALVES-Ethan <86202958+SHARKgamestudio@users.noreply.github.com> Date: Mon, 14 Sep 2026 13:49:25 +0200 Subject: [PATCH 04/14] style(docs): wrap lines over 160 chars in get_tokens.py (ruff E501) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Python string literals: adjacent-literal concatenation (identical values) - Favicon / fonts / noise data-URIs: shared constants injected via the existing __key__ placeholder machinery (also fully percent-encodes the noise SVG, which previously mixed raw spaces with %20) - HTML: break between attributes, with a neutralizing comment between inline elements so no whitespace node is introduced - CSS: break between declarations inside rules Rendered setup/results pages and the bookmarklet are unchanged except for comment text and the percent-encoded noise URI. 🤖 --- docs/get_tokens.py | 112 ++++++++++++++++++++++++++++++++++++--------- 1 file changed, 90 insertions(+), 22 deletions(-) diff --git a/docs/get_tokens.py b/docs/get_tokens.py index f49d687..4027716 100644 --- a/docs/get_tokens.py +++ b/docs/get_tokens.py @@ -52,20 +52,25 @@ # --- Wizard page ----------------------------------------------------- "page_title": "DanyAPI - Token Utils", "header_title": "Token Utilities", - "header_sub": "DanyAPI uses the internal APIs of DeepSeek and Qwen's free web clients, so it needs your auth tokens.
This tool simply helps you to retrieve them.", + "header_sub": "DanyAPI uses the internal APIs of DeepSeek and Qwen's free web clients, so it needs your auth tokens." + "
This tool simply helps you to retrieve them.", # Step 0 - bookmarklet "step0_heading": "One-time: add the token utility bookmarklet", "step0_intro": "Drag this button onto your browser's bookmarks bar,
(press Ctrl+Shift+B if you don't see the bar):", "bookmarklet_label": "🔍 Run DanyAPI token utility", "bookmarklet_aria": "DanyAPI token utility - drag this button onto your bookmarks bar", - "step0_fineprint": "Why is this necessary? We know this looks weird and unfamiliar, but while other methods for extracting tokens exist, they are not browser-agnostic. This bookmarklet will execute JavaScript in the context of the provider's page (deepseek.com or qwen.ai), extract your token, and send it to this page.", + "step0_fineprint": "Why is this necessary? We know this looks weird and unfamiliar, but while other methods for" + " extracting tokens exist, they are not browser-agnostic. This bookmarklet will execute JavaScript in the" + " context of the provider's page (deepseek.com or qwen.ai), extract your token, and send it to this page.", "step0_next": "I added the bookmarklet - Next →", # Step 1 - DeepSeek "step1_heading": "DeepSeek token", "step1_p1": "1. Open DeepSeek by clicking the button below.", "step1_p2": "2. Sign in to your account if needed.", "step1_p3": "3. On the DeepSeek page, click your “🔍 Run DanyAPI token utility” bookmark.", - "step1_fineprint": "The tab closes automatically after the token is sent. If the token is valid, a green checkmark will appear on this page and you will be guided to the next step within a few seconds. Overwise a red cross will appear, and you can click the button below to try again.", + "step1_fineprint": "The tab closes automatically after the token is sent. If the token is valid, a green checkmark" + " will appear on this page and you will be guided to the next step within a few seconds. Overwise a red cross will" + " appear, and you can click the button below to try again.", "step1_button": "Open DeepSeek →", "step1_waiting": "Waiting for the DeepSeek token…", # Step 2 - Qwen @@ -73,7 +78,9 @@ "step2_p1": "1. Open Qwen by clicking the button below.", "step2_p2": "2. Sign in to your account if needed.", "step2_p3": "3. On the Qwen page, click the “🔍 Run DanyAPI token utility” bookmark.", - "step2_fineprint": "The tab closes automatically after the token is sent. If the token is valid, a green checkmark will appear on this page and you will be guided to the next step within a few seconds. Overwise a red cross will appear, and you can click the button below to try again.", + "step2_fineprint": "The tab closes automatically after the token is sent. If the token is valid, a green checkmark" + " will appear on this page and you will be guided to the next step within a few seconds. Overwise a red cross will" + " appear, and you can click the button below to try again.", "step2_button": "Open Qwen →", "step2_waiting": "Waiting for the Qwen token…", # Step 3 - done @@ -99,7 +106,9 @@ # --- Results page ---------------------------------------------------- "results_page_title": "DanyAPI - Your tokens", "results_title": "Your Tokens", - "results_sub": "Tokens for DeepSeek & Qwen were successfully extracted. Use them in your .env when running the API locally.

To support us, you can also add them to the public API instance: {public_url}", + "results_sub": "Tokens for DeepSeek & Qwen were successfully extracted. Use them in your .env when" + " running the API locally.

To support us, you can also add them to the public API instance:" + " {public_url}", "results_public_instance": "Public instance", "results_pane_ds": "DeepSeek token", "results_pane_qw": "Qwen token", @@ -125,6 +134,47 @@ "qwen_failed": False, } +# ---------------------------------------------------------------------------- +# Shared HTML assets +# +# The setup page and the results page are visually identical shells, so these +# assets are defined once and injected through the same __key__ placeholder +# machinery used for TEXTS (see _apply_texts). All three are plain URL/URI +# strings; the setup/results templates embed them verbatim. +# ---------------------------------------------------------------------------- + +# Inline SVG favicon (DanyAPI hexagon logo) as a data: URI, URL-encoded. +FAVICON_DATA_URI = ( + "data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2040%2040'%3E" + "%3Cdefs%3E%3ClinearGradient%20id='g'%20x1='0'%20y1='0'%20x2='1'%20y2='1'%3E" + "%3Cstop%20offset='0'%20stop-color='%236c7bff'/%3E%3Cstop%20offset='1'%20stop-color='%2322d3ee'/%3E" + "%3C/linearGradient%3E%3C/defs%3E" + "%3Cpath%20d='M20%202.5L35%2011V29L20%2037.5L5%2029V11Z'%20fill='none'%20stroke='url(%23g)'" + "%20stroke-width='2.6'%20stroke-linejoin='round'/%3E" + "%3Cpath%20d='M20%2013.5L12.5%2026.5H27.5Z'%20fill='none'%20stroke='url(%23g)'" + "%20stroke-width='1.8'%20stroke-linejoin='round'/%3E" + "%3Ccircle%20cx='20'%20cy='13.5'%20r='3'%20fill='url(%23g)'/%3E" + "%3Ccircle%20cx='12.5'%20cy='26.5'%20r='3'%20fill='url(%23g)'/%3E" + "%3Ccircle%20cx='27.5'%20cy='26.5'%20r='3'%20fill='url(%23g)'/%3E%3C/svg%3E" +) + +# Single Google Fonts request covering all families/weights used by both pages. +FONTS_CSS_URL = ( + "https://fonts.googleapis.com/css2?" + "family=Unbounded:wght@500;700;900" + "&family=Manrope:wght@400;500;600;700;800" + "&family=JetBrains+Mono:wght@400;500;600;700" + "&display=swap" +) + +# Inline SVG feTurbulence noise overlay as a data: URI, URL-encoded. +NOISE_DATA_URI = ( + "url(\"data:image/svg+xml,%3Csvg%20xmlns='http://www.w3.org/2000/svg'%20width='120'%20height='120'%3E" + "%3Cfilter%20id='n'%3E%3CfeTurbulence%20type='fractalNoise'%20baseFrequency='0.9'%20numOctaves='2'/%3E" + "%3C/filter%3E%3Crect%20width='120'%20height='120'%20filter='url(%23n)'/%3E%3C/svg%3E" + '\")' +) + # ---------------------------------------------------------------------------- # Bookmarklet (runs on chat.deepseek.com / chat.qwen.ai, sends token to us) # @@ -257,10 +307,10 @@ def html_escape(s: str) -> str: __page_title__ - + - +