fix: avoid rotating Synology display dimensions twice
This commit is contained in:
@@ -30,4 +30,4 @@ CMD ["python", "-m", "uvicorn", "pigway_frame_flow.main:app", "--host", "0.0.0.0
|
|||||||
ARG BUILD_COMMIT
|
ARG BUILD_COMMIT
|
||||||
ARG BUILD_TIME
|
ARG BUILD_TIME
|
||||||
ENV BUILD_COMMIT=$BUILD_COMMIT BUILD_TIME=$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.18" org.opencontainers.image.revision=$BUILD_COMMIT
|
LABEL org.opencontainers.image.title="PIGWay Frame Flow" org.opencontainers.image.version="0.1.19" org.opencontainers.image.revision=$BUILD_COMMIT
|
||||||
|
|||||||
+3
-3
@@ -2,7 +2,7 @@
|
|||||||
"openapi": "3.1.0",
|
"openapi": "3.1.0",
|
||||||
"info": {
|
"info": {
|
||||||
"title": "PIGWay Frame Flow API",
|
"title": "PIGWay Frame Flow API",
|
||||||
"version": "0.1.18"
|
"version": "0.1.19"
|
||||||
},
|
},
|
||||||
"paths": {
|
"paths": {
|
||||||
"/api/v1/devices/{device_id}/widgets/selection": {
|
"/api/v1/devices/{device_id}/widgets/selection": {
|
||||||
@@ -15227,7 +15227,7 @@
|
|||||||
"version": {
|
"version": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"title": "Version",
|
"title": "Version",
|
||||||
"default": "0.1.18"
|
"default": "0.1.19"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"type": "object",
|
"type": "object",
|
||||||
@@ -17490,7 +17490,7 @@
|
|||||||
"version": {
|
"version": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"title": "Version",
|
"title": "Version",
|
||||||
"default": "0.1.18"
|
"default": "0.1.19"
|
||||||
},
|
},
|
||||||
"api_version": {
|
"api_version": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
|
|||||||
@@ -126,7 +126,7 @@ def create_app(settings=None, start_worker=True):
|
|||||||
app = FastAPI(
|
app = FastAPI(
|
||||||
title="PIGWay Frame Flow API",
|
title="PIGWay Frame Flow API",
|
||||||
docs_url=None,
|
docs_url=None,
|
||||||
version="0.1.18",
|
version="0.1.19",
|
||||||
lifespan=lifespan,
|
lifespan=lifespan,
|
||||||
responses=error_responses,
|
responses=error_responses,
|
||||||
)
|
)
|
||||||
@@ -1040,7 +1040,7 @@ def create_app(settings=None, start_worker=True):
|
|||||||
supports_upload=True,
|
supports_upload=True,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
version="0.1.18",
|
version="0.1.19",
|
||||||
mock=settings.mock,
|
mock=settings.mock,
|
||||||
write_enabled=settings.write_enabled,
|
write_enabled=settings.write_enabled,
|
||||||
api_key_configured=bool(settings.api_key)
|
api_key_configured=bool(settings.api_key)
|
||||||
|
|||||||
@@ -366,7 +366,7 @@ class SettingsView(BaseModel):
|
|||||||
|
|
||||||
class Health(BaseModel):
|
class Health(BaseModel):
|
||||||
status: str
|
status: str
|
||||||
version: str = "0.1.18"
|
version: str = "0.1.19"
|
||||||
|
|
||||||
|
|
||||||
class Readiness(BaseModel):
|
class Readiness(BaseModel):
|
||||||
@@ -397,7 +397,7 @@ class RestoreRequest(StrictModel):
|
|||||||
|
|
||||||
class Version(BaseModel):
|
class Version(BaseModel):
|
||||||
product: str = "PIGWay Frame Flow"
|
product: str = "PIGWay Frame Flow"
|
||||||
version: str = "0.1.18"
|
version: str = "0.1.19"
|
||||||
api_version: str = "v1"
|
api_version: str = "v1"
|
||||||
commit: str = "development"
|
commit: str = "development"
|
||||||
build_time: str = "unknown"
|
build_time: str = "unknown"
|
||||||
|
|||||||
@@ -481,9 +481,7 @@ class PhotoSources:
|
|||||||
continue
|
continue
|
||||||
size = row.get("additional", {}).get("resolution", {})
|
size = row.get("additional", {}).get("resolution", {})
|
||||||
width, height = size.get("width", 0), size.get("height", 0)
|
width, height = size.get("width", 0), size.get("height", 0)
|
||||||
rotation = row.get("additional", {}).get("orientation", 1)
|
# Photos resolution is already oriented; EXIF must not swap it twice.
|
||||||
if rotation in (5, 6, 7, 8):
|
|
||||||
width, height = height, width
|
|
||||||
if not self.resolution_matches(source, width, height):
|
if not self.resolution_matches(source, width, height):
|
||||||
continue
|
continue
|
||||||
direction = orientation(width, height)
|
direction = orientation(width, height)
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
<!doctype html>
|
<!doctype html>
|
||||||
<html lang="zh-CN"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1,viewport-fit=cover"><meta name="color-scheme" content="light dark"><title>PIGWay Frame Flow</title><link rel="stylesheet" href="/ui/style.css"></head>
|
<html lang="zh-CN"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1,viewport-fit=cover"><meta name="color-scheme" content="light dark"><title>PIGWay Frame Flow</title><link rel="stylesheet" href="/ui/style.css"></head>
|
||||||
<body><aside class="sidebar"><a class="brand" href="/"><span>PIGWay Frame Flow<small>Smart Frame Automation</small></span></a><nav id="nav"></nav><div class="sidebar-bottom"><small>Version 0.1.18</small></div></aside><div class="workspace"><header><div><span class="eyebrow">PIGWay Frame Flow</span><h1 id="page-title"></h1></div><div class="toolbar"><select id="device" aria-label="Device"></select><button id="lang" class="icon-button" aria-label="Change language">EN</button><button id="theme" class="icon-button" aria-label="Change theme">◐</button></div></header><main id="main"></main><footer id="footer"></footer></div><div id="toast" role="status" aria-live="polite"></div><dialog id="modal"><div id="modal-content"></div></dialog><script src="/ui/i18n.js?v=photo-quality-v0117"></script><script src="/ui/features.js?v=photo-quality-v0117"></script><script src="/ui/extensions.js?v=photo-quality-v0117"></script><script src="/ui/app.js?v=photo-quality-v0117"></script></body></html>
|
<body><aside class="sidebar"><a class="brand" href="/"><span>PIGWay Frame Flow<small>Smart Frame Automation</small></span></a><nav id="nav"></nav><div class="sidebar-bottom"><small>Version 0.1.19</small></div></aside><div class="workspace"><header><div><span class="eyebrow">PIGWay Frame Flow</span><h1 id="page-title"></h1></div><div class="toolbar"><select id="device" aria-label="Device"></select><button id="lang" class="icon-button" aria-label="Change language">EN</button><button id="theme" class="icon-button" aria-label="Change theme">◐</button></div></header><main id="main"></main><footer id="footer"></footer></div><div id="toast" role="status" aria-live="polite"></div><dialog id="modal"><div id="modal-content"></div></dialog><script src="/ui/i18n.js?v=photo-quality-v0117"></script><script src="/ui/features.js?v=photo-quality-v0117"></script><script src="/ui/extensions.js?v=photo-quality-v0117"></script><script src="/ui/app.js?v=photo-quality-v0117"></script></body></html>
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
[project]
|
[project]
|
||||||
name = "pigway-frame-flow"
|
name = "pigway-frame-flow"
|
||||||
version = "0.1.18"
|
version = "0.1.19"
|
||||||
requires-python = ">=3.14,<3.15"
|
requires-python = ">=3.14,<3.15"
|
||||||
dependencies = ["paho-mqtt==2.1.0", "python-dateutil==2.9.0.post0", "fastapi==0.142.2", "uvicorn==0.54.0", "pillow==12.3.0", "requests==2.34.2", "croniter==6.2.4", "python-multipart==0.0.32", "pyyaml==6.0.3"]
|
dependencies = ["paho-mqtt==2.1.0", "python-dateutil==2.9.0.post0", "fastapi==0.142.2", "uvicorn==0.54.0", "pillow==12.3.0", "requests==2.34.2", "croniter==6.2.4", "python-multipart==0.0.32", "pyyaml==6.0.3"]
|
||||||
[project.optional-dependencies]
|
[project.optional-dependencies]
|
||||||
|
|||||||
@@ -155,7 +155,7 @@ def release(lock):
|
|||||||
assert dst.execute("pragma quick_check").fetchone()[0] == "ok"
|
assert dst.execute("pragma quick_check").fetchone()[0] == "ok"
|
||||||
base = "pigway-frame-flow:release-base-" + commit[:12]
|
base = "pigway-frame-flow:release-base-" + commit[:12]
|
||||||
run("docker", "image", "tag", before["Image"], base)
|
run("docker", "image", "tag", before["Image"], base)
|
||||||
image = "pigway-frame-flow:0.1.18-" + commit[:12]
|
image = "pigway-frame-flow:0.1.19-" + commit[:12]
|
||||||
try:
|
try:
|
||||||
run(
|
run(
|
||||||
"docker",
|
"docker",
|
||||||
|
|||||||
@@ -405,7 +405,7 @@ def test_explicit_offline_conversion_preserves_task_reference(service, settings)
|
|||||||
|
|
||||||
@pytest.mark.parametrize("space", ["shared", "personal"])
|
@pytest.mark.parametrize("space", ["shared", "personal"])
|
||||||
@pytest.mark.parametrize("exif", [5, 6, 7, 8])
|
@pytest.mark.parametrize("exif", [5, 6, 7, 8])
|
||||||
def test_api_requests_orientation_before_filtering_rotated_portraits(
|
def test_api_filters_already_oriented_resolution_without_rotating_twice(
|
||||||
service, settings, monkeypatch, space, exif
|
service, settings, monkeypatch, space, exif
|
||||||
):
|
):
|
||||||
session(settings)
|
session(settings)
|
||||||
@@ -415,7 +415,8 @@ def test_api_requests_orientation_before_filtering_rotated_portraits(
|
|||||||
def pages(api, version, **params):
|
def pages(api, version, **params):
|
||||||
requested[:] = json.loads(params["additional"])
|
requested[:] = json.loads(params["additional"])
|
||||||
item = row(1)
|
item = row(1)
|
||||||
# Model Photos' opt-in fields: stored pixels alone look landscape.
|
# Photos returns display dimensions even when EXIF retains a rotation.
|
||||||
|
item["additional"]["resolution"] = {"width": 16, "height": 24}
|
||||||
if "orientation" in requested:
|
if "orientation" in requested:
|
||||||
item["additional"]["orientation"] = exif
|
item["additional"]["orientation"] = exif
|
||||||
return [item]
|
return [item]
|
||||||
@@ -469,6 +470,7 @@ def test_fetched_photo_direction_is_checked_before_cropping(
|
|||||||
# A correctly selected portrait remains readable, including EXIF-only rotation.
|
# A correctly selected portrait remains readable, including EXIF-only rotation.
|
||||||
item = row(1)
|
item = row(1)
|
||||||
item["additional"]["orientation"] = 8
|
item["additional"]["orientation"] = 8
|
||||||
|
item["additional"]["resolution"] = {"width": 16, "height": 24}
|
||||||
monkeypatch.setattr(photos.synology, "items", lambda *a, **k: [item])
|
monkeypatch.setattr(photos.synology, "items", lambda *a, **k: [item])
|
||||||
photos.save(
|
photos.save(
|
||||||
"direction",
|
"direction",
|
||||||
|
|||||||
Reference in New Issue
Block a user