From cea457ff94113b8ce0f20904dc6bf854118d20fd Mon Sep 17 00:00:00 2001
From: Azalea <22280294+hykilpikonna@users.noreply.github.com>
Date: Fri, 13 Mar 2026 21:13:23 -0400
Subject: [PATCH] [+] Bubble graph
---
.gitignore | 2 +-
public/bubble.html | 205 +++++++++++++++++++++++++++++++++++++++++++++
src/bot.py | 36 ++++++++
uv.lock | 14 ++++
4 files changed, 256 insertions(+), 1 deletion(-)
create mode 100644 public/bubble.html
diff --git a/.gitignore b/.gitignore
index 570bf9d..acdd999 100644
--- a/.gitignore
+++ b/.gitignore
@@ -161,5 +161,5 @@ cython_debug/
*.iml
config.toml
public/index.html
-admin
+admin.html
user_states.json
\ No newline at end of file
diff --git a/public/bubble.html b/public/bubble.html
new file mode 100644
index 0000000..6c9b3a3
--- /dev/null
+++ b/public/bubble.html
@@ -0,0 +1,205 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/bot.py b/src/bot.py
index 9338fa0..6ab24ca 100644
--- a/src/bot.py
+++ b/src/bot.py
@@ -586,6 +586,42 @@ def api_tree():
return tree_to_dict("azaneko")
+@app.get("/api/graph_data")
+def api_graph_data():
+ nodes = []
+ links = []
+
+ r_chan = re.compile(r"([\d ]+) subscribers")
+ r_grp = re.compile(r"([\d ]+) members")
+
+ for entity in db.Channel.select().where(db.Channel.hidden == False):
+ html_t = channel_html(entity.username)
+
+ subs = 0
+ if m1 := r_chan.search(html_t):
+ subs = int(m1.group(1).replace(" ", ""))
+ elif m2 := r_grp.search(html_t):
+ subs = int(m2.group(1).replace(" ", ""))
+
+ waters = db.get_votes(entity.username)
+
+ nodes.append({
+ "id": entity.username,
+ "name": entity.name,
+ "subscribers": subs,
+ "waters": waters,
+ "height": entity.height
+ })
+
+ if entity.parent_id:
+ links.append({
+ "source": entity.parent_id,
+ "target": entity.username
+ })
+
+ return {"nodes": nodes, "links": links}
+
+
@app.get("/api/admin/channels")
def api_admin_channels(x_admin_password: str = Header(None)):
if x_admin_password not in CONFIG.get("admin-passwords", [CONFIG.get("init-password")]):
diff --git a/uv.lock b/uv.lock
index 00e3370..8050c9f 100644
--- a/uv.lock
+++ b/uv.lock
@@ -58,6 +58,7 @@ dependencies = [
{ name = "python-telegram-bot" },
{ name = "requests" },
{ name = "starlette" },
+ { name = "tqdm" },
{ name = "uvicorn" },
]
@@ -71,6 +72,7 @@ requires-dist = [
{ name = "python-telegram-bot", specifier = ">=22.6" },
{ name = "requests", specifier = ">=2.32.5" },
{ name = "starlette", specifier = ">=0.52.1" },
+ { name = "tqdm", specifier = ">=4.67.3" },
{ name = "uvicorn", specifier = ">=0.41.0" },
]
@@ -343,6 +345,18 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/81/0d/13d1d239a25cbfb19e740db83143e95c772a1fe10202dda4b76792b114dd/starlette-0.52.1-py3-none-any.whl", hash = "sha256:0029d43eb3d273bc4f83a08720b4912ea4b071087a3b48db01b7c839f7954d74", size = 74272, upload-time = "2026-01-18T13:34:09.188Z" },
]
+[[package]]
+name = "tqdm"
+version = "4.67.3"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "colorama", marker = "sys_platform == 'win32'" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/09/a9/6ba95a270c6f1fbcd8dac228323f2777d886cb206987444e4bce66338dd4/tqdm-4.67.3.tar.gz", hash = "sha256:7d825f03f89244ef73f1d4ce193cb1774a8179fd96f31d7e1dcde62092b960bb", size = 169598, upload-time = "2026-02-03T17:35:53.048Z" }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/16/e1/3079a9ff9b8e11b846c6ac5c8b5bfb7ff225eee721825310c91b3b50304f/tqdm-4.67.3-py3-none-any.whl", hash = "sha256:ee1e4c0e59148062281c49d80b25b67771a127c85fc9676d3be5f243206826bf", size = 78374, upload-time = "2026-02-03T17:35:50.982Z" },
+]
+
[[package]]
name = "typing-extensions"
version = "4.15.0"