This commit is contained in:
lda committed 2025-12-29 15:03:03 +07:00
1 parent 58d3e58759
commit c09e018bc5
4 files changed
+50 -44

No files matched your search

+41 -6
View File
@@ -4,11 +4,12 @@ import string
from collections import deque from collections import deque
from itertools import islice from itertools import islice
from random import choice from random import choice
from typing import Iterator, Optional, cast from typing import AsyncIterator, Iterator, Optional, TypedDict, cast
from urllib.parse import urlsplit, urlunsplit from urllib.parse import urlsplit, urlunsplit
import fastapi
import urlextract import urlextract
from fastapi import FastAPI, Form, HTTPException, Request from fastapi import Body, FastAPI, Form, HTTPException, Request
from fastapi.responses import HTMLResponse, PlainTextResponse, RedirectResponse from fastapi.responses import HTMLResponse, PlainTextResponse, RedirectResponse
from fastapi.staticfiles import StaticFiles from fastapi.staticfiles import StaticFiles
from fastapi.templating import Jinja2Templates from fastapi.templating import Jinja2Templates
@@ -131,8 +132,12 @@ async def manage_view(request: Request):
) )
class _queueCount(TypedDict):
count: int
@app.post("/api/queue/dedup") @app.post("/api/queue/dedup")
async def api_queue_dedup(): async def api_queue_dedup() -> _queueCount:
"""Deduplicate the queue.""" """Deduplicate the queue."""
global queue global queue
# Preserve order while removing duplicates # Preserve order while removing duplicates
@@ -147,7 +152,7 @@ async def api_queue_dedup():
@app.post("/api/queue/sort") @app.post("/api/queue/sort")
async def api_queue_sort(reverse: bool = False): async def api_queue_sort(reverse: bool = False) -> _queueCount:
"""Sort the queue.""" """Sort the queue."""
global queue global queue
queue = deque(sorted(queue, reverse=reverse)) queue = deque(sorted(queue, reverse=reverse))
@@ -156,15 +161,39 @@ async def api_queue_sort(reverse: bool = False):
# --- Routes: Queue (API) --- # --- Routes: Queue (API) ---
@app.get("/api/queue") @app.get("/api/queue")
async def api_queue_list(n: int | None = None, s: int | None = None): async def api_queue_list(n: int | None = None, s: int | None = None) -> list[str]:
return list(islice(queue, s, n)) return list(islice(queue, s, n))
@app.get("/api/queue/len") @app.get("/api/queue/len")
async def api_queue_len(): async def api_queue_len() -> int:
return len(queue) return len(queue)
@app.post("/api/queue")
async def api_queue_push(uhh: list[str] = Body(default_factory=list)) -> _queueCount:
queue.extend(map(link_extract_from_onetab, uhh))
return {"count": len(queue)}
@app.delete("/api/queue")
async def api_queue_pop(n: int = 1) -> list[str]:
def c() -> Iterator[str]:
for _ in range(n):
if not queue:
break
yield queue.popleft()
return list(c())
@app.get("/api/queue/first")
async def api_queue_first() -> str:
if not queue:
raise HTTPException(fastapi.status.HTTP_404_NOT_FOUND)
return queue[0]
@app.post("/api/queue/clear") @app.post("/api/queue/clear")
async def api_queue_clear(): async def api_queue_clear():
queue.clear() queue.clear()
@@ -248,6 +277,12 @@ async def api_extract_jumblang(request: ExtractRequest):
return list(extract_urls_from_jumblang(request.text)) return list(extract_urls_from_jumblang(request.text))
@app.post("/api/extract/plaintext")
async def api_extract_plaintext(text: str = Body(..., media_type="text/plain")):
"""Extract URLs from messy text using urlextract."""
return list(extract_urls_from_jumblang(text))
def encode_safe(link: str) -> str: def encode_safe(link: str) -> str:
return base64.urlsafe_b64encode(link.encode()).rstrip(b"=").decode() return base64.urlsafe_b64encode(link.encode()).rstrip(b"=").decode()
+3 -3
View File
@@ -149,10 +149,10 @@ body_class %}layout-wide{% endblock %}{% block content %}
if (mode === "jumblang") { if (mode === "jumblang") {
try { try {
const response = await fetch("/api/extract/jumblang", { const response = await fetch("/api/extract/plaintext", {
method: "POST", method: "POST",
headers: { "Content-Type": "application/json" }, headers: { "Content-Type": "text/plain" },
body: JSON.stringify({ text: content }), body: content,
}); });
if (!response.ok) throw new Error("Extraction failed"); if (!response.ok) throw new Error("Extraction failed");
links = await response.json(); links = await response.json();
+6 -4
View File
@@ -64,12 +64,15 @@ import qrcode_queue %}
} }
function filterQueue() { function filterQueue() {
/** @type {HTMLInputElement} */
const input = document.getElementById("search-input"); const input = document.getElementById("search-input");
const filter = input.value.toLowerCase(); const filter = input.value.toLowerCase();
/** @type {NodeListOf<HTMLLIElement>} */
const listItems = document.querySelectorAll(".queue-grid li"); const listItems = document.querySelectorAll(".queue-grid li");
let visibleCount = 0; let visibleCount = 0;
listItems.forEach((li) => { listItems.forEach((li) => {
/** @type {HTMLAnchorElement} */
const link = li.querySelector("a"); const link = li.querySelector("a");
const text = link.textContent || link.innerText; const text = link.textContent || link.innerText;
if (text.toLowerCase().indexOf(filter) > -1) { if (text.toLowerCase().indexOf(filter) > -1) {
@@ -79,10 +82,9 @@ import qrcode_queue %}
li.style.display = "none"; li.style.display = "none";
} }
}); });
/** @type {HTMLParagraphElement} */
document.getElementById( const countDisplay = document.getElementById("count-display");
"count-display" countDisplay.textContent = `Showing: ${visibleCount} / ${listItems.length}`;
).textContent = `Showing: ${visibleCount} / ${listItems.length}`;
} }
</script> </script>
{% endblock %} {% endblock %}
-31
View File
@@ -45,37 +45,6 @@
}); });
// Trigger the message event to run the swap on the next tick // Trigger the message event to run the swap on the next tick
newTab.postMessage(""); newTab.postMessage("");
// background. This block is racing with the slow internet.
if (newTab.document.body) {
newTab.document.body.style.backgroundColor =
getComputedStyle(document.body).backgroundColor;
document
.querySelectorAll("body > *:not(script)")
.forEach((f) =>
newTab.document.body.appendChild(
f.cloneNode(true)
)
);
// maybe just replace the whole document with this one and then use API to check length
// i aint doing that
const st = new newTab.CSSStyleSheet();
[
...document.styleSheets,
...document.adoptedStyleSheets,
].forEach((i) =>
Array.from(i.cssRules).forEach((ii) =>
st.insertRule(
ii.cssText,
st.cssRules.length
)
)
);
newTab.document.adoptedStyleSheets.push(st);
newTab.document.close();
}
} }
}); });
}); });