Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
next root-level module can't ship broken.

### Added
- **`routers/` — extracting `server.py`'s route layer, cheapest-first (R3).** Each PR moves a cohesive route group into a `fastapi.APIRouter` under `lib/routers/`, mounted with `app.include_router(...)` at its original site (FastAPI matches in registration order; the full route table stays byte-identical). Bodies are verbatim — only the decorator receiver (`@app` → `@router`) and singleton reads (`meta_db` → `appstate.meta_db`, resolved at call time) change. So far: `audio_effects` (5 routes), `artist_aliases` (5 routes — the Tidy-up/P4 alias overrides). The next cut is picked by a dependency-closure scan that ranks groups by how many `monkeypatch.setattr(server, …)` targets they'd drag along.
- **`routers/` — extracting `server.py`'s route layer, cheapest-first (R3).** Each PR moves a cohesive route group into a `fastapi.APIRouter` under `lib/routers/`, mounted with `app.include_router(...)` at its original site (FastAPI matches in registration order; the full route table stays byte-identical). Bodies are verbatim — only the decorator receiver (`@app` → `@router`) and singleton reads (`meta_db` → `appstate.meta_db`, resolved at call time) change. So far: `audio_effects` (5), `artist_aliases` (5), `loops` (3 — saved A/B practice regions). The next cut is picked by a dependency-closure scan that ranks groups by how many `monkeypatch.setattr(server, …)` targets they'd drag along.
- **`routers/` — the first extracted route module (R3).** The five audio-effects mapping
endpoints move out of `server.py` into `lib/routers/audio_effects.py` as a
`fastapi.APIRouter`, mounted with `app.include_router(...)` **at the point in the file
Expand Down
4 changes: 2 additions & 2 deletions docs/size-exemptions.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,8 @@ without a *signed* exemption" is unenforceable.
## Planned, NOT exempt (owned by split plans — listed so nothing falls between states)

core `static/app.js` (11,852) · `static/highway.js` (4,168, whole file) · `server.py`
(9,337 — was 14,037; ratcheted by the R3 `MetadataDB` + `AudioEffectsMappingDB`
extractions and the first two `routers/` modules) ·
(9,302 — was 14,037; ratcheted by the R3 `MetadataDB` + `AudioEffectsMappingDB`
extractions and the first three `routers/` modules) ·
`lib/metadata_db.py` (4,373 — new in R3; the `MetadataDB` class alone is 4,018 lines
and is a monolith in its own right, to be split per-table once the router train
lands) · `static/v3/songs.js` (4,134) · `static/capabilities/audio-session.js`
Expand Down
52 changes: 52 additions & 0 deletions lib/routers/loops.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
"""Practice loops — saved A/B regions per song.

Extracted verbatim from ``server.py`` (R3); only the decorator receiver
(``@app`` -> ``@router``) and the singleton reads (``meta_db`` ->
``appstate.meta_db``) changed. See ``appstate.py`` for why the reads stay
module attributes.
"""

from fastapi import APIRouter

import appstate

router = APIRouter()


@router.get("/api/loops")
def list_loops(filename: str):
rows = appstate.meta_db.conn.execute(
"SELECT id, name, start_time, end_time FROM loops WHERE filename = ? ORDER BY start_time",
(filename,)
).fetchall()
Comment thread
byrongamatos marked this conversation as resolved.
return [{"id": r[0], "name": r[1], "start": r[2], "end": r[3]} for r in rows]


@router.post("/api/loops")
def save_loop(data: dict):
filename = data.get("filename", "")
name = data.get("name", "").strip()
start = data.get("start")
end = data.get("end")
if not filename or start is None or end is None:
return {"error": "Missing fields"}
if not name:
count = appstate.meta_db.conn.execute(
"SELECT COUNT(*) FROM loops WHERE filename = ?", (filename,)
).fetchone()[0]
name = f"Loop {count + 1}"
with appstate.meta_db._lock:
appstate.meta_db.conn.execute(
"INSERT INTO loops (filename, name, start_time, end_time) VALUES (?, ?, ?, ?)",
(filename, name, float(start), float(end))
)
appstate.meta_db.conn.commit()
Comment thread
byrongamatos marked this conversation as resolved.
return {"ok": True, "name": name}


@router.delete("/api/loops/{loop_id}")
def delete_loop(loop_id: int):
with appstate.meta_db._lock:
appstate.meta_db.conn.execute("DELETE FROM loops WHERE id = ?", (loop_id,))
appstate.meta_db.conn.commit()
return {"ok": True}
43 changes: 4 additions & 39 deletions server.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@
# Lives in lib/ because that is the one core dir every packaging path copies.
import appstate
# Extracted route modules. They import `appstate`, never `server` — one-way graph.
from routers import audio_effects, artist_aliases
from routers import audio_effects, artist_aliases, loops
import sloppak as sloppak_mod
import drums as drums_mod
import notation as notation_mod
Expand Down Expand Up @@ -5903,44 +5903,9 @@ def api_remove_wanted(wanted_id: int):


# ── Loops API ────────────────────────────────────────────────────────────────

@app.get("/api/loops")
def list_loops(filename: str):
rows = meta_db.conn.execute(
"SELECT id, name, start_time, end_time FROM loops WHERE filename = ? ORDER BY start_time",
(filename,)
).fetchall()
return [{"id": r[0], "name": r[1], "start": r[2], "end": r[3]} for r in rows]


@app.post("/api/loops")
def save_loop(data: dict):
filename = data.get("filename", "")
name = data.get("name", "").strip()
start = data.get("start")
end = data.get("end")
if not filename or start is None or end is None:
return {"error": "Missing fields"}
if not name:
count = meta_db.conn.execute(
"SELECT COUNT(*) FROM loops WHERE filename = ?", (filename,)
).fetchone()[0]
name = f"Loop {count + 1}"
with meta_db._lock:
meta_db.conn.execute(
"INSERT INTO loops (filename, name, start_time, end_time) VALUES (?, ?, ?, ?)",
(filename, name, float(start), float(end))
)
meta_db.conn.commit()
return {"ok": True, "name": name}


@app.delete("/api/loops/{loop_id}")
def delete_loop(loop_id: int):
with meta_db._lock:
meta_db.conn.execute("DELETE FROM loops WHERE id = ?", (loop_id,))
meta_db.conn.commit()
return {"ok": True}
# Mounted here, where these routes used to be defined (FastAPI matches in
# registration order). Implementation in lib/routers/loops.py.
app.include_router(loops.router)


# ── Audio Effects Mapping API ───────────────────────────────────────────────
Expand Down
Loading