#!/usr/bin/env python3 """Delete corrupted +1 video files from Immich.""" import requests API_KEY = "GsWQUTR6EXlkKp1M82jDJ3KmzhM0fMAbbIbfHDyI" BASE_URL = "http://localhost:2283/api" # Corrupted files: (filename, corrupted path) CORRUPTED_FILES = [ ("2010-04-14_07-38-01_290_Heerenveen+1.mp4", "/data/library/admin/2010/04/2010-04-14_07-38-01_290_Heerenveen+1.mp4"), ("IMG_0259+1.mov", "/data/library/admin/2012/01/IMG_0259+1.mov"), ("IMG_0262+1.mov", "/data/library/admin/2012/01/IMG_0262+1.mov"), ("IMG_0169+1.mov", "/data/library/admin/2010/08/IMG_0169+1.mov"), ("MVI_0342+1.mov", "/data/library/admin/2012/08/MVI_0342+1.mov"), ("MVI_0496+1.mov", "/data/library/admin/2012/08/MVI_0496+1.mov"), ("MVI_0462+1.mov", "/data/library/admin/2012/08/MVI_0462+1.mov"), ("MVI_0452+1.mov", "/data/library/admin/2012/08/MVI_0452+1.mov"), ("MVI_0448+1.mov", "/data/library/admin/2012/08/MVI_0448+1.mov"), ("MVI_0463+1.mov", "/data/library/admin/2012/08/MVI_0463+1.mov"), ("MVI_0468+1.mov", "/data/library/admin/2012/08/MVI_0468+1.mov"), ("MVI_0534+1.mov", "/data/library/admin/2012/08/MVI_0534+1.mov"), ("MVI_0446+1.mov", "/data/library/admin/2012/08/MVI_0446+1.mov"), ("MVI_0466+1.mov", "/data/library/admin/2012/08/MVI_0466+1.mov"), ("MVI_0335+1.mov", "/data/library/admin/2012/08/MVI_0335+1.mov"), ("MVI_0495+1.mov", "/data/library/admin/2012/08/MVI_0495+1.mov"), ("MVI_0531+1.mov", "/data/library/admin/2012/08/MVI_0531+1.mov"), ("MVI_0404+1.mov", "/data/library/admin/2012/08/MVI_0404+1.mov"), ("MVI_0467+1.mov", "/data/library/admin/2012/08/MVI_0467+1.mov"), ("MVI_0454+1.mov", "/data/library/admin/2012/08/MVI_0454+1.mov"), ("MVI_0389+1.mov", "/data/library/admin/2012/08/MVI_0389+1.mov"), ("MVI_0469+1.mov", "/data/library/admin/2012/08/MVI_0469+1.mov"), ("IMG_0147+1.mov", "/data/library/admin/2011/06/IMG_0147+1.mov"), ("MVI_0465+1.mov", "/data/library/admin/2012/08/MVI_0465+1.mov"), ("MVI_0444+1.mov", "/data/library/admin/2012/08/MVI_0444+1.mov"), ("MVI_0470+1.mov", "/data/library/admin/2012/08/MVI_0470+1.mov"), ("MVI_0440+1.mov", "/data/library/admin/2012/08/MVI_0440+1.mov"), ("2010-04-04_16-06-22_374_Noordoostpolder+1.mp4", "/data/library/admin/2010/04/2010-04-04_16-06-22_374_Noordoostpolder+1.mp4"), ("MVI_0060+1.mov", "/data/library/admin/2012/06/MVI_0060+1.mov"), ("IMG_0582+1.mov", "/data/library/admin/2012/11/IMG_0582+1.mov"), ] def search_file(filename): resp = requests.post( f"{BASE_URL}/search/metadata", headers={"x-api-key": API_KEY, "Content-Type": "application/json"}, json={"originalFileName": filename} ) if resp.status_code == 200: return resp.json().get("assets", {}).get("items", []) return [] def delete_asset(asset_id, path): resp = requests.delete( f"{BASE_URL}/assets", headers={"x-api-key": API_KEY, "Content-Type": "application/json"}, json={"ids": [asset_id], "force": True} ) if resp.status_code == 204: print(f"DELETED: {path}") return True else: print(f"FAILED: {path} - {resp.status_code}") return False deleted = 0 not_found = 0 for filename, expected_path in CORRUPTED_FILES: # Search for this filename # The filename in Immich might not have +1 in the originalFileName # Try searching without the +1 base_name = filename.replace("+1", "") assets = search_file(base_name) found = False for asset in assets: if asset["originalPath"] == expected_path: if delete_asset(asset["id"], expected_path): deleted += 1 found = True break if not found: # Try with +1 in filename assets = search_file(filename) for asset in assets: if asset["originalPath"] == expected_path: if delete_asset(asset["id"], expected_path): deleted += 1 found = True break if not found: print(f"NOT FOUND: {filename} at {expected_path}") not_found += 1 print(f"\nTotal deleted: {deleted}") print(f"Not found: {not_found}")