diff --git a/deploy/Dockerfile.runtime-update b/deploy/Dockerfile.runtime-update index 0443f4a..b5dee9d 100644 --- a/deploy/Dockerfile.runtime-update +++ b/deploy/Dockerfile.runtime-update @@ -30,4 +30,4 @@ CMD ["python", "-m", "uvicorn", "pigway_frame_flow.main:app", "--host", "0.0.0.0 ARG BUILD_COMMIT ARG BUILD_TIME ENV BUILD_COMMIT=$BUILD_COMMIT BUILD_TIME=$BUILD_TIME -LABEL org.opencontainers.image.title="PIGWay Frame Flow" org.opencontainers.image.version="0.1.17" org.opencontainers.image.revision=$BUILD_COMMIT +LABEL org.opencontainers.image.title="PIGWay Frame Flow" org.opencontainers.image.version="0.1.18" org.opencontainers.image.revision=$BUILD_COMMIT diff --git a/docs/openapi.json b/docs/openapi.json index 456f826..fba81c2 100644 --- a/docs/openapi.json +++ b/docs/openapi.json @@ -2,7 +2,7 @@ "openapi": "3.1.0", "info": { "title": "PIGWay Frame Flow API", - "version": "0.1.9" + "version": "0.1.18" }, "paths": { "/api/v1/devices/{device_id}/widgets/selection": { @@ -15227,7 +15227,7 @@ "version": { "type": "string", "title": "Version", - "default": "0.1.9" + "default": "0.1.18" } }, "type": "object", @@ -17490,7 +17490,7 @@ "version": { "type": "string", "title": "Version", - "default": "0.1.9" + "default": "0.1.18" }, "api_version": { "type": "string", diff --git a/docs/releases/v0.1.18.md b/docs/releases/v0.1.18.md new file mode 100644 index 0000000..ab9f361 --- /dev/null +++ b/docs/releases/v0.1.18.md @@ -0,0 +1,6 @@ +# v0.1.18 + +- Synology Photos 列表显式请求照片方向信息;按 EXIF 旋转后的宽高筛选横向、竖向和自动方向,避免存储像素为横向的竖拍照片误入横图来源。 +- 渲染前复核实际取得图片的 EXIF 方向;若元数据或缓存预览与来源方向不符,则跳过该候选。显式选择方向不符的照片时返回明确错误。 +- 保持既有水印和铺满布局,不修改 NAS 原照片、来源设置或现有图库;修复不自动重新生成、上传或切换已显示图片。 +- 源码及镜像保留 LICENSE、NOTICE;公开验证只使用合成照片和通用示例,私有部署参数与回执保存在仓库之外。 diff --git a/pigway_frame_flow/api/app.py b/pigway_frame_flow/api/app.py index aae546a..8135077 100644 --- a/pigway_frame_flow/api/app.py +++ b/pigway_frame_flow/api/app.py @@ -126,7 +126,7 @@ def create_app(settings=None, start_worker=True): app = FastAPI( title="PIGWay Frame Flow API", docs_url=None, - version="0.1.17", + version="0.1.18", lifespan=lifespan, responses=error_responses, ) @@ -1040,7 +1040,7 @@ def create_app(settings=None, start_worker=True): supports_upload=True, ), ], - version="0.1.17", + version="0.1.18", mock=settings.mock, write_enabled=settings.write_enabled, api_key_configured=bool(settings.api_key) diff --git a/pigway_frame_flow/models.py b/pigway_frame_flow/models.py index 0472fee..af1c681 100644 --- a/pigway_frame_flow/models.py +++ b/pigway_frame_flow/models.py @@ -366,7 +366,7 @@ class SettingsView(BaseModel): class Health(BaseModel): status: str - version: str = "0.1.17" + version: str = "0.1.18" class Readiness(BaseModel): @@ -397,7 +397,7 @@ class RestoreRequest(StrictModel): class Version(BaseModel): product: str = "PIGWay Frame Flow" - version: str = "0.1.17" + version: str = "0.1.18" api_version: str = "v1" commit: str = "development" build_time: str = "unknown" diff --git a/pigway_frame_flow/providers/photo_sources.py b/pigway_frame_flow/providers/photo_sources.py index fefcf3f..6447b12 100644 --- a/pigway_frame_flow/providers/photo_sources.py +++ b/pigway_frame_flow/providers/photo_sources.py @@ -662,13 +662,27 @@ class PhotoSources: data = self.assets.fetch_url(item["id"], headers=self.headers(source)) if len(data) > self.settings.max_bytes: raise FlowError(E.INVALID_REQUEST, "Image exceeds size limit") - if source.minimum_short_edge or source.minimum_long_edge: + if source.orientation or source.minimum_short_edge or source.minimum_long_edge: from io import BytesIO from PIL import Image with Image.open(BytesIO(data)) as image: - if not self.resolution_matches(source, *image.size): + width, height = image.size + if image.getexif().get(274, 1) in (5, 6, 7, 8): + width, height = height, width + wanted = ( + orientation(*target_size) + if source.orientation == "auto" + else source.orientation + ) + # Validate the fetched rendition before a crop can hide a mismatch. + if wanted and orientation(width, height) != wanted: + raise FlowError( + E.INVALID_REQUEST, + "Photo direction does not match the source orientation", + ) + if not self.resolution_matches(source, width, height): raise FlowError( E.INVALID_REQUEST, "Photo is below the configured minimum resolution", diff --git a/pigway_frame_flow/providers/synology_photos.py b/pigway_frame_flow/providers/synology_photos.py index 07f615f..1c84c52 100644 --- a/pigway_frame_flow/providers/synology_photos.py +++ b/pigway_frame_flow/providers/synology_photos.py @@ -299,7 +299,9 @@ class SynologyPhotos: rows = self.pages( prefix + ".Browse.Item", 7, - additional=json.dumps(["folder", "thumbnail", "resolution"]), + additional=json.dumps( + ["folder", "thumbnail", "resolution", "orientation"] + ), **({"person_id": person} if person is not None else {}), ) groups.append( diff --git a/pigway_frame_flow/web/index.html b/pigway_frame_flow/web/index.html index 837c3a5..b133672 100644 --- a/pigway_frame_flow/web/index.html +++ b/pigway_frame_flow/web/index.html @@ -1,3 +1,3 @@