#!/usr/bin/env bash VERSION=1.2.2 # Retrieve script directory (not following link) SCRIPT="${BASH_SOURCE[0]}" SCRIPT_DIR="$( cd "$( dirname "${SCRIPT}" )" && pwd )" INVOCATION_DIR=`pwd` # Retrieve script name (follow link) PROG=`basename "$0"` CONFIGFILE=".${PROG}.conf" JOPLIN_DIR= CLIPPER_TOKEN= CLIPPER_PORT= TMPFILE=`mktemp "${TMPDIR:-/tmp/}$PROG.XXXXXXXX"` # on macOS, the default getopt is a useless piece of shit # install getopt via MacPorts or brew and put it in the PATH before /usr/bin if [ "`getopt -V |cut -d\" \" -f1`" != "getopt" ]; then echo "Error: getopt not compatible enough." exit 1 fi trap cleanup 0 1 2 3 6 15 function cleanup { if [ -a "$TMPFILE" ]; then unlink "$TMPFILE" fi } function eexit { cleanup trap - 0 1 2 3 6 15 exit $1 } function usage { echo "usage: ${PROG} [-c CONFIGFILE] [-f] [-q|--quiet] [-n|--dry-run] [-d|--debug] [-V|--version] [-h] [--help]" } function long_usage { echo "${PROG} - remove orphaned resources in Joplin" echo "" usage echo "" echo " -c CONFIGFILE " echo " use CONFIGFILE, instead of searching the default locations: " echo " $SCRIPT_DIR/$CONFIGFILE " echo " $HOME/$CONFIGFILE " echo " ${XDG_CONFIG_HOME:-$HOME/.config}/$CONFIGFILE " echo " The first file found is used. " echo "" echo " -f " echo " run without confirmation " echo "" echo " -q, --quiet " echo " do not print informational messages " echo " (errors will be shown) " echo "" echo " -n, --dry-run " echo " only show orphaned resources (do not actually delete them) " echo " implies -f " echo "" echo " -d, --debug " echo " print debug information " echo "" echo " --zero-history " echo " DO NOT USE THIS - it is very dangerous - DATA LOSS!!! " echo " override history timeframe and set to 0 " echo "" echo " --ignore-revisions " echo " DO NOT USE THIS - it is very dangerous - DATA LOSS!!! " echo " delete resources, even if they are used in revisions " echo "" echo " -V, --version " echo " version information " echo "" echo " -h " echo " usage information " echo "" echo " --help " echo " this help " echo "" } cflag=0 fflag=0 qflag=0 nflag=0 dflag=0 Vflag=0 hflag=0 hlflag=0 zhflag=0 irflag=0 options=$(getopt -n $PROG -q -o c:fnqdVh -l help,version,debug,dry-run,quiet,zero-history,ignore-revisions -- "$@") if [ $? != 0 ] then echo "${PROG}: Error: unrecognized option $1" usage exit 1 fi eval set -- "$options" while [ $# -gt 0 ] do case "$1" in -c) cflag=1 carg=$2 shift;; -f) fflag=1;; -q|--quiet) qflag=1;; -n|--dry-run) nflag=1;; -V|--version) Vflag=1;; -d|--debug) dflag=1;; -h) hflag=1;; --help) hlflag=1;; --zero-history) zhflag=1;; --ignore-revisions) irflag=1;; --) shift; break;; *) exit; break;; esac shift done if [ "$hflag" == "1" ] then usage exit fi if [ "$hlflag" == "1" ] then long_usage exit fi if [ "$nflag" == "1" ] then fflag=1 fi if [ "$Vflag" == "1" ] then echo "$PROG $VERSION" exit fi function debug { if [ "$dflag" == "1" ]; then echo "[debug] $@" fi } function info { if [ "$qflag" != "1" ]; then echo "$@" fi } function info_n { if [ "$qflag" != "1" ]; then echo -n "$@" fi } function noConfigFound { FN=' ' if [ ! -z "$1" ]; then FN=" '$1' " fi echo "Error: No config file${FN}found." exit 1 } # precedence of config files: # command line options # config file specified on the command line # environment vars # local config file - same dir as script (if exists; not following link for dir) # local config file - $HOME dir (if exists) # global config file (if exists) if [ "$cflag" == "1" ]; then if [ -e "$carg" ]; then . "$carg" debug "Using config file: $carg" else noConfigFound "$carg" fi elif [ -e "$SCRIPT_DIR/$CONFIGFILE" ]; then . "$SCRIPT_DIR/$CONFIGFILE" debug "Using config file: $SCRIPT_DIR/$CONFIGFILE" elif [ -e "$HOME/$CONFIGFILE" ]; then . "$HOME/$CONFIGFILE" debug "Using config file: $HOME/$CONFIGFILE" elif [ -e "${XDG_CONFIG_HOME:-$HOME/.config}/$CONFIGFILE" ]; then . "${XDG_CONFIG_HOME:-$HOME/.config}/$CONFIGFILE" debug "Using config file: ${XDG_CONFIG_HOME:-$HOME/.config}/$CONFIGFILE" else noConfigFound fi DB=${JOPLIN_DIR}/database.sqlite if [ ! -e "$DB" ]; then echo "Error: Joplin database not found." exit 1 fi debug "Joplin database: $DB" if [ -z "$CLIPPER_TOKEN" ]; then echo "Error: Web Clipper token not set." exit 1 fi if [ -z "$CLIPPER_PORT" ]; then echo "Error: Web Clipper port not set." exit 1 fi debug "Web Clipper port: $CLIPPER_PORT" # retrieve the IDs of orphaned resources from the database KEEP=`sqlite3 $DB "select value from settings where key = 'revisionService.ttlDays'"` if [ -z "$KEEP" ]; then KEEP=90 fi if [ "$zhflag" == "1" ]; then KEEP=0 fi sqlite3 $DB "select resource_id from note_resources where is_associated = 0 and resource_id not in (select resource_id from note_resources where is_associated = 1) group by resource_id having max(last_seen_time) < strftime('%s','now','-${KEEP} days')*1000" >$TMPFILE if [ "$irflag" == "1" ]; then sqlite3 $DB "select resource_id from note_resources where is_associated = 0" >$TMPFILE fi if [ ! -s "$TMPFILE" ]; then info "No orphaned resources found." exit fi ERR=0 if [[ "$irflag" == "1" || "$zhflag" == "1" ]]; then if [ "$nflag" == "0" ]; then echo "DANGER: You are using a very dangerous option." echo "DANGER: Data loss is not only possible but rather almost certain." echo "" echo -n "Are you absolutely sure you know what you are doing? (yes/no): " read answer if [ "$answer"x != "yes"x ]; then exit 1 fi echo "" unset answer fi fi if [ "$fflag" != "1" ]; then echo -n "Delete orphaned resources? (yes/no): " read answer if [ "$answer"x != "yes"x ]; then exit 1 fi fi for id in `sed 's/\s\+$//' $TMPFILE` do curlCMD="curl -s -X DELETE http://localhost:${CLIPPER_PORT}/resources/${id}?token=${CLIPPER_TOKEN}" debug "$curlCMD" infotext="Deleting resource id: $id" info_n "$infotext" if [ "$nflag" == "0" ]; then # Delete ID rc="" rc=`$curlCMD` if [ ! -z "$rc" ]; then # error occured while deleting resource ERR=1 if [ "$qflag" == "1" ]; then # if --quiet, infotext has to be output, otherwise we don't know where the error occured echo -n "$infotext - $rc" else echo -n " - $rc" fi else info_n " - Success" fi fi # A line break is required here # Don't print empty lines, if --quiet and no error if [[ "$qflag" == "1" && -z "$rc" ]]; then : else echo "" fi done if [ "$ERR" != "0" ]; then exit 1 fi