fix: close library upload flow and harden image storage
Community checks / verify (push) Skipped
Verify Frame Flow / verify (push) Successful in 8m9s

This commit is contained in:
渡口浪人
2026-10-24 00:38:00 +08:00
parent 0859871363
commit 1494904b12
39 changed files with 1471 additions and 240 deletions
+40 -2
View File
@@ -30,7 +30,13 @@ from pigway_frame_flow.storage.database import encode
class PhotoSourceInput(StrictModel):
name: str = Field(min_length=1, max_length=120)
kind: Literal[
"local", "synology-photos", "webdav", "google-drive", "alipan", "baidu"
"local",
"synology-photos",
"webdav",
"google-drive",
"alipan",
"baidu",
"uploads",
]
location: str = Field(min_length=1, max_length=2048)
nas_root_path: str | None = Field(default=None, max_length=2048, pattern=r"^/")
@@ -132,6 +138,12 @@ class PhotoSources:
def save(self, source_id, source):
self.require_api_source(source)
if source.kind == "uploads" and (
source_id != "manual-uploads" or source.location != "."
):
raise FlowError(E.INVALID_REQUEST, "Invalid manual upload source")
if source_id == "manual-uploads" and source.kind != "uploads":
raise FlowError(E.CONFLICT, "Reserved manual upload source")
if source.minimum_brightness > source.maximum_brightness:
raise FlowError(E.INVALID_REQUEST, "Brightness range is reversed")
if source.kind not in ("local", "synology-photos") and (
@@ -310,6 +322,20 @@ class PhotoSources:
self.require_api_source(source)
if not source.enabled:
raise FlowError(E.CONFLICT, "Photo source is disabled", 409)
if source.kind == "uploads":
return [
{
"id": row["item_id"],
"name": row["name"],
"caption": json.loads(row["caption"]),
"starred": bool(row["starred"]),
"excluded": bool(row["excluded"]),
}
for row in self.db.all(
"SELECT s.item_id,s.caption,a.name,COALESCE(p.starred,0) AS starred,COALESCE(p.excluded,0) AS excluded FROM source_images s JOIN assets a ON a.id=s.id LEFT JOIN photo_preferences p ON p.source_id=s.source_id AND p.item_id=s.item_id WHERE s.source_id=? ORDER BY s.created_at DESC,s.id DESC",
(source_id,),
)
]
session_identity = (
self.synology.sid() if source.kind == "synology-photos" else None
)
@@ -610,6 +636,18 @@ class PhotoSources:
)
if item is None:
raise FlowError(E.NOT_FOUND, "Photo is not in this source", 404)
if source.kind == "uploads":
row = self.db.one(
"SELECT id,caption FROM source_images WHERE source_id=? AND item_id=?",
(source_id, item["id"]),
)
if not row:
raise FlowError(E.NOT_FOUND, "Uploaded source picture not found", 404)
return (
self.assets.path(row["id"]).read_bytes(),
item["name"],
json.loads(row["caption"]),
)
if source.kind == "local":
root = self.settings.photo_root.resolve()
path = root / item["id"]
@@ -688,7 +726,7 @@ class PhotoSources:
from PIL import Image
with Image.open(BytesIO(data)) as image:
with Image.open(BytesIO(data), formats=("JPEG", "PNG", "WEBP")) as image:
width, height = image.size
if image.getexif().get(274, 1) in (5, 6, 7, 8):
width, height = height, width