|
|
|
|
@ -1418,8 +1418,8 @@ def android_upload():
|
|
|
|
|
if not files: |
|
|
|
|
return jsonify({"ok": False, "error": "no_files"}), 400 |
|
|
|
|
|
|
|
|
|
upload_base = Path(current_app.config["STORAGE_ROOT"]) / "tenants" / row["tenant_slug"] / row["relative_path"] / "originals" |
|
|
|
|
upload_base.mkdir(parents=True, exist_ok=True) |
|
|
|
|
base_path = Path(current_app.config["STORAGE_ROOT"]) / "tenants" / row["tenant_slug"] / row["relative_path"] / "originals" |
|
|
|
|
base_path.mkdir(parents=True, exist_ok=True) |
|
|
|
|
|
|
|
|
|
uploaded_count = 0 |
|
|
|
|
|
|
|
|
|
@ -1428,6 +1428,16 @@ def android_upload():
|
|
|
|
|
original_filename = incoming.filename or "upload.bin" |
|
|
|
|
|
|
|
|
|
stored_name = _stored_name(original_filename) |
|
|
|
|
mime = (incoming.mimetype or "").lower() |
|
|
|
|
|
|
|
|
|
if mime.startswith("video/"): |
|
|
|
|
subdir = "video" |
|
|
|
|
else: |
|
|
|
|
subdir = "images" |
|
|
|
|
|
|
|
|
|
upload_base = base_path / subdir |
|
|
|
|
upload_base.mkdir(parents=True, exist_ok=True) |
|
|
|
|
|
|
|
|
|
target_path = upload_base / stored_name |
|
|
|
|
incoming.save(target_path) |
|
|
|
|
|
|
|
|
|
@ -1439,8 +1449,8 @@ def android_upload():
|
|
|
|
|
else: |
|
|
|
|
basename, extension = original_filename, "" |
|
|
|
|
|
|
|
|
|
relative_path = f"{row['relative_path']}/originals/{stored_name}" |
|
|
|
|
directory_path = f"{row['relative_path']}/originals" |
|
|
|
|
relative_path = f"{row['relative_path']}/originals/{subdir}/{stored_name}" |
|
|
|
|
directory_path = f"{row['relative_path']}/originals/{subdir}" |
|
|
|
|
|
|
|
|
|
cur.execute( |
|
|
|
|
""" |
|
|
|
|
@ -1637,11 +1647,41 @@ from app.services.video_jobs import create_video_job, list_jobs_for_tenant
|
|
|
|
|
|
|
|
|
|
@bp.route("/workshop/<int:device_id>") |
|
|
|
|
def workshop(device_id): |
|
|
|
|
return render_template("cloud/workshop.html", device_id=device_id) |
|
|
|
|
from app.db import get_db |
|
|
|
|
|
|
|
|
|
db = get_db() |
|
|
|
|
|
|
|
|
|
with db.cursor() as cur: |
|
|
|
|
cur.execute( |
|
|
|
|
""" |
|
|
|
|
SELECT COUNT(*) AS queued_jobs |
|
|
|
|
FROM video_jobs |
|
|
|
|
WHERE status = 'queued' |
|
|
|
|
""" |
|
|
|
|
) |
|
|
|
|
qrow = cur.fetchone() or {"queued_jobs": 0} |
|
|
|
|
|
|
|
|
|
cur.execute( |
|
|
|
|
""" |
|
|
|
|
SELECT COUNT(DISTINCT tenant_id) AS active_users |
|
|
|
|
FROM video_jobs |
|
|
|
|
WHERE status IN ('queued', 'processing') |
|
|
|
|
""" |
|
|
|
|
) |
|
|
|
|
arow = cur.fetchone() or {"active_users": 0} |
|
|
|
|
|
|
|
|
|
return render_template( |
|
|
|
|
"cloud/workshop.html", |
|
|
|
|
device_id=device_id, |
|
|
|
|
queued_jobs=qrow["queued_jobs"] or 0, |
|
|
|
|
active_users=arow["active_users"] or 0, |
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
@bp.route("/api/video/enqueue", methods=["POST"]) |
|
|
|
|
def video_enqueue(): |
|
|
|
|
data = request.json |
|
|
|
|
from uuid import uuid4 |
|
|
|
|
|
|
|
|
|
data = request.json or {} |
|
|
|
|
tenant = session.get("tenant") or 'def' |
|
|
|
|
device_id = data.get("device_id") |
|
|
|
|
files = data.get("files", []) |
|
|
|
|
@ -1651,6 +1691,7 @@ def video_enqueue():
|
|
|
|
|
if not profiles: |
|
|
|
|
profiles = ["default"] |
|
|
|
|
|
|
|
|
|
batch_id = uuid4().hex |
|
|
|
|
job_ids = [] |
|
|
|
|
|
|
|
|
|
for f in files: |
|
|
|
|
@ -1660,15 +1701,12 @@ def video_enqueue():
|
|
|
|
|
device_id=device_id, |
|
|
|
|
source_file_id=f, |
|
|
|
|
profile=profile, |
|
|
|
|
rotation_override=rotation_override |
|
|
|
|
rotation_override=rotation_override, |
|
|
|
|
batch_id=batch_id |
|
|
|
|
) |
|
|
|
|
job_ids.append(job_id) |
|
|
|
|
|
|
|
|
|
return jsonify({"status": "ok", "jobs": job_ids}) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return jsonify({"status": "ok", "jobs": job_ids, "batch_id": batch_id}) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@bp.route("/video-jobs") |
|
|
|
|
@ -2045,3 +2083,27 @@ def video_jobs():
|
|
|
|
|
jobs = list_jobs_for_tenant(tenant) |
|
|
|
|
return jsonify(jobs) |
|
|
|
|
|
|
|
|
|
@bp.route("/api/video/queue-summary") |
|
|
|
|
def video_queue_summary(): |
|
|
|
|
from app.db import get_db |
|
|
|
|
|
|
|
|
|
db = get_db() |
|
|
|
|
cur = db.cursor() |
|
|
|
|
|
|
|
|
|
cur.execute("SELECT COUNT(*) AS c FROM video_jobs WHERE status='queued'") |
|
|
|
|
row1 = cur.fetchone() |
|
|
|
|
queue_count = row1["c"] if isinstance(row1, dict) else row1[0] |
|
|
|
|
|
|
|
|
|
cur.execute(""" |
|
|
|
|
SELECT COUNT(DISTINCT tenant_id) AS c |
|
|
|
|
FROM video_jobs |
|
|
|
|
WHERE status IN ('queued','processing') |
|
|
|
|
""") |
|
|
|
|
row2 = cur.fetchone() |
|
|
|
|
active_users = row2["c"] if isinstance(row2, dict) else row2[0] |
|
|
|
|
|
|
|
|
|
return { |
|
|
|
|
"queue_count": queue_count, |
|
|
|
|
"active_users": active_users |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|