decentralized and customizable links page on top of atproto ligo.at
atproto link-in-bio python uv
9
fork

Configure Feed

Select the types of activity you want to include in your feed.

add own typeahead endpoint

+47 -2
+7
packages/xrpc/pyproject.toml
··· 1 + [project] 2 + name = "xrpc" 3 + version = "0.0.0" 4 + 5 + [build-system] 6 + requires = ["uv_build>=0.10.0,<0.11.0"] 7 + build-backend = "uv_build"
+26
packages/xrpc/src/xrpc/__init__.py
··· 1 + from urllib.parse import urljoin 2 + 3 + from aiohttp.client import ClientSession 4 + from flask import Blueprint, request 5 + 6 + xrpc = Blueprint("xrpc", __name__, url_prefix="/xrpc") 7 + 8 + 9 + @xrpc.get("/app.bsky.actor.searchActorsTypeahead") 10 + async def search_actors_typeahead(): 11 + base = "https://public.api.bsky.app" 12 + url = urljoin(base, "xrpc/app.bsky.actor.searchActorsTypeahead") 13 + url += f"?{request.query_string.decode('utf-8')}" 14 + async with ClientSession() as client: 15 + async with client.get(url) as response: 16 + json = await response.json() 17 + try: 18 + res = [ 19 + {"avatar": actor["avatar"], "handle": actor["handle"]} 20 + for actor in json["actors"] 21 + ] 22 + return { 23 + "actors": res, 24 + } 25 + except KeyError: 26 + return json
+3 -1
pyproject.toml
··· 11 11 "flask-htmx>=0.4.0", 12 12 "flask[async,dotenv]>=3.1.2", 13 13 "gunicorn>=25.0.3", 14 - "ingestor==0.0.0", 14 + "ingestor", 15 + "xrpc", 15 16 ] 16 17 17 18 [tool.uv.sources] 18 19 ingestor = { workspace = true } 20 + xrpc = { workspace = true } 19 21 20 22 [tool.uv.workspace] 21 23 members = ["packages/*"]
+2
src/main.py
··· 6 6 from flask import Flask, g, redirect, render_template, request, session, url_for 7 7 from flask_htmx import HTMX 8 8 from flask_htmx import make_response as htmx_response 9 + from xrpc import xrpc 9 10 10 11 from src.atproto import ( 11 12 get_record, ··· 27 28 app = Flask(__name__) 28 29 _ = app.config.from_prefixed_env() 29 30 app.register_blueprint(oauth) 31 + app.register_blueprint(xrpc) 30 32 htmx = HTMX() 31 33 htmx.init_app(app) 32 34 init_db(app, name="config")
+1 -1
src/templates/login.html
··· 21 21 <form action="{{ url_for('auth_login') }}" method="post"> 22 22 <label> 23 23 <span>Handle</span> 24 - <actor-typeahead> 24 + <actor-typeahead host="location"> 25 25 <input 26 26 type="text" 27 27 name="username"
+8
uv.lock
··· 6 6 members = [ 7 7 "ingestor", 8 8 "ligo-at", 9 + "xrpc", 9 10 ] 10 11 11 12 [[package]] ··· 397 398 { name = "flask-htmx" }, 398 399 { name = "gunicorn" }, 399 400 { name = "ingestor" }, 401 + { name = "xrpc" }, 400 402 ] 401 403 402 404 [package.metadata] ··· 408 410 { name = "flask-htmx", specifier = ">=0.4.0" }, 409 411 { name = "gunicorn", specifier = ">=25.0.3" }, 410 412 { name = "ingestor", editable = "packages/ingestor" }, 413 + { name = "xrpc", editable = "packages/xrpc" }, 411 414 ] 412 415 413 416 [[package]] ··· 597 600 wheels = [ 598 601 { url = "https://files.pythonhosted.org/packages/ad/e4/8d97cca767bcc1be76d16fb76951608305561c6e056811587f36cb1316a8/werkzeug-3.1.5-py3-none-any.whl", hash = "sha256:5111e36e91086ece91f93268bb39b4a35c1e6f1feac762c9c822ded0a4e322dc", size = 225025, upload-time = "2026-01-08T17:49:21.859Z" }, 599 602 ] 603 + 604 + [[package]] 605 + name = "xrpc" 606 + version = "0.0.0" 607 + source = { editable = "packages/xrpc" } 600 608 601 609 [[package]] 602 610 name = "yarl"