Skip to content

Instantly share code, notes, and snippets.

@2q2code
Created February 14, 2025 01:33
Show Gist options
  • Select an option

  • Save 2q2code/331265beed478d8d150781d8bc43536c to your computer and use it in GitHub Desktop.

Select an option

Save 2q2code/331265beed478d8d150781d8bc43536c to your computer and use it in GitHub Desktop.
Python script that removes non-HEIC duplicates of HEIC files from immich
#!/usr/bin/env python3
import sys
import json
import argparse
import requests
# PREREQUISITES:
# - python 3 of some variety (I used 3.12.7)
# - python venv module (if using a virtual environment as described below)
# - this script file
# PREPARATION:
# In your immich user profile, go to `Account Settings`, `API Keys`, and create a new API key for use
# with this script (or use an existing one idc :)) - copy it down somewhere you can copy-paste from later.
# Also note down the URL of your immich instance. You'll need that too.
# INSTALLATION:
# - create a virtual environment for this script (you can delete it later) on any computer that can access your immich instance
# > python -m venv heic_dup_keep
# - activate the virtual environment
# > cd heic_dup_keep/bin; source ./activate
# - copy this script into the directory (optional, but tidy)
# > cp WHEREVER_THIS_IS/heic_dup_keep.py .
# - make it executable
# > chmod +x heic_dup_keep.py
# - install the required library
# > pip install requests
# RUNNING:
# - run the script with -h to see how to use it, but here is an example:
# > ./heic_dup_keep.py https://immich.awesomeperson.net 12345NONSENSEAPIKEYHERE
# CLEANUP:
# - deactivate the virtual environment
# > deactivate
# - delete the virtual environment directory and all in it
# > rm -r heic_dup_keep
# - fin!
def do_get(base_url, headers, url):
try:
response = requests.get(f'{base_url}/{url}', headers=headers)
response.raise_for_status()
return response.json()
except requests.exceptions.RequestException as e:
print(f"Error: {e}", file=sys.stderr)
sys.exit(1)
def delete_assets(base_url, headers, asset_list):
ids = list(map(lambda item: item['id'], asset_list))
payload = json.dumps({
"force": False,
"ids": ids
})
requests.request("DELETE", f'{base_url}/assets', headers=headers, data=payload)
print(f'Removed {len(ids)} assets')
def list_dups(base_url, api_key):
print('Retrieving duplicates list...')
print(f"url: {base_url}, api_key: {api_key}\n")
headers = {
'Content-Type': 'application/json',
'Accept': 'application/json',
'x-api-key': api_key
}
response = do_get(base_url, headers, 'duplicates')
remove_assets_list = []
summary_list = []
for dupItem in response:
# print(json.dumps(dupItem, indent=2))
heic_file = False
temp_asset = []
duplicates_for_removal = []
heic_filename = ''
for asset in dupItem['assets']:
if 'image/heic' != asset['originalMimeType']:
temp_asset.append(asset)
duplicates_for_removal.append(asset['originalPath'])
else:
heic_file = True
heic_filename = asset['originalPath']
if heic_file and temp_asset:
remove_assets_list.extend(temp_asset)
sum_obj = {
"would_keep": heic_filename,
"would_trash": duplicates_for_removal
}
summary_list.append(sum_obj)
if remove_assets_list:
print('Review the following list and confirm to remove:\n')
print(json.dumps(summary_list, indent=2))
print(f"\nTotal number of unique images (duplicate sets): {len(summary_list)}")
print(f"Total number of non-HEIC duplicate images to be removed: {len(remove_assets_list)}\n")
user_input = input('\nProceed to trash the duplicates? (y/n)')
if user_input.lower() in ('y','yes'):
delete_assets(base_url, headers, remove_assets_list)
else:
print('Cancelled.')
else:
print('No duplicates found.')
def main():
desc = "A slightly more user-friendly HEIC duplicate keeper,\n \
based on github user `dahool`'s original gist.\n \
This script will identify all existing duplicate images sets in\n \
your immich library that contain (at least) one HEIC file, print a summary of proposed action, then offer\n \
to move the non-HEIC duplicates to immich trash. All actions can be undone by restoring the items from trash in immich."
epilog = "WARNING: Do NOT use this script if you use RAW files (and wish to keep them) like DNG etc - as it\n \
will remove them in favour of the HEIC files also. I will likely make a modified version of this for that case later.\n \
AUTHOR TAKES NO RESPONSIBILITY for effects of this script. Please use with caution and make sure you back up first."
parser = argparse.ArgumentParser(description=desc, epilog=epilog)
parser.add_argument("url", type=str, help="The URL of your immich instance e.g. https://immich.awesomeplace.com, or http://localhost:2283")
parser.add_argument("apikey", type=str, help="An API key generated in your user profile, on your immich instance")
args = parser.parse_args()
list_dups(args.url + '/api', args.apikey)
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment