Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix downloading shared photos from shared album #344

Merged
merged 8 commits into from
Aug 11, 2024
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 38 additions & 19 deletions src/synology_dsm/api/photos/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,12 @@ async def get_albums(

alexismarquis marked this conversation as resolved.
Show resolved Hide resolved
for album in data["list"]:
albums.append(
SynoPhotosAlbum(album["id"], album["name"], album["item_count"])
SynoPhotosAlbum(album["id"], album["name"], album["item_count"], album["passphrase"] if album["passphrase"] != '' else None)
)
return albums

def _raw_data_to_items(
self, raw_data: bytes | dict | str
self, raw_data: bytes | dict | str, passphrase: str | None = None
) -> list[SynoPhotosItem] | None:
"""Parse the raw data response to a list of photo items."""
items: list[SynoPhotosItem] = []
Expand All @@ -62,6 +62,7 @@ def _raw_data_to_items(
item["additional"]["thumbnail"]["cache_key"],
size,
item["owner_user_id"] == 0,
passphrase,
)
)
return items
Expand All @@ -80,7 +81,7 @@ async def get_items_from_album(
"additional": '["thumbnail"]',
},
)
return self._raw_data_to_items(raw_data)
return self._raw_data_to_items(raw_data, album.passphrase)

async def get_items_from_shared_space(
self, offset: int = 0, limit: int = 100
Expand Down Expand Up @@ -118,13 +119,19 @@ async def download_item(self, item: SynoPhotosItem) -> bytes | None:
download_api = self.DOWNLOAD_API_KEY
if item.is_shared:
download_api = self.DOWNLOAD_FOTOTEAM_API_KEY

params = {
"unit_id": f"[{item.item_id}]",
"cache_key": item.thumbnail_cache_key,
}

if item.passphrase is not None :
params["passphrase"] = item.passphrase

raw_data = await self._dsm.get(
download_api,
"download",
{
"unit_id": f"[{item.item_id}]",
"cache_key": item.thumbnail_cache_key,
},
params,
)
if isinstance(raw_data, bytes):
return raw_data
Expand All @@ -135,15 +142,21 @@ async def download_item_thumbnail(self, item: SynoPhotosItem) -> bytes | None:
download_api = self.THUMBNAIL_API_KEY
if item.is_shared:
download_api = self.THUMBNAIL_FOTOTEAM_API_KEY

params = {
"id": item.item_id,
"cache_key": item.thumbnail_cache_key,
"size": item.thumbnail_size,
"type": "unit",
}

if item.passphrase is not None :
params["passphrase"] = item.passphrase

raw_data = await self._dsm.get(
download_api,
"get",
{
"id": item.item_id,
"cache_key": item.thumbnail_cache_key,
"size": item.thumbnail_size,
"type": "unit",
},
params,
)
if isinstance(raw_data, bytes):
return raw_data
Expand All @@ -154,13 +167,19 @@ async def get_item_thumbnail_url(self, item: SynoPhotosItem) -> str:
download_api = self.THUMBNAIL_API_KEY
if item.is_shared:
download_api = self.THUMBNAIL_FOTOTEAM_API_KEY

params = {
"id": item.item_id,
"cache_key": item.thumbnail_cache_key,
"size": item.thumbnail_size,
"type": "unit",
}

if item.passphrase is not None :
params["passphrase"] = item.passphrase

return await self._dsm.generate_url(
download_api,
"get",
{
"id": item.item_id,
"cache_key": item.thumbnail_cache_key,
"size": item.thumbnail_size,
"type": "unit",
},
params,
)
2 changes: 2 additions & 0 deletions src/synology_dsm/api/photos/model.py
alexismarquis marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ class SynoPhotosAlbum:
album_id: int
name: str
item_count: int
passphrase: str
alexismarquis marked this conversation as resolved.
Show resolved Hide resolved


@dataclass
Expand All @@ -23,3 +24,4 @@ class SynoPhotosItem:
thumbnail_cache_key: str
thumbnail_size: str
is_shared: bool
passphrase: str
alexismarquis marked this conversation as resolved.
Show resolved Hide resolved
2 changes: 1 addition & 1 deletion src/synology_dsm/synology_dsm.py
Original file line number Diff line number Diff line change
Expand Up @@ -384,7 +384,7 @@ async def _execute_request(
]:
return dict(await response.json(content_type=content_type))

if content_type.startswith("image"):
if content_type == "application/octet-stream" or content_type.startswith("image"):
return await response.read()

return await response.text()
Expand Down
6 changes: 5 additions & 1 deletion tests/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@
DSM_7_DSM_INFORMATION,
DSM_7_FOTO_ALBUMS,
DSM_7_FOTO_ITEMS,
DSM_7_FOTO_ITEMS_SHARED_ALBUM,
DSM_7_FOTO_ITEMS_SEARCHED,
DSM_7_FOTO_SHARED_ITEMS,
)
Expand Down Expand Up @@ -285,7 +286,10 @@ async def _execute_request(self, method, url, params, **kwargs):
return DSM_7_FOTO_ALBUMS

if SynoPhotos.BROWSE_ITEM_API_KEY in url:
return DSM_7_FOTO_ITEMS
if "album_id=3" in url:
return DSM_7_FOTO_ITEMS_SHARED_ALBUM
else:
return DSM_7_FOTO_ITEMS

if SynoPhotos.SEARCH_API_KEY in url:
return DSM_7_FOTO_ITEMS_SEARCHED
Expand Down
4 changes: 3 additions & 1 deletion tests/api_data/dsm_7/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
"""DSM 6 datas."""
"""DSM 7 datas."""

