commit 45fa779bc63120aeb7fbec5c26030cb339ac19a8 Author: Oneric Date: Wed Sep 25 17:28:30 2024 +0200 Initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e7c09f2 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +# Ignore remote emoji data cache +.cache diff --git a/README.rst b/README.rst new file mode 100644 index 0000000..8aa61fd --- /dev/null +++ b/README.rst @@ -0,0 +1,62 @@ +=========== +Yoink-Emoji +=========== + +Lets you yoink emoji packs from any other instance with MastoAPI suppport, +instead of only shareable packs from other \*oma instances like admin-fe does. + +Note this currently might not work as well for updating packs not created by this script. +It expects files t be named after their shortocde, if an meoji already exists but with +a different filename this will leave duplicate images behind. +*(shortocde names are checked to be safe wrt to path traversal before writing anything)* + +Installing +========== + +Just plop the script somewhere. + +A ``.cache`` for remote emoji data will be created at the script location. +*(Caches remain valid within the same UTC day, currently not cleaned up automatically so just `rm -fr .cache` from time to time if it becomes too big)* + +Usage +===== + +Enter the emoji pack dir (or create an new empty dir for this), then incoke the script; +the third argument is optional: + +``` +yoink-or-update-emoj.sh domain_of_server_to_be_yoinked_from category_to yoink [additional_conditions] +``` + +Additionally the follwoing env vars affect the result: + +- ``OVERWRITE_IMG=YES``: overwrite existing images instead of skipping download +- ``OVERWRITE_METAKEYS=YES``: overwrite existing shortcode file path entries instead of preserving the original + +Example +------- + +Yoinking the blobcat pack from an Akkoma instance and also merge any blobcat emotes from another category into the local pack: +```sh +yoink-or-update-emoji.sh example.org "pack:blobcat" 'or (.shortcode | test("blobcatpnd|^ameow|^blobcat|^ablobcat"))' +``` + +Yoink woozy pack from a Sharkey instance *(no ``pack:`` prefix)*: +```sh +yoink-or-update-emoji.sh example.org "woozy" +``` + +Merge multiple remote packs into one local pack: +```sh +yoink-or-update-emoji.sh example.org "pack:touhou" 'or .category == "pack:reimu" or .category == "pack:marisa"' +``` + + +Dependencies +============ + +- POSIX ``sh`` and ``awk`` _(in general all POSIX tools)_ +- ``date`` with ``-I`` extension +- jq +- wget **and** curl _(idk why i used both, might remove one at some point)_ +- ``mktemp`` diff --git a/yoink-or-update-emojipack.sh b/yoink-or-update-emojipack.sh new file mode 100755 index 0000000..c5a0ff9 --- /dev/null +++ b/yoink-or-update-emojipack.sh @@ -0,0 +1,104 @@ +#!/bin/sh +set -eu + +if [ "$#" -lt 2 ] ; then + echo "Usage: $0 []" >&2 + exit 2 +fi + +DOMAIN="$1" +CATEGORY="$2" +ADDCOND="${3:-}" + +OVERWRITE_IMG="${OVERWRITE_IMG:-NO}" +OVERWRITE_METAKEYS="${OVERWRITE_METAKEYS:-NO}" + +json_str_escape() { + echo "$1" | sed -e 's/"/\\"/g' +} + +CACHE_DIR="$(dirname "$0")"/.cache +cached_list="$CACHE_DIR"/"$(date -I)_${DOMAIN}" + +if [ ! -e "$cached_list" ] ; then + mkdir -p "$CACHE_DIR" + curl https://"$DOMAIN"/api/v1/custom_emojis | jq > "$cached_list" +fi + +# Track additions in "pack.json".files format +META_ADD="$(mktemp)" +meta_prefix="{" + +# @tsv doesn't actually directly produce TSV, but for each line a string which escapes tabs as \t... +cat "$cached_list" \ + | jq '.[] | select(.category == "'"$CATEGORY"'"'"${ADDCOND:+ }${ADDCOND}"') | [.shortcode, .static_url] | @tsv' \ + | awk '1 {gsub(/^"|"$/, ""); sub(/\\t/, "\t"); print}' \ + | while IFS="$(printf '\t')" read -r name url; do + urlfile="$(basename "$url")" + ext="${urlfile##*.}"; + if [ "$ext" = "$urlfile" ] ; then + ext="" + fi + + if [ "$name" != "$(basename "$name")" ] ; then + echo "ERROR: unsafe, potentially malicious shortcode '$name'; aborting!" + exit 1 + fi + + out="${name}${ext:+.}${ext}" + if [ "$OVERWRITE_IMG" = "YES" ] || [ ! -e "$out" ] ; then + echo "Downloading $out ..." + wget --quiet --output-document="$out" "$url" + printf '%s\n\t"%s": "%s"' "$meta_prefix" \ + "$(json_str_escape "$name")" "$(json_str_escape "$out")" \ + >> "$META_ADD" + meta_prefix="," + fi + done + +if [ "$meta_prefix" = "{" ] ; then + echo "No emoji matched search criteria" + rm "$META_ADD" + exit 0 +fi +printf '\n}\n' >> "$META_ADD" + +cnt_dl="$(jq '. | length' "$META_ADD")" +echo "Finished downloading $cnt_dl images." + +if [ ! -e pack.json ] ; then + printf '{"files": {}, "files_count": 0, "pack": {"description": "%s: %s%s%s"}}' \ + "$(json_str_escape "$DOMAIN")" \ + "$(json_str_escape "$CATEGORY")" \ + "${ADDCOND:+ }" \ + "$(json_str_escape "$ADDCOND")" \ + > pack.json +fi + +cnt_old="$(jq '.files | length' pack.json)" +echo "Found $cnt_old preƫxisting emoji." + +new_files="$( + if [ "$OVERWRITE_METAKEYS" = "YES" ] ; then + jq --sort-keys -s '.[0].files + .[1]' pack.json "$META_ADD" + else + jq --sort-keys -s '.[0] + .[1].files' "$META_ADD" pack.json + fi +)" +echo "$new_files" > "$META_ADD" + +cnt_new="$(jq '. | length' "$META_ADD")" +cnt_diff=$((cnt_new - cnt_old)) +echo "After merging there are a total of $cnt_new emoji." +if [ "$cnt_diff" != "$cnt_dl" ] ; then + echo "WARNING: expected a gain of $cnt_dl but got $cnt_diff additional entries!" + echo " (the existing pack may not follow the expected filename scheme)" +fi + +jq --argjson new_files "$new_files" \ + --arg cnt_new "$cnt_new" \ + '.files = $new_files | .files_count = $cnt_new' \ + pack.json \ + > "$META_ADD" + +mv "$META_ADD" pack.json