HEX
Server: Apache/2.4.63 (Unix)
System: Linux Synopilou92 4.4.302+ #72806 SMP Mon Jul 21 23:16:00 CST 2025 x86_64
User: pilou92 (1026)
PHP: 8.0.30
Disabled: NONE
Upload Files
File: /volume1/@appstore/SynologyPhotos/migration/python/fix_metadata_filter_error.py
#!/usr/bin/env python3

from collections import namedtuple
import json
import sys

import pg8000

has_cannot_handle_type = False
has_count_not_match = False


def init_cursor():
    user = "postgres"
    unix_sock = "/var/run/postgresql/.s.PGSQL.5432"
    database = "synofoto"
    conn = pg8000.connect(user, unix_sock=unix_sock, database=database)

    cursor = conn.cursor()
    cursor.execute("SET CLIENT_ENCODING TO 'UTF8'")

    return cursor


def get_duplication_filters(cursor):

    cursor.execute(
        """
        SELECT id_user, id_unit, filter_type, COUNT(id_filter) as count
        FROM filter
        WHERE filter_type in ('flash', 'aperture', 'camera', 'exposure_time', 'focal_length', 'folder', 'iso', 'item_type', 'lens', 'takentime')
        GROUP BY id_user, id_unit, filter_type
        HAVING count(id_filter) > 1;
        """
    )

    filters = []
    for id_user, id_unit, filter_type, count in cursor:
        item = {
            "id_user": id_user,
            "id_unit": id_unit,
            "filter_type": filter_type,
            "count": count,
        }
        filters.append(item)

    return filters


def can_handle_type(filter_type):
    global has_cannot_handle_type

    if filter_type in [
        "flash",
        "aperture",
        "camera",
        "exposure_time",
        "focal_length",
        "iso",
        "lens",
    ]:
        return True

    # folder, item_type, takentime
    # This should not happen
    has_cannot_handle_type = True
    return False


def remove_dup_meta(cursor, item):
    global has_count_not_match

    cursor.execute(
        """
        SELECT {filter_type}
        FROM metadata
        WHERE id_unit = {id_unit}
        """.format(
            **item
        )
    )

    [value] = cursor.fetchone()

    if isinstance(value, str) and len(value) == 0:
        cursor.execute(
            """
            DELETE
            FROM filter
            WHERE id_user = {id_user} AND id_unit = {id_unit} AND filter_type = '{filter_type}'
            """.format(
                **item
            )
        )
        return

    if item["filter_type"] == "flash":
        id_filter = value
    else:
        cursor.execute(
            """
            SELECT id
            FROM {filter_type}
            WHERE name = %s
            """.format(
                **item
            ),
            (value,),
        )

        [id_filter] = cursor.fetchone()

    # print(id_filter)

    cursor.execute(
        """
        SELECT COUNT(*) as count
        FROM filter
        WHERE id_user = {id_user} AND id_unit = {id_unit} AND filter_type = '{filter_type}' AND id_filter != {id_filter}
        """.format(
            **item, id_filter=id_filter
        )
    )

    [count] = cursor.fetchone()

    if count != item["count"] - 1:
        print(">>> count not match")
        has_count_not_match = True
        return

    print(">>> delete count match, do delete")

    cursor.execute(
        """
        DELETE
        FROM filter
        WHERE id_user = {id_user} AND id_unit = {id_unit} AND filter_type = '{filter_type}' AND id_filter != {id_filter}
        """.format(
            **item, id_filter=id_filter
        )
    )


def handle(cursor, dup_filters):

    for item in dup_filters:
        print(item)
        if not can_handle_type(item["filter_type"]):
            continue

        remove_dup_meta(cursor, item)


def main():
    cursor = init_cursor()

    dup_filters = get_duplication_filters(cursor)

    if len(dup_filters) == 0:
        print("No need to do autofix")
        return

    success = handle(cursor, dup_filters)

    cursor.execute("COMMIT")

    if has_count_not_match:
        print("FATAL!! Has delete count not match. Cannot autofix.")
        sys.exit(1)

    if has_cannot_handle_type:
        print("FATAL!! Has unsupported filter_type. Cannot autofix.")
        sys.exit(1)

    print("Autofix successfully.")


if __name__ == "__main__":
    main()