IMPORTANT: When working with this repository:
- ❌ DO NOT create reports automatically (only on request)
- ❌ DO NOT run tests automatically (only on request)
- ❌ DO NOT change
versionorversionCodeunless the user explicitly asks for a version bump - ✅ Execute the task and briefly report the result
- ✅ Show diff of changes when necessary
- ✅ After code changes or new functionality, build a fresh Magisk/KernelSU ZIP using the current version/build number unless a version bump was explicitly requested
Sortify is a Magisk and KernelSU module for Android that automatically sorts downloaded files into categorized folders. The module runs in the background and periodically scans the download folder, moving files to appropriate categories based on their extensions.
Original Author: xCaptaiN09 (Sortify v4.0)
Fork: MeteorBurn (v4.3.2)
License: MIT
Current Version: 4.3.2 (versionCode: 28)
- ✅ Automatic file sorting by type (documents, images, videos, audio, archives, apps)
- ✅ ZIP-based Magisk module detection (
module.propinside archive) - ✅ Recursive subfolder scanning with configurable depth
- ✅ Automatic target folder exclusion to prevent sorting loops
- ✅ Configurable folder exclusions via JSON configuration
- ✅ Duplicate file handling via
Duplicates/ - ✅ Hidden and incomplete download protection
- ✅ Native WebUI - Full-featured WebUI for KsuWebUI/WebUI X
- ✅ Enable/Disable Toggle - Control module operation without rebooting
- ✅ Manual Sort Button - Run sorting immediately from WebUI without waiting for the timer
- ✅ Internal Storage Folder Picker - Pick Base Path and Download Path from user-accessible shared storage only
- ✅ Live Log Viewer - Read, refresh, and clear the last 200 log lines
- ✅ Configurable File Categories - Enable/disable sorting per category directly from WebUI
- ✅ Cyber Blue Coral WebUI Theme - Dark blue UI with blue/coral action accents
- ✅ Volume Key Setup - Enable/disable module during installation
- ✅ Versioned Installer Output - Installation log reads version/versionCode from
module.prop - ✅ Enhanced Config Loading - Reliable multiline JSON reading via
tr '\n' ' ' - ✅ Proven Volume Key Detection - Tested implementation adapted from Bootloop Protector
Sortify/
├── module.prop # Magisk module metadata (version, description, author)
├── config.json # Module configuration (paths, intervals, settings, enabled)
├── common.sh # Shared POSIX helpers for config, logging, and category folders
├── service.sh # Main service (runs on Android boot)
├── action.sh # File sorting logic (called by service.sh)
├── customize.sh # Installation script with volume key detection
├── uninstall.sh # Module uninstallation script
├── scripts/
│ └── build-module.ps1 # Reproducible ZIP builder with LF normalization
├── tests/
│ └── sortify-behavior.sh # Local shell smoke test for sorting behavior
├── webroot/ # 🆕 WebUI interface
│ └── index.html # Single-page web interface for configuration
├── banner.png # Module banner image
├── LICENSE # MIT license
├── README.md # Module documentation
├── AGENTS.md # Developer guide
└── .git/ # Git repository
- Defines module ID, name, version, and description
- Used by Magisk/KernelSU for module identification and display
- Key fields:
id=sortify- unique identifierversion=4.3.2- displayed versionversionCode=28- numeric version code for updatesauthor=xCaptaiN09- module author
Configuration file for module behavior:
{
"enabled": false, // 🆕 Enable/disable module (disabled by default)
"interval": 3600, // Scan interval in seconds
"base_path": "/sdcard/Sortify", // Where to sort files
"download_path": "/sdcard/Download", // Where to take files from
"recursive": true, // Recursive scanning
"max_depth": 5, // Maximum scan depth
"enabled_categories": { // Enabled sorting categories
"documents": true,
"images": true,
"videos": true,
"audio": true,
"archives": true,
"apps": true,
"magisk": true,
"others": true
},
"exclude_folders": ["WhatsApp", "Music", "Screenshots"] // Excluded folders
}Current defaults and behavior:
enabled=falsekeeps auto-sorting disabled until installation choice or WebUI toggleinterval=3600gives a one-hour default scan interval for battery savingbase_path=/sdcard/Sortifyis the sorted output rootdownload_path=/sdcard/Downloadis the source folderenabled_categoriesdefaults all sortable categories to enabledexclude_foldersskips common user folders by name
- Runs automatically on Android boot
- Waits for storage readiness (
/sdcard) - Works in infinite loop with configurable interval
- Parses
config.jsonand exports variables foraction.sh - Maintains log (
sortify.log) with automatic rotation (last 200 lines) - Copies log to
base_pathfor easy access
Key functions:
get_json_value()- parsing string and numeric values from JSONget_json_bool()- parsing boolean valueswait_until_storage()- waiting for storage mount
Main script that performs file sorting. Current behavior includes:
- Automatic Magisk module detection by checking for
module.propin ZIP archives - Special
Magisk/folder for modules - Recursive search with depth control (
recursive,max_depth) - Automatic
base_pathexclusion if it's insidedownload_path - Custom exclusions via
exclude_foldersarray - Category toggles via
enabled_categories
File Categories:
Documents/ : pdf, doc, docx, txt, xls, xlsx, ppt, pptx, csv
Images/ : jpg, jpeg, png, gif, bmp, webp, heic, heif, svg
Videos/ : mp4, mkv, avi, mov, webm, flv, mpeg, mpg, 3gp
Audio/ : mp3, m4a, flac, wav, ogg, opus, aac, wma
Archives/ : zip, rar, 7z, tar, gz, bz2, iso (except Magisk modules)
Apps/ : apk, xapk, apks
Magisk/ : zip files with module.prop inside
Others/ : all other files
Duplicates/: files with conflicting namesExcluded Files:
- Hidden files (starting with
.) - Temporary files (
.crdownload,.partial,.tmp) - Files in excluded folders
Key Functions:
get_json_value()- parsing values from config.jsonget_json_bool()- parsing boolean valuesget_json_array()- parsing arrays from config.jsonis_magisk_module()- checking ZIP file for module.proplog_msg()- logging with timestampmove_files()- moving files with duplicate handling
Algorithm:
- Read configuration from
config.json - Build exclusion list (auto + custom)
- Create folder structure in
base_path - Sequential sorting by categories:
- Documents → Images → Videos → Audio
- ZIP files (check for Magisk modules) → Magisk/
- Archives → Apps
- Remaining files → Others
- Handle duplicates (move to
Duplicates/)
- Runs during module installation via Magisk Manager
- Reads
versionandversionCodefrommodule.propfor installer output - Creates folder structure in
base_path - Sets script permissions (0755)
- Shows information about configuration and new features
- Runs during module removal
- Stops background processes (
pkill -f sortify) - By default does NOT delete sorted files (commented out)
- Logs removal to
sortify.log
New feature from MeteorBurn fork!
Single-page web interface for full module management via KsuWebUI or WebUI X.
Main Sections:
- Module Status - Enable/disable toggle and manual sort button
- General Settings - Configure interval, paths, recursion, depth, and open internal-storage folder picker
- Folder Exclusions - Manage excluded folders (multiline textarea)
- File Categories - Enable/disable sorting for each supported category and view supported extensions
- Sortify Log - 🆕 Live log viewing with Refresh/Clear buttons
- Debug Info - Hidden debug panel (display: none)
- Theme - Cyber Blue Coral palette via CSS custom properties in
:root
Technical Details:
- Config Loading: Uses
cat | tr '\n' ' 'to read multiline JSON - Config Saving: Heredoc with
cat > file << 'EOFCONFIG'for safe writing - Log Loading: Uses
tail -n 200 | base64 | tr -d '\n'so WebUI receives complete multiline output - Manual Sorting: Uses
ksu.execto log wrapper start/completion lines and runaction.sh - Folder Picker: Lists directories via
find, restricted to/sdcardand/storage/emulated/0 - ksu.exec API: All operations run through KernelSU/WebUI shell bridge
- Responsive Design: Adaptive design with dark theme
- Auto-scroll: Logs automatically scroll to bottom
- Scrollbar: min-height: 400px, max-height: 600px, overflow-y: scroll
Benefits:
- No separate web server required
- Works entirely in KSU WebUI/WebUI X
- Instant changes without reboot (for
enabledparameter) - Manual sort button logs wrapper start/completion lines and the normal
action.shsorting log output - Manual path entry remains available even though picker is limited to user-accessible shared storage
- Convenient log viewing without ADB
- Modify necessary scripts (
action.sh,service.sh) - Create module ZIP archive with correct structure
- Install via Magisk Manager
- Check logs at
/data/adb/modules/sortify/sortify.log
After changing module behavior, scripts, WebUI, config defaults, or adding functionality, build a fresh installable archive immediately after the edits. Use the current module.prop version and versionCode for the archive name unless the user explicitly requested a version change.
Installable archives are sensitive to Android shell formatting:
- ✅ Build from a temporary staging folder, not directly from the Windows working tree
- ✅ Normalize all text files to Unix LF before archiving (
.sh,.json,.html,module.prop) - ✅ Use a minimal root-level archive structure:
module.propservice.shaction.shcommon.shcustomize.shuninstall.shconfig.jsonbanner.pngwebroot/index.html
- ✅ Use
7zor another ZIP tool that preserves this simple root layout - ❌ Do not include
.git,AGENTS.md,README.md,LICENSE, or a parent folder in the install ZIP - ❌ Do not create the install ZIP directly from CRLF-normalized Windows files
Known issue: PowerShell Compress-Archive can produce a ZIP that looks valid locally but fails during Magisk/Kitsune extraction or script execution if shell files contain CRLF line endings. Before release, verify:
7z t dist\Sortify-v4.3.2-vc28-magisk.zip
# Then extract/check all text files: CRLF count must be 0- Open
action.sh - Add new extension to appropriate variable (e.g.,
DOC_EXT) - Or create new category:
NEW_EXT="ext1 ext2 ext3" mkdir -p "$BASE_PATH/NewCategory" move_files "$BASE_PATH/NewCategory" $NEW_EXT
- Main logic is in
move_files()function inaction.sh - Use
findcommand with filters to search for files - Handle exclusions via
EXCLUDE_LISTcheck - Log important actions via
log_msg()
Scripts use only basic POSIX shell commands:
find,grep,sed,cut,tr,mv,mkdir- Avoid bash-specific constructs (arrays,
[[,+=) - Use simple
while readloops instead offor file in $(find ...)
# Via adb
adb shell cat /data/adb/modules/sortify/sortify.log
# Or in target folder
cat /sdcard/Sortify/sortify.logcat /data/adb/modules/sortify/config.jsonsu
cd /data/adb/modules/sortify
sh action.shps aux | grep sortify- v4.3.2 (versionCode 28) - WebUI layout polish
- Added Cyber Blue Coral WebUI palette
- Added File Categories enable/disable controls
- Installer output reads version and versionCode from module.prop
- Moved recursive scanning controls into General Settings
- Restored always-visible File Categories below exclusions
- Removed default-disabled warning text from Module Status
- Removed purple gradient from Base Path and Download Path picker buttons
- v4.3.1 (versionCode 27) - WebUI convenience update
- Manual Sort button in Module Status
- Internal-storage-only folder picker for Base Path and Download Path
- Collapsible File Categories section
- Updated default interval to 3600 seconds
- v4.3.0 (versionCode 26) - 🆕 Fork by MeteorBurn
- Native WebUI with full module management
- Live log viewer with clear functionality
- Volume key setup during installation (Vol UP/DOWN)
enabledparameter for enabling/disabling- Fixed JSON reading via
tr '\n' ' ' - Proven volume key detection implementation from Bootloop Protector
- Increased log min-height to 400px with overflow-y: scroll
- Updated default settings: interval=1000s, exclude=[WhatsApp, Music, Screenshots]
- v4.3.0 - Automatic Magisk module detection
- v4.3 - Recursive scanning, auto base_path exclusion, custom exclusions
- v4.2 - JSON-based configuration
- v4.0 - First stable release
When making changes:
- Check compatibility with Android busybox
- Test on real device
- Update
version/versionCodeinmodule.proponly when the user explicitly requested a version bump - Build a fresh Magisk/KernelSU ZIP after code changes or new functionality
- Document changes in description
- Commit changes to
devbranch - After testing, merge to
master