massive cleanup

main
oscar 2 months ago
parent d4ed0dfb0a
commit 6ee06cba7b

@ -1,36 +1,9 @@
# app.py — Streamaster, DB-Only, Clean
from flask import Flask
import os
# ───────── CONFIG ───────── #
app = Flask(__name__)
THUMB_DIR = "static/thumbnails"
VIDEOS_PER_PAGE = 40
DASHBOARD_PER_PAGE = 100
THUMB_WIDTH = 640
FF_QUALITY = "80"
os.makedirs(THUMB_DIR, exist_ok=True)
VIDEO_DIRS = [
"U:/encoded",
"U:/count_sorted",
"E:/streamaster/downloaded"
]
def find_video_file(filename: str) -> str | None:
for directory in VIDEO_DIRS:
candidate = os.path.join(directory, filename)
if os.path.exists(candidate):
return candidate
return None
# ───────── BLUEPRINTS ───────── #
from helpers.favorites import db_init_favorites_table
from routes.web import web
from routes.api import api
from helpers.favorites import db_init_favorites_table
app = Flask(__name__)
app.register_blueprint(web)
app.register_blueprint(api)

@ -29,3 +29,15 @@ def get_local_db_connection():
)
cursor = conn.cursor(cursor_factory=RealDictCursor)
return conn, cursor
VIDEOS_PER_PAGE = 40
DASHBOARD_PER_PAGE = 100
THUMB_DIR = "static/thumbnails"
THUMB_WIDTH = 640
FF_QUALITY = "80"
VIDEO_DIRS = [
"U:/encoded",
"U:/count_sorted",
"E:/streamaster/downloaded"
]

