img-chon.sh 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. #!/bin/bash
  2. IMG_BASE="$HOME"
  3. DATABASE="$HOME/Pictures/image_tags.sqlite"
  4. SQLITE="sqlite3"
  5. SQL="$SQLITE $DATABASE"
  6. SXIV="sxiv -t -"
  7. join_by () {
  8. local IFS="$1"
  9. shift
  10. echo "$*"
  11. }
  12. sp="/-\|"
  13. sc=0
  14. spin() {
  15. printf "\r%s [%s/%s] %s" "${sp:sc++:1}" "$1" "$2" "$3"
  16. if ((sc==${#sp})); then
  17. sc=0
  18. fi
  19. }
  20. endspin() {
  21. printf "\r\n"
  22. }
  23. get_hash() {
  24. [ -f "$1" ] || exit 1
  25. read -ra sha < <(sha256sum "$1")
  26. echo "${sha[0]}"
  27. }
  28. case $1 in
  29. "init")
  30. $SQL "CREATE TABLE image (
  31. path STRING NOT NULL UNIQUE ON CONFLICT REPLACE,
  32. hash STRING PRIMARY KEY NOT NULL UNIQUE ON CONFLICT ABORT
  33. );"
  34. $SQL "CREATE TABLE image_tag (
  35. hash STRING NOT NULL,
  36. tag STRING NOT NULL,
  37. UNIQUE (hash, tag) ON CONFLICT ABORT
  38. );"
  39. $SQL "CREATE TRIGGER image_exists
  40. BEFORE INSERT ON image_tag
  41. BEGIN
  42. SELECT CASE
  43. WHEN (SELECT COUNT(*) FROM image WHERE image.hash = NEW.hash) = 0 THEN
  44. RAISE(FAIL, 'image not in database')
  45. END;
  46. END;"
  47. ;;
  48. "add")
  49. total="${#@}"
  50. i=0
  51. for f in "${@:2}"; do
  52. spin "$i" "$total" "$f"
  53. i=$((i+1))
  54. hsh="$(get_hash "$f")"
  55. path="$(realpath --relative-to="$IMG_BASE" "$f")"
  56. $SQL "INSERT INTO image (path, hash) VALUES ('$path', '$hsh');"
  57. done
  58. endspin
  59. ;;
  60. "tag")
  61. tag=$2
  62. for f in "${@:3}"; do
  63. hsh="$(get_hash "$f")"
  64. $SQL "INSERT INTO image_tag (hash, tag) VALUES ('$hsh','$tag');"
  65. done
  66. ;;
  67. "untag")
  68. tag=$2
  69. for f in "${@:3}"; do
  70. hsh="$(get_hash "$f")"
  71. $SQL "DELETE FROM image_tag WHERE (hash, tag) = ('$hsh','$tag');"
  72. done
  73. ;;
  74. "query")
  75. tags=()
  76. anti_tags=()
  77. for t in "${@:2}"; do
  78. if [[ "$t" == -* ]]; then
  79. anti_tags+=( "'${t:1}'" )
  80. else
  81. tags+=( "'$t'" )
  82. fi
  83. done
  84. tags_str=$(join_by , "${tags[@]}")
  85. anti_tags_str=$(join_by , "${anti_tags[@]}")
  86. $SQL "SELECT path FROM image WHERE ${#tags[@]} = (SELECT COUNT(*) FROM image_tag WHERE image.hash = image_tag.hash AND image_tag.tag IN ($tags_str)) AND (0 = (SELECT COUNT(*) FROM image_tag WHERE image.hash = image_tag.hash AND image_tag.tag IN ($anti_tags_str)));" | awk "{ print \"$IMG_BASE/\" \$0 }"
  87. ;;
  88. "tags")
  89. if [ -f "$2" ]; then
  90. hsh="$(get_hash "$2")"
  91. $SQL "SELECT DISTINCT tag FROM image_tag WHERE hash = '$hsh' ORDER BY tag;"
  92. else
  93. $SQL "SELECT DISTINCT tag FROM image_tag ORDER BY tag;"
  94. fi
  95. ;;
  96. "query-dmenu")
  97. selected_tags=()
  98. while selection=$($0 tags | dmenu -p "Select tags, <esc> when done.") && [ -n "$selection" ]; do
  99. selected_tags+=("$selection")
  100. done
  101. $0 query "${selected_tags[@]}" | $SXIV
  102. ;;
  103. "tag-dmenu")
  104. while selection=$($0 tags | dmenu -p "Select tags, <esc> when done.") && [ -n "$selection" ]; do
  105. $0 tag "$selection" "${@:2}"
  106. done
  107. ;;
  108. "stats")
  109. echo "Number of images: $($SQL "SELECT COUNT(*) FROM image;")"
  110. echo "Number of distinct tags: $($SQL "SELECT COUNT(DISTINCT tag) FROM image_tag;")"
  111. ;;
  112. "")
  113. name="$(basename "$0")"
  114. echo -e "Usage:"
  115. echo -e " $name init Create a new database."
  116. echo -e " $name add IMAGE... Add new image(s) to the database."
  117. echo -e " $name tag TAG IMAGE... Tag image(s) with TAG."
  118. echo -e " $name untag TAG IMAGE... Remove tag from image(s)."
  119. echo -e " $name query TAG... List images with specified tags."
  120. echo -e " $name tags [IMAGE] Show all tags, or tags for IMAGE."
  121. echo -e " $name query-dmenu Interactively construct a query using dmenu and opens the result in sxiv."
  122. echo -e " $name tag-dmenu IMAGE... Interactively tag specified image(s) using dmenu."
  123. echo -e " $name stats Show database statistics."
  124. ;;
  125. esac