Store mp3 size in database
Persist file size at creation and backfill missing sizes on list responses so the UI can display sizes reliably.
This commit is contained in:
25
server/db.py
25
server/db.py
@@ -29,10 +29,17 @@ def init_db():
|
|||||||
id SERIAL PRIMARY KEY,
|
id SERIAL PRIMARY KEY,
|
||||||
text TEXT NOT NULL,
|
text TEXT NOT NULL,
|
||||||
filename TEXT,
|
filename TEXT,
|
||||||
|
size_bytes BIGINT,
|
||||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||||
);
|
);
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
|
cur.execute(
|
||||||
|
"""
|
||||||
|
ALTER TABLE tts_items
|
||||||
|
ADD COLUMN IF NOT EXISTS size_bytes BIGINT;
|
||||||
|
"""
|
||||||
|
)
|
||||||
cur.execute(
|
cur.execute(
|
||||||
"""
|
"""
|
||||||
CREATE INDEX IF NOT EXISTS tts_items_created_at_idx
|
CREATE INDEX IF NOT EXISTS tts_items_created_at_idx
|
||||||
@@ -72,12 +79,26 @@ def update_filename(tts_id: int, filename: str) -> None:
|
|||||||
conn.commit()
|
conn.commit()
|
||||||
|
|
||||||
|
|
||||||
|
def update_size_bytes(tts_id: int, size_bytes: int) -> None:
|
||||||
|
with get_conn() as conn:
|
||||||
|
with conn.cursor() as cur:
|
||||||
|
cur.execute(
|
||||||
|
"""
|
||||||
|
UPDATE tts_items
|
||||||
|
SET size_bytes = %s
|
||||||
|
WHERE id = %s;
|
||||||
|
""",
|
||||||
|
(size_bytes, tts_id),
|
||||||
|
)
|
||||||
|
conn.commit()
|
||||||
|
|
||||||
|
|
||||||
def list_items() -> List[Dict[str, Any]]:
|
def list_items() -> List[Dict[str, Any]]:
|
||||||
with get_conn() as conn:
|
with get_conn() as conn:
|
||||||
with conn.cursor(cursor_factory=psycopg2.extras.RealDictCursor) as cur:
|
with conn.cursor(cursor_factory=psycopg2.extras.RealDictCursor) as cur:
|
||||||
cur.execute(
|
cur.execute(
|
||||||
"""
|
"""
|
||||||
SELECT id, created_at, filename
|
SELECT id, created_at, filename, size_bytes
|
||||||
FROM tts_items
|
FROM tts_items
|
||||||
ORDER BY created_at DESC;
|
ORDER BY created_at DESC;
|
||||||
"""
|
"""
|
||||||
@@ -91,7 +112,7 @@ def get_item(tts_id: int) -> Optional[Dict[str, Any]]:
|
|||||||
with conn.cursor(cursor_factory=psycopg2.extras.RealDictCursor) as cur:
|
with conn.cursor(cursor_factory=psycopg2.extras.RealDictCursor) as cur:
|
||||||
cur.execute(
|
cur.execute(
|
||||||
"""
|
"""
|
||||||
SELECT id, text, filename, created_at
|
SELECT id, text, filename, size_bytes, created_at
|
||||||
FROM tts_items
|
FROM tts_items
|
||||||
WHERE id = %s;
|
WHERE id = %s;
|
||||||
""",
|
""",
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ from .db import (
|
|||||||
init_db,
|
init_db,
|
||||||
create_item,
|
create_item,
|
||||||
update_filename,
|
update_filename,
|
||||||
|
update_size_bytes,
|
||||||
list_items,
|
list_items,
|
||||||
get_item,
|
get_item,
|
||||||
delete_items,
|
delete_items,
|
||||||
@@ -72,13 +73,19 @@ def format_size(bytes_size: int) -> str:
|
|||||||
return f"{bytes_size / (1024 * 1024):.1f}MB"
|
return f"{bytes_size / (1024 * 1024):.1f}MB"
|
||||||
|
|
||||||
|
|
||||||
def get_file_size_display(filename: str | None) -> str | None:
|
def get_file_size_display(size_bytes: int | None) -> str | None:
|
||||||
|
if size_bytes is None:
|
||||||
|
return None
|
||||||
|
return format_size(size_bytes)
|
||||||
|
|
||||||
|
|
||||||
|
def get_file_size_bytes(filename: str | None) -> int | None:
|
||||||
if not filename:
|
if not filename:
|
||||||
return None
|
return None
|
||||||
file_path = RESOURCES_DIR / filename
|
file_path = RESOURCES_DIR / filename
|
||||||
if not file_path.exists():
|
if not file_path.exists():
|
||||||
return None
|
return None
|
||||||
return format_size(file_path.stat().st_size)
|
return file_path.stat().st_size
|
||||||
|
|
||||||
|
|
||||||
@app.on_event("startup")
|
@app.on_event("startup")
|
||||||
@@ -95,16 +102,24 @@ def index(request: Request):
|
|||||||
@app.get("/api/tts")
|
@app.get("/api/tts")
|
||||||
def api_list_tts():
|
def api_list_tts():
|
||||||
rows = list_items()
|
rows = list_items()
|
||||||
return [
|
payload = []
|
||||||
{
|
for row in rows:
|
||||||
"id": row["id"],
|
size_bytes = row.get("size_bytes")
|
||||||
"created_at": row["created_at"].isoformat(),
|
if size_bytes is None and row.get("filename"):
|
||||||
"display_time": format_display_time(row["created_at"]),
|
computed = get_file_size_bytes(row["filename"])
|
||||||
"filename": row["filename"],
|
if computed is not None:
|
||||||
"size_display": get_file_size_display(row["filename"]),
|
update_size_bytes(row["id"], computed)
|
||||||
}
|
size_bytes = computed
|
||||||
for row in rows
|
payload.append(
|
||||||
]
|
{
|
||||||
|
"id": row["id"],
|
||||||
|
"created_at": row["created_at"].isoformat(),
|
||||||
|
"display_time": format_display_time(row["created_at"]),
|
||||||
|
"filename": row["filename"],
|
||||||
|
"size_display": get_file_size_display(size_bytes),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
return payload
|
||||||
|
|
||||||
|
|
||||||
@app.post("/api/tts")
|
@app.post("/api/tts")
|
||||||
@@ -128,14 +143,17 @@ def api_create_tts(payload: TtsCreateRequest):
|
|||||||
delete_item_by_id(tts_id)
|
delete_item_by_id(tts_id)
|
||||||
raise HTTPException(status_code=500, detail=str(exc)) from exc
|
raise HTTPException(status_code=500, detail=str(exc)) from exc
|
||||||
|
|
||||||
|
size_bytes = get_file_size_bytes(filename)
|
||||||
update_filename(tts_id, filename)
|
update_filename(tts_id, filename)
|
||||||
|
if size_bytes is not None:
|
||||||
|
update_size_bytes(tts_id, size_bytes)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"id": tts_id,
|
"id": tts_id,
|
||||||
"created_at": created_at.isoformat(),
|
"created_at": created_at.isoformat(),
|
||||||
"display_time": format_display_time(created_at),
|
"display_time": format_display_time(created_at),
|
||||||
"filename": filename,
|
"filename": filename,
|
||||||
"size_display": get_file_size_display(filename),
|
"size_display": get_file_size_display(size_bytes),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user