", 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'
'
)
trusted_html = (
f''
f'from your trusted sites ({len(trusted)})'
f'
{items}
'
f''
)
# search synced pages from subscriptions
remote_rows = db.execute(
"SELECT rp.url, rp.title, rp.note, s.name AS source_name "
"FROM remote_pages_fts rpf "
"JOIN remote_pages rp ON rpf.rowid = rp.id "
"JOIN subscriptions s ON rp.subscription_id = s.id "
"WHERE remote_pages_fts MATCH ? ORDER BY rank LIMIT 50",
(q,),
).fetchall()
remote_html = ""
if q and remote_rows:
# group by source
by_source = {}
for r in remote_rows:
source = r["source_name"] or "unknown"
by_source.setdefault(source, []).append(r)
for source, items in by_source.items():
source_items = ""
for r in items:
note_html = f' — {esc(r["note"])}' if r["note"] else ""
source_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'
{esc(s["name"] or "unknown")} {esc(s["dest_hash"])}
'
f'{table}'
f' back'
)
def handle_subscription_add(body):
dest_hash = body.get("dest_hash", [""])[0].strip().replace("<", "").replace(">", "")
if not dest_hash or len(dest_hash) != 32:
return handle_subscriptions("Enter a valid 32-character destination hash.")
try:
int(dest_hash, 16)
except ValueError:
return handle_subscriptions("Invalid destination hash (must be hex).")
try:
data = fetch_remote_sites(dest_hash)
name = data.get("name", "")
except PermissionError:
return handle_subscriptions("That instance has sharing disabled.")
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 (dest_hash, name) VALUES (?, ?) "
"ON CONFLICT(dest_hash) DO UPDATE SET name=excluded.name",
(dest_hash, name),
)
db.commit()
finally:
db.close()
return handle_subscriptions(f"Subscribed to {esc(name or dest_hash)}.")
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())
# Use locally synced data if available, otherwise fetch live
remote_rows = db.execute(
"SELECT url, title, note FROM remote_pages WHERE subscription_id = ?",
(sub_id,),
).fetchall()
db.close()
if remote_rows:
sites = [{"url": r["url"], "title": r["title"], "note": r["note"]} for r in remote_rows]
else:
try:
data = fetch_remote_sites(sub["dest_hash"])
sites = data.get("sites", [])
except PermissionError:
return handle_subscriptions("That instance has sharing disabled.")
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'