-
-
Save MineBartekSA/1d42d6973ddafb82793fd49b4fb06591 to your computer and use it in GitHub Desktop.
#!/bin/bash | |
# | |
# CatBox v2.0 | |
# An implementation of catbox.moe API in Bash | |
# Author: MineBartekSA | |
# Gist: https://gist.github.com/MineBartekSA/1d42d6973ddafb82793fd49b4fb06591 | |
# Change log: https://gist.github.com/MineBartekSA/1d42d6973ddafb82793fd49b4fb06591?permalink_comment_id=4596132#gistcomment-4596132 | |
# | |
# MIT License | |
# | |
# Copyright (c) 2023 Bartłomiej Skoczeń | |
# | |
# Permission is hereby granted, free of charge, to any person obtaining a copy | |
# of this software and associated documentation files (the "Software"), to deal | |
# in the Software without restriction, including without limitation the rights | |
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
# copies of the Software, and to permit persons to whom the Software is | |
# furnished to do so, subject to the following conditions: | |
# | |
# The above copyright notice and this permission notice shall be included in all | |
# copies or substantial portions of the Software. | |
# | |
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |
# SOFTWARE. | |
# | |
VERSION="2.0" | |
CATBOX_HOST="https://catbox.moe/user/api.php" | |
LITTER_HOST="https://litterbox.catbox.moe/resources/internals/api.php" | |
HASH_FILE="$HOME/.catbox" | |
CURL_ADD="" | |
RESET="\e[0m" | |
BOLD="\e[1m" | |
RED="\e[91m" | |
YELLOW="\e[93m" | |
## Utils | |
function no_color() { | |
unset RESET BOLD RED YELLOW | |
} | |
function version() { | |
echo -e $BOLD"CatBox"$RESET" v"$VERSION >&5 | |
echo "A catbox.moe API implementation in Bash" | |
} | |
function usage() { | |
[ -z $1 ] && version || echo $1 | |
echo | |
echo "Usage: catbox <command> [arguments] [options]" | |
echo | |
echo "Commands:" | |
echo " user [user hash] - Gets current or sets global user hash. Pass 'off' to remove global user hash" | |
echo " file <filename(s)> - Upload files to catbox.moe" | |
echo " temp <filename(s)> [expiary] - Upload files to litterbox.catbox.moe" | |
echo " url <url(s)> - Upload files from URLs to catbox.moe" | |
echo " delete <filenames(s)> - Delete files from catbox.moe" | |
echo " album - Album Managment" | |
echo | |
echo "Global options:" | |
echo " -s, --silent - Only output upload links (stderr will still show)" | |
echo " -S, --silent-all - Silent option but also silences stderr" | |
echo " -n, --no-color - Disable output coloring" | |
echo " -u, --user-hash[=] - Pass user hash" | |
echo " -V, --verbose - Show verbose output (in album)" | |
} | |
function has_hash() { | |
[ -z "$HASH" ] && [ -z "$USER_HASH" ] && echo false || echo true | |
} | |
## Command functions | |
function upload_files() { | |
declare -i fail=0 | |
for file in "${@:2}" | |
do | |
name=$(basename -- "$file") | |
echo -e $BOLD"$name"$RESET":" | |
if ! ( [ -f "$file" ] || [ -L "$file" ] || [ "$file" == "-" ] ) | |
then | |
echo -e $BOLD$RED"File '$file' doesn't exist!"$RESET >&2 | |
fail+=1 | |
continue | |
fi | |
link=$(curl --fail-with-body -F reqtype=fileupload $CURL_ADD -F "fileToUpload=@$file" $1) | |
if [ $? -ne 0 ] | |
then | |
echo -e $BOLD$RED"Failed to upload: "$RESET$RED$link$RESET >&2 | |
fail+=1 | |
continue | |
fi | |
echo -n $link | xclip -selection clipboard | |
echo -en "Uploaded to: "$BOLD | |
echo $link >&5 | |
echo -en $RESET | |
done | |
[ $fail -eq $[$#-1] ] && exit 2 | |
return 0 | |
} | |
function catbox_command() { | |
curl -s --fail-with-body -F reqtype=$1 $CURL_ADD "${@:2}" $CATBOX_HOST & | |
pid=$! | |
if [ ! $SILENT ] | |
then | |
echo -en "\e[sPlase wait... |" >&5 | |
declare -i stage=1 | |
while ps -p $pid > /dev/null | |
do | |
case $stage in | |
0 | 4) | |
echo -en "\e[1D|" >&5 | |
;; | |
1 | 5) | |
echo -en "\e[1D/" >&5 | |
;; | |
3 | 7) | |
echo -en "\e[1D\\" >&5 | |
;; | |
2 | 6) | |
echo -en "\e[1D-" >&5 | |
;; | |
esac | |
stage+=1 | |
[ $stage -eq 8 ] && stage=0 | |
sleep 0.1 | |
done | |
echo -ne "\e[u\e[KDone!" >&5 | |
fi | |
wait $pid | |
} | |
function generic_command() { | |
declare -i fail=0 | |
for item in "${@:5}" | |
do | |
echo -en $BOLD"$($3 "$item")"$RESET": " | |
res=$(catbox_command $1 -F "$2=$item") | |
if [ $? -eq 0 ] | |
then | |
$4 "$res" | |
else | |
[ $SILENT ] && echo -en $RED"$item: " >&2 || echo -en "\e[u" | |
echo -e $RED$res$RESET >&2 | |
fail+=1 | |
fi | |
done | |
[ $fail -eq $[$#-4] ] && exit 2 | |
return 0 | |
} | |
function url_success() { | |
echo -en "\e[u" | |
echo $* >&5 | |
echo -n $* | xclip -selection clipboard | |
} | |
function upload_urls() { | |
generic_command urlupload url "basename -- " url_success $@ | |
} | |
function delete_success() { | |
echo -e "\e[uSuccesfully deleted" | |
} | |
function delete_files() { | |
echo "Deleting..." | |
generic_command deletefiles files echo delete_success $@ | |
} | |
function album_usage() { | |
echo "Usage: catbox album <command> [arguments]" | |
echo | |
echo -e $BOLD$YELLOW"Note: Every album command requires user hash" | |
echo -e " For title or description, double quote every text longer than one word"$RESET | |
echo | |
echo "Commands:" | |
echo " create <title> <description> <file(s)> - Create album" | |
echo " edit <short> <title> <description> [file(s)] - Modify album" | |
echo " add <short> <file(s)> - Add files to an album" | |
echo " remove <short> <file(s)> - Remove files from an album" | |
echo " delete <short> - Delete album" | |
} | |
function album_create() { | |
files="${@:3}" | |
echo "Creating album..." | |
if [ $VERBOSE ] | |
then | |
echo "Title : $1" >&5 | |
echo "Description: $2" >&5 | |
echo "Files : $files" >&5 | |
fi | |
album=$(catbox_command createalbum -F "title=$1" -F "desc=$2" -F "files=$files") | |
if [ $? -ne 0 ] | |
then | |
exec >&2 | |
echo -e $RED$BOLD"Failed to create a new album!"$RESET | |
echo -e $RED$album$RESET | |
exit 2 | |
fi | |
echo -n $album | xclip -selection clipboard | |
echo -e "\nAlbum created successfully" | |
if [ $VERBOSE ] | |
then | |
echo "Album short: ${album:21}" >&5 | |
echo "Album url : $album" >&5 | |
else | |
echo "${album:21} | $album" >&5 | |
fi | |
} | |
function album_edit() { | |
files="${@:4}" | |
echo "Modifing album..." | |
if [ $VERBOSE ] | |
then | |
echo "Album Short: $1" >&5 | |
echo "Title : $2" >&5 | |
echo "Description: $3" >&5 | |
echo "Files : $files" >&5 | |
fi | |
res=$(catbox_command editalbum -F "short=$1" -F "title=$2" -F "desc=$3" -F "files=$files") | |
if [ $? -ne 0 ] | |
then | |
exec >&2 | |
echo -e $RED$BOLD"Failed to modify album!"$RESET | |
echo -e $RED$res$RESET | |
exit 2 | |
fi | |
echo -e "\nAlbum modified successfully" | |
} | |
function album_add() { | |
files="${@:2}" | |
echo "Adding files to the album..." | |
if [ $VERBOSE ] | |
then | |
echo "Album short: $1" | |
echo "Files : $files" | |
fi | |
res=$(catbox_command addtoalbum -F "short=$1" -F "files=$files") | |
if [ $? -ne 0 ] | |
then | |
exec >&2 | |
echo -e $RED$BOLD"Failed to add files to the album!"$RESET | |
echo -e $RED$res$RESET | |
exit 2 | |
fi | |
echo -e "\nSuccessfully added files to the album" | |
} | |
function album_remove() { | |
files="${@:2}" | |
echo "Removing files from the album..." | |
if [ $VERBOSE ] | |
then | |
echo "Album short: $1" | |
echo "Files : $files" | |
fi | |
res=$(catbox_command removefromalbum -F "short=$1" -F "files=$files") | |
if [ $? -ne 0 ] | |
then | |
exec >&2 | |
echo -e $RED$BOLD"Failed to remove files from the album!"$RESET | |
echo -e $RED$res$RESET | |
exit 2 | |
fi | |
echo -e "\nSuccessfully removed files from the album" | |
} | |
function album_delete() { | |
echo "Deleting albums..." | |
generic_command deletealbum short echo delete_success $@ | |
} | |
## Start | |
# Check if curl exists | |
curl --version >> /dev/null | |
if [ $? -ne 0 ] | |
then | |
echo -e $RED"cURL not found!"$RESET >&2 | |
echo "Please check if you have cURL installed on your system" >&2 | |
exit 3 | |
fi | |
# Setup a file descriptor for bypassing silent option | |
exec 5<&1 | |
# Handle global options | |
declare -i count=1 | |
while [ $count -le $# ] | |
do | |
case ${!count} in | |
-S | --silent-all) | |
exec 2>/dev/null | |
set -- "${@:1:$count-1}" -s -s "${@:$count+1}" | |
;; | |
-s | --silent) | |
exec >/dev/null | |
SILENT=1 | |
;; | |
-h | --help | --usage) | |
exec 5>/dev/null | |
usage | |
exit 0 | |
;; | |
-v | --version) | |
version | |
exit 0 | |
;; | |
-n | --no-color) | |
no_color | |
;; | |
-u | --user-hash | --user-hash=*) | |
if [[ ${!count} == --user-hash=* ]] | |
then | |
HASH=${!count:12} | |
else | |
get=$[$count+1] | |
HASH=${!get} | |
set -- "${@:1:$count-1}" "${@:$count+1}" | |
fi | |
[ ! -z "$HASH" ] && CURL_ADD="-F userhash=$HASH " | |
;; | |
-V | --verbose) | |
VERBOSE=1 | |
;; | |
*) | |
count+=1 | |
continue | |
esac | |
set -- "${@:1:$count-1}" "${@:$count+1}" | |
done | |
unset count no_color | |
# Read user hash if it was not given through global options | |
if [ -z ${HASH+x} ] && [ -f $HASH_FILE ] | |
then | |
while read line | |
do | |
if [[ $line != \#* ]] && [ "$line" != "" ] | |
then | |
USER_HASH=$line | |
CURL_ADD="-F userhash=$USER_HASH " | |
break | |
fi | |
done < $HASH_FILE | |
unset line | |
fi | |
# Handle commands | |
case $1 in | |
version) | |
version | |
;; | |
help | usage) | |
exec 5>&1 | |
usage | |
;; | |
user) | |
if [ -z $2 ] | |
then | |
if [ "$(has_hash)" == "true" ] | |
then | |
if ! [ -z "$HASH" ] | |
then | |
echo "User hash given!" | |
echo -n "User hash: " | |
echo $HASH >&5 | |
else | |
echo "User hash present!" | |
echo -n "User hash: " | |
echo $USER_HASH >&5 | |
fi | |
echo "CatBox will act as you" | |
else | |
echo "No user hash" | |
echo "CatBox will act annonymously" | |
fi | |
elif [ "$2" == "off" ] | |
then | |
rm $HASH_FILE | |
echo "CatBox will now upload annonymously" | |
else | |
echo -e "# CatBox v2 User Hash\n$2" > $HASH_FILE | |
echo "User hash set!" | |
echo "CatBox will now upload files to your account" | |
fi | |
;; | |
file) | |
if [ $# -eq 1 ] | |
then | |
exec >&2 | |
echo "Usage: catbox file <filename> [<filename>...] - Upload files to catbox.moe" | |
echo "Anonymously uploaded files cannot be deleted" | |
exit 1 | |
fi | |
[ "$(has_hash)" == "false" ] && echo "Uploading annonymously..." || echo "Uploading..." | |
upload_files $CATBOX_HOST "${@:2}" | |
;; | |
temp) | |
if [ $# -lt 2 ] | |
then | |
exec >&2 | |
echo "Usage: catbox temp <filename> [<filename>...] [1h/12h/24h/72h] - Upload files to litterbox.catbox.moe" | |
echo "Only the given expiry times are supported" | |
echo "By default, temporary files will expire after an hour" | |
exit 1; | |
fi | |
[[ ${@: -1:1} == @(1|12|24|72)h ]] && time=${@: -1:1} && end=-1 || time=1h || end=0 | |
CURL_ADD="-F time=$time" | |
echo "Uploading temporarily..." | |
upload_files $LITTER_HOST "${@:2:$#-1$end}" | |
;; | |
url) | |
if [ $# -eq 1 ] | |
then | |
exec >&2 | |
echo "Usage: catbox url <url> [<url>...] - Upload files from urls to catbox.moe" | |
echo "Anonymously uploaded files cannot be deleted" | |
exit 1 | |
fi | |
[ "$(has_hash)" == "false" ] && echo "Uploading annonymously..." || echo "Uploading..." | |
upload_urls "${@:2}" | |
;; | |
delete) | |
if [ $# -eq 1 ] | |
then | |
exec >&2 | |
echo "Usage: catbox delete <filename> [<filename>...] - Delete files from your catbox.moe account" | |
echo "This command required a catbox.moe account" | |
echo "Please add your user hash by using the catbox user command" | |
echo "Filenames must be the names of files already hosted on catbox.moe" | |
echo "Anonymously uploaded files cannot be deleted" | |
exit 1 | |
elif [ "$(has_hash)" == "false" ] | |
then | |
exec >&2 | |
echo -e $BOLD$RED"No user hash!"$RESET | |
echo -e $RED"Please add your user hash" | |
echo -e "Use the catbox user command to do so"$RESET | |
exit 1 | |
fi | |
delete_files ${@:2} | |
;; | |
album) | |
if [ $# -gt 1 ] && [ "$(has_hash)" == "false" ] | |
then | |
exec >&2 | |
echo -e $BOLD$RED"No user hash!"$RESET | |
echo -e $RED"Please add your user hash" | |
echo -e "Use the catbox user command to do so"$RESET | |
exit 1 | |
fi | |
case $2 in | |
create) | |
if [ $# -lt 5 ] | |
then | |
exec >&2 | |
echo "Usage: catbox album create <title> <description> <filename> [<filename> ...] - Create an album with given title, description, and files" | |
echo -e $YELLOW"For title or description, double quote every text longer than one word"$RESET | |
echo "Filenames must be the names of files already hosted on catbox.moe" | |
exit 1 | |
fi | |
album_create "$3" "$4" ${@:5} | |
;; | |
edit) | |
if [ $# -lt 5 ] | |
then | |
exec >&2 | |
echo "Usage: catbox album edit <short> <title> <description> [<filename> ...] - Modify the entirety of the album" | |
echo -e $YELLOW"For title or description, double quote every text longer than one word" | |
echo -e "Filenames are not necessary, but given none, the album will become empty"$RESET | |
echo "Filenames must be the names of files already hosted on catbox.moe" | |
exit 1 | |
fi | |
album_edit $3 "$4" "$5" ${@:6} | |
;; | |
add) | |
if [ $# -lt 4 ] | |
then | |
exec >&2 | |
echo "Usage: catbox album add <short> <filename> [<filename> ...] - Add files to the album" | |
echo "Filenames must be the names of files already hosted on catbox.moe" | |
exit 1 | |
fi | |
album_add $3 ${@:4} | |
;; | |
remove) | |
if [ $# -lt 4 ] | |
then | |
exec >&2 | |
echo "Usage: catbox album remove <short> <filename> [<filename> ...] - Remove files from the album" | |
echo "Filenames must be the names of files already hosted on catbox.moe" | |
exit 1 | |
fi | |
album_remove $3 ${@:4} | |
;; | |
delete) | |
if [ $# -lt 3 ] | |
then | |
echo "Usage: catbox album delete <short> [<short> ...] - Delete album(s)" >&2 | |
exit 1 | |
fi | |
album_delete ${@:3} | |
;; | |
*) | |
exec >&2 | |
album_usage | |
exit 1 | |
esac | |
;; | |
*) | |
exec >&2 | |
exec 5>&2 | |
usage | |
exit 1 | |
esac |
Hello Catbox users!
I've come to you bearing good news!
Catbox v2.0 is now out!
Catbox v2.0
This version comes with many changes and additions, mainly because catbox was rewritten from scratch.
After the recent temp
command addition, I thought that catbox code was ancient, clunky, and just dog shit.
After 4 and a half years it was time for some changes, so I sat down and rewrote catbox.
My two main goals for this rewrite were:
- Remove as much duplication as possible
- Make the code more maintainable
I'd say that I managed to achieve my main goals pretty well.
As for my other goals, I wanted to make the script more script friendly, more uniform, and generally better.
A quick list of these changes (from biggest to smallest):
- Added global options (-s, -S, -n, -u, -V)
- Added support for
-
(stdin) while uploading files (you no longer need to pass/dev/stdin
) - Better error handling and reporting (all errors are now sent to
stderr
) - Made output more uniform
- Reworded, fixed, and added more output text
This would be the end of the quick update, you should be able to grasp everything that has changed from the script itself.
But if you want to read more about these changes, feel free to keep reading my ramblings.
Global options
With v2 I've added 5 global options. (not counting -h/--help/--usage
or -v/--version
)
Global options can be passed in any part of the command.
You can put them in the beginning, end, or even in the middle of the command.
For example, catbox file file1 -s file2
will only upload files file1
and file2
, while being in silent mode showing only links.
These options are more or less self-explanatory, but I'd like to go into a bit more detail about them here:
-
--silent
- Silent modeThe coveted mode!
Most forks change catbox to be more silent, so I heard you and added a global option to suppress most output tostdout
.
Only important output will be sent tostdout
, so only links, version, and verbose output will show up.
Also, please note that this mode does not suppress anystderr
output, so when using thefile
command, cURL's transfer info will still show up. -
--silent-all
- Silent all modePretty much the same as
--silent
with the exception that it will also suppressstderr
output.
This output mode should be the best for scripts and CI usage. -
--no-color
- Disable colouringThis one is pretty much self-explanatory.
Any output will no longer be coloured.
Useful when using a terminal or CI output logs with no colour support. -
--user-hash=
- Pass user hashYou can now pass the user hash in the command itself with no need to set it globally.
If you have a user hash set globally, this option will disable reading that file.
When using-u
or--user-hash
, the next argument will be interpreted as the user hash.
You can also pass it as a single argument using--user-hash=<your user hash>
.
It is also possible to use this option to be anonymous despite the global user hash file by passing-u ""
or--user-hash=
.
Also pretty useful in scripts and CI. -
--verbose
- Verbose outputThis is the least useful option.
When using most of thealbum
commands, more output will be shown.
That's it.
Errors
In this section, I'd like to talk about two major changes:
- Errors now are properly sent to
stderr
- The script now consistently outputs three exit codes (not counting
0
)
First, let's go over the exit codes:
-
exit code
1
Catbox will emit the exit code of
1
if the command lacks arguments.
For example, just runningcatbox
will show you the help message, but also will emit1
since the command was not fully written.
On the other hand, runningcatbox help
will show you the same message but will emit0
sincehelp
is a valid catbox command.
Any usage message will emit an exit code of1
.
This will might help you in debugging when using catbox in a script or CI. -
exit code
2
Catbox will emit the exit code of
2
when the command fully failed.
For example, when runningcatbox file nonexistant
, catbox will emit2
, since no file was properly uploaded.
On the other hand, when runningcatbox file nonexistent existing-file
, catbox will emit0
since it did not fully fail. -
exit code
3
Catbox will only emit the exit code of
3
when the only dependency is missing.
This is useful in an event when you are using catbox in a script or CI.
You might not be the owner of these machines, so this exit code will tell you that you are missing cURL.
Now, let's talk about the second thing.
I've taken my time to make sure that any error message, produced by me, cURL, or the API, will be properly sent to stderr
.
Any red text you might see on your terminal when using catbox was sent to stderr
.
Another thing to note is, all usage messages that are sent out alongside the 1
exit code, are sent out to stderr
Uniform output?
Maybe calling catbox output uniform is a bit of a stretch, but I'd say it's more uniform than it was.
There are three output formats depending on how many and the type of requests the script is making to catbox.moe.
-
Uploading format
This output format is used by the
file
andtemp
commands.
It's pretty much identical to how it looked in previous versions.
I opted to not make any changes since the default cURL transfer status perfectly shows what you might want to see.
I did make some small changes to it, like removing the empty line, adding API error reporting, and small text changes. -
Multiple request format
This output format is used by the
url
,delete
, andalbum delete
commands.
This format now shows you aPlease wait...
message with a spinner to indicate that the script is waiting for a response.
API errors are not properly colour-coded and are sent to stderr. -
Single request format
This output format is used by most album commands.
It differs the most from the previous versions.
Without the--verbose
options, I opted to have the least amount of information presented.
The only outlier is the user
command since it does not conform to any of the formats above.
It does not make any requests to catbox.moe, so it has its own simple output format.
This version of the user
command better presents you your user hash and foregoes repeating it when setting it.
You can also see if you are using a user hash passed with the --user-hash
option or not.
Technical changes
In this section, I'd like to point out a few technical things and the new script structure.
Catbox v2.0 has a completely altered internal structure.
You can segment it into the following segments:
- Constants
- Util and command functions
- Start and global option handler
- Read user hash file
- Command handler
If someone wonders how catbox handles global options, here is a quick explanation.
Catbox goes through all arguments and tries to match them to one of the options.
When an argument matches, a proper action is executed and then the argument is deleted.
The command handler, or the big case statement at the end of the script, handles the interpretation of catbox commands.
For every command, it should only contain the usage message, simple data processing, and a call to a matching function.
Simple commands, like user
, can be fully implemented in the command handler, but more complex commands must use a function.
Command handler should also check for prerequisites, like user hash, and inform the user about them.
These constraints should always be followed to maintain ease of maintenance and better readability.
If you read through all of this, you have my utmost thanks!
For anyone else, thank you for looking at my little script and I hope it will be useful to you!
thank you @MineBartekSA for all the work you're putting into this project - I'll update the version on the AUR soon!
really great for linux users since we dont have sharex nor macos users have it
Added support for litterbox.catbox.moe (Temp files)