from .const_7_api_auth import (
DSM_7_AUTH_LOGIN,
Expand All @@ -14,6 +14,7 @@
from .photos.const_7_photo import (
DSM_7_FOTO_ALBUMS,
DSM_7_FOTO_ITEMS,
DSM_7_FOTO_ITEMS_SHARED_ALBUM,
DSM_7_FOTO_ITEMS_SEARCHED,
DSM_7_FOTO_SHARED_ITEMS,
)
Expand All @@ -29,6 +30,7 @@
"DSM_7_DSM_INFORMATION",
"DSM_7_FOTO_ALBUMS",
"DSM_7_FOTO_ITEMS",
"DSM_7_FOTO_ITEMS_SHARED_ALBUM",
"DSM_7_FOTO_ITEMS_SEARCHED",
"DSM_7_FOTO_SHARED_ITEMS",
]
2 changes: 1 addition & 1 deletion tests/api_data/dsm_7/core/const_7_core_external_usb.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
"""DSM 6 SYNO.Core.ExternalDevice.Storage.USB data."""
"""DSM 7 SYNO.Core.ExternalDevice.Storage.USB data."""

DSM_7_CORE_EXTERNAL_USB_DS1821_PLUS_NO_EXTERNAL_USB = {
"data": {"devices": []},
Expand Down
47 changes: 47 additions & 0 deletions tests/api_data/dsm_7/photos/const_7_photo.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,25 @@
"type": "normal",
"version": 195694,
},
{
"cant_migrate_condition": {},
"condition": {},
"create_time": 1718658534,
"end_time": 1719075481,
"freeze_album": False,
"id": 3,
"item_count": 1,
"name": "Album3",
"owner_user_id": 7,
"passphrase": "NiXlv1i2N",
alexismarquis marked this conversation as resolved.
Show resolved Hide resolved
"shared": False,
"sort_by": "default",
"sort_direction": "default",
"start_time": 1659724703,
"temporary_shared": False,
"type": "normal",
"version": 102886,
},
]
},
"success": True,
Expand Down Expand Up @@ -111,6 +130,34 @@
},
}

DSM_7_FOTO_ITEMS_SHARED_ALBUM = {
"success": True,
"data": {
"list": [
{
"id": 29807,
"filename": "20221115_185645.jpg",
"filesize": 2644859,
"time": 1668538602,
"indexed_time": 1668564550862,
"owner_user_id": 7,
"folder_id": 597,
"type": "photo",
"additional": {
"thumbnail": {
"m": "ready",
"xl": "ready",
"preview": "broken",
"sm": "ready",
"cache_key": "29810_1668560967",
"unit_id": 29807,
}
},
},
]
},
}

DSM_7_FOTO_SHARED_ITEMS = {
"success": True,
"data": {
Expand Down
32 changes: 31 additions & 1 deletion tests/test_synology_dsm_7.py
Original file line number Diff line number Diff line change
Expand Up @@ -179,26 +179,39 @@ async def test_photos(self, dsm_7):
albums = await dsm_7.photos.get_albums()

assert albums
assert len(albums) == 2
assert len(albums) == 3
assert albums[0].album_id == 4
assert albums[0].name == "Album1"
assert albums[0].item_count == 3
assert albums[0].passphrase is None

assert albums[1].album_id == 1
assert albums[1].name == "Album2"
assert albums[1].item_count == 1
assert albums[1].passphrase is None

assert albums[2].album_id == 3
assert albums[2].name == "Album3"
assert albums[2].item_count == 1
assert albums[2].passphrase == 'NiXlv1i2N'

items = await dsm_7.photos.get_items_from_album(albums[0])
assert items
assert len(items) == 3
assert items[0].file_name == "20221115_185642.jpg"
assert items[0].thumbnail_cache_key == "29807_1668560967"
assert items[0].thumbnail_size == "xl"
assert items[0].passphrase is None

assert items[1].file_name == "20221115_185643.jpg"
assert items[1].thumbnail_cache_key == "29808_1668560967"
assert items[1].thumbnail_size == "m"
assert items[1].passphrase is None

assert items[2].file_name == "20221115_185644.jpg"
assert items[2].thumbnail_cache_key == "29809_1668560967"
assert items[2].thumbnail_size == "sm"
assert items[2].passphrase is None

thumb_url = await dsm_7.photos.get_item_thumbnail_url(items[0])
assert thumb_url
Expand All @@ -218,6 +231,23 @@ async def test_photos(self, dsm_7):
"&_sid=session_id&SynoToken=Sy%C3%B10_T0k%E2%82%AC%C3%B1"
)

items = await dsm_7.photos.get_items_from_album(albums[2])
assert items
assert len(items) == 1
assert items[0].file_name == "20221115_185645.jpg"
assert items[0].thumbnail_cache_key == "29810_1668560967"
assert items[0].thumbnail_size == "xl"
assert items[0].passphrase == 'NiXlv1i2N'

thumb_url = await dsm_7.photos.get_item_thumbnail_url(items[0])
assert thumb_url
assert thumb_url == (
"https://nas.mywebsite.me:443/webapi/entry.cgi?"
"id=29807&cache_key=29810_1668560967&size=xl&type=unit"
"&passphrase=NiXlv1i2N&api=SYNO.Foto.Thumbnail&version=2&method=get"
"&_sid=session_id&SynoToken=Sy%C3%B10_T0k%E2%82%AC%C3%B1"
)

items = await dsm_7.photos.get_items_from_search(albums[0])
assert items
assert len(items) == 2
Expand Down