Skip to content

Instantly share code, notes, and snippets.

@NetOpWibby
Created February 21, 2025 17:40
Show Gist options
  • Save NetOpWibby/7e39068c1d0209e4412e3a05e800120c to your computer and use it in GitHub Desktop.
Save NetOpWibby/7e39068c1d0209e4412e3a05e800120c to your computer and use it in GitHub Desktop.
Johnny Decimal Downloads folder sorter
#!/bin/zsh
# Johnny Decimal Download Sorter
# Usage: ./jd-sort.sh [-d|--dry-run]
# Process command line arguments
DRY_RUN=0
while [[ "$#" -gt 0 ]]; do
case $1 in
-d|--dry-run) DRY_RUN=1 ;;
*) echo "Unknown parameter: $1"; exit 1 ;;
esac
shift
done
# Create base directories if they do not exist
JD_BASE="$HOME/Desktop/Index"
FOLDER_SYSTEM="00-09 System Management"
FOLDER_DEVELOPMENT="10-19 Development"
FOLDER_MEDIA="20-29 Media"
FOLDER_DOCUMENTS="30-39 Documents"
# System Management (00-09)
mkdir -p "$JD_BASE/$FOLDER_SYSTEM/Inbox"
mkdir -p "$JD_BASE/$FOLDER_SYSTEM/01 JD System Files"
mkdir -p "$JD_BASE/$FOLDER_SYSTEM/02 Templates"
mkdir -p "$JD_BASE/$FOLDER_SYSTEM/03 Scripts & Automation"
mkdir -p "$JD_BASE/$FOLDER_SYSTEM/04 Backups"
# Development (10-19)
mkdir -p "$JD_BASE/$FOLDER_DEVELOPMENT/Inbox"
mkdir -p "$JD_BASE/$FOLDER_DEVELOPMENT/11 Source Code"
mkdir -p "$JD_BASE/$FOLDER_DEVELOPMENT/12 Libraries & Dependencies"
mkdir -p "$JD_BASE/$FOLDER_DEVELOPMENT/13 Development Tools"
mkdir -p "$JD_BASE/$FOLDER_DEVELOPMENT/14 Documentation"
mkdir -p "$JD_BASE/$FOLDER_DEVELOPMENT/15 Project Resources"
# Media (20-29)
mkdir -p "$JD_BASE/$FOLDER_MEDIA/Inbox"
mkdir -p "$JD_BASE/$FOLDER_MEDIA/21 Images"
mkdir -p "$JD_BASE/$FOLDER_MEDIA/22 Videos"
mkdir -p "$JD_BASE/$FOLDER_MEDIA/23 Audio"
mkdir -p "$JD_BASE/$FOLDER_MEDIA/24 Design Assets"
mkdir -p "$JD_BASE/$FOLDER_MEDIA/25 Fonts"
# Documents (30-39)
mkdir -p "$JD_BASE/$FOLDER_DOCUMENTS/Inbox"
mkdir -p "$JD_BASE/$FOLDER_DOCUMENTS/31 Work Documents"
mkdir -p "$JD_BASE/$FOLDER_DOCUMENTS/32 Personal Documents"
mkdir -p "$JD_BASE/$FOLDER_DOCUMENTS/33 Technical Specs"
mkdir -p "$JD_BASE/$FOLDER_DOCUMENTS/34 Reference Materials"
# Project Files (40-49)
# mkdir -p "$JD_BASE/40-49/Inbox"
# mkdir -p "$JD_BASE/40-49/41 Project A"
# mkdir -p "$JD_BASE/40-49/42 Project B"
# mkdir -p "$JD_BASE/40-49/43 Project C"
# Function to determine file type and destination category (00-09, 10-19, etc.)
get_category() {
local file="$1"
local ext="${file:l:e}" # lowercase extension
case "$ext" in
# Development files
py|js|ts|jsx|tsx|java|cpp|h|c|go|rs|rb|zip|tar|gz|npm|jar|gem|json|yml|yaml|toml|xml|config)
echo $FOLDER_DEVELOPMENT;;
# Media files
jpg|jpeg|png|gif|svg|webp|psd|ai|mp4|mov|avi|mkv|webm|mp3|wav|m4a|aac|flac|ttf|otf|woff|woff2)
echo $FOLDER_MEDIA;;
# Documents
pdf|doc|docx|txt|md|rtf)
echo $FOLDER_DOCUMENTS;;
# Default category
*)
echo $FOLDER_DOCUMENTS;; # Documents as default
esac
}
# Watch Downloads folder and sort files
process_downloads() {
local source_dir="$HOME/Downloads"
# Process existing files
for file in "$source_dir"/*(.N); do
[[ -f "$file" ]] || continue
# Skip hidden files and partial downloads
[[ "$file" = .* ]] && continue
[[ "$file" = *.part ]] && continue
[[ "$file" = *.crdownload ]] && continue
local category=$(get_category "$file")
local dest="$JD_BASE/$category/Inbox"
# Move file (or simulate in dry run)
if [[ $DRY_RUN -eq 1 ]]; then
echo "[DRY RUN] ${file:t} → $category/Inbox/${file:t}"
else
mv "$file" "$dest/${file:t}"
echo "[MOVED] ${file:t} → $category/Inbox/${file:t}"
fi
done
echo "\n…sorting finished"
}
# Set up filesystem monitoring using fswatch if available
if command -v fswatch >/dev/null 2>&1; then
if [[ $DRY_RUN -eq 1 ]]; then
echo "Starting Johnny Decimal sorting monitor (DRY RUN mode)…"
else
echo "Starting Johnny Decimal sorting monitor…"
fi
fswatch -0 "$HOME/Downloads" | while read -d "" event; do
process_downloads
done
else
echo "fswatch not found. Please install it using: brew install fswatch"
echo "For now, running one-time sort…\n"
process_downloads
fi
@NetOpWibby
Copy link
Author

This script currently ignores folders in ~/Downloads so if you don't want files moved, put them in a folder.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment