File: /volume1/@appstore/SynologyPhotos/migration/python/dump_photo_station_shared_album.py
#!/usr/bin/env python3
import datetime
import json
import logging
import sys
import pg8000
DOWNLOAD_CONFIG_KEYS = ["allow_user_download", "allow_guest_download"]
class BaseAlbum:
def __init__(self, cursor):
self.cursor = cursor
self.for_admin = False
def get_album_table(self):
if self.for_admin:
return "photo_personal_collection_for_admin"
return "photo_personal_collection_for_dsm_account"
def get_photo_relation_table(self):
if self.for_admin:
return "photo_personal_collection_photo_for_admin"
return "photo_personal_collection_photo_for_dsm_account"
def get_video_relation_table(self):
if self.for_admin:
return "photo_personal_collection_video_for_admin"
return "photo_personal_collection_video_for_dsm_account"
def get_advanced_table(self):
if self.for_admin:
return "photo_advanced_personal_collection_for_admin"
return "photo_advanced_personal_collection_for_dsm_account"
def get_album_uid_field(self):
if self.for_admin:
return "1024 AS userid"
return "userid"
def get_album_sql(self):
return """
SELECT id, {}, name, is_shared, start_time, end_time, is_advanced
FROM {}
""".format(
self.get_album_uid_field(), self.get_album_table()
)
def get_albums(self):
self.for_admin = False
from_dsm_account = self.get_albums_internal()
self.for_admin = True
from_admin = self.get_albums_internal()
albums = from_dsm_account + from_admin
self.filter_albums(albums)
return albums
def filter_albums(self, albums):
pass
def get_albums_internal(self):
self.cursor.execute(self.get_album_sql())
albums = []
for (
id_album,
uid,
name,
is_shared,
start_time,
end_time,
is_advanced,
) in self.cursor:
album = {
"id": id_album,
"uid": uid,
"name": name,
"shared": is_shared,
"start_time": self.to_timestamp(start_time),
"end_time": self.to_timestamp(end_time),
"is_advanced": is_advanced,
}
albums.append(album)
self.fill_item(albums)
self.fill_md5ed_password(albums)
return albums
def fill_item(self, albums):
for album in albums:
id_album = album["id"]
photos = self.get_photos_by_normal_album_id(id_album)
videos = self.get_videos_by_normal_album_id(id_album)
album["item"] = photos + videos
def fill_md5ed_password(self, albums):
for album in albums:
is_advanced = album["is_advanced"]
id_album = album["id"]
md5ed_password = ""
if is_advanced:
md5ed_password = self.get_password_by_album_id(id_album)
album["md5ed_password"] = md5ed_password
def to_timestamp(self, date_object):
if not date_object:
return 0
delta = date_object - datetime.date.fromtimestamp(0)
return int(delta.total_seconds())
def get_photos_by_normal_album_id(self, id_album):
self.cursor.execute(
"""
SELECT path
FROM {} as Relation, photo_image as Image
WHERE
Relation.collectionid={} AND
Image.id = Relation.photoid
""".format(
self.get_photo_relation_table(), id_album
)
)
items = []
for [path] in self.cursor:
items.append(path)
return items
def get_videos_by_normal_album_id(self, id_album):
self.cursor.execute(
"""
SELECT path
FROM {} as Relation, video as Video
WHERE
Relation.collectionid={} AND
Video.id = Relation.videoid
""".format(
self.get_video_relation_table(), id_album
)
)
items = []
for [path] in self.cursor:
items.append(path)
return items
def get_password_by_album_id(self, id_album):
self.cursor.execute(
"""
SELECT enable_password, password
FROM {}
WHERE collectionid = {}
""".format(
self.get_advanced_table(), id_album
)
)
row = self.cursor.fetchone()
if row is None:
return ""
enable_password, md5ed_password = row
if enable_password:
return md5ed_password
return ""
class NormalAlbum(BaseAlbum):
def get_album_sql(self):
return """
SELECT id, {}, name, is_shared, start_time, end_time, is_advanced
FROM {}
WHERE hidden='f' AND shareid IS NULL
""".format(
self.get_album_uid_field(), self.get_album_table()
)
class SharedAlbums:
def __init__(self):
self.cursor = self.init_cursor("photo")
self.config = self.init_config()
self.normal_albums = self.init_normal_albums()
self.apply_share_permission()
self.uids = self.init_uids()
def init_cursor(self, db_name):
user = "postgres"
unix_sock = "/var/run/postgresql/.s.PGSQL.5432"
database = db_name
conn = pg8000.connect(user, unix_sock=unix_sock, database=database)
cursor = conn.cursor()
cursor.execute("SET CLIENT_ENCODING TO 'UTF8'")
return cursor
def get_config(self):
return self.config
def get_normal_albums(self):
return self.normal_albums
def get_uids(self):
return self.uids
def init_config(self):
download_config = self.get_download_config()
sharing_config = self.get_sharing_config()
return {**download_config, **sharing_config}
def init_normal_albums(self):
return NormalAlbum(self.cursor).get_albums()
def apply_share_permission(self):
role = "download" if self.config["allow_guest_download"] else "view"
for album in self.normal_albums:
album["permission"] = {"role": role, "member": {"type": "public"}}
def init_uids(self):
uid_set = set()
for album in self.normal_albums:
uid = album["uid"]
uid_set.add(uid)
return sorted(list(uid_set))
def get_download_config(self):
self.cursor.execute(
"""
SELECT config_key, config_value
FROM photo_config
WHERE config_key IN ({})
""".format(
",".join(["%s"] * len(DOWNLOAD_CONFIG_KEYS))
),
DOWNLOAD_CONFIG_KEYS,
)
d = {}
for key in DOWNLOAD_CONFIG_KEYS:
d[key] = False
for key, value in self.cursor:
d[key] = True if value == "on" else False
return d
def get_sharing_privilege(self):
privilege_map = {
"0": "administrators",
"1": "everyone",
"2": "uids",
}
default_privilege = privilege_map["0"]
self.cursor.execute(
"""
SELECT config_key, config_value
FROM photo_config
WHERE config_key = 'public_sharing_privilege'
"""
)
row = self.cursor.fetchone()
if row is None:
return default_privilege
_, privilege_index = row
return privilege_map.get(privilege_index, default_privilege)
def get_sharing_uids(self):
self.cursor.execute(
"""
SELECT userid
FROM photo_public_share_right_for_dsm_account
"""
)
uid_rows = self.cursor.fetchall()
return [x for [x] in uid_rows]
def get_sharing_config(self):
privilege = self.get_sharing_privilege()
user_ids = []
if privilege == "uids":
user_ids = self.get_sharing_uids()
return {
"public_sharing_privilege": privilege,
"public_sharing_uids": user_ids,
}
def main():
shared = SharedAlbums()
result = {
"config": shared.get_config(),
"normal_albums": shared.get_normal_albums(),
"uids": shared.get_uids(),
}
return result
if __name__ == "__main__":
logging.basicConfig(level=logging.INFO)
result = main()
if len(sys.argv) >= 2:
path = sys.argv[1]
json.dump(result, open(path, "w"))
else:
print(json.dumps(result, indent=2))