from db import get_db, return_db, get_setting, set_setting, get_site_name import templates as templates_mod from templates import esc, DEFAULT_TEMPLATE from ._helpers import _respond, _csrf_field, _get_bookmark_token from .subscriptions import _count_shared_pages def handle_style_form(msg="", gateway_host="", scheme="http"): template = get_setting("custom_template") or DEFAULT_TEMPLATE name = get_site_name() sharing = get_setting("sharing_enabled", "0") checked = " checked" if sharing == "1" else "" sharing_mode = get_setting("sharing_mode", "exclude_private") forum = get_setting("forum_enabled", "0") forum_checked = " checked" if forum == "1" else "" exclude_checked = " checked" if sharing_mode != "require_public" else "" require_checked = " checked" if sharing_mode == "require_public" else "" shared_count = _count_shared_pages() semantic = get_setting("semantic_search", "0") semantic_checked = " checked" if semantic == "1" else "" reranker = get_setting("use_reranker", "0") reranker_checked = " checked" if reranker == "1" else "" disabled = "" if semantic == "1" else " disabled" dimmed = ' style="opacity:0.4"' if semantic != "1" else "" tcp_enabled = get_setting("tcp_enabled", "1") tcp_checked = " checked" if tcp_enabled == "1" else "" tcp_disabled = "" if tcp_enabled == "1" else " disabled" transport_host = get_setting("transport_host", "rnode.bre.land") transport_port = get_setting("transport_port", "4242") compress = get_setting("compress_embeddings", "0") compress_checked = " checked" if compress == "1" else "" lora_enabled = get_setting("lora_enabled", "0") lora_checked = " checked" if lora_enabled == "1" else "" lora_disabled = "" if lora_enabled == "1" else " disabled" lora_dimmed = ' style="opacity:0.4"' if lora_enabled != "1" else "" lora_port = get_setting("lora_port", "") lora_frequency = get_setting("lora_frequency", "867200000") lora_bandwidth = get_setting("lora_bandwidth", "125000") lora_txpower = get_setting("lora_txpower", "7") lora_sf = get_setting("lora_sf", "8") lora_cr = get_setting("lora_cr", "5") from handlers import forum_plugin as _fp if _fp is not None: forum_section = ( f"

forum

" f'
" f"Share URLs and discuss them with other TinyWeb instances. " f"Requires tinyweb-forum — " f'more info.

' ) else: forum_section = "" return _respond( f"

customize

" f"

name your search engine

" f'
' f'{_csrf_field()}' f'

' f"

sharing

" f'
" f'
' f"What to share:
" f'
' f'
' f'The private tag always excludes a page, even in public-only mode.' f'
' f'

' f'Currently sharing {shared_count} page(s). ' f'preview what subscribers would see' f'

' f"

mesh network

" f"

Choose how to connect to the mesh. You can enable both for maximum reach.

" f"

internet

" f'
" f"Reach peers anywhere online.
" f'
' f"Default: rnode.bre.land:4242
" f'' f'
' f'

discover more nodes

' f'

' f"

LoRa

" f'
" f"Reach nearby peers off-grid with an RNode.

" f'
' f'

' f'
advanced radio settings' f'
' f'
' f"ISM band frequency. Default: 867200000 (868 MHz EU). US: 915000000.

" f'
' f"Default: 125000

" f'
' f"0-17 typical. Check local regulations.

" f'
' f"5-12. Higher = longer range, slower speed.

" f'
' f"5-8. Higher = more error correction.
" f'

' f"

search

" f"

ai

" f'
" f"Requires onnxruntime, tokenizers, hnswlib. Downloads ~30MB of models on first use.

" f'
' f'
" f"Uses a 22MB model. Adds ~50ms per search. Disable for faster results.

" f'
" f"Saves ~50% on storage for embeddings. Slight quality reduction at large scale.

" f'manage semantic index

' f"
" f"{forum_section}" f"

custom html

" f"

Edit the full page template. Use {esc('{{content}}')} " f"where page content should appear.

" f'

' f'' f"
" f"

bookmarklet

" f"

Drag this link to your bookmarks bar. Click it on any page to index it instantly.

" f'

r.text()).then(t=>alert(t)).catch(()=>alert(\'tinyweb not running\')))">+ save to {esc(name)}

' f"

reset

" f'
' f'{_csrf_field()}' f'' f"
" f"

maintenance

" f'
' f'{_csrf_field()}' f'' f"
" f"

{msg}

" f'back', use_default=True, ) def handle_style_submit(body, gateway_host="", scheme="http"): template = body.get("template", [""])[0].replace("\r\n", "\n").replace("\r", "\n") name = body.get("site_name", ["tinyweb"])[0].strip() sharing = "1" if body.get("sharing_enabled") else "0" sharing_mode = body.get("sharing_mode", ["exclude_private"])[0] if sharing_mode not in ("exclude_private", "require_public"): sharing_mode = "exclude_private" set_setting("sharing_mode", sharing_mode) semantic = "1" if body.get("semantic_search") else "0" reranker = "1" if body.get("use_reranker") else "0" compress = "1" if body.get("compress_embeddings") else "0" tcp_enabled = "1" if body.get("tcp_enabled") else "0" transport_host = body.get("transport_host", [""])[0].strip() transport_port = body.get("transport_port", [""])[0].strip() set_setting("custom_template", template if template.strip() != DEFAULT_TEMPLATE.strip() else "") set_setting("site_name", name or "tinyweb") set_setting("sharing_enabled", sharing) set_setting("semantic_search", semantic) set_setting("use_reranker", reranker) set_setting("compress_embeddings", compress) set_setting("tcp_enabled", tcp_enabled) if transport_host: set_setting("transport_host", transport_host) if transport_port: set_setting("transport_port", transport_port) lora_enabled = "1" if body.get("lora_enabled") else "0" set_setting("lora_enabled", lora_enabled) set_setting("lora_port", body.get("lora_port", [""])[0].strip()) set_setting("lora_frequency", body.get("lora_frequency", ["867200000"])[0].strip()) set_setting("lora_bandwidth", body.get("lora_bandwidth", ["125000"])[0].strip()) set_setting("lora_txpower", body.get("lora_txpower", ["7"])[0].strip()) set_setting("lora_sf", body.get("lora_sf", ["8"])[0].strip()) set_setting("lora_cr", body.get("lora_cr", ["5"])[0].strip()) forum_enabled = "1" if body.get("forum_enabled") else "0" current_forum = get_setting("forum_enabled", "0") if forum_enabled != current_forum: from handlers import forum_plugin if forum_enabled == "1" and forum_plugin is None: return handle_style_form( "Forum plugin not installed. Run: pip install tinyweb-forum", gateway_host=gateway_host, scheme=scheme, ) if forum_enabled == "1": forum_plugin.enable() try: forum_plugin.fdb.set_setting("forum_enabled", "1") except Exception: pass else: forum_plugin.disable() try: forum_plugin.fdb.set_setting("forum_enabled", "0") except Exception: pass set_setting("forum_enabled", forum_enabled) templates_mod.FORUM_ENABLED = (forum_enabled == "1") return handle_style_form("Saved. Restart TinyWeb for mesh network changes to take effect.", gateway_host=gateway_host, scheme=scheme) def handle_about(): name = get_site_name() dest_hash = get_setting("dest_hash") sharing = get_setting("sharing_enabled", "0") == "1" db = get_db() try: page_count = db.execute("SELECT count(*) FROM pages").fetchone()[0] tag_count = db.execute("SELECT count(DISTINCT tag_id) FROM page_tags").fetchone()[0] sub_count = db.execute("SELECT count(*) FROM subscriptions").fetchone()[0] finally: return_db(db) sharing_html = ( '

This instance shares its index publicly. Subscribe to join the network.

' if sharing else '

This instance is private.

' ) hash_html = "" if dest_hash: hash_html = ( f'

subscribe

' f'

To subscribe to this instance, add this destination hash in your TinyWeb:

' f'
{esc(dest_hash)}
' ) return _respond( f'

{esc(name)}

' f'

A personal, decentralized search engine.

' f'

You save pages you find. They are stored locally and shared over a mesh network ' f'so other people can find them too.

' f'

Search results come from your index and the indexes of people you are connected to.

' f'' f'{sharing_html}' f'{hash_html}' f'

your data

' f'

Everything is stored locally under ~/.tinyweb/:

' f'' f'

Back up ~/.tinyweb/ periodically. ' f'Copying the whole directory to another device preserves your identity and index together. ' f'The export page gives you a JSON dump of pages only — ' f'it does not preserve your identity or subscription state, so it is a migration aid, ' f'not a substitute for a full backup.

' f'

search | browse | tags

' )