@ -1,3 +1,6 @@
import time
from helpers.db import db_get_videos
# from helpers.thumbnails import generate_thumbnails_for_videos # optional
# ───────── CACHE BUILDER ───────── #
def build_cache():
@ -28,6 +31,7 @@ def build_cache():
video_map[key] = vids
# Thumbnail generation is optional, uncomment if you want it auto-built:
# generate_thumbnails_for_videos(videos)
return {

@ -1,17 +1,27 @@
import psycopg2.extras
from config import get_local_db_connection # central config
# ───────── DB HELPER ───────── #
def db_get_videos(username = None):
def db_get_videos(username: str = None):
conn, cur = get_local_db_connection()
cur = conn.cursor(cursor_factory=psycopg2.extras.DictCursor)
query = "SELECT video_id, username, site AS platform, filepath, size, duration, gender, created_at, updated_at, thumbnail FROM videos WHERE status != 'missing'"
if username:
query += f" AND username = '{username}'"
query = """
SELECT video_id, username, site AS platform,
filepath, size, duration, gender,
created_at, updated_at, thumbnail
FROM videos
WHERE status != 'missing'
"""
params = []
if True:
query += " ORDER BY created_at DESC"
if username:
query += " AND username = %s"
params.append(username)
cur.execute(query)
query += " ORDER BY created_at DESC"
cur.execute(query, params)
rows = cur.fetchall()
cur.close(); conn.close()
return [dict(r) for r in rows]
@ -29,14 +39,13 @@ def db_get_video(video_id: str):
""", (video_id,))
row = cur.fetchone()
cur.close(); conn.close()
return dict(row)
return dict(row) if row else None
def db_get_recent(page: int, per_page: int):
offset = (page - 1) * per_page
conn, cur = get_local_db_connection()
cur = conn.cursor(cursor_factory=psycopg2.extras.DictCursor)
# Order by created_at desc (fallback to updated_at if you prefer)
cur.execute("""
SELECT
video_id, username, site AS platform,

@ -1,6 +1,5 @@
import psycopg2.extras
from config import get_local_db_connection # centralize DB connection
# ───────── FAVORITES ───────── #
def db_init_favorites_table():
@ -8,7 +7,7 @@ def db_init_favorites_table():
cur = conn.cursor()
cur.execute("""
CREATE TABLE IF NOT EXISTS favorites (
video_id TEXT PRIMARY KEY,
video_id UUID PRIMARY KEY, -- better: store as uuid
created_at TIMESTAMPTZ DEFAULT NOW()
)
""")
@ -19,14 +18,13 @@ def db_get_fav_set():
conn, cur = get_local_db_connection()
cur = conn.cursor()
cur.execute("SELECT video_id FROM favorites")
favs = {row[0] for row in cur.fetchall()}
favs = {str(row[0]) for row in cur.fetchall()}
cur.close(); conn.close()
return favs
def db_toggle_fav(video_id: str):
conn, cur = get_local_db_connection()
cur = conn.cursor()
# Try to delete; if nothing deleted, insert
cur.execute("DELETE FROM favorites WHERE video_id = %s", (video_id,))
if cur.rowcount == 0:
cur.execute("INSERT INTO favorites (video_id) VALUES (%s)", (video_id,))

@ -1,4 +1,9 @@
# ───────── THUMBNAIL HELPERS ───────── #
import os, hashlib, subprocess
from concurrent.futures import ThreadPoolExecutor
# pull constants from app.py
from app import THUMB_DIR, THUMB_WIDTH, FF_QUALITY
def _hashed_thumb_path(video_id: str):
h = hashlib.md5(video_id.encode()).hexdigest()
sub1, sub2 = h[:2], h[2:4]
@ -21,7 +26,7 @@ def generate_thumbnails_for_videos(videos):
for v in videos:
video_id = v.get("video_id")
filepath = v.get("filepath")
filepath = v.get("filepath")
thumb_path = _hashed_thumb_path(video_id)
if not filepath:
@ -39,8 +44,11 @@ def generate_thumbnails_for_videos(videos):
if tasks:
with ThreadPoolExecutor(max_workers=os.cpu_count() * 2) as exe:
list(exe.map(lambda t: subprocess.run(
_gen_thumb_cmd(*t),
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL
), tasks))
list(exe.map(
lambda t: subprocess.run(
_gen_thumb_cmd(*t),
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL
),
tasks
))

@ -1,4 +1,12 @@
@app.route('/open-folder', methods=['POST'])
from flask import Blueprint, request, jsonify
import os, subprocess
from helpers.db import db_get_video
from helpers.favorites import db_toggle_fav, db_get_fav_set
from config import get_local_db_connection
api = Blueprint("api", __name__)
@api.route('/open-folder', methods=['POST'])
def open_folder():
data = request.json
file_path = data.get("file_path")
@ -13,7 +21,7 @@ def open_folder():
return jsonify({"success": True})
@app.route("/api/fav/toggle/<video_id>", methods=["POST"])
@api.route("/api/fav/toggle/<video_id>", methods=["POST"])
def api_fav_toggle(video_id):
# Optional: validate video exists
try:
@ -24,11 +32,13 @@ def api_fav_toggle(video_id):
is_fav = db_toggle_fav(video_id)
return jsonify({"ok": True, "video_id": video_id, "is_favorite": is_fav})
@app.route("/api/fav/list")
@api.route("/api/fav/list")
def api_fav_list():
return jsonify({"favorites": sorted(list(db_get_fav_set()))})
@app.route('/delete-file', methods=['POST'])
@api.route('/delete-file', methods=['POST'])
def delete_file():
data = request.json
file_path = data.get("file_path")

@ -1,7 +1,9 @@
from flask import Blueprint, render_template, request, send_file
from flask import Blueprint, render_template, request, send_file, jsonify
import math, time
from helpers.db import db_get_videos, db_get_video, db_get_recent
from helpers.favorites import mark_favorites, db_get_favorites, db_get_fav_set
from helpers.cache import build_cache
from config import VIDEOS_PER_PAGE, DASHBOARD_PER_PAGE
web = Blueprint("web", __name__)
@ -9,23 +11,20 @@ web = Blueprint("web", __name__)
def dashboard():
cache = build_cache()
query = request.args.get("q", "").lower().strip()
sort = request.args.get("sort", "total_size") # user | platform | total_size | video_count | avg_size
dir_ = request.args.get("dir", "desc") # asc | desc
sort = request.args.get("sort", "total_size")
dir_ = request.args.get("dir", "desc")
reverse = (dir_ == "desc")
# Start with list of (key, stats)
items = list(cache["storage_usage"].items())
# Search (by user)
if query:
items = [e for e in items if query in e[0].split("::")[0].lower()]
# Sorting
def k_user(x): return x[0].split("::")[0].lower()
def k_platform(x): return x[0].split("::")[1].lower()
def k_total(x): return x[1]["total_size"]
def k_count(x): return x[1]["video_count"]
def k_avg(x): return cache["avg_sizes"][x[0]]
def k_user(x): return x[0].split("::")[0].lower()
def k_platform(x): return x[0].split("::")[1].lower()
def k_total(x): return x[1]["total_size"]
def k_count(x): return x[1]["video_count"]
def k_avg(x): return cache["avg_sizes"][x[0]]
key_map = {
"user": k_user,
@ -36,7 +35,6 @@ def dashboard():
}
items.sort(key=key_map.get(sort, k_total), reverse=reverse)
# Pagination
page = max(1, int(request.args.get("page", 1)))
total_pages = max(1, math.ceil(len(items) / DASHBOARD_PER_PAGE))
start = (page - 1) * DASHBOARD_PER_PAGE
@ -53,8 +51,6 @@ def dashboard():
dir=dir_
)
@web.route("/refresh")
def refresh():
cache = build_cache()
@ -67,7 +63,6 @@ def refresh():
@web.route("/user/<username>")
def user_page(username):
videos = db_get_videos(username=username)
page = max(1, int(request.args.get("page", 1)))
total_pages = max(1, math.ceil(len(videos) / VIDEOS_PER_PAGE))
start = (page - 1) * VIDEOS_PER_PAGE
@ -101,10 +96,8 @@ def view_video(video_id):
def recent():
page = max(1, int(request.args.get("page", 1)))
per_page = VIDEOS_PER_PAGE
videos, total = db_get_recent(page, per_page)
total_pages = max(1, math.ceil(total / per_page))
mark_favorites(videos)
return render_template(
@ -118,11 +111,8 @@ def recent():
def favorites_page():
page = max(1, int(request.args.get("page", 1)))
per_page = VIDEOS_PER_PAGE
videos, total = db_get_favorites(page, per_page)
total_pages = max(1, math.ceil(total / per_page))
# tag stars (not strictly necessary since everything here is fav, but keeps UI consistent)
mark_favorites(videos)
return render_template(
@ -131,4 +121,3 @@ def favorites_page():
page=page,
total_pages=total_pages
)

Loading…
Cancel
Save