1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
#!/bin/bash
#
# sort.sh
# Cycle through all image files in a directory and prompt for a
# directory in which to move them. Useful for organizing downloaded pics
# after a 4chan or ffffound hunt.
#
# Copyright (c) 2011
# Alexandre de Verteuil 2011-07-31
#
# This program is free software. It comes without any warranty, to
# the extent permitted by applicable law. You can redistribute it
# and/or modify it under the terms of the Do What The Fuck You Want
# To Public License, Version 2, as published by Sam Hocevar. See
# http://sam.zoy.org/wtfpl/COPYING for more details.
#
# Optional dependency: rlwrap for tags autocompletion.
# Bugs: Does not work well with directory names containing spaces.
# Usage: sort.sh [files]
# Filename structure: ffffff_tag1[_tagn ...].ext
#     where ffffff are the first 6 characters of the md5sum, useful for
#     autocompleting a filename with just a few characters.

VIEWER="feh --scale-down"
GIFVIEWER="gifview --animate"
TAGSFILE="/home/alex/mm/p/collection/.tags"
RLWRAP=$(which rlwrap 2>/dev/null)
DEBUG=

[ -f "$TAGSFILE" ] || touch "$TAGSFILE"

f_view () {
# Spawn the appropriate viewer.
# Return 1 if not a supported file extension.
if [ ! -f "$candidate" ]; then
    echo Skipping "${candidate}, file doesn't exist..."
    return 1
fi
ext=${candidate##*.}  # Get extension.
ext=${ext,,}  # Lowercase.
debug file extension "$ext"
case $ext in
    jpg|jpeg|png) $VIEWER "$candidate" & ;;
    gif) $GIFVIEWER "$candidate";;
    *) echo Skipping "${candidate}, ${ext} not supported..."
       echo
       return 1
       ;;
esac
}

debug () {
if [ "$DEBUG" ]; then
    echo "##DEBUG: "$* >&2
fi
}

debug is ON

if [ $# -gt 0 ]; then
batch="$*"
else
batch=$(find . -maxdepth 1 -type f -iregex ".*\(jpg\|jpeg\|png\|gif\)")
fi
debug $batch

for candidate in $batch; do
echo =====================================================
echo "    Processing $candidate"
echo '  -------------------------------------------------'
while :; do
    # Show an image
    f_view "$candidate" || break
    # Print available directories and prompt for a target.
    # Rebuild list of dirs because dirs may be created in the process.
    if [ "$RLWRAP" ]; then
    echo "key in target directory, or again|quit, empty string for ./"
    # This does NOT work if a directory name contains whitespace.
    target=$(rlwrap --one-shot \
            --substitute-prompt="dir: " \
            --prompt-colour="Blue" \
            --file <(find . -mindepth 1 -type d | cut -b 3-) \
            cat)
    target=${target// /}
    case "$target" in
        ""|"0") targetdir=".";;
        a|again) continue;;
        q|quit) exit;;
        *) if ! [ -d "$target" ]; then
           mkdir -pv "$target" || exit 1
           fi
           targetdir="$target"
    esac
    else
    unset -v dirs
    dirs[0]="."
    i=1
    while read dir; do
        echo $i: $dir
        dirs[$((i++))]="$dir"
    done < <(find . -mindepth 1 -type d -printf '%p\n' | sort) | column
    echo -n "key in target directory, or New|Again|Quit, "
    echo "empty string for ./"
    read -ep "Move to: " target
    case "$target" in
        ""|"0") targetdir=".";;
        n*|N*) read -p "New directory name: " dirname
         mkdir -pv "$dirname" || exit 1
         targetdir="$dirname"
         ;;
        a*|A*) continue;;
        q*|Q*|exit) exit;;
        *) if [ -d "${dirs[$target]}" ]; then
           targetdir="${dirs[$target]}"
           fi
           ;;
    esac
    fi
    echo "Destination directory: ${targetdir}/"
    echo

    # Parse tags from filename
    if [[ "$candidate" =~ (^|^\./)[[:xdigit:]]{5,6}((_[[:alnum:]$&%\!.-]{1,}){1,})\..{3,4}$ ]]; then
    debug BASH_REMATCH is ${BASH_REMATCH[*]}
    buffer=$(tr "_" " " <<< "${BASH_REMATCH[2]:1}")
    for tag in $buffer; do
        if ! grep "^${tag}$" "$TAGSFILE" &>/dev/null; then
        buffer=$(sed "s/${tag}/\!&/" <<< "${buffer}")
        fi
    done
    else
    buffer=
    fi
    # Read tags from user
    echo -n "Key in tags, space separated, !tags are not added to "
    echo "dictionary, empty string aborts."
    if [ "$RLWRAP" ]; then
    # http://stackoverflow.com/questions/4726695/
    # bash-and-readline-tab-completion-in-a-user-input-loop
    # This explains how read -e only supports default
    # completion.  I use rlwrap, an external program, as a
    # wrapper for readline with my custom word list.
    tags=$(rlwrap --prompt-colour=Yellow \
              --substitute-prompt="tags: " \
              --pre-given="$buffer" \
              --file="$TAGSFILE" \
              --one-shot \
              cat)
    debug rlwrap returnded $?
    else
    cat $TAGSFILE | column
    read -ep ": " -i "$buffer" tags
    fi
    if [ ! "$tags" ]; then
    echo Cancelled.
    break
    fi
    debug tags are: \"$tags\"

    # Add new tags to $TAGSFILE
    for tag in $tags; do
    [[ ${tag:0:1} = "!" ]] || echo $tag
    done | cat - $TAGSFILE | sort | uniq > $TAGSFILE.tmp
    mv $TAGSFILE{.tmp,}
    debug TAGSFILE updated.

    # Filename structure :
    tags=$(sed "s/\!\(\w\{1,\}\)/\1/g" <<< "$tags")  # remove '!' prefixes
    tags=$(sed "s/ $//" <<< "$tags")
    tags=$(tr " " "_" <<< "$tags")
    hash=$(md5sum ${candidate})
    hash=${hash:0:6}
    ext=${candidate##*.}  # Get extension.
    ext=${ext,,}  # Lowercase.
    newname="${targetdir}/${hash}_${tags}.${ext}"
    debug newname is: \"$newname\"

    if [ "$candidate" == "$newname" -o "./$candidate" == "$newname" ]; then
    echo No change... Moving on.
    else
    mv -v "$candidate" "$newname" || exit 1
    fi
    echo; echo
    break
done
sleep 0.5s
done

Comments

Comment Atom Feed

There are no comments yet.

Add a Comment

You can use the Markdown syntax to format your comment.