summaryrefslogtreecommitdiffstats
path: root/contrib
diff options
context:
space:
mode:
authorLibravatarLarge Libravatar memdmp <memdmpmemewarenet>2025-01-13 16:54:34 +0100
committerLibravatarLarge Libravatar memdmp <memdmpmemewarenet>2025-01-13 16:54:34 +0100
commit6e3b3c8013e6d8814dbf70c854e55d062bedbdf4 (patch)
tree5b07a6d26c349293bc61a71a32d6e368fed11c4e /contrib
downloadbibata-cursor-cli-6e3b3c8013e6d8814dbf70c854e55d062bedbdf4.tar.gz
bibata-cursor-cli-6e3b3c8013e6d8814dbf70c854e55d062bedbdf4.tar.bz2
bibata-cursor-cli-6e3b3c8013e6d8814dbf70c854e55d062bedbdf4.tar.lz
bibata-cursor-cli-6e3b3c8013e6d8814dbf70c854e55d062bedbdf4.zip

chore: initial commit

HEADmaster
Diffstat (limited to 'contrib')
-rwxr-xr-xcontrib/gen-meta.sh145
-rwxr-xr-xcontrib/get-cursors.sh80
-rw-r--r--contrib/util.sh215
3 files changed, 440 insertions, 0 deletions
diff --git a/contrib/gen-meta.sh b/contrib/gen-meta.sh
new file mode 100755
index 0000000..2f51e80
--- /dev/null
+++ b/contrib/gen-meta.sh
@@ -0,0 +1,145 @@
+#!/bin/bash
+# Generates usable metadata for the cursors, allowing them to be more easily processed
+# TODO: Rewite in Amber - https://amber-lang.com
+set -e
+
+source contrib/util.sh
+
+CANCER_PATH="$(realpath cancer-meta.toml)"
+CANCER="$(yq e -p toml -o json . "$CANCER_PATH")"
+get_meta_from_cancer() {
+ jq -Mc '.cursor[]' <<< "$CANCER" | while read cursor_json; do
+ if [[ "$(jq -Mc .id <<< "$cursor_json")" == "$1" ]]; then
+ echo -n "$cursor_json"
+ return 0
+ fi
+ done
+}
+
+cd cursors
+# Process metadata into usable files
+for type in ./*; do
+ type="$(sed 's|./||' <<< "$type")"
+ start "Processing CursorType($type)"
+ cd "$type"
+ for cursor in ./*; do
+ cursor="$(sed 's|./||' <<< "$cursor")"
+ if [[ -d "$cursor" ]]; then
+ cd "$cursor"
+ cursor_meta="./meta.json"
+ cursor_assets="./assets"
+ get_from_orig() {
+ jq -Mc "$1" "$cursor_meta"
+ }
+ get_from_orig_raw() {
+ jq -Mcr "$1" "$cursor_meta"
+ }
+
+ is_animated="$(get_from_orig .isAnimated)"
+ start "Processing Cursor(CursorType($type), name=$cursor, animated=$is_animated)"
+
+ if [[ "$is_animated" == "true" ]]; then
+ # Animated files tend to have lots of SVGs, resulting in us being unable to store the entire JSON object in memory
+ # This results in us getting an "Argument list too long" error - even though its not the arg list, but rather the env
+ # We solve this by placing the temporary storage on a real file on the filesystem
+ jsettempstorage "/tmp/_$(date)"
+ else
+ # Otherwise, we (dangerously!) assume the file will fit in env, and clear the temp storage.
+ jsettempstorage
+ fi
+
+ additional_meta="$(get_meta_from_cancer "$(get_from_orig .name)")"
+
+ jnew "./cursor.json"
+ jtransaction
+ jrun ".animated=$is_animated"
+ jrun ".id=$(get_from_orig .id)"
+ jrun ".name=$(get_from_orig .name)"
+ jrun ".aliases=$(jq -Mc 'if has("links") then .links else [] end' <<< "$additional_meta")"
+ jrun ".hot={}"
+ jrun ".hot.x=$(jq -Mc 'if has("x") then .x else 128 end' <<< "$additional_meta")"
+ jrun ".hot.y=$(jq -Mc 'if has("y") then .y else 128 end' <<< "$additional_meta")"
+ jrun ".platform_names={}"
+ jrun ".platform_names.windows=$(jq -Mc 'if has("winname") then .winname else null end' <<< "$additional_meta")"
+ jrun ".platform_names.xorg=$(jq -Mc 'if has("xname") then .xname else .id end' <<< "$additional_meta")"
+ jrun ".frames=[]"
+ idx=0
+ trx_ctr=1
+ while read node_id; do
+ url="$(jq -Mc ".urls[${idx}]" < "$cursor_meta")"
+ raw_node_id="$(jq -Mcr . <<< "$node_id")"
+ frame="$cursor_assets/$raw_node_id.svg"
+ [[ "$is_animated" == "true" ]] && start "Processing CursorFrame(Cursor(CursorType($type), name=$cursor, animated=$is_animated), frame=$raw_node_id)"
+ if [[ "$trx_ctr" == "1" ]]; then
+ jcommit
+ jtransaction
+ trx_ctr=32
+ else
+ ((trx_ctr=trx_ctr-1))
+ fi
+ jrun ".frames[$idx]={}"
+ jrun ".frames[$idx].idx=$idx"
+ jrun ".frames[$idx].id=$node_id"
+ jrun ".frames[$idx].url=$url"
+ jrun ".frames[$idx].delay=(if $node_id | contains(\":\") then $node_id | split(\":\") | .[0] | tonumber else 60 end)"
+ jrun ".frames[$idx].sha512=$(escape_str "$(sha512sum "$frame" | awk '{print $1}')")"
+ jsetasset "$(cat "$frame")" && jrun ".frames[$idx].svg=$(jgetassetref)"
+ [[ "$is_animated" == "true" ]] && complete "Finished $(_last | sed s/Pr/pr/)"
+ ((idx=idx+1))
+ done <<< "$(jq -Mc '.node_ids[]' "$cursor_meta")"
+ jrun ".frame_count=${idx}"
+ jcommit
+ jsave
+
+ # We're done with the file, let's empty the storage
+ jnew
+ # If we started using tmpfs, let's go back to in-memory storage
+ if [[ "$is_animated" == "true" ]]; then
+ jsettempstorage
+ fi
+
+ complete "Finished $(_last | sed s/Pr/pr/)"
+
+ cd ..
+ fi
+ done
+ complete "Finished $(_last | sed s/Pr/pr/)"
+ cd ..
+done
+# Process outputs into single file
+jsettempstorage "/tmp/_$(date)"
+jnew ../.cursors
+jtransaction
+jrun '.=[]'
+typeidx=0
+for type in ./*; do
+ type="$(sed 's|./||' <<< "$type")"
+ start "Bundle all CursorType($type)"
+ jrun ".[${typeidx}]={}"
+ jrun ".[${typeidx}].kind=$(escape_str "$type")"
+ jrun ".[${typeidx}].cursors=[]"
+ jcommit
+ jsave
+ trx_ctr=1
+ cd "$type"
+ for cursor in ./*; do
+ cursor="$(sed 's|./||' <<< "$cursor")"
+ if [[ -d "$cursor" ]]; then
+ start "Push Cursor(CursorType($type), name=$cursor, animated=null)"
+ cd "$cursor"
+ _jrun_file ".[${typeidx}].cursors += [$(jq -M . ./cursor.json)]"
+ cd ..
+ complete
+ fi
+ done
+ complete
+ jtransaction
+ cd ..
+ ((typeidx=typeidx+1))
+done
+jcommit
+jsave
+
+cd ..
+
+jq -Mc . .cursors > .cursors.min
diff --git a/contrib/get-cursors.sh b/contrib/get-cursors.sh
new file mode 100755
index 0000000..755213a
--- /dev/null
+++ b/contrib/get-cursors.sh
@@ -0,0 +1,80 @@
+#!/bin/bash
+# Fetches bibata cursor svgs
+set -e
+
+start() {
+ _LAST_MSG="$@"
+ echo -e "\x1b[0;1;34m@\x1b[0;34m $@\x1b[0m"
+}
+complete() {
+ if [[ "$1" == "" ]]; then
+ complete "$_LAST_MSG"
+ else
+ echo -e "\x1b[0;1;32m+\x1b[0;32m $@\x1b[0m"
+ fi
+}
+err() {
+ if [[ "$1" == "" ]]; then
+ err "$_LAST_MSG"
+ else
+ echo -e "\x1b[0;1;31m!\x1b[0;31m $@\x1b[0m" 1>&2;
+ fi
+}
+info() {
+ echo -e "\x1b[0;1;94mi\x1b[0;94m $@\x1b[0m" 1>&2;
+}
+
+mkdir -p cursors
+for type in Modern Original; do
+ type_dir="cursors/$type"
+ type_meta="$type_dir/meta.json"
+ mkdir -p "$type_dir"
+ start "Get Cursor Metadata for CursorType($type)"
+ curl -fsSL "https://www.bibata.live/api/svg?type=${type}&v=1.0.2" | jq -M > "$type_meta"
+ complete
+
+ jq -Mc '.data[]' "$type_meta" | while read cursor_json; do
+ cursor_name="$(jq -r .name <<< "$cursor_json")"
+ cursor_dir="$type_dir/$cursor_name"
+ cursor_assets="$cursor_dir/assets"
+ cursor_meta="$cursor_dir/meta.json"
+ cursorfile="$cursor_dir/cursor.json"
+ mkdir -p "$cursor_dir" "$cursor_assets"
+ if [[ -f "$cursor_meta" ]] && [[ "$(jq -M "." "$cursor_meta" | sha512sum | awk '{print $1}')" == "$(jq -M "." <<< "$cursor_json" | sha512sum | awk '{print $1}')" ]]; then
+ start "Ensuring all keyframes for Cursor($type, $cursor_name) are present"
+ idx=0
+ jq -Mcr '.node_ids[]' "$cursor_meta" | while read node_id; do
+ node="Node($type, $cursor_name, Node($idx, $node_id))"
+ if ! [[ -f "$cursor_assets/$node_id.svg" ]]; then
+ cursor_url="$(jq -Mr ".urls[${idx}]" "$cursor_meta")"
+ start "Fetch missing $node - NodeIndex($idx)"
+ curl -fsSL "$cursor_url" -o "$cursor_assets/$node_id.svg"
+ ((idx=idx+1))
+ complete "Fetched missing $node"
+ else
+ info "$node is already present"
+ fi
+ done
+ complete "Ensured all keyframes for Cursor($type, $cursor_name) are present"
+ else
+ if [[ -f "$cursor_meta" ]]; then info "MetaFile($cursor_meta) already exists but differs (it has FileHash(sha512, $(jq -M "$cursor_meta" | sha512sum | awk '{print $1}')), new version has FileHash(sha512, $(jq -M <<< "$cursor_json" | sha512sum | awk '{print $1}')))"; mv "$cursor_meta"; fi
+ jq -M <<< "$cursor_json" > "$cursor_meta"
+ start "Get keyframes for Cursor($type, $cursor_name)"
+ idx=0
+ total=0
+ jq -Mcr '.node_ids[]' "$cursor_meta" | while read id; do
+ rm -f "$cursor_assets/$node_id.svg"
+ ((total=total+1))
+ done
+ jq -Mcr '.urls[]' "$cursor_meta" | while read cursor_url; do
+ node_id="$(jq -Mr ".node_ids[${idx}]" "$cursor_meta")"
+ node="Node($type, $cursor_name, Node($idx, $node_id))"
+ start "Fetch $node - NodeIndex($idx) of NodeCount($total)"
+ curl -fsSL "$cursor_url" -o "$cursor_assets/$node_id.svg"
+ ((idx=idx+1))
+ complete "Fetched $node"
+ done
+ complete "Got keyframes for Cursor($type, $cursor_name)"
+ fi
+ done
+done
diff --git a/contrib/util.sh b/contrib/util.sh
new file mode 100644
index 0000000..5f846be
--- /dev/null
+++ b/contrib/util.sh
@@ -0,0 +1,215 @@
+#!/bin/bash
+set -e
+
+# Logging
+TASKS=()
+_last() {
+ echo -n "${TASKS[0]}"
+}
+start() {
+ for n in "${TASKS[@]}"; do
+ echo -n ' '
+ done
+ TASKS=(
+ "$@"
+ "${TASKS[@]}"
+ )
+ echo -e "\x1b[0;1;34m@\x1b[0;34m $@\x1b[0m"
+}
+complete() {
+ last="$(_last)"
+ if [[ "$NOSHIFT" != 1 ]]; then
+ TASKS=(
+ "${TASKS[@]:1}"
+ )
+ fi
+ if [[ "$1" == "" ]] && [[ "$last" != "" ]]; then
+ NOSHIFT=1 complete "$last"
+ else
+ for n in "${TASKS[@]}"; do
+ echo -n ' '
+ done
+ echo -e "\x1b[0;1;32m+\x1b[0;32m $@\x1b[0m"
+ fi
+}
+err() {
+ last="$(_last)"
+ if [[ "$NOSHIFT" != 1 ]]; then
+ TASKS=(
+ "${TASKS[@]:1}"
+ )
+ fi
+ if [[ "$1" == "" ]] && [[ "$last" != "" ]]; then
+ NOSHIFT=1 err "$last"
+ else
+ for n in "${TASKS[@]}"; do
+ echo -n ' '
+ done
+ echo -e "\x1b[0;1;31m!\x1b[0;31m $@\x1b[0m" 1>&2;
+ fi
+}
+info() {
+ echo -e "\x1b[0;1;94mi\x1b[0;94m $@\x1b[0m" 1>&2;
+}
+
+# Bash Array Joiner
+join_array() {
+ printf -v __ "${1//%/%%}%s" "${@:2}"
+ echo -n "${__:${#1}}"
+}
+
+# jq abstraction layer
+
+# Determines where to store the JSON - if the value is `IN_MEM`, then the value is kept in the JQ_BUFFER variable
+JSON_STORAGE_LOCATION="IN_MEM"
+JQ_BUFFER=""
+JQ_BUFFER_OUTPUT_FILE=""
+JQ_TRANSACTION=()
+JQ_IS_DOING_TRANSACTION=false
+JQ_POSITIONALS=()
+JQ_POSITIONAL_IDX=1
+ARG=null
+jsettempstorage() {
+ newstorage="${1:-"IN_MEM"}"
+ if [[ "$newstorage" == "$JSON_STORAGE_LOCATION" ]]; then return 0; fi
+ if [[ "$JSON_STORAGE_LOCATION" == "IN_MEM" ]]; then
+ touch "$newstorage"
+ <<< "$JQ_BUFFER" > "$newstorage"
+ JQ_BUFFER=""
+ elif [[ "$newstorage" == "IN_MEM" ]]; then
+ JQ_BUFFER="$(<"$JSON_STORAGE_LOCATION")"
+ rm "$JSON_STORAGE_LOCATION"
+ else
+ mv "$JSON_STORAGE_LOCATION" "$newstorage"
+ fi
+ JSON_STORAGE_LOCATION="$newstorage"
+}
+# Reads the storage buffer
+jreadbuffer() {
+ if [[ "$JSON_STORAGE_LOCATION" == "IN_MEM" ]]; then
+ echo -n "$JQ_BUFFER"
+ else
+ cat "$JSON_STORAGE_LOCATION"
+ fi
+}
+# Writes the storage buffer
+jwritebuffer() {
+ if [[ "$JSON_STORAGE_LOCATION" == "IN_MEM" ]]; then
+ JQ_BUFFER="$@"
+ else
+ echo -n "$@" > "$JSON_STORAGE_LOCATION"
+ fi
+}
+
+# Creates a new jq blank file
+jnew() {
+ JQ_BUFFER_OUTPUT_FILE="$(realpath "${1:-"/dev/null"}")"
+ jwritebuffer "${2:-"{}"}"
+}
+# Loads an existing jq file, falling back to creating a blank one if it doesnt exist
+jload() {
+ JQ_BUFFER_OUTPUT_FILE="$(realpath "${1:-"/dev/null"}")"
+ if [[ -f "$JQ_BUFFER_OUTPUT_FILE" ]]; then
+ jwritebuffer "$(cat $JQ_BUFFER_OUTPUT_FILE)"
+ else
+ jwritebuffer "${2:-"{}"}"
+ fi
+}
+
+# SQL-like Transaction Logic
+jtransaction() {
+ if [[ "$JQ_IS_DOING_TRANSACTION" == "true" ]]; then
+ err "Already performing transaction!"
+ return 1
+ fi
+ JQ_IS_DOING_TRANSACTION=true
+ JQ_TRANSACTION=()
+}
+jabort() {
+ if [[ "$JQ_IS_DOING_TRANSACTION" == "false" ]]; then
+ err "No pending transaction!"
+ return 1
+ fi
+ JQ_IS_DOING_TRANSACTION=false
+ JQ_TRANSACTION=()
+}
+jcommit() {
+ if [[ "$JQ_IS_DOING_TRANSACTION" == "false" ]]; then
+ err "No pending transaction!"
+ return 1
+ fi
+ JQ_IS_DOING_TRANSACTION=false
+ # Incase it's empty:
+ JQ_TRANSACTION+=(
+ "."
+ )
+ # As we are no longer in a transaction, jrun will run the pipe-delimited query
+ jrun "$(join_array ' | ' "${JQ_TRANSACTION[@]}")"
+ # We can, after running, clear the transaction
+ JQ_TRANSACTION=()
+}
+
+# Loads a string that jq can positionally access later
+jsetasset() {
+ ARG="(\$ARGS.positional[$JQ_POSITIONAL_IDX] | @base64d)"
+ JQ_POSITIONALS+=(
+ "$(base64 -w 0 <<< "$@")"
+ );
+ ((JQ_POSITIONAL_IDX=JQ_POSITIONAL_IDX+1))
+}
+jgetassetref() {
+ echo -n "$ARG"
+ ARG=null
+}
+
+# Perform a jq write operation
+jrun() {
+ if [[ "$JQ_IS_DOING_TRANSACTION" == "true" ]]; then
+ # If we're in a transaction, just push it to the list
+ JQ_TRANSACTION+=(
+ "($@)"
+ )
+ else
+ # Otherwise, perform the operation and write to the buffer
+ if [[ "$JSON_STORAGE_LOCATION" == "IN_MEM" ]]; then
+ JQ_BUFFER="$(jq -Mc "$@" --args owo ${JQ_POSITIONALS[@]} <<< "$JQ_BUFFER")"
+ else
+ jq -Mc "$@" --args owo ${JQ_POSITIONALS[@]} < "$JSON_STORAGE_LOCATION" > "$JSON_STORAGE_LOCATION~"
+ mv "$JSON_STORAGE_LOCATION~" "$JSON_STORAGE_LOCATION"
+ fi
+ JQ_POSITIONALS=()
+ JQ_POSITIONAL_IDX=1
+ fi
+}
+# Perform a jq write operation using a temp file
+_jrun_file() {
+ if [[ "$JQ_IS_DOING_TRANSACTION" == "true" ]]; then
+ # Does not work for transactions
+ err "Cannot use _jrun_file in transaction!";
+ return 1;
+ else
+ # Otherwise, perform the operation and write to the buffer
+ if [[ "$JSON_STORAGE_LOCATION" == "IN_MEM" ]]; then
+ echo -n "$@" > /tmp/.operation.jq
+ JQ_BUFFER="$(jq -Mcf /tmp/.operation.jq --args owo ${JQ_POSITIONALS[@]} <<< "$JQ_BUFFER")"
+ rm /tmp/.operation.jq
+ else
+ echo -n "$@" > /tmp/.operation.jq
+ jq -Mcf /tmp/.operation.jq --args owo ${JQ_POSITIONALS[@]} < "$JSON_STORAGE_LOCATION" > "$JSON_STORAGE_LOCATION~"
+ rm /tmp/.operation.jq
+ mv "$JSON_STORAGE_LOCATION~" "$JSON_STORAGE_LOCATION"
+ fi
+ JQ_POSITIONALS=()
+ JQ_POSITIONAL_IDX=1
+ fi
+}
+jsave() {
+ if [[ "$JQ_IS_DOING_TRANSACTION" == "true" ]]; then
+ err "There is a pending transaction."
+ return 1
+ fi
+ jreadbuffer | jq -M . > "${1:-"$JQ_BUFFER_OUTPUT_FILE"}"
+}
+escape_str() {
+ jq '.=$ARGS.positional[0]' --args "$@" -M <<< '""'
+}