├── .gitattributes ├── .gitignore ├── Folder File Download Monitor & Sorter.ahk └── README.md /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | #Temp files 2 | *.bak -------------------------------------------------------------------------------- /Folder File Download Monitor & Sorter.ahk: -------------------------------------------------------------------------------- 1 | ;---------------------------------------------------------------------------------------------------------------------------------------; 2 | ; Initialization 3 | ;---------------------------------------------------------------------------------------------------------------------------------------; 4 | #NoEnv ; Recommended for performance and compatibility with future AutoHotkey releases. 5 | SendMode Input ; Recommended for new scripts due to its superior speed and reliability. 6 | SetWorkingDir %A_ScriptDir% ; Ensures a consistent starting directory. 7 | #SingleInstance Force 8 | #Persistent 9 | #NoTrayIcon 10 | 11 | ;---------------------------------------------------------------------------------------------------------------------------------------; 12 | ; User Variables 13 | ;---------------------------------------------------------------------------------------------------------------------------------------; 14 | ;Behaviour 15 | MonitoredFolder = D:\Downloads 16 | UnzipTo = D:\Downloads\Compressed 17 | HowOftenToScanInSeconds = 60 ;How long we wait before re-scanning the folder for any changes. 18 | ToolTips = 1 ;Show helper popups showing what the program is doing. 19 | OverWrite = 1 ;Overwrite duplicate files? 20 | RemoveEmptyFolders = 1 ;Delete any folders in the monitored folder that are now empty. (recursive) 21 | 22 | ;Zip files 23 | 7ZipLocation = C:\Program Files\7-Zip\7z.exe ;Needed to provide unzipping functionality. 24 | OpenExtractedZip = False ;Open the folder up after extraction has finished? 25 | DeleteZipFileAfterExtract = 1 ;Recycle the zip file after a successful extract. 26 | UnzipSuccessSound = 1 ;Play a jingle when unzipped something. 27 | 28 | ;What filetypes belong to what group, and what their folder name should be sorted into. 29 | FiletypeObjectArray := [] ;Array needs to be initiated first to work. 30 | PushFiletypeToArray(FiletypeObjectArray,["zip","7z","rar","r00","001"], "Compressed") 31 | PushFiletypeToArray(FiletypeObjectArray,["jpg","bmp","gif","gifv","webm","png","jpeg","swf","tga","tiff","exr","psd"], "Images") 32 | PushFiletypeToArray(FiletypeObjectArray,["txt","nfo","rtf","pdf","docx","doc"], "Documents") 33 | PushFiletypeToArray(FiletypeObjectArray,["mp3","flac","wav"], "Audio") 34 | PushFiletypeToArray(FiletypeObjectArray,["avi","mpg","mpeg","mov","mp4","mkv","wmv"], "Videos") 35 | PushFiletypeToArray(FiletypeObjectArray,["exe","msi","jar","cmd","bat","ahk"], "Programs") 36 | 37 | ;---------------------------------------------------------------------------------------------------------------------------------------; 38 | ; Main 39 | ;---------------------------------------------------------------------------------------------------------------------------------------; 40 | ;Start the folder monitor 41 | WaitTimeBetweenScans := HowOftenToScanInSeconds * 1000 42 | SetTimer, SearchFiles, %WaitTimeBetweenScans% 43 | GoSub,SearchFiles ; Immediately do a scan 44 | return 45 | 46 | ;---------------------------------------------------------------------------------------------------------------------------------------; 47 | ; Functions 48 | ;---------------------------------------------------------------------------------------------------------------------------------------; 49 | ;Utilities 50 | HasVal(haystack, needle) 51 | { 52 | for index, value in haystack 53 | if (value = needle) 54 | return index 55 | if !IsObject(haystack) 56 | throw Exception("Bad haystack!", -1, haystack) 57 | return 0 58 | } 59 | 60 | MakeFolderIfNotExist(TheFolderDir) 61 | { 62 | ifnotexist,%TheFolderDir% 63 | FileCreateDir,%TheFolderDir% 64 | } 65 | 66 | RemoveEmptyFolders(Folder) 67 | { 68 | global Tooltips 69 | Loop, %Folder%\*, 2, 1 70 | { 71 | FL := ((FL<>"") ? "`n" : "" ) A_LoopFileFullPath 72 | Sort, FL, R D`n ; Arrange folder-paths inside-out 73 | Loop, Parse, FL, `n 74 | { 75 | FileRemoveDir, %A_LoopField% ; Do not remove the folder unless is empty 76 | If ! ErrorLevel 77 | { 78 | Del := Del+1, RFL := ((RFL<>"") ? "`n" : "" ) A_LoopField 79 | if Tooltips 80 | { 81 | Tooltip,Removing empty folder %FL% 82 | SetTimer, RemoveToolTip, 3000 83 | } 84 | } 85 | } 86 | } 87 | } 88 | return 89 | 90 | FindZipFiles(Folder,GoalObjectDestination) 91 | { 92 | global FiletypeObjectArray 93 | global MonitoredFolder 94 | global Tooltips 95 | i = 0 96 | 97 | loop % FiletypeObjectArray.Count() 98 | { 99 | i ++ 100 | ;Get a ref to the object that holds the array of extensions we want. 101 | if FiletypeObjectArray[i].Destination != GoalObjectDestination 102 | continue 103 | o := FiletypeObjectArray[i] 104 | 105 | ;Unzip 106 | if o ;Without this it may end up unzipping to the root of C drive? i THINK "" defaults to C:\ when using Loop Files 107 | { 108 | Loop, Files, %MonitoredFolder%\*.*,R 109 | { 110 | if HasVal(o.Extensions,A_LoopFileExt) 111 | UnZip(A_LoopFileName,A_LoopFileDir,A_LoopFileFullPath) 112 | } 113 | } 114 | } 115 | } 116 | return 117 | 118 | UnZip(FileFullName,Dir,FullPath) 119 | { 120 | global 7ZipLocation ;Saves having to re-pass this dir each time you use this function. 121 | global DeleteZipFileAfterExtract 122 | global OpenExtractedZip 123 | global Tooltips 124 | global UnzipTo 125 | global UnzipSuccessSound 126 | 127 | ;Get filename 128 | StringGetPos,ExtentPos,FileFullName,.,R 129 | FileName := SubStr(FileFullName,1,ExtentPos) 130 | if Tooltips 131 | { 132 | Tooltip,Unzipping %FileName% > %Dir%\%FileName% 133 | SetTimer, RemoveToolTip, 3000 134 | } 135 | MakeFolderIfNotExist(UnzipTo . "\" . FileName) 136 | Runwait, "%7ZipLocation%" x "%FullPath%" -o"%UnzipTo%\%FileName%" 137 | sleep,2000 138 | 139 | IfExist %UnzipTo%\%FileName% 140 | { 141 | if DeleteZipFileAfterExtract 142 | Filerecycle, %FullPath% 143 | if OpenExtractedZip 144 | run, %UnzipTo%\%FileName% 145 | if UnzipSuccessSound 146 | soundplay, *64 147 | } 148 | else 149 | msgbox,,Oh Noes!,Something went wrong and I couldn't unzip %FileName% to %UnzipTo%\%FileName% 150 | } 151 | 152 | 153 | ;Objects 154 | PushFiletypeToArray(InputArray,FiletypesArray,Destination) 155 | { 156 | InputArray.Push(MakeFiletypeObject(FiletypesArray,Destination)) 157 | return InputArray 158 | } 159 | 160 | MakeFiletypeObject(InputArray,Destination) 161 | { 162 | object := [] 163 | object.Extensions := InputArray 164 | object.Destination := Destination 165 | return object 166 | } 167 | 168 | GetDestination(TheFile) 169 | { 170 | global FiletypeObjectArray 171 | for i in FiletypeObjectArray 172 | { 173 | if HasVal(FiletypeObjectArray[i].Extensions,A_LoopFileExt) 174 | Destination := FiletypeObjectArray[i].Destination 175 | } 176 | return Destination 177 | } 178 | 179 | ;---------------------------------------------------------------------------------------------------------------------------------------; 180 | ; Subroutines 181 | ;---------------------------------------------------------------------------------------------------------------------------------------; 182 | ;Main 183 | SearchFiles: 184 | Loop, Files, %MonitoredFolder%\* 185 | { 186 | DestinationFolder := GetDestination(A_LoopFileFullPath) 187 | if (DestinationFolder = "Compressed") 188 | UnZip(A_LoopFileName,A_LoopFileDir,A_LoopFileFullPath) 189 | else if DestinationFolder 190 | { 191 | DestinationFolder := MonitoredFolder . "\" . DestinationFolder 192 | MakeFolderIfNotExist(DestinationFolder) 193 | FileMove,%A_LoopFileFullPath%,%DestinationFolder%\*.*,%OverWrite% ; *.* is needed else it could be renamed to no extension! (If dest folder failed) 194 | if Tooltips 195 | { 196 | Tooltip,Moving %A_LoopFileName% > %DestinationFolder% 197 | SetTimer, RemoveToolTip, 3000 198 | } 199 | } 200 | } 201 | if RemoveEmptyFolders 202 | RemoveEmptyFolders(MonitoredFolder) 203 | FindZipFiles(MonitoredFolder,"Compressed") 204 | 205 | ;Other 206 | RemoveToolTip: 207 | SetTimer, RemoveToolTip, Off 208 | ToolTip 209 | return 210 | 211 | ^Esc::ExitApp 212 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Automatic Folder Monitor & File Sorter 2 | ## Overview: 3 | 4 | This tool takes the hassle out of manually sorting your downloads folder, or any other folder you tend to just throw files into. 5 | It will move files that fall under a category to a specified subfolder. It will also auto-unzip any zipped files for you. 6 | So you can assign a bulk set of image extensions, and any time the script sees one in your monitored folder, it will move it to your "Images" folder. 7 | Eg: photo.jpg > Photos folder\photo.jpg. ZipFile.7z > ZipFile\ZipFileContents*.* 8 | 9 | Fully customizable to suit your needs! 10 | 11 | 12 | ## Initial Setup 13 | 1. Download and install 7zip or easy-7Zip (http://www.e7z.org/free-download.htm) 14 | 2. Download and install AutoHotKey (https://www.autohotkey.com/download/) 15 | 3. Open the .ahk file in a text editor. 16 | 4. Change the "MonitoredFolder" value near the top of the script to point to the folder that you want to be monitored for changes. 17 | 5. Change "UnzipTo" value to point to where you want zip files to be unzipped to. 18 | 5. Change "HowOftenToScanInSeconds" To how often it should check if anything within the folder has changed. 19 | 6. Change the "7ZipLocation" to point to where your 7zip's 7z.exe is. 20 | 7. Under the "Destination folders" section, you can change where files that match a specific file type will be placed. Eg MoveImagesTo = %MonitoredFolder%\Images 21 | 22 | ## Adding more file types to a category 23 | 1. Starting on Line 27, add in the file extension to the list of file extensions on the PushFiletypeToArray command. Eg. "jpeg" and use a comma to seperate the entries. 24 | 25 | ## Adding custom categories 26 | 1. Copy and paste this onto a new line just after the last one on line 32, and adjust the file types within the [ ] brackets, and label what folder they go into at the end to what you'd like to use. 27 | 28 | PushFiletypeToArray(FiletypeObjectArray,["exe","msi","cmd"], "FolderNameGoesHere") 29 | --------------------------------------------------------------------------------