Skip to content

Commit

Permalink
Merge pull request #88 from Salvoxia/fix/apiRequestTimeout
Browse files Browse the repository at this point in the history
Fix/api request timeout
  • Loading branch information
Salvoxia authored Dec 21, 2024
2 parents 7fa1733 + 8d6d797 commit c156481
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 20 deletions.
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,8 @@ This script is mostly based on the following original script: [REDVM/immich_auto
By default, the script only finds assets that are not archived in Immich. Set this option to make the script discover assets that are already archived. If -A/--find-assets-in-albums is set as well, both options apply. (default: False)
--read-album-properties
If set, the script tries to access all passed root paths and recursively search for .albumprops files in all contained folders. These properties will be used to set custom options on an per-album level. Check the readme for a complete documentation. (default: False)
--api-timeout API_TIMEOUT
Timeout when requesting Immich API in seconds (default: 20)
```
__Plain example without optional arguments:__
Expand Down Expand Up @@ -166,6 +168,7 @@ The environment variables are analoguous to the script's command line arguments.
| ARCHIVE | no | Set this option to automatically archive all assets that were newly added to albums.<br>If this option is set in combination with `MODE` = `CLEANUP` or `DELETE_ALL`, archived images of deleted albums will be unarchived.<br>Archiving hides the assets from Immich's timeline. (default: `False`)<br>Refer to [Automatic Archiving](#automatic-archiving). |
| FIND_ARCHIVED_ASSETS | no | By default, the script only finds assets that are not archived in Immich. Set this option make the script discover assets that are already archived. If -A/--find-assets-in-albums is set as well, both options apply. (default: `False`)<br>Refer to [Automatic Archiving](#automatic-archiving). |
| READ_ALBUM_PROPERTIES | no | Set to `True` to enable discovery of `.albumprops` files in root paths, allowing to set different album properties for differnt albums. (default: `False`)<br>Refer to [Setting Album-Fine Properties](#setting-album-fine-properties). |
| API_TIMEOUT | no | Timeout when requesting Immich API in seconds (default: `20`) |
#### Run the container with Docker
Expand Down
4 changes: 4 additions & 0 deletions docker/immich_auto_album.sh
Original file line number Diff line number Diff line change
Expand Up @@ -145,5 +145,9 @@ if [ ! -z "$READ_ALBUM_PROPERTIES" ]; then
args="--read-album-properties $args"
fi

if [ ! -z "$API_TIMEOUT" ]; then
args="--api-timeout \"$API_TIMEOUT\" $args"
fi

BASEDIR=$(dirname "$0")
echo $args | xargs python3 -u $BASEDIR/immich_auto_album.py
43 changes: 23 additions & 20 deletions immich_auto_album.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
SHARE_ROLES = ["editor", "viewer"]

# Immich API request timeout
REQUEST_TIMEOUT = 20
REQUEST_TIMEOUT_DEFAULT = 20

# Constants for album thumbnail setting
ALBUM_THUMBNAIL_RANDOM_ALL = "random-all"
Expand Down Expand Up @@ -666,12 +666,12 @@ def fetch_server_version() -> dict:
- patch
"""
api_endpoint = f'{root_url}server/version'
r = requests.get(api_endpoint, **requests_kwargs, timeout=REQUEST_TIMEOUT)
r = requests.get(api_endpoint, **requests_kwargs, timeout=api_timeout)
# The API endpoint changed in Immich v1.118.0, if the new endpoint
# was not found try the legacy one
if r.status_code == 404:
api_endpoint = f'{root_url}server-info/version'
r = requests.get(api_endpoint, **requests_kwargs, timeout=REQUEST_TIMEOUT)
r = requests.get(api_endpoint, **requests_kwargs, timeout=api_timeout)

if r.status_code == 200:
server_version = r.json()
Expand Down Expand Up @@ -729,7 +729,7 @@ def fetch_assets_with_options(search_options: dict) -> list:
# Initial API call, let's fetch our first chunk
page = 1
body['page'] = str(page)
r = requests.post(root_url+'search/metadata', json=body, **requests_kwargs, timeout=REQUEST_TIMEOUT)
r = requests.post(root_url+'search/metadata', json=body, **requests_kwargs, timeout=api_timeout)
r.raise_for_status()
response_json = r.json()
assets_received = response_json['assets']['items']
Expand All @@ -740,7 +740,7 @@ def fetch_assets_with_options(search_options: dict) -> list:
while len(assets_received) == number_of_assets_to_fetch_per_request_search:
page += 1
body['page'] = page
r = requests.post(root_url+'search/metadata', json=body, **requests_kwargs, timeout=REQUEST_TIMEOUT)
r = requests.post(root_url+'search/metadata', json=body, **requests_kwargs, timeout=api_timeout)
check_api_response(r)
response_json = r.json()
assets_received = response_json['assets']['items']
Expand All @@ -754,7 +754,7 @@ def fetch_albums():

api_endpoint = 'albums'

r = requests.get(root_url+api_endpoint, **requests_kwargs, timeout=REQUEST_TIMEOUT)
r = requests.get(root_url+api_endpoint, **requests_kwargs, timeout=api_timeout)
check_api_response(r)
return r.json()

Expand All @@ -771,7 +771,7 @@ def fetch_album_info(album_id_for_info: str):

api_endpoint = f'albums/{album_id_for_info}'

r = requests.get(root_url+api_endpoint, **requests_kwargs, timeout=REQUEST_TIMEOUT)
r = requests.get(root_url+api_endpoint, **requests_kwargs, timeout=api_timeout)
check_api_response(r)
return r.json()

Expand All @@ -795,7 +795,7 @@ def delete_album(album_delete: dict):
api_endpoint = 'albums'

logging.debug("Deleting Album: Album ID = %s, Album Name = %s", album_delete['id'], album_delete['albumName'])
r = requests.delete(root_url+api_endpoint+'/'+album_delete['id'], **requests_kwargs, timeout=REQUEST_TIMEOUT)
r = requests.delete(root_url+api_endpoint+'/'+album_delete['id'], **requests_kwargs, timeout=api_timeout)
try:
check_api_response(r)
return True
Expand Down Expand Up @@ -827,7 +827,7 @@ def create_album(album_name_to_create: str) -> str:
data = {
'albumName': album_name_to_create
}
r = requests.post(root_url+api_endpoint, json=data, **requests_kwargs, timeout=REQUEST_TIMEOUT)
r = requests.post(root_url+api_endpoint, json=data, **requests_kwargs, timeout=api_timeout)
check_api_response(r)

return r.json()['id']
Expand Down Expand Up @@ -903,7 +903,7 @@ def add_assets_to_album(assets_add_album_id: str, asset_list: list[str]) -> list
asset_list_added = []
for assets_chunk in assets_chunked:
data = {'ids':assets_chunk}
r = requests.put(root_url+api_endpoint+f'/{assets_add_album_id}/assets', json=data, **requests_kwargs, timeout=REQUEST_TIMEOUT)
r = requests.put(root_url+api_endpoint+f'/{assets_add_album_id}/assets', json=data, **requests_kwargs, timeout=api_timeout)
check_api_response(r)
response = r.json()

Expand All @@ -921,7 +921,7 @@ def fetch_users():

api_endpoint = 'users'

r = requests.get(root_url+api_endpoint, **requests_kwargs, timeout=REQUEST_TIMEOUT)
r = requests.get(root_url+api_endpoint, **requests_kwargs, timeout=api_timeout)
check_api_response(r)
return r.json()

Expand Down Expand Up @@ -1024,7 +1024,7 @@ def unshare_album_with_user(album_id_to_unshare: str, unshare_user_id: str):
HTTPError if the API call fails
"""
api_endpoint = f'albums/{album_id_to_unshare}/user/{unshare_user_id}'
r = requests.delete(root_url+api_endpoint, **requests_kwargs, timeout=REQUEST_TIMEOUT)
r = requests.delete(root_url+api_endpoint, **requests_kwargs, timeout=api_timeout)
check_api_response(r)

def update_album_share_user_role(album_id_to_share: str, share_user_id: str, share_user_role: str):
Expand Down Expand Up @@ -1052,7 +1052,7 @@ def update_album_share_user_role(album_id_to_share: str, share_user_id: str, sha
'role': share_user_role
}

r = requests.put(root_url+api_endpoint, json=data, **requests_kwargs, timeout=REQUEST_TIMEOUT)
r = requests.put(root_url+api_endpoint, json=data, **requests_kwargs, timeout=api_timeout)
check_api_response(r)

def share_album_with_user_and_role(album_id_to_share: str, user_ids_to_share_with: list[str], user_share_role: str):
Expand Down Expand Up @@ -1090,7 +1090,7 @@ def share_album_with_user_and_role(album_id_to_share: str, user_ids_to_share_wit
'albumUsers': album_users
}

r = requests.put(root_url+api_endpoint, json=data, **requests_kwargs, timeout=REQUEST_TIMEOUT)
r = requests.put(root_url+api_endpoint, json=data, **requests_kwargs, timeout=api_timeout)
check_api_response(r)

def trigger_offline_asset_removal():
Expand Down Expand Up @@ -1167,7 +1167,7 @@ def delete_assets(assets_to_delete: list, force: bool):
'ids': asset_ids_to_delete
}

r = requests.delete(root_url+api_endpoint, json=data, **requests_kwargs, timeout=REQUEST_TIMEOUT)
r = requests.delete(root_url+api_endpoint, json=data, **requests_kwargs, timeout=api_timeout)
check_api_response(r)


Expand Down Expand Up @@ -1200,7 +1200,7 @@ def fetch_libraries() -> list[dict]:

api_endpoint = 'libraries'

r = requests.get(root_url+api_endpoint, **requests_kwargs, timeout=REQUEST_TIMEOUT)
r = requests.get(root_url+api_endpoint, **requests_kwargs, timeout=api_timeout)
check_api_response(r)
return r.json()

Expand All @@ -1219,7 +1219,7 @@ def trigger_offline_asset_removal_async(library_id: str):

api_endpoint = f'libraries/{library_id}/removeOffline'

r = requests.post(root_url+api_endpoint, **requests_kwargs, timeout=REQUEST_TIMEOUT)
r = requests.post(root_url+api_endpoint, **requests_kwargs, timeout=api_timeout)
if r.status_code == 403:
logging.fatal("--sync-mode 2 requires an Admin User API key!")
else:
Expand All @@ -1244,7 +1244,7 @@ def set_album_thumb(thumbnail_album_id: str, thumbnail_asset_id: str):

data = {"albumThumbnailAssetId": thumbnail_asset_id}

r = requests.patch(root_url+api_endpoint, json=data, **requests_kwargs, timeout=REQUEST_TIMEOUT)
r = requests.patch(root_url+api_endpoint, json=data, **requests_kwargs, timeout=api_timeout)
check_api_response(r)

def choose_thumbnail(thumbnail_setting: str, thumbnail_asset_list: list[dict]) -> str:
Expand Down Expand Up @@ -1334,7 +1334,7 @@ def update_album_properties(album_to_update: AlbumModel):
if len(data) > 0:
api_endpoint = f'albums/{album_to_update.id}'

respnonse = requests.patch(root_url+api_endpoint, json=data, **requests_kwargs, timeout=REQUEST_TIMEOUT)
respnonse = requests.patch(root_url+api_endpoint, json=data, **requests_kwargs, timeout=api_timeout)
check_api_response(respnonse)

def set_assets_archived(asset_ids_to_archive: list[str], is_archived: bool):
Expand All @@ -1359,7 +1359,7 @@ def set_assets_archived(asset_ids_to_archive: list[str], is_archived: bool):
"isArchived": is_archived
}

r = requests.put(root_url+api_endpoint, json=data, **requests_kwargs, timeout=REQUEST_TIMEOUT)
r = requests.put(root_url+api_endpoint, json=data, **requests_kwargs, timeout=api_timeout)
check_api_response(r)

def check_api_response(response: requests.Response):
Expand Down Expand Up @@ -1684,6 +1684,7 @@ def find_user_by_name_or_email(name_or_email: str, user_list: list[dict]) -> dic
parser.add_argument("--read-album-properties", action="store_true",
help="""If set, the script tries to access all passed root paths and recursively search for .albumprops files in all contained folders.
These properties will be used to set custom options on an per-album level. Check the readme for a complete documentation.""")
parser.add_argument("--api-timeout", default=REQUEST_TIMEOUT_DEFAULT, type=int, help="Timeout when requesting Immich API in seconds")


args = vars(parser.parse_args())
Expand Down Expand Up @@ -1718,6 +1719,7 @@ def find_user_by_name_or_email(name_or_email: str, user_list: list[dict]) -> dic
archive = args["archive"]
find_archived_assets = args["find_archived_assets"]
read_album_properties = args["read_album_properties"]
api_timeout = args["api_timeout"]

# Override unattended if we're running in destructive mode
if mode != SCRIPT_MODE_CREATE:
Expand Down Expand Up @@ -1750,6 +1752,7 @@ def find_user_by_name_or_email(name_or_email: str, user_list: list[dict]) -> dic
logging.debug("archive = %s", archive)
logging.debug("find_archived_assets = %s", find_archived_assets)
logging.debug("read_album_properties = %s", read_album_properties)
logging.debug("api_timeout = %s", api_timeout)

# Verify album levels
if is_integer(album_levels) and album_levels == 0:
Expand Down

0 comments on commit c156481

Please sign in to comment.