forked from Thoroslives/immich_remove_offline_files
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathAddOfflineToAlbum.py
121 lines (104 loc) · 5.21 KB
/
AddOfflineToAlbum.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
#!/usr/bin/env python3
# Note: you might need to run "pip install requests halo tabulate tqdm" if these dependencies are missing on your machine
import argparse
import json
import requests
from urllib.parse import urlparse
from halo import Halo
from tabulate import tabulate
from tqdm import tqdm
def parse_arguments():
parser = argparse.ArgumentParser(description='Fetch file report and add orphaned media assets to Album from Immich.')
# Make API key and Immich address arguments optional
parser.add_argument('--admin_apikey', help='Immich admin API key for fetching reports', nargs='?', default=None)
parser.add_argument('--user_apikey', help='User-specific Immich API key for deletion', nargs='?', default=None)
parser.add_argument('--user_id', help='Immich admin Profile ID', nargs='?', default=None)
parser.add_argument('--immichaddress', help='Full address for Immich, including protocol and port', nargs='?', default=None)
parser.add_argument('--no_prompt', action='store_true', help='Delete orphaned media assets without confirmation')
return parser.parse_args()
def filter_entities(response_json, entity_type):
return [
{'pathValue': entity['pathValue'], 'entityId': entity['entityId'], 'entityType': entity['entityType']}
for entity in response_json.get('orphans', []) if entity.get('entityType') == entity_type
]
def main():
args = parse_arguments()
# Prompt for admin API key if not provided
admin_api_key = args.admin_apikey if args.admin_apikey else input('Enter the Immich admin API key: ')
# Prompt for user API key if not provided
user_api_key = args.user_apikey if args.user_apikey else input('Enter the Immich user API key for deletion: ')
# Prompt for USER ID if not provided
user_id = args.user_id if args.user_id else input('Enter the Immich ProfileID: ')
# Prompt for Immich address if not provided
immich_server = args.immichaddress if args.immichaddress else input('Enter the full web address for Immich, including protocol and port: ')
if not admin_api_key or not user_api_key:
print("Both admin and user API keys are required.")
return
immich_parsed_url = urlparse(immich_server)
base_url = f'{immich_parsed_url.scheme}://{immich_parsed_url.netloc}'
api_url = f'{base_url}/api'
file_report_url = api_url + '/reports'
headers = {'x-api-key': admin_api_key}
print()
spinner = Halo(text='Retrieving list of orphaned media assets...', spinner='dots')
spinner.start()
try:
response = requests.get(file_report_url, headers=headers)
response.raise_for_status()
spinner.succeed('Success!')
except requests.exceptions.RequestException as e:
spinner.fail(f'Failed to fetch assets: {str(e)}')
return
orphan_media_assets = filter_entities(response.json(), 'asset')
num_entries = len(orphan_media_assets)
if num_entries == 0:
print('No orphaned media assets found; exiting.')
return
if not args.no_prompt:
table_data = [[asset['pathValue'], asset['entityId']] for asset in orphan_media_assets]
print(tabulate(table_data, headers=['Path Value', 'Entity ID'], tablefmt='pretty'))
print()
summary = f'There {"is" if num_entries == 1 else "are"} {num_entries} orphaned media asset{"s" if num_entries != 1 else ""}. Would you like to add to album {"them" if num_entries != 1 else "it"} in Immich? (yes/no): '
user_input = input(summary).lower()
print()
if user_input not in ('y', 'yes'):
print('Exiting without making any changes.')
return
headers['x-api-key'] = user_api_key # Use user API key for deletion
with tqdm(total=num_entries, desc="Managing orphaned media assets", unit="asset") as progress_bar:
for asset in orphan_media_assets:
entity_id = asset['entityId']
asset_url = f'{api_url}/albums'
url = f'{api_url}/albums'
payload = json.dumps({'force': True, 'ids': [entity_id]})
payload = json.dumps({
"albumName": "OfflineAssetPyScript",
"albumUsers": [
{
"role": "editor",
"userId": "{user_id}"
}
],
"assetIds": [
"{entity_id}"
],
"description": "Files From Script"
})
headers = {
'Content-Type': 'application/json',
'Accept': 'application/json'
}
headers = {'Content-Type': 'application/json', 'x-api-key': user_api_key}
try:
response = requests.request("POST", url, headers=headers, data=payload)
response.raise_for_status()
except requests.exceptions.HTTPError as e:
if response.status_code == 400:
print(f"Failed to manage asset {entity_id} due to potential API key mismatch. Ensure you're using the asset owners API key as the User API key.")
else:
print(f"Failed to manage asset {entity_id}: {str(e)}")
continue
progress_bar.update(1)
print('Orphaned media assets managed successfully!')
if __name__ == '__main__':
main()