Add optional photo providers, layout studio and scoped integrations

This commit is contained in:
Pigway
2026-10-08 23:18:11 +08:00
parent 3643fae86a
commit 69a0841868
38 changed files with 2843 additions and 41 deletions
+30 -3
View File
@@ -27,7 +27,7 @@ from pigway_frame_flow.storage.database import encode
class PhotoSourceInput(StrictModel):
name: str = Field(min_length=1, max_length=120)
kind: Literal["local", "webdav"]
kind: Literal["local", "webdav", "google-drive", "alipan", "baidu"]
location: str = Field(min_length=1, max_length=2048)
recursive: bool = True
enabled: bool = True
@@ -36,6 +36,11 @@ class PhotoSourceInput(StrictModel):
organized_only: bool = False
folder_caption: bool = False
orientation: Literal["auto", "landscape", "portrait"] | None = None
minimum_sharpness: float = Field(default=0, ge=0, le=10000)
minimum_brightness: float = Field(default=0, ge=0, le=255)
maximum_brightness: float = Field(default=255, ge=0, le=255)
avoid_duplicates: bool = False
people_space: Literal["shared", "personal"] = "shared"
people_filter: bool = False
person_ids: list[int] = Field(default_factory=list, max_length=50)
person_match: Literal["any", "all"] = "any"
@@ -102,6 +107,15 @@ class PhotoSources:
return PhotoSourceInput.model_validate_json(row["payload"])
def save(self, source_id, source):
if source.minimum_brightness > source.maximum_brightness:
raise FlowError(E.INVALID_REQUEST, "Brightness range is reversed")
if source.kind != "local" and (
source.organized_only or source.folder_caption or source.synology_previews
):
raise FlowError(
E.UNSUPPORTED_CAPABILITY,
"Folder captions and Synology previews require a local photo source",
)
if source.orientation and source.kind != "local":
raise FlowError(
E.UNSUPPORTED_CAPABILITY,
@@ -126,7 +140,7 @@ class PhotoSources:
raise FlowError(
E.INVALID_REQUEST, "Local sources do not use credentials"
)
else:
elif source.kind == "webdav":
source = source.model_copy(
update={
"recursive": False,
@@ -266,7 +280,12 @@ class PhotoSources:
):
return cached[1]
allowed = (
self.synology.paths(source.person_ids, source.person_match, refresh=refresh)
self.synology.paths(
source.person_ids,
source.person_match,
refresh=refresh,
space=source.people_space,
)
if source.people_filter
else None
)
@@ -387,6 +406,10 @@ class PhotoSources:
break
if len(items) >= source.catalog_limit:
break
elif source.kind in ("google-drive", "alipan", "baidu"):
from pigway_frame_flow.providers.cloud_drives import CloudDrives
items = CloudDrives(self).catalog(source_id, source)
else:
data = self.assets.fetch_url(
source.location,
@@ -503,6 +526,10 @@ class PhotoSources:
os.close(parent_fd)
except OSError:
raise FlowError(E.NOT_FOUND, "Photo is unavailable", 404) from None
elif source.kind in ("google-drive", "alipan", "baidu"):
from pigway_frame_flow.providers.cloud_drives import CloudDrives
data = CloudDrives(self).read(source_id, source, item)
else:
data = self.assets.fetch_url(item["id"], headers=self.headers(source))
if len(data) > self.settings.max_bytes: