Export Simply Plural Member Avatars
This guide explains how to retrieve Simply Plural member avatar images using REST commands from a Bash shell.
The procedure creates local image files named by Simply Plural member ID. This keeps avatar filenames data-stable and avoids placing member or decorator display names into the filesystem.
PluralBridge is published by Needs of the Many.
PluralBridge is independent and has no affiliation with Simply Plural, Apparyllis, or the Simply Plural development team.
Purpose
This document explains how to retrieve Simply Plural member avatar images using REST commands from a Bash shell. It follows the same working model as the JSON data extraction and SQL Server database creation guides: inspect first, save outputs to files, validate each result, and avoid embedding decorator/member display names in generated filenames.
The procedure creates local image files named by Simply Plural member ID. This keeps avatar filenames data-stable and avoids putting member/decorator names into the filesystem.
Required tools
Bash shell, such as Git Bash on Windows.
curl, used to execute the REST calls.
Python, used instead of jq to parse JSON because jq was not installed in the working environment.
file command, used to verify the downloaded images and identify image types.
A Simply Plural API token with Read permission.
Create and enter the Simply Plural token
In Simply Plural, create a token from Settings -> Account -> Tokens. Enable Read permission. In Chrome, press and hold the token value to copy it. If the token begins with a prefix such as TBD///, keep the full value exactly as copied.
Enter the token into Bash without displaying it on screen:
set +H
export SP_API='https://api.apparyllis.com'
read -s -p "Paste NEW Simply Plural token: " SP_TOKEN
echo
export SP_TOKEN
printf 'Token length: %s\n' "${#SP_TOKEN}"
Test API authorization
This REST call verifies that the token works before any member or avatar extraction begins.
curl -i -sS \
-H "Authorization: ${SP_TOKEN}" \
"${SP_API}/v1/me"
Expected result: HTTP 200 with JSON. If the response is HTTP 401 Unauthorized and says the authorization token is missing or invalid, revoke the token and create a fresh token with Read permission.
Prepare the local folders
Create the avatar output folder and move into the export working folder.
set +H
cd exports
mkdir -p member_images
Retrieve the account/system record
This saves the authenticated account/system record as me_api.json.
curl -sS \
-H "Authorization: ${SP_TOKEN}" \
"${SP_API}/v1/me" \
-o me_api.json
Inspect the file if needed:
cat me_api.json
Extract the system/user ID without jq
The local Bash environment did not have jq installed, so Python is used to extract the ID safely.
export SP_UID="$(
python - <<'PY'
import json
with open("me_api.json", "r", encoding="utf-8") as f:
data = json.load(f)
value = (
data.get("id")
or data.get("uid")
or data.get("content", {}).get("id")
or data.get("content", {}).get("uid")
)
print(value or "")
PY
)"
printf 'SP_UID=%s\n' "$SP_UID"
Expected result: SP_UID prints a non-empty ID. If it prints blank, inspect me_api.json before continuing.
Retrieve the member list
This REST call retrieves all members for the authenticated system and saves the result as members_api.json.
curl -sS \
-H "Authorization: ${SP_TOKEN}" \
"${SP_API}/v1/members/${SP_UID}" \
-o members_api.json
Validate that the file contains JSON member records:
head -20 members_api.json
Observed member avatar fields
The retrieved member records used this useful structure:
{
"id": "<member_id>",
"content": {
"uid": "<system_uid>",
"avatarUrl": "",
"avatarUuid": "<avatar_uuid>"
}
}
Most member records had an empty avatarUrl and a populated avatarUuid. Therefore the working image URL is constructed from content.uid and avatarUuid:
https://spaces.apparyllis.com/avatars/<content.uid>/<avatarUuid>
Build the member avatar URL list
This Python block creates member_avatar_urls.tsv. The file contains only member IDs and avatar URLs. It does not place member/decorator display names into the generated filenames.
cd exports
python - <<'PY'
import json
with open("members_api.json", "r", encoding="utf-8") as f:
members = json.load(f)
with open("member_avatar_urls.tsv", "w", encoding="utf-8", newline="\n") as out:
for row in members:
member_id = row.get("id", "")
c = row.get("content", {}) or {}
uid = c.get("uid", "")
avatar_uuid = c.get("avatarUuid", "")
avatar_url = c.get("avatarUrl", "")
if avatar_url:
url = avatar_url
elif uid and avatar_uuid:
url = f"https://spaces.apparyllis.com/avatars/{uid}/{avatar_uuid}"
else:
continue
out.write(f"{member_id}\t{url}\n")
PY
Verify the count and sample contents:
wc -l member_avatar_urls.tsv
head member_avatar_urls.tsv
The avatar manifest count may be lower than the member count because some members may not have an avatar image reference.
Download the avatar images
This loop downloads each avatar image and saves it as <member_id>.img. The temporary .img extension is used because the downloaded content type is verified afterward.
mkdir -p member_images
while IFS=$'\t' read -r member_id avatar_url
do
curl -L -sS "$avatar_url" \
-o "member_images/${member_id}.img"
done < member_avatar_urls.tsv
Verify downloaded image types
This checks the first downloaded files. In the verified run, the files reported as PNG image data, 512 x 512.
file member_images/*.img | head
Expected output looks like this:
member_images/<member_id>.img: PNG image data, 512 x 512, 8-bit/color RGB, non-interlaced
Rename .img files to real image extensions
This version renames files according to their actual MIME type.
cd member_images
for f in *.img
do
mime="$(file -b --mime-type "$f")"
case "$mime" in
image/png) mv "$f" "${f%.img}.png" ;;
image/jpeg) mv "$f" "${f%.img}.jpg" ;;
image/gif) mv "$f" "${f%.img}.gif" ;;
image/webp) mv "$f" "${f%.img}.webp" ;;
*) echo "Unknown type: $f -> $mime" ;;
esac
done
If every downloaded file verifies as PNG, this simpler rename is also acceptable after verification:
cd member_images
for f in *.img
do
mv "$f" "${f%.img}.png"
done
Final verification
Count the downloaded image files:
find member_images -maxdepth 1 -type f | wc -l
Expected result: a number matching the count of downloaded avatar files.
List the downloaded files:
find member_images -maxdepth 1 -type f | sort