Skip to content

Instantly share code, notes, and snippets.

@daniele-athome
Last active May 13, 2024 20:53
Show Gist options
  • Save daniele-athome/82ce8af869ec0e20cd73b69acbc589bd to your computer and use it in GitHub Desktop.
Save daniele-athome/82ce8af869ec0e20cd73b69acbc589bd to your computer and use it in GitHub Desktop.
Synchronize library folder structure with immich albums
#!/usr/bin/env bash
# Synchronize library folder structure with immich albums
# Usage: ./sync-albums.sh http://immich-host:port/api <api-key> <library-path>
set -e
BASE_URL="$1"
API_KEY="$2"
LIBRARY_PATH="${3%/}/"
album_list=$(mktemp)
api_get() {
curl -s -X GET --location -H "X-api-key: $API_KEY" "$BASE_URL/$1"
}
_api_body() {
method="$1"
shift
curl -s -X "$method" --data-raw "$2" --location -H "content-type: application/json" -H "X-api-key: $API_KEY" "$BASE_URL/$1"
}
urlencode() {
jq -rn --arg data "$1" '$data|@uri'
}
api_post() {
_api_body "POST" "$@"
}
api_delete() {
_api_body "DELETE" "$@"
}
api_put() {
_api_body "PUT" "$@"
}
_ere_quote() {
# shellcheck disable=SC2016
# shellcheck disable=SC2001
sed 's/[][\.|$(){}?+*^]/\\&/g' <<< "$*"
}
get_album_id() {
grep -E '^.*\|'"$(_ere_quote "$1")"'$' "$album_list" | awk -F'|' '{print $1}'
}
echo "Requesting all albums..."
while read -r album; do
echo "$(echo "$album" | jq -r '.id')|$(echo "$album" | jq -r '.albumName')" >>"$album_list"
done < <(api_get album | jq -c '.[]')
echo "Requesting all albums assets..."
album_assets_dir="$(mktemp -d)"
while read -r album; do
album_id="$(echo "$album" | awk -F'|' '{print $1}')"
api_get "album/$(urlencode "$album_id")" | jq -r '.assets[].id' >"$album_assets_dir/$album_id"
done < "$album_list"
echo "Requesting all assets..."
while read -r asset; do
original_path="$(echo "$asset" | jq -r '.originalPath')"
album_name="$(dirname "${original_path#$LIBRARY_PATH}")"
# create album if it doesn't exist
album_id="$(get_album_id "$album_name")"
if [ "$album_id" == "" ]; then
echo "Creating album '$album_name'"
# shellcheck disable=SC2016
album_id="$(api_post album "$(jq -ncM --arg name "$album_name" '{"albumName":$name}')" | jq -r '.id')"
# add the newly created album to the list so it will be found later
echo "$album_id|$album_name" >>"$album_list"
fi
asset_id="$(echo "$asset" | jq -r '.id')"
# retrieve albums that contain the asset
# add this one (if not present), remove all the others
# this reflects a file system structure: a photo cannot belong to multiple albums
skip_add_to_album=
while read -r asset_album_id; do
if [ "$asset_album_id" != "$album_id" ]; then
# asset must always belong to one album only
api_delete "album/$(urlencode "$asset_album_id")/assets" "$(jq -ncM --arg id "$asset_id" '{"ids":[$id]}')" >/dev/null
else
# asset already belongs to album
skip_add_to_album=y
echo "Asset $asset_id already in album '$album_name'"
fi
done < <(grep -l "$asset_id" "$album_assets_dir"/* | xargs -r basename)
if [ "$skip_add_to_album" == "" ]; then
# TODO make a single call per album
echo "Adding asset $asset_id to album '$album_name'"
api_put "album/$(urlencode "$album_id")/assets" "$(jq -ncM --arg id "$asset_id" '{"ids":[$id]}')" >/dev/null
fi
done < <(api_get asset | jq -c '.[]')
@tonyich
Copy link

tonyich commented May 3, 2024

Hello. I received an error:

Requesting all albums...
jq: error (at <stdin>:1): Cannot index string with string "id"
jq: error (at <stdin>:1): Cannot index string with string "albumName"
jq: error (at <stdin>:1): Cannot index string with string "id"
jq: error (at <stdin>:1): Cannot index string with string "albumName"
jq: error (at <stdin>:1): Cannot index number with string "id"
jq: error (at <stdin>:1): Cannot index number with string "albumName"
Requesting all albums assets...
./sync-albums.sh: line 58: /tmp/tmp.7jpPw9kTiq/: Is a directory

When I try to run script step-by-step it stop on line 50

# read -r album
parse error: Invalid numeric literal at line 2, column 0

@daniele-athome
Copy link
Author

daniele-athome commented May 3, 2024

It works here... did you pass the API key as the 2nd argument?

EDIT: I get exactly that error if I don't pass the API key (or if the API key is not valid, or other errors in the HTTP requests occur).

@tonyich
Copy link

tonyich commented May 4, 2024

Thanks for your help, apparently I have problems with my hands :). everything worked when I wrote all the variables in the script.

@daniele-athome
Copy link
Author

For anyone still using this: I switched to this great tool: https://github.com/Salvoxia/immich-folder-album-creator which does kind of the same thing, but with more options and much faster.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment