", status)
# --- Route handlers ---
def handle_search(query):
q = query.get("q", [""])[0].strip()
db = get_db()
count = db.execute("SELECT count(*) FROM pages").fetchone()[0]
name = get_site_name()
result_html = ""
trusted_html = ""
if q:
rows = db.execute(
"SELECT p.id, p.url, p.title, p.body, p.note "
"FROM pages_fts f JOIN pages p ON f.rowid = p.id "
"WHERE pages_fts MATCH ? ORDER BY rank LIMIT 50",
(q,),
).fetchall()
if rows:
for r in rows:
note_html = ""
if r["note"]:
note_html = f'
{esc(r["note"])}
'
result_html += (
f'
'
f'{esc(r["title"])} '
f'{esc(r["url"])} '
f'{esc(snippet(r["body"], q))}'
f'{note_html}'
f'
'
)
else:
result_html = "
No results in your index.
"
# search all linked pages from trusted sites
words = q.lower().split()
all_links = db.execute(
"SELECT l.url, l.label, p.title AS source_title "
"FROM links l JOIN pages p ON l.page_id = p.id",
).fetchall()
indexed_urls = set(r["url"] for r in rows) if rows else set()
seen = set()
trusted = []
for l in all_links:
if l["url"] in indexed_urls or l["url"] in seen:
continue
if any(w in l["label"].lower() for w in words):
seen.add(l["url"])
trusted.append(l)
if len(trusted) >= 20:
break
if trusted:
items = ""
for l in trusted:
items += (
f'
"
f'back'
)
def handle_add_submit(body):
url = body.get("url", [""])[0].strip()
note = body.get("note", [""])[0].strip()
if not url:
return handle_add_form("URL is required.")
if not url.startswith(("http://", "https://")):
return handle_add_form("URL must start with http:// or https://")
try:
title = index_url(url, note)
return handle_add_form(f'Indexed: {esc(title)}')
except Exception as e:
return handle_add_form(f"Error: {esc(str(e))}")
def handle_pages():
db = get_db()
rows = db.execute("SELECT id, url, title, note FROM pages ORDER BY id DESC").fetchall()
db.close()
items = ""
for r in rows:
note_html = f' — {esc(r["note"])}' if r["note"] else ""
items += (
f'
"
f'back'
)
def handle_style_submit(body):
css = body.get("css", [""])[0]
name = body.get("site_name", ["tinyweb"])[0].strip()
sharing = "1" if body.get("sharing_enabled") else "0"
set_setting("custom_css", css)
set_setting("site_name", name or "tinyweb")
set_setting("sharing_enabled", sharing)
return handle_style_form("Saved.")
def handle_api_sites():
if get_setting("sharing_enabled", "0") != "1":
return _json_response(
{"error": "sharing disabled"},
status=403,
headers={"Access-Control-Allow-Origin": "*"},
)
db = get_db()
rows = db.execute("SELECT url, title, note FROM pages ORDER BY id DESC").fetchall()
db.close()
data = {
"name": get_site_name(),
"sites": [{"url": r["url"], "title": r["title"], "note": r["note"]} for r in rows],
}
return _json_response(data, headers={"Access-Control-Allow-Origin": "*"})
def handle_subscriptions(msg=""):
db = get_db()
subs = db.execute("SELECT * FROM subscriptions ORDER BY id DESC").fetchall()
db.close()
items = ""
for s in subs:
auto_label = "on" if s["auto_sync"] else "off"
last = s["last_sync"] or "never"
items += (
f'
'
f'{table}'
f' back'
)
def handle_subscription_add(body):
url = body.get("url", [""])[0].strip().rstrip("/")
if not url or not url.startswith(("http://", "https://")):
return handle_subscriptions("URL must start with http:// or https://")
try:
resp = requests.get(f"{url}/api/sites", timeout=5)
if resp.status_code == 403:
return handle_subscriptions("That instance has sharing disabled.")
resp.raise_for_status()
data = resp.json()
name = data.get("name", "")
except Exception as e:
return handle_subscriptions(f"Could not reach that instance: {esc(str(e))}")
db = get_db()
try:
db.execute(
"INSERT INTO subscriptions (url, name) VALUES (?, ?) "
"ON CONFLICT(url) DO UPDATE SET name=excluded.name",
(url, name),
)
db.commit()
finally:
db.close()
return handle_subscriptions(f"Subscribed to {esc(name or url)}.")
def handle_subscription_browse(sub_id):
db = get_db()
sub = db.execute("SELECT * FROM subscriptions WHERE id = ?", (sub_id,)).fetchone()
if not sub:
db.close()
return _error(404)
local_urls = set(r["url"] for r in db.execute("SELECT url FROM pages").fetchall())
db.close()
try:
resp = requests.get(f"{sub['url']}/api/sites", timeout=5)
if resp.status_code == 403:
return handle_subscriptions("That instance has sharing disabled.")
resp.raise_for_status()
sites = resp.json().get("sites", [])
except Exception as e:
return handle_subscriptions(f"Could not fetch sites: {esc(str(e))}")
new_items = ""
existing_items = ""
new_count = 0
for s in sites:
if s["url"] in local_urls:
existing_items += (
f'