chore: Update everything
This commit is contained in:
@@ -0,0 +1,105 @@
|
||||
import httpx
|
||||
import os
|
||||
from datetime import datetime
|
||||
from collections import defaultdict
|
||||
from typing import List, Dict, Any
|
||||
|
||||
# Get environment variables
|
||||
IMMICH_API_KEY = os.environ.get("IMMICH_API_KEY")
|
||||
IMMICH_SERVER_URL = os.environ.get("IMMICH_SERVER_URL")
|
||||
|
||||
if not IMMICH_API_KEY or not IMMICH_SERVER_URL:
|
||||
raise ValueError("IMMICH_API_KEY and IMMICH_SERVER_URL environment variables must be set")
|
||||
|
||||
# Setup HTTP client with auth headers
|
||||
headers = {"Content-Type": "application/json", "Accept": "application/json", "x-api-key": IMMICH_API_KEY}
|
||||
|
||||
# Global HTTP client
|
||||
client = httpx.Client(headers=headers)
|
||||
|
||||
|
||||
def get_albums() -> List[Dict[str, Any]]:
|
||||
"""Fetch all albums from Immich API"""
|
||||
response = client.get(f"{IMMICH_SERVER_URL}/api/albums")
|
||||
response.raise_for_status()
|
||||
return response.json()
|
||||
|
||||
|
||||
def get_album_assets(album_id: str) -> List[str]:
|
||||
"""Fetch all asset IDs from a specific album"""
|
||||
response = client.get(f"{IMMICH_SERVER_URL}/api/albums/{album_id}?withoutAssets=false")
|
||||
response.raise_for_status()
|
||||
album_data = response.json()
|
||||
return [asset["id"] for asset in album_data.get("assets", [])]
|
||||
|
||||
|
||||
def add_assets_to_album(album_id: str, asset_ids: List[str]) -> None:
|
||||
"""Add assets to an album"""
|
||||
if not asset_ids:
|
||||
return
|
||||
|
||||
response = client.put(f"{IMMICH_SERVER_URL}/api/albums/{album_id}/assets", json={"ids": asset_ids})
|
||||
response.raise_for_status()
|
||||
|
||||
|
||||
def delete_album(album_id: str) -> None:
|
||||
"""Delete an album"""
|
||||
response = client.delete(f"{IMMICH_SERVER_URL}/api/albums/{album_id}")
|
||||
response.raise_for_status()
|
||||
|
||||
|
||||
def deduplicate_albums():
|
||||
"""Main function to deduplicate albums"""
|
||||
print("Fetching albums...")
|
||||
albums = get_albums()
|
||||
|
||||
# Group albums by name (case-insensitive)
|
||||
album_groups = defaultdict(list)
|
||||
for album in albums:
|
||||
album_name = album["albumName"].lower().strip()
|
||||
album_groups[album_name].append(album)
|
||||
|
||||
# Process groups with duplicates
|
||||
for album_name, album_list in album_groups.items():
|
||||
if len(album_list) <= 1:
|
||||
continue # Skip groups with only one album
|
||||
|
||||
print(f"\nProcessing duplicate albums for: '{album_name}' ({len(album_list)} albums)")
|
||||
|
||||
# Sort by creation date to find the oldest
|
||||
album_list.sort(key=lambda x: datetime.fromisoformat(x["createdAt"].replace("Z", "+00:00")))
|
||||
oldest_album = album_list[0]
|
||||
duplicate_albums = album_list[1:]
|
||||
|
||||
print(f" Oldest album: {oldest_album['id']} (created: {oldest_album['createdAt']})")
|
||||
|
||||
# Collect assets from duplicate albums
|
||||
all_asset_ids = []
|
||||
for dup_album in duplicate_albums:
|
||||
print(f" Processing duplicate: {dup_album['id']} (created: {dup_album['createdAt']})")
|
||||
asset_ids = get_album_assets(dup_album["id"])
|
||||
all_asset_ids.extend(asset_ids)
|
||||
print(f" Found {len(asset_ids)} assets")
|
||||
|
||||
# Add assets to oldest album
|
||||
if all_asset_ids:
|
||||
print(f" Adding {len(all_asset_ids)} assets to oldest album...")
|
||||
add_assets_to_album(oldest_album["id"], all_asset_ids)
|
||||
|
||||
# Delete duplicate albums
|
||||
for dup_album in duplicate_albums:
|
||||
print(f" Deleting duplicate album: {dup_album['id']}")
|
||||
delete_album(dup_album["id"])
|
||||
|
||||
print(f" ✓ Merged {len(duplicate_albums)} duplicate albums into {oldest_album['id']}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
try:
|
||||
deduplicate_albums()
|
||||
print("\n✓ Album deduplication completed successfully!")
|
||||
except Exception as e:
|
||||
print(f"\n✗ Error: {e}")
|
||||
raise
|
||||
finally:
|
||||
client.close()
|
||||
Reference in New Issue
Block a user