aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore2
-rwxr-xr-xbot.sh172
-rw-r--r--commands/callback149
-rw-r--r--commands/clean7
-rw-r--r--commands/commands395
-rw-r--r--commands/ib_callback248
-rw-r--r--commands/ib_inline443
-rw-r--r--commands/inline345
-rw-r--r--functions/help83
-rw-r--r--functions/ib_auth171
-rw-r--r--functions/ib_authconfig57
-rw-r--r--functions/ib_config339
-rw-r--r--functions/ib_date33
-rw-r--r--functions/ib_lock13
-rw-r--r--functions/ib_meta110
-rw-r--r--functions/ib_original42
-rw-r--r--functions/ib_post92
-rw-r--r--functions/ib_size21
-rw-r--r--functions/ib_token38
19 files changed, 2760 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..0633ad7
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+cache
+config
diff --git a/bot.sh b/bot.sh
new file mode 100755
index 0000000..7c6e904
--- /dev/null
+++ b/bot.sh
@@ -0,0 +1,172 @@
+#!/usr/bin/env dash
+#
+# Copyright (C) 2024 Maria Lisina
+# Copyright (C) 2024 Danil Lisin
+#
+# Run this software with `env -i` to avoid variable conflict
+
+set -e
+umask 77
+
+for required in busybox curl jq recode
+do
+ if ! command -v ${required} > /dev/null
+ then
+ missing="${missing} ${required}"
+ fi
+done
+
+if [ -n "${missing}" ]
+then
+ echo "Missing dependencies:${missing}\n" \
+ "For more information follow: https://command-not-found.com/"
+ exit 1
+fi
+
+dir="${0%/*}"
+cache="${dir}/cache"
+config="${dir}/config"
+commands="${dir}/commands"
+functions="${dir}/functions"
+offset="-1"
+
+if [ -n "${1}" ]
+then
+ while getopts ha:s:p: options
+ do
+ case "${options}" in
+ (h)
+ help=0
+ ;;
+ (a)
+ address="${OPTARG}"
+ ;;
+ (s)
+ max_size=${OPTARG}
+ ;;
+ (p)
+ proxy="${OPTARG}"
+ ;;
+ (*)
+ echo "See '${0} -h'"
+ exit 1
+ ;;
+ esac
+ done
+
+ shift $((OPTIND - 1))
+else
+ help=0
+fi
+
+if [ -n "${help}" ]
+then
+ echo "Sekoohaka Bot" \
+ "\n\nUsage: ${0} [options] [token]" \
+ "\n\nOptions:" \
+ "\n -h\t\tShow help information" \
+ "\n -a <addr>\tTelegram Bot API address, default: api.telegram.org" \
+ "\n -s <size>\tMax file size allowed to send with URL, default: 10485760" \
+ "\n -p <addr>\tProxy address for external requests"
+ exit 0
+fi
+
+if [ -z "${address}" ]
+then
+ address="https://api.telegram.org"
+fi
+
+if [ -n "${max_size}" ]
+then
+ if ! test ${max_size} -gt 0 > /dev/null 2>&1
+ then
+ echo "Illegal file size"
+ exit 1
+ fi
+else
+ max_size=10485760
+fi
+
+if [ -n "${1}" ]
+then
+ token="${1}"
+ shift
+else
+ echo "No access token specified"
+ exit 1
+fi
+
+for function in $(busybox --list)
+do
+ if ! type ${function} | busybox grep -q "shell builtin"
+ then
+ alias ${function}="busybox ${function}"
+ fi
+done
+
+alias stop="wait && exit"
+alias htmlescape="sed -e 's/</\&#60;/g' -e 's/>/\&#62;/g'"
+alias urlencode="jq -Rr @uri"
+
+ascii_table="$(awk 'BEGIN{for(c=33;c<127;c++)printf"%c ",c}')"
+
+rm -fr "${cache}"
+mkdir -p "${cache}"
+mkdir -p "${config}"
+
+curl --get \
+ --max-time 10 \
+ --output "${cache}/getMe.json" \
+ --show-error \
+ --silent \
+ "${address}/bot${token}/getMe"
+
+if ! jq -e '.' "${cache}/getMe.json" > /dev/null
+then
+ cat "${cache}/getMe.json"
+ exit 1
+fi
+
+username="$(jq -r '.result.username' "${cache}/getMe.json")"
+
+if [ "${username}" = "null" ]
+then
+ echo "Failed to authorize the bot"
+ exit 1
+fi
+
+echo "Bot: ${username}"
+
+while trap 'stop 0' INT TERM
+do
+ if ! curl --data "offset=${offset}" \
+ --get \
+ --output "${cache}/getUpdates.json" \
+ --silent \
+ "${address}/bot${token}/getUpdates"
+ then
+ continue
+ fi
+
+ if ! update_id="$(jq -r '.result.[0].update_id' "${cache}/getUpdates.json")"
+ then
+ continue
+ fi
+
+ if [ "${update_id}" != "null" ]
+ then
+ update="${cache}/${update_id}.json"
+
+ if ! jq '.result.[0]' "${cache}/getUpdates.json" > "${update}"
+ then
+ continue
+ fi
+
+ for command in "${commands}"/*
+ do
+ . "${command}" &
+ done
+
+ offset="$((update_id + 1))"
+ fi
+done
diff --git a/commands/callback b/commands/callback
new file mode 100644
index 0000000..093ee26
--- /dev/null
+++ b/commands/callback
@@ -0,0 +1,149 @@
+#!/usr/bin/env dash
+#
+# Copyright (C) 2024 Maria Lisina
+# Copyright (C) 2024 Danil Lisin
+
+set -- $(jq -r '.callback_query.data' "${update}")
+
+if [ -n "${1}" ]
+then
+ case "${1}" in
+ ("short")
+ command_short=0
+ ;;
+ ("reset")
+ command_reset=0
+ ;;
+ ("stop")
+ command_stop=0
+ ;;
+ (*)
+ exit 0
+ ;;
+ esac
+
+ shift
+else
+ exit 0
+fi
+
+query_id="$(jq -r '.callback_query.id' "${update}")"
+
+if [ -n "${command_short}" ]
+then
+ user_id="$(jq -r '.callback_query.from.id' "${update}")"
+ short_config="${config}/${user_id}/short"
+
+ if [ -n "${1}" ]
+ then
+ short_query="${@}"
+ shift ${#}
+ else
+ notification_text="You must specify the query"
+ fi
+
+ until mkdir "${config}/${user_id}_short.lock" > /dev/null 2>&1
+ do
+ sleep 1
+ done
+
+ if [ -z "${notification_text}" ] && ! mkdir -p "${short_config}"
+ then
+ notification_text="Failed to create user config"
+ fi
+
+ if [ -z "${notification_text}" ]
+ then
+ if short="$(grep -lrx "${short_query}" "${short_config}")"
+ then
+ rm -f "${short}"
+ notification_text="Removed shortcut"
+ else
+ set -- $(ls -x "${short_config}")
+
+ if [ ${#} -le 50 ]
+ then
+ printf "%s" "${short_query}" > "${short_config}/$(date +%s)${query_id}"
+ notification_text="Saved shortcut"
+ else
+ notification_text="Too many shortcuts"
+ fi
+ fi
+ fi
+
+ rm -fr "${config}/${user_id}_short.lock"
+fi
+
+if [ -n "${command_reset}" ]
+then
+ user_id="$(jq -r '.callback_query.from.id' "${update}")"
+
+ if mkdir "${config}/${user_id}_reset.lock" > /dev/null 2>&1
+ then
+ notification_text="Click again to confirm shortcuts removing"
+ fi
+
+ if [ -z "${notification_text}" ]
+ then
+ short_config="${config}/${user_id}/short"
+
+ until mkdir "${config}/${user_id}_short.lock" > /dev/null 2>&1
+ do
+ sleep 1
+ done
+
+ if rm -fr "${short_config}"
+ then
+ notification_text="Removed all shortcuts"
+ else
+ notification_text="Something went wrong, try again later"
+ fi
+
+ rm -fr "${config}/${user_id}_short.lock"
+ rm -fr "${config}/${user_id}_reset.lock"
+ fi
+fi
+
+if [ -n "${command_stop}" ]
+then
+ user_id="$(jq -r '.callback_query.from.id' "${update}")"
+
+ if mkdir "${config}/${user_id}_stop.lock" > /dev/null 2>&1
+ then
+ notification_text="Click again to confirm data removing"
+ fi
+
+ if [ -z "${notification_text}" ]
+ then
+ locks="auth short"
+
+ for lock in ${locks}
+ do
+ until mkdir "${config}/${user_id}_${lock}.lock" > /dev/null 2>&1
+ do
+ sleep 1
+ done
+ done
+
+ if rm -fr "${config}/${user_id}"
+ then
+ notification_text="Removed all your data"
+ else
+ notification_text="Something went wrong, try again later"
+ fi
+
+ for lock in ${locks}
+ do
+ rm -fr "${config}/${user_id}_${lock}.lock"
+ done
+
+ rm -fr "${config}/${user_id}_stop.lock"
+ fi
+fi
+
+curl --data-urlencode "callback_query_id=${query_id}" \
+ --data-urlencode "text=${notification_text}" \
+ --data-urlencode "cache_time=0" \
+ --get \
+ --silent \
+ "${address}/bot${token}/answerCallbackQuery" > /dev/null
diff --git a/commands/clean b/commands/clean
new file mode 100644
index 0000000..83c33a9
--- /dev/null
+++ b/commands/clean
@@ -0,0 +1,7 @@
+#!/usr/bin/env dash
+#
+# Copyright (C) 2024 Maria Lisina
+# Copyright (C) 2024 Danil Lisin
+
+find "${cache}" -type f -mmin +5 -delete > /dev/null 2>&1
+find "${config}" -name "*.lock" -type d -mmin +1 -delete > /dev/null 2>&1
diff --git a/commands/commands b/commands/commands
new file mode 100644
index 0000000..60d8a70
--- /dev/null
+++ b/commands/commands
@@ -0,0 +1,395 @@
+#!/usr/bin/env dash
+#
+# Copyright (C) 2024 Maria Lisina
+# Copyright (C) 2024 Danil Lisin
+
+set -- $(jq -r '.message.text' "${update}")
+
+if [ -n "${1}" ]
+then
+ case "${1}" in
+ ("/start" | "/start@${username}")
+ command_help=0
+ ;;
+ ("/help" | "/help@${username}")
+ command_help=0
+ ;;
+ ("/authorize" | "/authorize@${username}")
+ command_authorize=0
+ ;;
+ ("/original" | "/original@${username}")
+ command_original=0
+ ;;
+ ("/post" | "/post@${username}")
+ command_post=0
+ ;;
+ ("/short" | "/short@${username}")
+ command_short=0
+ ;;
+ ("/shorts" | "/shorts@${username}")
+ command_shorts=0
+ ;;
+ ("/stop" | "/stop@${username}")
+ command_stop=0
+ ;;
+ ("/prpr" | "/prpr@${username}")
+ command_prpr=0
+ ;;
+ (*)
+ exit 0
+ ;;
+ esac
+
+ shift
+else
+ exit 0
+fi
+
+chat_id="$(jq -r '.message.chat.id' "${update}")"
+message_thread_id="$(jq -r '.message.message_thread_id' "${update}")"
+message_id="$(jq -r '.message.message_id' "${update}")"
+
+reply_parameters="$(jq --null-input --compact-output \
+ --arg message_id "${message_id}" \
+ '{"message_id": $message_id, "allow_sending_without_reply": true}')"
+
+if [ "${message_thread_id}" = "null" ]
+then
+ unset message_thread_id
+fi
+
+if [ -n "${command_help}" ]
+then
+ . "${functions}/help"
+fi
+
+if [ -n "${command_authorize}" ]
+then
+ if [ -n "${1}" ]
+ then
+ user_id="$(jq -r '.message.from.id' "${update}")"
+
+ ib_board="${1}"
+ . "${functions}/ib_authconfig"
+
+ if [ -z "${ib_config}" ]
+ then
+ output_text="Unsupported image board"
+ fi
+
+ shift
+ else
+ output_text="You must specify the image board"
+ fi
+
+ if [ -z "${output_text}" ]
+ then
+ if [ -n "${1}" ]
+ then
+ ib_login="${1}"
+ shift
+ fi
+
+ if [ -n "${1}" ]
+ then
+ ib_api_key="${1}"
+ shift
+ fi
+
+ . "${functions}/ib_lock"
+ fi
+
+ if [ -z "${output_text}" ]
+ then
+ if [ -n "${ib_noverify}" ]
+ then
+ output_text="Authorization cannot be verified, make sure you provided the correct credentials"
+ else
+ output_text="Authorized successfully"
+ fi
+ fi
+fi
+
+if [ -n "${command_original}" ] || [ -n "${command_post}" ]
+then
+ if [ -z "${1}" ]
+ then
+ reply_text="$(jq -r '.message.reply_to_message.text' "${update}")"
+
+ if [ "${reply_text}" = "null" ]
+ then
+ reply_text="$(jq -r '.message.reply_to_message.caption' "${update}")"
+ fi
+
+ if [ "${reply_text}" != "null" ]
+ then
+ ib_reply_name="$(printf "%s" "${reply_text}" | awk 'NR==1')"
+ ib_post_id="$(printf "%s" "${reply_text}" | awk '/ID:/ {print $2}')"
+
+ for ib_board in ${ascii_table}
+ do
+ . "${functions}/ib_config"
+ unset output_text
+
+ if [ "${ib_reply_name}" = "${ib_name}" ]
+ then
+ break
+ fi
+ done
+
+ set -- ${ib_board} ${ib_post_id}
+ fi
+ fi
+
+ if [ -n "${1}" ]
+ then
+ user_id="$(jq -r '.message.from.id' "${update}")"
+
+ ib_board="${1}"
+ ib_mode="p"
+ . "${functions}/ib_config"
+ . "${functions}/ib_authconfig"
+
+ shift
+ else
+ output_text="You must specify the image board"
+ fi
+
+ if [ -n "${1}" ]
+ then
+ ib_post_id="${1}"
+ shift
+ elif [ -z "${output_text}" ]
+ then
+ output_text="You must specify the post ID"
+ fi
+
+ if [ -z "${output_text}" ] && [ -n "${ib_config}" ]
+ then
+ . "${functions}/ib_token"
+ fi
+
+ if [ -z "${output_text}" ]
+ then
+ if [ -n "${ib_exception_idol}" ]
+ then
+ ib_query="id_range:${ib_post_id}"
+ else
+ ib_query="id:${ib_post_id}"
+ fi
+
+ ib_file="${cache}/${update_id}_data.json"
+
+ if ! curl --data-urlencode "${ib_dfield1}" \
+ --data-urlencode "${ib_dfield2}" \
+ --data-urlencode "${ib_dfield3}" \
+ --data-urlencode "${ib_dfield4}" \
+ --data-urlencode "${ib_dfield5}" \
+ --data-urlencode "${ib_dfield6}" \
+ --data-urlencode "${ib_dlimit}=1" \
+ --data-urlencode "${ib_dquery}=${ib_query}" \
+ --get \
+ --header "${ib_header}" \
+ --max-time 5 \
+ --output "${ib_file}" \
+ --proxy "${proxy}" \
+ --silent \
+ --user-agent "Sekoohaka" \
+ "${ib_data_url}"
+ then
+ output_text="Failed to access ${ib_name} API"
+ fi
+
+ if [ -z "${output_text}" ] && ! [ -f "${ib_file}" ]
+ then
+ output_text="Failed to access ${ib_name} API"
+ fi
+
+ if [ -z "${output_text}" ] && ! jq -e '.' "${ib_file}" > /dev/null 2>&1
+ then
+ output_text="An unknown error occurred"
+ fi
+
+ if [ -z "${output_text}" ] && ! jq -e ".${ib_iarray}[0]|has(\"${ib_iid}\")" "${ib_file}" > /dev/null 2>&1
+ then
+ output_text="No results found. Try different post ID"
+ fi
+ fi
+
+ if [ -z "${output_text}" ]
+ then
+ if [ -n "${command_original}" ]
+ then
+ . "${functions}/ib_original"
+
+ if [ -n "${ib_file_url}" ] && [ "${ib_file_url}" != "null" ]
+ then
+ reply_markup="$(jq --null-input --compact-output \
+ --arg text1 "Original file link" \
+ --arg url1 "${ib_file_url}" \
+ '{"inline_keyboard": [[{"text": $text1, "url": $url1}]]}')"
+ fi
+
+ if [ -z "${output_text}" ]
+ then
+ curl --data-urlencode "chat_id=${chat_id}" \
+ --data-urlencode "message_thread_id=${message_thread_id}" \
+ --data-urlencode "action=upload_document" \
+ --get \
+ --silent \
+ "${address}/bot${token}/sendChatAction" > /dev/null
+
+ output_file="${cache}/${update_id}_sendDocument.json"
+
+ curl --data-urlencode "chat_id=${chat_id}" \
+ --data-urlencode "message_thread_id=${message_thread_id}" \
+ --data-urlencode "document=${ib_file_url}" \
+ --data-urlencode "thumbnail=${ib_preview_url}" \
+ --data-urlencode "reply_parameters=${reply_parameters}" \
+ --data-urlencode "reply_markup=${reply_markup}" \
+ --get \
+ --max-time 5 \
+ --output "${output_file}" \
+ --silent \
+ "${address}/bot${token}/sendDocument"
+
+ if [ -z "${output_text}" ] && ! jq -e '.' "${output_file}" > /dev/null 2>&1
+ then
+ output_text="An unknown error occurred"
+ fi
+
+ if [ -z "${output_text}" ] && [ "$(jq -r '.ok' "${output_file}")" != "true" ]
+ then
+ output_text="Failed to send the original file"
+ fi
+
+ if [ -z "${output_text}" ]
+ then
+ exit 0
+ fi
+ fi
+ elif [ -n "${command_post}" ]
+ then
+ . "${functions}/ib_post"
+
+ link_preview_options="$(jq --null-input --compact-output \
+ --arg url1 "${ib_sample_url}" \
+ '{"url": $url1, "prefer_small_media": true, "show_above_text": true}')"
+
+ reply_markup="$(jq --null-input --compact-output \
+ --arg text1 "Post link" \
+ --arg url1 "${ib_page_url}$(printf "%s" "${ib_post_id}" | urlencode)" \
+ '{"inline_keyboard": [[{"text": $text1, "url": $url1}]]}')"
+
+ if [ ${ib_tags_count} -gt 0 ]
+ then
+ reply_markup="$(printf "%s" "${reply_markup}" | jq --compact-output \
+ --arg text1 "Tags (${ib_tags_count})" \
+ --arg data1 "tags ${ib_board} ${ib_post_id}" \
+ '.inline_keyboard.[0] += [{"text": $text1, "callback_data": $data1}]')"
+ fi
+ fi
+ elif [ -n "${command_post}" ]
+ then
+ reply_markup="$(jq --null-input --compact-output \
+ --arg text1 "Retry" \
+ --arg data1 "post ${ib_board} ${ib_post_id}" \
+ '{"inline_keyboard": [[{"text": $text1, "callback_data": $data1}]]}')"
+ fi
+fi
+
+if [ -n "${command_short}" ]
+then
+ if [ -n "${1}" ]
+ then
+ short_query="${@}"
+ shift ${#}
+ else
+ output_text="You must specify the query"
+ fi
+
+ if [ ${#short_query} -gt 1024 ]
+ then
+ output_text="Query is too long"
+ fi
+
+ if [ -z "${output_text}" ]
+ then
+ output_text="<b>Shortcut:</b> <code>$(printf "%s" "${short_query}" | htmlescape)</code>"
+
+ reply_markup="$(jq --null-input --compact-output \
+ --arg text1 "Open inline" \
+ --arg query1 "${short_query}" \
+ '{"inline_keyboard": [[{"text": $text1, "switch_inline_query_current_chat": $query1}]]}')"
+
+ short_query="short ${short_query}"
+
+ if [ ${#short_query} -le 64 ]
+ then
+ reply_markup="$(printf "%s" "${reply_markup}" | jq --compact-output \
+ --arg text1 "Manage" \
+ --arg data1 "${short_query}" \
+ '.inline_keyboard.[0] += [{"text": $text1, "callback_data": $data1}]')"
+ fi
+ fi
+fi
+
+if [ -n "${command_shorts}" ]
+then
+ user_id="$(jq -r '.message.from.id' "${update}")"
+ short_config="${config}/${user_id}/short"
+
+ until mkdir "${config}/${user_id}_short.lock" > /dev/null 2>&1
+ do
+ sleep 1
+ done
+
+ if [ -d "${short_config}" ]
+ then
+ shorts="$(ls -x "${short_config}")"
+ fi
+
+ set -- ${shorts}
+
+ if [ ${#} -gt 0 ]
+ then
+ output_text="You have ${#} saved shortcuts"
+
+ reply_markup="$(jq --null-input --compact-output \
+ --arg text1 "Open inline" \
+ --arg query1 "shorts" \
+ --arg text2 "Remove all" \
+ --arg data2 "reset" \
+ '{"inline_keyboard": [[{"text": $text1, "switch_inline_query_current_chat": $query1}, {"text": $text2, "callback_data": $data2}]]}')"
+ else
+ output_text="You have no saved shortcuts yet"
+ fi
+
+ rm -fr "${config}/${user_id}_short.lock"
+fi
+
+if [ -n "${command_stop}" ]
+then
+ output_text="Remove all your data including login data and saved shortcuts"
+
+ reply_markup="$(jq --null-input --compact-output \
+ --arg text1 "Remove my data" \
+ --arg data1 "stop" \
+ '{"inline_keyboard": [[{"text": $text1, "callback_data": $data1}]]}')"
+fi
+
+if [ -n "${command_prpr}" ]
+then
+ output_text="ฅ^•ﻌ•^ฅ"
+fi
+
+curl --data-urlencode "chat_id=${chat_id}" \
+ --data-urlencode "message_thread_id=${message_thread_id}" \
+ --data-urlencode "text=${output_text}" \
+ --data-urlencode "parse_mode=HTML" \
+ --data-urlencode "link_preview_options=${link_preview_options}" \
+ --data-urlencode "reply_parameters=${reply_parameters}" \
+ --data-urlencode "reply_markup=${reply_markup}" \
+ --get \
+ --silent \
+ "${address}/bot${token}/sendMessage" > /dev/null
diff --git a/commands/ib_callback b/commands/ib_callback
new file mode 100644
index 0000000..e759f33
--- /dev/null
+++ b/commands/ib_callback
@@ -0,0 +1,248 @@
+#!/usr/bin/env dash
+#
+# Copyright (C) 2024 Maria Lisina
+# Copyright (C) 2024 Danil Lisin
+
+set -- $(jq -r '.callback_query.data' "${update}")
+
+if [ -n "${1}" ]
+then
+ case "${1}" in
+ ("post")
+ ib_post=0
+ ;;
+ ("tags")
+ ib_tags=0
+ ;;
+ (*)
+ exit 0
+ ;;
+ esac
+
+ shift
+else
+ exit 0
+fi
+
+query_id="$(jq -r '.callback_query.id' "${update}")"
+
+if [ -n "${1}" ]
+then
+ user_id="$(jq -r '.callback_query.from.id' "${update}")"
+
+ ib_board="${1}"
+ ib_mode="p"
+ . "${functions}/ib_config"
+ . "${functions}/ib_authconfig"
+
+ notification_text="${output_text}"
+ shift
+else
+ notification_text="No image board specified"
+fi
+
+if [ -n "${1}" ]
+then
+ ib_post_id="${1}"
+ shift
+elif [ -z "${notification_text}" ]
+then
+ notification_text="No post ID specified"
+fi
+
+if [ -z "${notification_text}" ] && [ -n "${ib_config}" ]
+then
+ ib_lock=0
+ . "${functions}/ib_token"
+
+ if [ -n "${output_text}" ]
+ then
+ notification_text="${output_text} Try again in a few seconds"
+ fi
+fi
+
+if [ -z "${notification_text}" ]
+then
+ if [ -n "${ib_exception_idol}" ]
+ then
+ ib_query="id_range:${ib_post_id}"
+ else
+ ib_query="id:${ib_post_id}"
+ fi
+
+ ib_file="${cache}/${update_id}_data.json"
+
+ if ! curl --data-urlencode "${ib_dfield1}" \
+ --data-urlencode "${ib_dfield2}" \
+ --data-urlencode "${ib_dfield3}" \
+ --data-urlencode "${ib_dfield4}" \
+ --data-urlencode "${ib_dfield5}" \
+ --data-urlencode "${ib_dfield6}" \
+ --data-urlencode "${ib_dlimit}=1" \
+ --data-urlencode "${ib_dquery}=${ib_query}" \
+ --get \
+ --header "${ib_header}" \
+ --max-time 5 \
+ --output "${ib_file}" \
+ --proxy "${proxy}" \
+ --silent \
+ --user-agent "Sekoohaka" \
+ "${ib_data_url}"
+ then
+ notification_text="Failed to access ${ib_name} API"
+ fi
+
+ if [ -z "${notification_text}" ] && ! [ -f "${ib_file}" ]
+ then
+ notification_text="Failed to access ${ib_name} API"
+ fi
+
+ if [ -z "${notification_text}" ] && ! jq -e '.' "${ib_file}" > /dev/null 2>&1
+ then
+ notification_text="An unknown error occurred"
+ fi
+
+ if [ -z "${notification_text}" ] && ! jq -e ".${ib_iarray}[0]|has(\"${ib_iid}\")" "${ib_file}" > /dev/null 2>&1
+ then
+ notification_text="No results found"
+ fi
+fi
+
+if [ -z "${notification_text}" ]
+then
+ chat_id="$(jq -r '.callback_query.message.chat.id' "${update}")"
+ message_id="$(jq -r '.callback_query.message.message_id' "${update}")"
+ inline_message_id="$(jq -r '.callback_query.inline_message_id' "${update}")"
+
+ if [ -n "${ib_post}" ]
+ then
+ . "${functions}/ib_post"
+
+ link_preview_options="$(jq --null-input --compact-output \
+ --arg url1 "${ib_sample_url}" \
+ '{"url": $url1, "prefer_small_media": true, "show_above_text": true}')"
+
+ reply_markup="$(jq --null-input --compact-output \
+ --arg text1 "Post link" \
+ --arg url1 "${ib_page_url}$(printf "%s" "${ib_post_id}" | urlencode)" \
+ '{"inline_keyboard": [[{"text": $text1, "url": $url1}]]}')"
+
+ if [ ${ib_tags_count} -gt 0 ]
+ then
+ reply_markup="$(printf "%s" "${reply_markup}" | jq --compact-output \
+ --arg text1 "Tags (${ib_tags_count})" \
+ --arg data1 "tags ${ib_board} ${ib_post_id}" \
+ '.inline_keyboard.[0] += [{"text": $text1, "callback_data": $data1}]')"
+ fi
+ elif [ -n "${ib_tags}" ]
+ then
+ ib_created_at="$(jq -r ".${ib_iarray}[${array_count}].${ib_icreated}" "${ib_file}")"
+ ib_file_url="$(jq -r ".${ib_iarray}[0].${ib_ifile}" "${ib_file}")"
+ ib_file_size="$(jq -r ".${ib_iarray}[0].${ib_isize}" "${ib_file}")"
+ ib_tags="$(jq -r ".${ib_iarray}[0].${ib_itags}" "${ib_file}" | htmlescape)"
+ ib_tags_offset=${1:-0}
+
+ . "${functions}/ib_size"
+ . "${functions}/ib_meta"
+
+ if [ -n "${ib_tags}" ] && [ "${ib_tags}" != "null" ]
+ then
+ set -- ${ib_tags}
+
+ if [ ${#} -ge $((ib_tags_offset + 1)) ]
+ then
+ shift ${ib_tags_offset}
+ else
+ notification_text="No tags found"
+ fi
+ else
+ notification_text="Failed to get tags"
+ fi
+
+ if [ -z "${notification_text}" ]
+ then
+ ib_tags_count=0
+
+ while [ -n "${1}" ]
+ do
+ ib_tag="<code>${1}</code>"
+ ib_tags_length=${#output_text}
+ ib_tag_length=${#ib_tag}
+
+ if [ $((ib_tags_length + ib_tag_length)) -gt 2048 ]
+ then
+ break
+ fi
+
+ output_text="${output_text} ${ib_tag}"
+ ib_tags_count=$((ib_tags_count + 1))
+ shift
+ done
+
+ link_preview_options="$(jq --null-input --compact-output \
+ --arg url1 "${ib_sample_url}" \
+ '{"url": $url1, "prefer_small_media": true, "show_above_text": true}')"
+
+ reply_markup="$(jq --null-input --compact-output \
+ --arg text1 "Back" \
+ --arg data1 "post ${ib_board} ${ib_post_id}" \
+ '{"inline_keyboard": [[{"text": $text1, "callback_data": $data1}]]}')"
+
+ if [ ${ib_tags_offset} -gt 0 ]
+ then
+ reply_markup="$(printf "%s" "${reply_markup}" | jq --compact-output \
+ --arg text1 "Over" \
+ --arg data1 "tags ${ib_board} ${ib_post_id}" \
+ '.inline_keyboard.[0] += [{"text": $text1, "callback_data": $data1}]')"
+ fi
+
+ if [ -n "${1}" ]
+ then
+ reply_markup="$(printf "%s" "${reply_markup}" | jq --compact-output \
+ --arg text1 "Next" \
+ --arg data1 "tags ${ib_board} ${ib_post_id} $((ib_tags_offset + ib_tags_count))" \
+ '.inline_keyboard.[0] += [{"text": $text1, "callback_data": $data1}]')"
+ fi
+ fi
+ fi
+
+ if [ -z "${notification_text}" ]
+ then
+ if [ "${chat_id}" = "null" ]
+ then
+ unset chat_id
+ unset message_id
+ fi
+
+ output_file="${cache}/${update_id}_editMessageText.json"
+
+ curl --data-urlencode "chat_id=${chat_id}" \
+ --data-urlencode "message_id=${message_id}" \
+ --data-urlencode "inline_message_id=${inline_message_id}" \
+ --data-urlencode "text=${output_text}" \
+ --data-urlencode "parse_mode=HTML" \
+ --data-urlencode "link_preview_options=${link_preview_options}" \
+ --data-urlencode "reply_markup=${reply_markup}" \
+ --get \
+ --output "${output_file}" \
+ --silent \
+ "${address}/bot${token}/editMessageText"
+
+ if [ -z "${notification_text}" ] && ! jq -e '.' "${output_file}" > /dev/null 2>&1
+ then
+ notification_text="An unknown error occurred"
+ fi
+
+ if [ -z "${notification_text}" ] && [ "$(jq -r '.ok' "${output_file}")" != "true" ]
+ then
+ notification_text="Failed to update message"
+ fi
+ fi
+fi
+
+curl --data-urlencode "callback_query_id=${query_id}" \
+ --data-urlencode "text=${notification_text}" \
+ --data-urlencode "cache_time=0" \
+ --get \
+ --silent \
+ "${address}/bot${token}/answerCallbackQuery" > /dev/null
diff --git a/commands/ib_inline b/commands/ib_inline
new file mode 100644
index 0000000..9d75e11
--- /dev/null
+++ b/commands/ib_inline
@@ -0,0 +1,443 @@
+#!/usr/bin/env dash
+#
+# Copyright (C) 2024 Maria Lisina
+# Copyright (C) 2024 Danil Lisin
+
+set -- $(jq -r '.inline_query.query' "${update}")
+
+if [ -n "${1}" ]
+then
+ ib_mode="${1}"
+
+ case "${ib_mode}" in
+ (l)
+ ib_opts="aq"
+ ;;
+ (p)
+ ib_opts="ampq"
+ ;;
+ (t)
+ ib_opts="aq"
+ ;;
+ (*)
+ exit 0
+ ;;
+ esac
+
+ shift
+else
+ exit 0
+fi
+
+query_id="$(jq -r '.inline_query.id' "${update}")"
+
+if [ -n "${1}" ]
+then
+ user_id="$(jq -r '.inline_query.from.id' "${update}")"
+
+ ib_board="${1}"
+ . "${functions}/ib_config"
+ . "${functions}/ib_authconfig"
+
+ shift
+else
+ output_text="You must specify the image board"
+fi
+
+if test "${1}" -gt 0 > /dev/null 2>&1
+then
+ ib_page="${1}"
+ shift
+else
+ ib_page="1"
+ set -- -a ${@}
+fi
+
+if [ -z "${output_text}" ] && [ -n "${1}" ]
+then
+ ib_options="${@}"
+
+ while getopts ${ib_opts} ib_getopts > /dev/null 2>&1
+ do
+ case "${ib_getopts}" in
+ (a)
+ ib_autopaging=0
+ ;;
+ (m)
+ ib_metadata=0
+ ;;
+ (p)
+ ib_preview=0
+ ;;
+ (q)
+ ib_quick=0
+ ;;
+ (*)
+ output_text="Illegal option use"
+ ;;
+ esac
+ done
+
+ shift $((OPTIND - 1))
+fi
+
+if [ -n "${1}" ]
+then
+ ib_query="${@}"
+ shift ${#}
+fi
+
+if [ -n "${output_text}" ]
+then
+ output_title="An error occurred"
+fi
+
+if [ -z "${output_text}" ] && [ -n "${ib_config}" ]
+then
+ ib_lock=0
+ . "${functions}/ib_token"
+
+ if [ -n "${output_text}" ]
+ then
+ output_title="${output_text}"
+ output_text="Try again in a few seconds"
+ fi
+fi
+
+if [ -z "${output_text}" ]
+then
+ ib_offset="$(jq -r '.inline_query.offset' "${update}")"
+
+ if [ -n "${ib_offset}" ] && [ "${ib_offset}" != "null" ]
+ then
+ ib_page="${ib_offset}"
+ fi
+
+ if [ -n "${ib_query}" ]
+ then
+ if [ -n "${ib_iwildcard}" ]
+ then
+ ib_query="$(printf "%s" "${ib_query}" | sed "s/${ib_iwildcard}/\\\\${ib_iwildcard}/g" | tr '*' "${ib_iwildcard}")"
+ fi
+
+ ib_query="${ib_dquery}=${ib_query}"
+ fi
+
+ ib_file="${cache}/${update_id}_data.json"
+
+ if ! curl --data-urlencode "${ib_dfield1}" \
+ --data-urlencode "${ib_dfield2}" \
+ --data-urlencode "${ib_dfield3}" \
+ --data-urlencode "${ib_dfield4}" \
+ --data-urlencode "${ib_dfield5}" \
+ --data-urlencode "${ib_dfield6}" \
+ --data-urlencode "${ib_dlimit}=10" \
+ --data-urlencode "${ib_dpage}=$((ib_page + ib_ioffset))" \
+ --data-urlencode "${ib_query}" \
+ --get \
+ --header "${ib_header}" \
+ --max-time 5 \
+ --output "${ib_file}" \
+ --proxy "${proxy}" \
+ --silent \
+ --user-agent "Sekoohaka" \
+ "${ib_data_url}"
+ then
+ output_text="Failed to access ${ib_name} API"
+ fi
+
+ if [ -z "${output_text}" ] && ! [ -f "${ib_file}" ]
+ then
+ output_text="Failed to access ${ib_name} API"
+ fi
+
+ if [ -n "${output_text}" ]
+ then
+ next_offset="${ib_page}"
+ fi
+
+ if [ -z "${output_text}" ] && ! jq -e '.' "${ib_file}" > /dev/null 2>&1
+ then
+ output_text="An unknown error occurred"
+ fi
+
+ if [ -n "${output_text}" ]
+ then
+ output_title="An error occurred"
+ fi
+
+ if [ -z "${output_text}" ] && ! jq -e ".${ib_iarray}[0]|has(\"${ib_iid}\")" "${ib_file}" > /dev/null 2>&1
+ then
+ if [ -n "${ib_offset}" ] && [ "${ib_offset}" != "null" ]
+ then
+ output_title="End of results"
+ else
+ output_title="No results found"
+ fi
+
+ case "${ib_mode}" in
+ (l)
+ output_text="Try different page or pool name"
+ ;;
+ (p)
+ output_text="Try different page or tags"
+ ;;
+ (t)
+ output_text="Try different page or tag name"
+ ;;
+ esac
+ fi
+fi
+
+if [ -z "${output_text}" ]
+then
+ results="[]"
+ array_count=0
+
+ while [ -n "${array_count}" ]
+ do
+ ib_id="$(jq -r ".${ib_iarray}[${array_count}].${ib_iid}" "${ib_file}")"
+
+ if [ "${ib_id}" = "null" ]
+ then
+ break
+ fi
+
+ case "${ib_mode}" in
+ (l)
+ ib_created_at="$(jq -r ".${ib_iarray}[${array_count}].${ib_icreated}" "${ib_file}")"
+ ib_pool="$(jq -r ".${ib_iarray}[${array_count}].${ib_ipool}" "${ib_file}")"
+ ib_count="$(jq -r ".${ib_iarray}[${array_count}].${ib_icount}" "${ib_file}")"
+
+ unset ib_date_text
+ . "${functions}/ib_date"
+
+ if [ -n "${ib_ispace}" ]
+ then
+ ib_pool="$(printf "%s" "${ib_pool}" | tr "${ib_ispace}" ' ')"
+ fi
+
+ ib_result_id="${ib_page}${array_count}"
+ ib_text="$(printf "<b>%s</b>\n<b>ID:</b> <code>%s</code>" "${ib_name}" "${ib_id}")"
+
+ if [ -n "${ib_date_text}" ]
+ then
+ ib_text="$(printf "%s\n<b>Date:</b> <code>%s</code>" "${ib_text}" "${ib_date_text}")"
+ fi
+
+ ib_text="$(printf "%s\n<b>Name:</b> %s" "${ib_text}" "$(printf "%s" "${ib_pool}" | htmlescape)")"
+ ib_text="$(printf "%s\n<b>Post count:</b> %s" "${ib_text}" "${ib_count}")"
+ ib_button1_text="Pool link"
+ ib_button1_url="${ib_page_url}$(printf "%s" "${ib_id}" | urlencode)"
+ ib_button2_text="Resume"
+ ib_button2_query="l ${ib_board} ${ib_page}"
+
+ if [ -n "${ib_options}" ]
+ then
+ ib_button2_query="${ib_button2_query} ${ib_options}"
+ fi
+
+ result="$(jq --null-input --compact-output \
+ --arg id "${ib_result_id}" \
+ --arg title "${ib_pool:- }" \
+ --arg text "${ib_text}" \
+ --arg description "Click to send the pool information" \
+ --arg text1 "${ib_button1_text}" \
+ --arg url1 "${ib_button1_url}" \
+ --arg text2 "${ib_button2_text}" \
+ --arg query2 "${ib_button2_query}" \
+ '{"type": "article", "id": $id, "title": $title, "input_message_content": {"message_text": $text, "parse_mode": "HTML"}, "description": $description, "reply_markup": {"inline_keyboard": [[{"text": $text1, "url": $url1}, {"text": $text2, "switch_inline_query_current_chat": $query2}]]}}')"
+
+ if [ -n "${ib_quick}" ]
+ then
+ if [ -n "${ib_iorder}" ]
+ then
+ ib_id="${ib_id} ${ib_iorder}"
+ fi
+
+ result="$(printf "%s" "${result}" | jq --compact-output \
+ --arg text1 "Search posts" \
+ --arg query1 "p ${ib_board} pool:${ib_id}" \
+ '.reply_markup.inline_keyboard += [[{"text": $text1, "switch_inline_query_current_chat": $query1}]]')"
+ fi
+ ;;
+ (p)
+ ib_created_at="$(jq -r ".${ib_iarray}[${array_count}].${ib_icreated}" "${ib_file}")"
+ ib_file_url="$(jq -r ".${ib_iarray}[${array_count}].${ib_ifile}" "${ib_file}")"
+ ib_file_size="$(jq -r ".${ib_iarray}[${array_count}].${ib_isize}" "${ib_file}")"
+
+ unset ib_date_text ib_resolution_text ib_type_text ib_size_text
+ . "${functions}/ib_date"
+ . "${functions}/ib_meta"
+
+ if [ -n "${ib_preview}" ]
+ then
+ case "${ib_type}" in
+ (gif | video)
+ ib_sample_url="${ib_preview_url}"
+ ib_type="photo"
+ ;;
+ esac
+ fi
+
+ ib_result_id="${ib_page}${array_count}"
+ ib_caption="$(printf "<b>%s</b>\n<b>ID:</b> <code>%s</code>" "${ib_name}" "${ib_id}")"
+ ib_button1_text="Post link"
+ ib_button1_url="${ib_page_url}$(printf "%s" "${ib_id}" | urlencode)"
+ ib_button2_text="Resume"
+ ib_button2_query="p ${ib_board} ${ib_page}"
+
+ if [ -n "${ib_date_text}" ]
+ then
+ ib_caption="$(printf "%s\n<b>Date:</b> <code>%s</code>" "${ib_caption}" "${ib_date_text}")"
+ fi
+
+ if [ -n "${ib_metadata}" ]
+ then
+ if [ -n "${ib_resolution_text}" ]
+ then
+ ib_caption="$(printf "%s\n<b>Resolution:</b> %s" "${ib_caption}" "${ib_resolution_text}")"
+ fi
+
+ if [ -n "${ib_size_text}" ]
+ then
+ ib_caption="$(printf "%s\n<b>Size:</b> %s" "${ib_caption}" "${ib_size_text}")"
+ fi
+
+ if [ -n "${ib_type_text}" ]
+ then
+ ib_caption="$(printf "%s\n<b>Type:</b> %s" "${ib_caption}" "${ib_type_text}")"
+ fi
+ fi
+
+ if [ -n "${ib_options}" ]
+ then
+ ib_button2_query="${ib_button2_query} ${ib_options}"
+ fi
+
+ case "${ib_type}" in
+ (photo)
+ result="$(jq --null-input --compact-output \
+ --arg id "${ib_result_id}" \
+ --arg photo_url "${ib_sample_url}" \
+ --arg thumbnail_url "${ib_preview_url}" \
+ --arg photo_width "${ib_width}" \
+ --arg photo_height "${ib_height}" \
+ --arg caption "${ib_caption}" \
+ --arg text1 "${ib_button1_text}" \
+ --arg url1 "${ib_button1_url}" \
+ --arg text2 "${ib_button2_text}" \
+ --arg query2 "${ib_button2_query}" \
+ '{"type": "photo", "id": $id, "photo_url": $photo_url, "thumbnail_url": $thumbnail_url, "photo_width": $photo_width, "photo_height": $photo_height, "caption": $caption, "parse_mode": "HTML", "reply_markup": {"inline_keyboard": [[{"text": $text1, "url": $url1}, {"text": $text2, "switch_inline_query_current_chat": $query2}]]}}')"
+ ;;
+ (gif)
+ result="$(jq --null-input --compact-output \
+ --arg id "${ib_result_id}" \
+ --arg gif_url "${ib_file_url}" \
+ --arg thumbnail_url "${ib_preview_url}" \
+ --arg gif_width "${ib_width}" \
+ --arg gif_height "${ib_height}" \
+ --arg caption "${ib_caption}" \
+ --arg text1 "${ib_button1_text}" \
+ --arg url1 "${ib_button1_url}" \
+ --arg text2 "${ib_button2_text}" \
+ --arg query2 "${ib_button2_query}" \
+ '{"type": "gif", "id": $id, "gif_url": $gif_url, "thumbnail_url": $thumbnail_url, "gif_width": $gif_width, "gif_height": $gif_height, "caption": $caption, "parse_mode": "HTML", "reply_markup": {"inline_keyboard": [[{"text": $text1, "url": $url1}, {"text": $text2, "switch_inline_query_current_chat": $query2}]]}}')"
+ ;;
+ (video)
+ result="$(jq --null-input --compact-output \
+ --arg id "${ib_result_id}" \
+ --arg mpeg4_url "${ib_file_url}" \
+ --arg thumbnail_url "${ib_preview_url}" \
+ --arg mpeg4_width "${ib_width}" \
+ --arg mpeg4_height "${ib_height}" \
+ --arg caption "${ib_caption}" \
+ --arg text1 "${ib_button1_text}" \
+ --arg url1 "${ib_button1_url}" \
+ --arg text2 "${ib_button2_text}" \
+ --arg query2 "${ib_button2_query}" \
+ '{"type": "mpeg4_gif", "id": $id, "mpeg4_url": $mpeg4_url, "thumbnail_url": $thumbnail_url, "mpeg4_width": $mpeg4_width, "mpeg4_height": $mpeg4_height, "caption": $caption, "parse_mode": "HTML", "reply_markup": {"inline_keyboard": [[{"text": $text1, "url": $url1}, {"text": $text2, "switch_inline_query_current_chat": $query2}]]}}')"
+ ;;
+ esac
+
+ if [ -n "${ib_quick}" ]
+ then
+ result="$(printf "%s" "${result}" | jq --compact-output \
+ --arg text1 "Original" \
+ --arg query1 "original ${ib_board} ${ib_id}" \
+ --arg text2 "Post" \
+ --arg query2 "post ${ib_board} ${ib_id}" \
+ '.reply_markup.inline_keyboard += [[{"text": $text1, "switch_inline_query_current_chat": $query1}, {"text": $text2, "switch_inline_query_current_chat": $query2}]]')"
+ fi
+ ;;
+ (t)
+ ib_tag="$(jq -r ".${ib_iarray}[${array_count}].${ib_itag}" "${ib_file}")"
+ ib_count="$(jq -r ".${ib_iarray}[${array_count}].${ib_icount}" "${ib_file}")"
+
+ if [ -n "${ib_irecode}" ]
+ then
+ if ib_tag_recode="$(printf "%s" "${ib_tag}" | recode ${ib_irecode}..ASCII 2>&1)"
+ then
+ ib_tag="${ib_tag_recode}"
+ fi
+ fi
+
+ ib_result_id="${ib_page}${array_count}"
+ ib_text="$(printf "<b>%s</b>\n<b>ID:</b> <code>%s</code>" "${ib_name}" "${ib_id}")"
+ ib_text="$(printf "%s\n<b>Name:</b> <code>%s</code>" "${ib_text}" "$(printf "%s" "${ib_tag}" | htmlescape)")"
+ ib_text="$(printf "%s\n<b>Post count:</b> %s" "${ib_text}" "${ib_count}")"
+ ib_button1_text="Wiki link"
+ ib_button1_url="${ib_page_url}$(printf "%s" "${ib_tag}" | urlencode)"
+ ib_button2_text="Resume"
+ ib_button2_query="t ${ib_board} ${ib_page}"
+
+ if [ -n "${ib_options}" ]
+ then
+ ib_button2_query="${ib_button2_query} ${ib_options}"
+ fi
+
+ result="$(jq --null-input --compact-output \
+ --arg id "${ib_result_id}" \
+ --arg title "${ib_tag:- }" \
+ --arg text "${ib_text}" \
+ --arg description "Click to send the tag information" \
+ --arg text1 "${ib_button1_text}" \
+ --arg url1 "${ib_button1_url}" \
+ --arg text2 "${ib_button2_text}" \
+ --arg query2 "${ib_button2_query}" \
+ '{"type": "article", "id": $id, "title": $title, "input_message_content": {"message_text": $text, "parse_mode": "HTML"}, "description": $description, "reply_markup": {"inline_keyboard": [[{"text": $text1, "url": $url1}, {"text": $text2, "switch_inline_query_current_chat": $query2}]]}}')"
+
+ if [ -n "${ib_quick}" ]
+ then
+ result="$(printf "%s" "${result}" | jq --compact-output \
+ --arg text1 "Search posts" \
+ --arg query1 "p ${ib_board} ${ib_tag}" \
+ '.reply_markup.inline_keyboard += [[{"text": $text1, "switch_inline_query_current_chat": $query1}]]')"
+ fi
+ ;;
+ esac
+
+ results="$(printf "%s" "${results}" | jq -c ".[${array_count}] += ${result}")"
+ array_count=$((array_count + 1))
+ done
+
+ if [ -n "${ib_autopaging}" ]
+ then
+ next_offset="$((ib_page + 1))"
+ fi
+else
+ results="$(jq --null-input --compact-output \
+ --arg id "${query_id}" \
+ --arg title "${output_title}" \
+ --arg text "${output_text}" \
+ --arg description "${output_text}" \
+ '[{"type": "article", "id": $id, "title": $title, "input_message_content": {"message_text": $text}, "description": $description}]')"
+fi
+
+curl --data-urlencode "inline_query_id=${query_id}" \
+ --data-urlencode "results=${results}" \
+ --data-urlencode "cache_time=0" \
+ --data-urlencode "next_offset=${next_offset}" \
+ --get \
+ --silent \
+ "${address}/bot${token}/answerInlineQuery" > /dev/null
diff --git a/commands/inline b/commands/inline
new file mode 100644
index 0000000..814782f
--- /dev/null
+++ b/commands/inline
@@ -0,0 +1,345 @@
+#!/usr/bin/env dash
+#
+# Copyright (C) 2024 Maria Lisina
+# Copyright (C) 2024 Danil Lisin
+
+set -- $(jq -r '.inline_query.query' "${update}")
+
+if [ -n "${1}" ]
+then
+ case "${1}" in
+ ("help")
+ inline_help=0
+ ;;
+ ("original")
+ inline_original=0
+ ;;
+ ("post")
+ inline_post=0
+ ;;
+ ("short")
+ inline_short=0
+ ;;
+ ("shorts")
+ inline_shorts=0
+ ;;
+ (*)
+ exit 0
+ ;;
+ esac
+
+ shift
+else
+ user_id="$(jq -r '.inline_query.from.id' "${update}")"
+ short_config="${config}/${user_id}/short"
+
+ until mkdir "${config}/${user_id}_short.lock" > /dev/null 2>&1
+ do
+ sleep 1
+ done
+
+ if [ -d "${short_config}" ]
+ then
+ shorts="$(ls -x "${short_config}")"
+ fi
+
+ if [ -n "${shorts}" ]
+ then
+ inline_shorts=0
+ else
+ inline_help=0
+ fi
+
+ rm -fr "${config}/${user_id}_short.lock"
+fi
+
+query_id="$(jq -r '.inline_query.id' "${update}")"
+
+if [ -n "${inline_help}" ]
+then
+ . "${functions}/help"
+
+ results="$(jq --null-input --compact-output \
+ --arg id "${query_id}" \
+ --arg title "Sekoohaka Bot" \
+ --arg text "${output_text}" \
+ --arg description "Click to send help message" \
+ '[{"type": "article", "id": $id, "title": $title, "input_message_content": {"message_text": $text, "parse_mode": "HTML"}, "description": $description}]')"
+fi
+
+if [ -n "${inline_original}" ] || [ -n "${inline_post}" ]
+then
+ if [ -n "${1}" ]
+ then
+ user_id="$(jq -r '.inline_query.from.id' "${update}")"
+
+ ib_board="${1}"
+ ib_mode="p"
+ . "${functions}/ib_config"
+ . "${functions}/ib_authconfig"
+
+ shift
+ else
+ output_text="You must specify the image board"
+ fi
+
+ if [ -n "${1}" ]
+ then
+ ib_post_id="${1}"
+ shift
+ elif [ -z "${output_text}" ]
+ then
+ output_text="You must specify the post ID"
+ fi
+
+ if [ -n "${output_text}" ]
+ then
+ output_title="An error occurred"
+ fi
+
+ if [ -z "${output_text}" ] && [ -n "${ib_config}" ]
+ then
+ ib_lock=0
+ . "${functions}/ib_token"
+
+ if [ -n "${output_text}" ]
+ then
+ output_title="${output_text}"
+ output_text="Try again in a few seconds"
+ fi
+ fi
+
+ if [ -z "${output_text}" ]
+ then
+ if [ -n "${ib_exception_idol}" ]
+ then
+ ib_query="id_range:${ib_post_id}"
+ else
+ ib_query="id:${ib_post_id}"
+ fi
+
+ ib_file="${cache}/${update_id}_data.json"
+
+ if ! curl --data-urlencode "${ib_dfield1}" \
+ --data-urlencode "${ib_dfield2}" \
+ --data-urlencode "${ib_dfield3}" \
+ --data-urlencode "${ib_dfield4}" \
+ --data-urlencode "${ib_dfield5}" \
+ --data-urlencode "${ib_dfield6}" \
+ --data-urlencode "${ib_dlimit}=1" \
+ --data-urlencode "${ib_dquery}=${ib_query}" \
+ --get \
+ --header "${ib_header}" \
+ --max-time 5 \
+ --output "${ib_file}" \
+ --proxy "${proxy}" \
+ --silent \
+ --user-agent "Sekoohaka" \
+ "${ib_data_url}"
+ then
+ output_text="Failed to access ${ib_name} API"
+ fi
+
+ if [ -z "${output_text}" ] && ! [ -f "${ib_file}" ]
+ then
+ output_text="Failed to access ${ib_name} API"
+ fi
+
+ if [ -z "${output_text}" ] && ! jq -e '.' "${ib_file}" > /dev/null 2>&1
+ then
+ output_text="An unknown error occurred"
+ fi
+
+ if [ -n "${output_text}" ]
+ then
+ output_title="An error occurred"
+ fi
+
+ if [ -z "${output_text}" ] && ! jq -e ".${ib_iarray}[0]|has(\"${ib_iid}\")" "${ib_file}" > /dev/null 2>&1
+ then
+ output_title="No results found"
+ output_text="Try different post ID"
+ fi
+ fi
+
+ if [ -z "${output_text}" ]
+ then
+ if [ -n "${inline_original}" ]
+ then
+ . "${functions}/ib_original"
+
+ if [ -n "${output_text}" ]
+ then
+ results="$(jq --null-input --compact-output \
+ --arg id "${query_id}" \
+ --arg title "An error occurred" \
+ --arg text "${output_text}" \
+ --arg description "${output_text}" \
+ '[{"type": "article", "id": $id, "title": $title, "input_message_content": {"message_text": $text}, "description": $description}]')"
+ else
+ results="$(jq --null-input --compact-output \
+ --arg id "${query_id}" \
+ --arg title "Original file of post ${ib_post_id}" \
+ --arg document_url "${ib_file_url}" \
+ --arg description "Click to send the original file" \
+ --arg thumbnail_url "${ib_preview_url}" \
+ '[{"type": "document", "id": $id, "title": $title, "document_url": $document_url, "mime_type": "application/zip", "description": $description, "thumbnail_url", $thumbnail_url}]')"
+ fi
+
+ if [ -n "${ib_file_url}" ] && [ "${ib_file_url}" != "null" ]
+ then
+ results="$(printf "%s" "${results}" | jq --compact-output \
+ --arg text1 "Original file link" \
+ --arg url1 "${ib_file_url}" \
+ '.[0] += {"reply_markup": {"inline_keyboard": [[{"text": $text1, "url": $url1}]]}}')"
+ fi
+ elif [ -n "${inline_post}" ]
+ then
+ . "${functions}/ib_post"
+
+ results="$(jq --null-input --compact-output \
+ --arg id "${query_id}" \
+ --arg title "Information of post ${ib_post_id}" \
+ --arg text "${output_text}" \
+ --arg url "${ib_sample_url}" \
+ --arg text1 "Post link" \
+ --arg url1 "${ib_page_url}$(printf "%s" "${ib_post_id}" | urlencode)" \
+ --arg description "Click to send the post information" \
+ --arg thumbnail_url "${ib_preview_url}" \
+ '[{"type": "article", "id": $id, "title": $title, "input_message_content": {"message_text": $text, "parse_mode": "HTML", "link_preview_options": {"url": $url, "prefer_small_media": true, "show_above_text": true}}, "reply_markup": {"inline_keyboard": [[{"text": $text1, "url": $url1}]]}, "description": $description, "thumbnail_url": $thumbnail_url}]')"
+
+ if [ ${ib_tags_count} -gt 0 ]
+ then
+ results="$(printf "%s" "${results}" | jq --compact-output \
+ --arg text1 "Tags (${ib_tags_count})" \
+ --arg data1 "tags ${ib_board} ${ib_post_id}" \
+ '.[0].reply_markup.inline_keyboard[0] += [{"text": $text1, "callback_data": $data1}]')"
+ fi
+ fi
+ else
+ results="$(jq --null-input --compact-output \
+ --arg id "${query_id}" \
+ --arg title "${output_title}" \
+ --arg text "${output_text}" \
+ --arg description "${output_text}" \
+ '[{"type": "article", "id": $id, "title": $title, "input_message_content": {"message_text": $text}, "description": $description}]')"
+
+ if [ -n "${inline_post}" ]
+ then
+ results="$(printf "%s" "${results}" | jq --compact-output \
+ --arg text1 "Retry" \
+ --arg data1 "post ${ib_board} ${ib_post_id}" \
+ '.[0] += {"reply_markup": {"inline_keyboard": [[{"text": $text1, "callback_data": $data1}]]}}')"
+ fi
+ fi
+fi
+
+if [ -n "${inline_short}" ]
+then
+ if [ -n "${1}" ]
+ then
+ short_query="${@}"
+ shift ${#}
+ else
+ output_title="An error occurred"
+ output_text="You must specify the query"
+ fi
+
+ if [ ${#short_query} -gt 1024 ]
+ then
+ output_title="An error occurred"
+ output_text="Query is too long"
+ fi
+
+ if [ -z "${output_text}" ]
+ then
+ results="$(jq --null-input --compact-output \
+ --arg id "${query_id}" \
+ --arg title "Shortcut" \
+ --arg text "<b>Shortcut:</b> <code>$(printf "%s" "${short_query}" | htmlescape)</code>" \
+ --arg text1 "Open inline" \
+ --arg query1 "${short_query}" \
+ --arg description "${short_query}" \
+ '[{"type": "article", "id": $id, "title": $title, "input_message_content": {"message_text": $text, "parse_mode": "HTML"}, "reply_markup": {"inline_keyboard": [[{"text": $text1, "switch_inline_query_current_chat": $query1}]]}, "description": $description}]')"
+
+ short_query="short ${short_query}"
+
+ if [ ${#short_query} -le 64 ]
+ then
+ results="$(printf "%s" "${results}" | jq --compact-output \
+ --arg text1 "Manage" \
+ --arg data1 "${short_query}" \
+ '.[0].reply_markup.inline_keyboard[0] += [{"text": $text1, "callback_data": $data1}]')"
+ fi
+ else
+ results="$(jq --null-input --compact-output \
+ --arg id "${query_id}" \
+ --arg title "${output_title}" \
+ --arg text "${output_text}" \
+ --arg description "${output_text}" \
+ '[{"type": "article", "id": $id, "title": $title, "input_message_content": {"message_text": $text}, "description": $description}]')"
+ fi
+fi
+
+if [ -n "${inline_shorts}" ]
+then
+ user_id="$(jq -r '.inline_query.from.id' "${update}")"
+ short_config="${config}/${user_id}/short"
+
+ until mkdir "${config}/${user_id}_short.lock" > /dev/null 2>&1
+ do
+ sleep 1
+ done
+
+ if [ -d "${short_config}" ]
+ then
+ shorts="$(ls -xt "${short_config}")"
+ fi
+
+ if [ -z "${shorts}" ]
+ then
+ output_title="An error occurred"
+ output_text="No shortcuts found"
+ fi
+
+ if [ -z "${output_text}" ]
+ then
+ results=[]
+ array_count=0
+
+ for short in ${shorts}
+ do
+ short_query="$(cat "${short_config}/${short}")"
+
+ result="$(jq --null-input --compact-output \
+ --arg id "${array_count}" \
+ --arg title "Shortcut" \
+ --arg text "<b>Shortcut:</b> <code>$(printf "%s" "${short_query}" | htmlescape)</code>" \
+ --arg text1 "Open inline" \
+ --arg query1 "${short_query}" \
+ --arg text2 "Manage" \
+ --arg data2 "short ${short_query}" \
+ --arg description "${short_query}" \
+ '{"type": "article", "id": $id, "title": $title, "input_message_content": {"message_text": $text, "parse_mode": "HTML"}, "reply_markup": {"inline_keyboard": [[{"text": $text1, "switch_inline_query_current_chat": $query1}, {"text": $text2, "callback_data": $data2}]]}, "description": $description}')"
+
+ results="$(printf "%s" "${results}" | jq -c ".[${array_count}] += ${result}")"
+ array_count=$((array_count + 1))
+ done
+ else
+ results="$(jq --null-input --compact-output \
+ --arg id "${query_id}" \
+ --arg title "${output_title}" \
+ --arg text "${output_text}" \
+ --arg description "${output_text}" \
+ '[{"type": "article", "id": $id, "title": $title, "input_message_content": {"message_text": $text}, "description": $description}]')"
+ fi
+
+ rm -fr "${config}/${user_id}_short.lock"
+fi
+
+curl --data-urlencode "inline_query_id=${query_id}" \
+ --data-urlencode "results=${results}" \
+ --data-urlencode "cache_time=0" \
+ --get \
+ --silent \
+ "${address}/bot${token}/answerInlineQuery" > /dev/null
diff --git a/functions/help b/functions/help
new file mode 100644
index 0000000..5de69f7
--- /dev/null
+++ b/functions/help
@@ -0,0 +1,83 @@
+#!/usr/bin/env dash
+#
+# Copyright (C) 2024 Maria Lisina
+# Copyright (C) 2024 Danil Lisin
+
+help_text="$(echo "<b>Sekoohaka Bot</b>" \
+ "\n\n<b>Fields descriptions:</b>" \
+ "\n[command] - Inline command" \
+ "\n[b] - Image board" \
+ "\n[page] - Search page number" \
+ "\n[options] - Search options" \
+ "\n[tags] - Search tags" \
+ "\n[name] - Search pool or tag name" \
+ "\n[id] - Post ID" \
+ "\n[query] - Inline query" \
+ "\n[login] - Image board login" \
+ "\n[key] - Image board API key or password" \
+ "\n\n<b>Inline commands:</b>" \
+ "\nhelp - Send this message" \
+ "\nl [b] [page] [options] [name] - Pool search" \
+ "\np [b] [page] [options] [tags] - Post search" \
+ "\nt [b] [page] [options] [name] - Tag search" \
+ "\noriginal [b] [id] - Get original file of post" \
+ "\npost [b] [id] - Get infromation of post" \
+ "\nshort [query] - Create inline shortcut" \
+ "\nshorts - List saved inline shortcuts" \
+ "\n\n<b>Search options:</b>" \
+ "\na - Enable autopaging (lpt)" \
+ "\nm - Show more metadata (p)" \
+ "\np - Show gif/video as preview only (p)" \
+ "\nq - Add quick buttons (lpt)" \
+ "\n\n<b>Commands:</b>" \
+ "\n/help - Send this message" \
+ "\n/authorize [b] [login] [key] - Authorize to image board" \
+ "\n/original [b] [id] - Get original file of post" \
+ "\n/post [b] [id] - Get infromation of post" \
+ "\n/short [query] - Create inline shortcut" \
+ "\n/shorts - Manage saved shortcuts" \
+ "\n/stop - Remove all your data" \
+ "\n\n<b>Inline examples:</b>" \
+ "\np d -mq sakurada_shiro" \
+ "\nt d *genshin*" \
+ "\noriginal d 5080413" \
+ "\nshort p d 1 -amq rating:g blue_archive" \
+ "\n\n<b>Supported image boards:</b>")"
+
+for ib_board in ${ascii_table}
+do
+ unset ib_name ib_config ib_features
+ . "${functions}/ib_config"
+ . "${functions}/ib_authconfig"
+
+ if [ -n "${ib_name}" ]
+ then
+ help_text="$(printf "%s\n%c - %s" "${help_text}" "${ib_board}" "${ib_name}")"
+
+ for ib_mode in ${ascii_table}
+ do
+ . "${functions}/ib_config"
+
+ if [ -z "${output_text}" ]
+ then
+ ib_features="${ib_features}${ib_mode}"
+ fi
+
+ unset output_text
+ done
+
+ if [ -n "${ib_config}" ]
+ then
+ help_text="$(printf "%s (authorize)" "${help_text}")"
+ fi
+
+ if [ -n "${ib_features}" ]
+ then
+ help_text="$(printf "%s (%s)" "${help_text}" "${ib_features}")"
+ fi
+ fi
+
+ unset output_text
+done
+
+output_text="${help_text}"
diff --git a/functions/ib_auth b/functions/ib_auth
new file mode 100644
index 0000000..6dfbe14
--- /dev/null
+++ b/functions/ib_auth
@@ -0,0 +1,171 @@
+#!/usr/bin/env dash
+#
+# Copyright (C) 2024 Maria Lisina
+# Copyright (C) 2024 Danil Lisin
+
+if ! mkdir -p "${ib_config}"
+then
+ output_text="Failed to create user config"
+ return 0
+fi
+
+if [ -n "${ib_login}" ]
+then
+ printf "%s" "${ib_login}" > "${ib_config}/${ib_login_file}"
+fi
+
+if [ -n "${ib_api_key}" ]
+then
+ printf "%s" "${ib_api_key}" > "${ib_config}/${ib_api_key_file}"
+fi
+
+if [ -f "${ib_config}/${ib_login_file}" ]
+then
+ ib_login="$(cat "${ib_config}/${ib_login_file}")"
+else
+ output_text="You must specify the ${ib_login_word}"
+ return 0
+fi
+
+if [ -f "${ib_config}/${ib_api_key_file}" ]
+then
+ ib_api_key="$(cat "${ib_config}/${ib_api_key_file}")"
+else
+ output_text="You must specify the ${ib_api_key_word}"
+ return 0
+fi
+
+case "${ib_board}" in
+ (d)
+ ib_file="${cache}/${update_id}_profile.json"
+
+ if ! curl --max-time 5 \
+ --output "${ib_file}" \
+ --proxy "${proxy}" \
+ --request GET \
+ --silent \
+ --user "${ib_login}:${ib_api_key}" \
+ --user-agent "Sekoohaka" \
+ "https://danbooru.donmai.us/profile.json"
+ then
+ output_text="Temporary error"
+ return 0
+ fi
+
+ if ! [ -f "${ib_file}" ]
+ then
+ output_text="Failed to process request"
+ return 0
+ fi
+
+ if ! jq -e '.' "${ib_file}" > /dev/null 2>&1
+ then
+ output_text="An unknown error occurred"
+ return 0
+ fi
+
+ if [ "$(jq -r '.success' "${ib_file}")" = "false" ]
+ then
+ output_text="Error: <code>$(jq -r '.message' "${ib_file}" | htmlescape)</code>"
+ return 0
+ fi
+
+ if [ "$(jq -r '.name' "${ib_file}")" != "${ib_login}" ]
+ then
+ output_text="An unexpected error occurred"
+ return 0
+ fi
+
+ printf "%s" "${ib_login}:${ib_api_key}" | base64 > "${ib_config}/token"
+ ;;
+ (g)
+ printf '%s="%s"\n%s="%s"' \
+ "ib_dfield5" "user_id=${ib_login}" \
+ "ib_dfield6" "api_key=${ib_api_key}" > "${ib_config}/legacy"
+ ;;
+ (i)
+ ib_login_lower="$(printf "%s" "${ib_login}" | tr '[:upper:]' '[:lower:]')"
+ ib_password_hash="$(printf "choujin-steiner--%s--" "${ib_api_key}" | sha1sum | awk '{print $1}')"
+ ib_appkey="$(printf "sankakuapp_%s_Z5NE9YASej" "${ib_login_lower}" | sha1sum | awk '{print $1}')"
+
+ printf '%s="%s"\n%s="%s"\n%s="%s"' \
+ "ib_dfield4" "login=${ib_login}" \
+ "ib_dfield5" "password_hash=${ib_password_hash}" \
+ "ib_dfield6" "appkey=${ib_appkey}" > "${ib_config}/legacy"
+ ;;
+ (s)
+ ib_login_data="$(jq --null-input --compact-output \
+ --arg login "${ib_login}" \
+ --arg password "${ib_api_key}" \
+ '{"login": $login, "password": $password}')"
+
+ ib_file="${cache}/${update_id}_token.json"
+
+ if ! curl --data "${ib_login_data}" \
+ --header "Content-Type: application/json" \
+ --max-time 5 \
+ --output "${ib_file}" \
+ --proxy "${proxy}" \
+ --request POST \
+ --silent \
+ --user-agent "Sekoohaka" \
+ "https://capi-v2.sankakucomplex.com/auth/token"
+ then
+ output_text="Temporary error"
+ return 0
+ fi
+
+ if ! [ -f "${ib_file}" ]
+ then
+ output_text="Failed to process request"
+ return 0
+ fi
+
+ if ! jq -e '.' "${ib_file}" > /dev/null 2>&1
+ then
+ output_text="An unknown error occurred"
+ return 0
+ fi
+
+ if [ "$(jq -r '.success' "${ib_file}")" != "true" ]
+ then
+ output_text="Error: <code>$(jq -r '.error' "${ib_file}" | htmlescape)</code>"
+ return 0
+ fi
+
+ jq -r '.access_token' "${ib_file}" > "${ib_config}/token"
+ date +%s > "${ib_config}/time"
+ ;;
+ (k | y)
+ ib_file="${cache}/${update_id}_user.json"
+
+ if ! curl --data-urlencode "username=${ib_login}" \
+ --data-urlencode "api_key=${ib_api_key}" \
+ --max-time 5 \
+ --output "${ib_file}" \
+ --proxy "${proxy}" \
+ --silent \
+ --user-agent "Sekoohaka" \
+ "${ib_api}/user.json"
+ then
+ output_text="Temporary error"
+ return 0
+ fi
+
+ if ! [ -f "${ib_file}" ]
+ then
+ output_text="Failed to process request"
+ return 0
+ fi
+
+ if ! jq -e '.' "${ib_file}" > /dev/null 2>&1
+ then
+ output_text="Invalid username or API key"
+ return 0
+ fi
+
+ printf '%s="%s"\n%s="%s"' \
+ "ib_dfield5" "username=${ib_login}" \
+ "ib_dfield6" "api_key=${ib_api_key}" > "${ib_config}/legacy"
+ ;;
+esac
diff --git a/functions/ib_authconfig b/functions/ib_authconfig
new file mode 100644
index 0000000..200583d
--- /dev/null
+++ b/functions/ib_authconfig
@@ -0,0 +1,57 @@
+#!/usr/bin/env dash
+#
+# Copyright (C) 2024 Maria Lisina
+# Copyright (C) 2024 Danil Lisin
+
+case "${ib_board}" in
+ (d)
+ ib_config="${config}/${user_id}/danbooru"
+ ib_authorization="Authorization: Baisc"
+ ib_login_file="login"
+ ib_api_key_file="api_key"
+ ib_login_word="login"
+ ib_api_key_word="API key"
+ ;;
+ (g)
+ ib_config="${config}/${user_id}/gelbooru"
+ ib_noverify=0
+ ib_login_file="user_id"
+ ib_api_key_file="api_key"
+ ib_login_word="user ID"
+ ib_api_key_word="API key"
+ ;;
+ (i)
+ ib_config="${config}/${user_id}/idol"
+ ib_noverify=0
+ ib_login_file="login"
+ ib_api_key_file="password"
+ ib_login_word="login"
+ ib_api_key_word="password"
+ ;;
+ (s)
+ ib_config="${config}/${user_id}/sankaku"
+ ib_authorization="Authorization: Bearer"
+ ib_time=36000
+ ib_login_file="login"
+ ib_api_key_file="password"
+ ib_login_word="login"
+ ib_api_key_word="password"
+ ;;
+ (k | y)
+ case "${ib_board}" in
+ (k)
+ ib_api="https://konachan.com"
+ ib_config="${config}/${user_id}/konachan"
+ ;;
+ (y)
+ ib_api="https://yande.re"
+ ib_config="${config}/${user_id}/yandere"
+ ;;
+ esac
+
+ ib_login_file="username"
+ ib_api_key_file="api_key"
+ ib_login_word="username"
+ ib_api_key_word="API key"
+ ;;
+esac
diff --git a/functions/ib_config b/functions/ib_config
new file mode 100644
index 0000000..7c640a2
--- /dev/null
+++ b/functions/ib_config
@@ -0,0 +1,339 @@
+#!/usr/bin/env dash
+#
+# Copyright (C) 2024 Maria Lisina
+# Copyright (C) 2024 Danil Lisin
+
+ib_error_url="https://cdn.donmai.us/original/fb/b6/fbb6c45cac3194754dd1feb997cb8ad6.jpg"
+ib_error_width=536
+ib_error_height=516
+
+case "${ib_board}" in
+ (d)
+ ib_name="Danbooru"
+ ib_api="https://danbooru.donmai.us"
+
+ ib_ratings="
+ g general
+ s sensitive
+ q questionable
+ e explicit"
+
+ case "${ib_mode}" in
+ (l)
+ ib_data_url="${ib_api}/pools.json"
+ ib_dlimit="limit"
+ ib_dpage="page"
+ ib_dquery="search[name_matches]"
+ ib_iid="id"
+ ib_icreated="created_at"
+ ib_ipool="name"
+ ib_icount="post_count"
+ ib_idate="%Y-%m-%dT%X"
+ ib_ispace="_"
+ ib_iorder="order:created_at_asc"
+ ib_page_url="${ib_api}/pools/"
+ ;;
+ (p)
+ ib_data_url="${ib_api}/posts.json"
+ ib_dlimit="limit"
+ ib_dpage="page"
+ ib_dquery="tags"
+ ib_iid="id"
+ ib_icreated="created_at"
+ ib_ifile="file_url"
+ ib_isize="file_size"
+ ib_isample="large_file_url"
+ ib_ipreview="preview_file_url"
+ ib_iwidth="image_width"
+ ib_iheight="image_height"
+ ib_irating="rating"
+ ib_iparent="parent_id"
+ ib_ichildren="has_children"
+ ib_imd5="md5"
+ ib_isource="source"
+ ib_itags="tag_string"
+ ib_idate="%Y-%m-%dT%X"
+ ib_ifilename="cut -d '/' -f 7"
+ ib_page_url="${ib_api}/posts/"
+ ;;
+ (t)
+ ib_data_url="${ib_api}/tags.json"
+ ib_dlimit="limit"
+ ib_dpage="page"
+ ib_dquery="search[name_matches]"
+ ib_iid="id"
+ ib_itag="name"
+ ib_icount="post_count"
+ ib_irecode="HTML"
+ ib_page_url="${ib_api}/wiki_pages/"
+ ;;
+ (*)
+ output_text="Unsupported image board"
+ ;;
+ esac
+ ;;
+ (g)
+ ib_name="Gelbooru"
+ ib_api="https://gelbooru.com"
+
+ ib_ratings="
+ safe safe
+ general general
+ sensitive sensitive
+ questionable questionable
+ explicit explicit"
+
+ case "${ib_mode}" in
+ (p)
+ ib_data_url="${ib_api}/index.php"
+ ib_dfield1="page=dapi"
+ ib_dfield2="s=post"
+ ib_dfield3="q=index"
+ ib_dfield4="json=1"
+ ib_dlimit="limit"
+ ib_dpage="pid"
+ ib_dquery="tags"
+ ib_ioffset="-1"
+ ib_iarray="post"
+ ib_iid="id"
+ ib_icreated="created_at"
+ ib_ifile="file_url"
+ ib_isize="deprecated"
+ ib_isample="sample_url"
+ ib_ipreview="preview_url"
+ ib_iwidth="width"
+ ib_iheight="height"
+ ib_irating="rating"
+ ib_iparent="parent_id"
+ ib_ichildren="has_children"
+ ib_imd5="md5"
+ ib_isource="source"
+ ib_itags="tags"
+ ib_itzfield=5
+ ib_idate="%a %b %d %X %Y"
+ ib_ifilename="cut -d '/' -f 7"
+ ib_page_url="${ib_api}/index.php?page=post&s=view&id="
+ ;;
+ (t)
+ ib_data_url="${ib_api}/index.php"
+ ib_dfield1="page=dapi"
+ ib_dfield2="s=tag"
+ ib_dfield3="q=index"
+ ib_dfield4="json=1"
+ ib_dlimit="limit"
+ ib_dpage="pid"
+ ib_dquery="name_pattern"
+ ib_iwildcard="%"
+ ib_ioffset="-1"
+ ib_iarray="tag"
+ ib_iid="id"
+ ib_itag="name"
+ ib_icount="count"
+ ib_irecode="HTML"
+ ib_page_url="${ib_api}/index.php?page=wiki&s=list&search="
+ ;;
+ (*)
+ output_text="Unsupported image board"
+ ;;
+ esac
+ ;;
+ (i)
+ ib_name="Idol Complex"
+ ib_api="https://iapi.sankakucomplex.com"
+
+ ib_ratings="
+ s safe
+ q questionable
+ e explicit"
+
+ case "${ib_mode}" in
+ (l)
+ ib_exception_idol=0
+
+ ib_data_url="${ib_api}/pools.json"
+ ib_dlimit="limit"
+ ib_dpage="page"
+ ib_dquery="name"
+ ib_iid="id"
+ ib_icreated="created_at"
+ ib_ipool="name"
+ ib_icount="post_count"
+ ib_idate="%Y-%m-%d %H:%M"
+ ib_ispace="_"
+ ib_page_url="https://idol.sankakucomplex.com/pools/"
+ ;;
+ (p)
+ ib_exception_idol=0
+
+ ib_data_url="${ib_api}/posts.json"
+ ib_dlimit="limit"
+ ib_dpage="page"
+ ib_dquery="tags"
+ ib_iid="id"
+ ib_icreated="created_at"
+ ib_ifile="file_url"
+ ib_isize="file_size"
+ ib_isample="sample_url"
+ ib_ipreview="preview_url"
+ ib_iwidth="width"
+ ib_iheight="height"
+ ib_irating="rating"
+ ib_iparent="parent_id"
+ ib_ichildren="has_children"
+ ib_imd5="md5"
+ ib_isource="deprecated"
+ ib_itags="tags[].name"
+ ib_idate="%Y-%m-%dT%X"
+ ib_ifilename="cut -d '?' -f 1 | cut -d '/' -f 7"
+ ib_page_url="https://idol.sankakucomplex.com/posts/"
+ ;;
+ (t)
+ ib_exception_idol=0
+
+ ib_data_url="${ib_api}/tags.json"
+ ib_dlimit="limit"
+ ib_dpage="page"
+ ib_dquery="name"
+ ib_iid="id"
+ ib_itag="name"
+ ib_icount="count"
+ ib_irecode="UTF-8"
+ ib_page_url="https://idol.sankakucomplex.com/wiki/"
+ ;;
+ (*)
+ output_text="Unsupported image board"
+ ;;
+ esac
+ ;;
+ (s)
+ ib_name="Sankaku Channel"
+ ib_api="https://capi-v2.sankakucomplex.com"
+
+ ib_ratings="
+ s safe
+ q questionable
+ e explicit"
+
+ case "${ib_mode}" in
+ (l)
+ ib_data_url="${ib_api}/pools"
+ ib_dlimit="limit"
+ ib_dpage="page"
+ ib_dquery="name"
+ ib_iid="id"
+ ib_icreated="created_at"
+ ib_ipool="name"
+ ib_icount="post_count"
+ ib_idate="%Y-%m-%d %H:%M"
+ ib_page_url="https://chan.sankakucomplex.com/pools/"
+ ;;
+ (p)
+ ib_data_url="${ib_api}/posts"
+ ib_dlimit="limit"
+ ib_dpage="page"
+ ib_dquery="tags"
+ ib_iid="id"
+ ib_icreated="created_at.s"
+ ib_ifile="file_url"
+ ib_isize="file_size"
+ ib_isample="sample_url"
+ ib_ipreview="preview_url"
+ ib_iwidth="width"
+ ib_iheight="height"
+ ib_irating="rating"
+ ib_iparent="parent_id"
+ ib_ichildren="has_children"
+ ib_imd5="md5"
+ ib_isource="deprecated"
+ ib_itags="tags[].name"
+ ib_ifilename="cut -d '?' -f 1 | cut -d '/' -f 7"
+ ib_page_url="https://chan.sankakucomplex.com/posts/"
+ ;;
+ (t)
+ ib_data_url="${ib_api}/tags"
+ ib_dlimit="limit"
+ ib_dpage="page"
+ ib_dquery="name"
+ ib_iid="id"
+ ib_itag="name"
+ ib_icount="post_count"
+ ib_page_url="https://chan.sankakucomplex.com/wiki/"
+ ;;
+ (*)
+ output_text="Unsupported image board"
+ ;;
+ esac
+ ;;
+ (k | y)
+ case "${ib_board}" in
+ (k)
+ ib_name="Konachan.com"
+ ib_api="https://konachan.com"
+ ;;
+ (y)
+ ib_name="yande.re"
+ ib_api="https://yande.re"
+ ;;
+ esac
+
+ ib_ratings="
+ s safe
+ q questionable
+ e explicit"
+
+ case "${ib_mode}" in
+ (l)
+ ib_data_url="${ib_api}/pool.json"
+ ib_dlimit="limit"
+ ib_dpage="page"
+ ib_dquery="query"
+ ib_iid="id"
+ ib_icreated="created_at"
+ ib_ipool="name"
+ ib_icount="post_count"
+ ib_idate="%Y-%m-%dT%X"
+ ib_ispace="_"
+ ib_page_url="${ib_api}/pool/show/"
+ ;;
+ (p)
+ ib_data_url="${ib_api}/post.json"
+ ib_dlimit="limit"
+ ib_dpage="page"
+ ib_dquery="tags"
+ ib_iid="id"
+ ib_icreated="created_at"
+ ib_ifile="file_url"
+ ib_isize="file_size"
+ ib_isample="sample_url"
+ ib_ipreview="preview_url"
+ ib_iwidth="width"
+ ib_iheight="height"
+ ib_irating="rating"
+ ib_iparent="parent_id"
+ ib_ichildren="has_children"
+ ib_imd5="md5"
+ ib_isource="source"
+ ib_itags="tags"
+ ib_ifilename="sed 's/\/${ib_name}.*\./\./' | cut -d '/' -f 5"
+ ib_page_url="${ib_api}/post/show/"
+ ;;
+ (t)
+ ib_data_url="${ib_api}/tag.json"
+ ib_dlimit="limit"
+ ib_dpage="page"
+ ib_dquery="name"
+ ib_iid="id"
+ ib_itag="name"
+ ib_icount="count"
+ ib_irecode="UTF-8"
+ ib_page_url="${ib_api}/wiki/show?title="
+ ;;
+ (*)
+ output_text="Unsupported image board"
+ ;;
+ esac
+ ;;
+ (*)
+ output_text="Unsupported image board"
+ ;;
+esac
diff --git a/functions/ib_date b/functions/ib_date
new file mode 100644
index 0000000..a476480
--- /dev/null
+++ b/functions/ib_date
@@ -0,0 +1,33 @@
+#!/usr/bin/env dash
+#
+# Copyright (C) 2024 Maria Lisina
+# Copyright (C) 2024 Danil Lisin
+
+if [ -n "${ib_created_at}" ] && [ "${ib_created_at}" != "null" ]
+then
+ if [ -n "${ib_itzfield}" ]
+ then
+ shift ${#}
+
+ field_count=0
+
+ for field in ${ib_created_at}
+ do
+ field_count=$((field_count + 1))
+
+ if ! [ ${field_count} -eq ${ib_itzfield} ]
+ then
+ set -- ${@} ${field}
+ fi
+ done
+
+ ib_created_at="${@}"
+ fi
+
+ if [ -n "${ib_idate}" ]
+ then
+ ib_date_text="$(date -ud "${ib_created_at}" -D "${ib_idate}" +"%Y-%m-%d %H:%M")"
+ else
+ ib_date_text="$(date -ud "@${ib_created_at}" +"%Y-%m-%d %H:%M")"
+ fi
+fi
diff --git a/functions/ib_lock b/functions/ib_lock
new file mode 100644
index 0000000..2c9dc1a
--- /dev/null
+++ b/functions/ib_lock
@@ -0,0 +1,13 @@
+#!/usr/bin/env dash
+#
+# Copyright (C) 2024 Maria Lisina
+# Copyright (C) 2024 Danil Lisin
+
+until mkdir "${config}/${user_id}_auth.lock" > /dev/null 2>&1
+do
+ sleep 1
+done
+
+. "${functions}/ib_auth"
+
+rm -fr "${config}/${user_id}_auth.lock"
diff --git a/functions/ib_meta b/functions/ib_meta
new file mode 100644
index 0000000..6c991ee
--- /dev/null
+++ b/functions/ib_meta
@@ -0,0 +1,110 @@
+#!/usr/bin/env dash
+#
+# Copyright (C) 2024 Maria Lisina
+# Copyright (C) 2024 Danil Lisin
+
+if [ -n "${ib_file_url}" ] && [ "${ib_file_url}" != "null" ]
+then
+ ib_sample_url="$(jq -r ".${ib_iarray}[${array_count}].${ib_isample}" "${ib_file}")"
+ ib_preview_url="$(jq -r ".${ib_iarray}[${array_count}].${ib_ipreview}" "${ib_file}")"
+ ib_width="$(jq -r ".${ib_iarray}[${array_count}].${ib_iwidth}" "${ib_file}")"
+ ib_height="$(jq -r ".${ib_iarray}[${array_count}].${ib_iheight}" "${ib_file}")"
+ ib_type="$(printf "%s" "${ib_file_url}" | eval ${ib_ifilename} | cut -d '.' -f 2)"
+
+ if [ -n "${ib_exception_idol}" ]
+ then
+ ib_file_url="https:${ib_file_url}"
+ fi
+
+ if [ -z "${ib_sample_url}" ] || [ "${ib_sample_url}" = "null" ]
+ then
+ ib_sample_url=${ib_file_url}
+ elif [ -n "${ib_exception_idol}" ]
+ then
+ ib_sample_url="https:${ib_sample_url}"
+ fi
+
+ if [ -z "${ib_preview_url}" ] || [ "${ib_preview_url}" = "null" ]
+ then
+ ib_preview_url=${ib_error_url}
+ elif [ -n "${ib_exception_idol}" ]
+ then
+ ib_preview_url="https:${ib_preview_url}"
+ fi
+
+ if [ -n "${ib_width}" ] && [ "${ib_width}" != "null" ] && [ ${ib_width} -gt 0 ]
+ then
+ ib_resolution_text="${ib_width}x${ib_height}"
+ fi
+
+ if [ -n "${ib_type}" ]
+ then
+ ib_type_text="$(printf "%s" "${ib_type}" | tr '[:lower:]' '[:upper:]')"
+ fi
+
+ case "${ib_type}" in
+ (jpeg | jpg | png | webp)
+ ib_type="photo"
+ ;;
+ (gif)
+ ib_type="gif"
+ ;;
+ (mp4)
+ ib_type="video"
+ ;;
+ (zip | webm)
+ ib_sample_url="${ib_preview_url}"
+ ib_type="photo"
+ ;;
+ (*)
+ ib_sample_url="${ib_error_url}"
+ ib_preview_url="${ib_error_url}"
+ ib_width="${ib_error_width}"
+ ib_height="${ib_error_height}"
+ ib_type="photo"
+ ;;
+ esac
+else
+ ib_file_url="${ib_error_url}"
+ ib_file_size=0
+
+ ib_sample_url="${ib_error_url}"
+ ib_preview_url="${ib_error_url}"
+ ib_width="${ib_error_width}"
+ ib_height="${ib_error_height}"
+ ib_type="photo"
+fi
+
+if [ -n "${ib_file_size}" ] && [ "${ib_file_size}" != "null" ] && [ ${ib_file_size} -gt 0 ]
+then
+ if [ ${ib_file_size} -gt ${max_size} ]
+ then
+ if [ "${ib_sample_url}" = "${ib_file_url}" ]
+ then
+ ib_sample_url="${ib_preview_url}"
+ fi
+
+ ib_type="photo"
+ fi
+
+ unit_offset=0
+ size_offset=1
+
+ for unit in B KiB MiB GiB TiB PiB
+ do
+ unit_offset=${size_offset}
+ size_offset=$((size_offset * 1024))
+
+ if [ ${ib_file_size} -lt ${size_offset} ]
+ then
+ break
+ fi
+ done
+
+ if [ ${ib_file_size} -ge 1024 ]
+ then
+ ib_size_text="$(printf "%.2f %s" "$(printf "%s" "${ib_file_size} / ${unit_offset}" | bc -l)" "${unit}")"
+ else
+ ib_size_text="$(printf "%u %s" "${ib_file_size}" "${unit}")"
+ fi
+fi
diff --git a/functions/ib_original b/functions/ib_original
new file mode 100644
index 0000000..b54f3ed
--- /dev/null
+++ b/functions/ib_original
@@ -0,0 +1,42 @@
+#!/usr/bin/env dash
+#
+# Copyright (C) 2024 Maria Lisina
+# Copyright (C) 2024 Danil Lisin
+
+ib_file_url="$(jq -r ".${ib_iarray}[0].${ib_ifile}" "${ib_file}")"
+ib_file_size="$(jq -r ".${ib_iarray}[0].${ib_isize}" "${ib_file}")"
+
+. "${functions}/ib_size"
+
+if [ -n "${ib_file_url}" ] && [ "${ib_file_url}" != "null" ]
+then
+ ib_preview_url="$(jq -r ".${ib_iarray}[0].${ib_ipreview}" "${ib_file}")"
+
+ if [ -n "${ib_exception_idol}" ]
+ then
+ ib_file_url="https:${ib_file_url}"
+ fi
+
+ if [ -z "${ib_preview_url}" ] || [ "${ib_preview_url}" = "null" ]
+ then
+ ib_preview_url=${ib_error_url}
+ elif [ -n "${ib_exception_idol}" ]
+ then
+ ib_preview_url="https:${ib_preview_url}"
+ fi
+else
+ output_text="No original file found"
+ return 0
+fi
+
+if [ -n "${ib_file_size}" ] && [ "${ib_file_size}" != "null" ] && [ ${ib_file_size} -gt 0 ]
+then
+ if [ ${ib_file_size} -gt ${max_size} ]
+ then
+ output_text="File size is too large"
+ return 0
+ fi
+else
+ output_text="Failed to get file size"
+ return 0
+fi
diff --git a/functions/ib_post b/functions/ib_post
new file mode 100644
index 0000000..02a426d
--- /dev/null
+++ b/functions/ib_post
@@ -0,0 +1,92 @@
+#!/usr/bin/env dash
+#
+# Copyright (C) 2024 Maria Lisina
+# Copyright (C) 2024 Danil Lisin
+
+ib_id="$(jq -r ".${ib_iarray}[0].${ib_iid}" "${ib_file}")"
+ib_created_at="$(jq -r ".${ib_iarray}[${array_count}].${ib_icreated}" "${ib_file}")"
+ib_file_url="$(jq -r ".${ib_iarray}[0].${ib_ifile}" "${ib_file}")"
+ib_file_size="$(jq -r ".${ib_iarray}[0].${ib_isize}" "${ib_file}")"
+ib_rating="$(jq -r ".${ib_iarray}[0].${ib_irating}" "${ib_file}")"
+ib_parent_id="$(jq -r ".${ib_iarray}[0].${ib_iparent}" "${ib_file}")"
+ib_has_children="$(jq -r ".${ib_iarray}[0].${ib_ichildren}" "${ib_file}")"
+ib_md5="$(jq -r ".${ib_iarray}[0].${ib_imd5}" "${ib_file}")"
+ib_source="$(jq -r ".${ib_iarray}[0].${ib_isource}" "${ib_file}" | htmlescape)"
+ib_tags="$(jq -r ".${ib_iarray}[0].${ib_itags}" "${ib_file}")"
+ib_tags_count=0
+
+. "${functions}/ib_size"
+. "${functions}/ib_date"
+. "${functions}/ib_meta"
+
+output_text="$(printf "<b>%s</b>\n<b>ID:</b> <code>%s</code>" "${ib_name}" "${ib_id}")"
+
+if [ -n "${ib_date_text}" ]
+then
+ output_text="$(printf "%s\n<b>Date:</b> <code>%s</code>" "${output_text}" "${ib_date_text}")"
+fi
+
+if [ -n "${ib_resolution_text}" ]
+then
+ output_text="$(printf "%s\n<b>Resolution:</b> %s" "${output_text}" "${ib_resolution_text}")"
+fi
+
+if [ -n "${ib_size_text}" ]
+then
+ output_text="$(printf "%s\n<b>Size:</b> %s" "${output_text}" "${ib_size_text}")"
+fi
+
+if [ -n "${ib_type_text}" ]
+then
+ output_text="$(printf "%s\n<b>Type:</b> %s" "${output_text}" "${ib_type_text}")"
+fi
+
+if [ -n "${ib_rating}" ] && [ "${ib_rating}" != "null" ]
+then
+ set -- ${ib_ratings}
+
+ while [ -n "${2}" ]
+ do
+ if [ "${ib_rating}" = "${1}" ]
+ then
+ output_text="$(printf "%s\n<b>Rating:</b> <code>%s</code>" "${output_text}" "${2}")"
+ break
+ else
+ shift 2
+ fi
+ done
+fi
+
+if [ -n "${ib_parent_id}" ] && [ "${ib_parent_id}" != "null" ] && [ ${ib_parent_id} -gt 0 ]
+then
+ output_text="$(printf "%s\n<b>Parent ID:</b> <code>%s</code>" "${output_text}" "${ib_parent_id}")"
+fi
+
+if [ "${ib_has_children}" = "true" ]
+then
+ output_text="$(printf "%s\n<b>Has children:</b> yes" "${output_text}")"
+fi
+
+if [ -n "${ib_md5}" ] && [ "${ib_md5}" != "null" ]
+then
+ output_text="$(printf "%s\n<b>MD5:</b> <code>%s</code>" "${output_text}" "${ib_md5}")"
+fi
+
+if [ -n "${ib_source}" ] && [ "${ib_source}" != "null" ]
+then
+ if echo "${ib_source}" | grep -q "pximg"
+ then
+ ib_source="https://www.pixiv.net/artworks/$(printf "%s" "${ib_source##*/}" | cut -d '_' -f 1)"
+ fi
+
+ if [ ${#ib_source} -le 2048 ]
+ then
+ output_text="$(printf "%s\n<b>Source:</b> %s" "${output_text}" "${ib_source}")"
+ fi
+fi
+
+if [ -n "${ib_tags}" ] && [ "${ib_tags}" != "null" ]
+then
+ set -- ${ib_tags}
+ ib_tags_count=${#}
+fi
diff --git a/functions/ib_size b/functions/ib_size
new file mode 100644
index 0000000..34603af
--- /dev/null
+++ b/functions/ib_size
@@ -0,0 +1,21 @@
+#!/usr/bin/env dash
+#
+# Copyright (C) 2024 Maria Lisina
+# Copyright (C) 2024 Danil Lisin
+
+if [ -n "${ib_file_size}" ] && [ "${ib_file_size}" != "null" ]
+then
+ return 0
+fi
+
+if [ -z "${ib_file_url}" ] || [ "${ib_file_url}" = "null" ]
+then
+ return 0
+fi
+
+ib_file_size="$(curl --head \
+ --max-time 2 \
+ --proxy "${ib_proxy}" \
+ --silent \
+ --user-agent "Sekoohaka" \
+ "${ib_file_url}" | grep -i "content-length" | awk '{print $2}')"
diff --git a/functions/ib_token b/functions/ib_token
new file mode 100644
index 0000000..a95bb14
--- /dev/null
+++ b/functions/ib_token
@@ -0,0 +1,38 @@
+#!/usr/bin/env dash
+#
+# Copyright (C) 2024 Maria Lisina
+# Copyright (C) 2024 Danil Lisin
+
+until mkdir "${config}/${user_id}_auth.lock" > /dev/null 2>&1
+do
+ sleep 1
+done
+
+if [ -f "${ib_config}/legacy" ]
+then
+ . "${ib_config}/legacy"
+fi
+
+if [ -f "${ib_config}/time" ]
+then
+ current_date=$(date +%s)
+ previous_date=$(cat "${ib_config}/time")
+
+ if [ $((current_date - previous_date)) -ge ${ib_time} ]
+ then
+ if [ -n "${ib_lock}" ]
+ then
+ . "${functions}/ib_lock" &
+ output_text="Refreshing access token..."
+ else
+ . "${functions}/ib_auth"
+ fi
+ fi
+fi
+
+if [ -f "${ib_config}/token" ]
+then
+ ib_header="${ib_authorization} $(cat "${ib_config}/token")"
+fi
+
+rm -fr "${config}/${user_id}_auth.lock"