I use a custom python script to actively organize my downloads. Since moving to Big Sur, it still works 100% of the time, but about 5-10% of the time on a big download I’ll end up with multiple copies of the same file.
This is due to safari writing the file to the incoming directory, but without any indication that it is an incomplete file. (Previously it would have a .download extension, which indicates it’s incomplete).
This application is not constantly running, it is only triggered by a folder action when a file is created in the incoming directory. Previously the script would have detected the .download extension, and skips those files, allowing those to be retriggered later.
Is there a way to turn that back on? Or using python detect it is actively being downloaded?
Since the script isn’t being run continuously there isn’t a good method to compare file sizes, to see if it’s increasing. Plus, what would be the finished file size? (eg. It stopped increasing, but does that mean it’s finished? How long do we wait after it’s stopped increasing to assume it’s done?) — My gut instinct is that file sizing monitoring could be made to work, but there might be a better method to solve this.
So I’m open to any suggestions that could solve this minor pita problem.
This code was written back in python 2.2 days? I’ve been thinking about updating it to use path lib, but it works.
#!/usr/bin/env python
"""
:Module: sort_downloads
:Date: 20150-20
:Platforms: Mac (Tested under Mac OS X)
:Version: 1
:Authors:
- Benjamin Schollnick
:Copyright (C) 2015, Benjamin Schollnick
:License - MIT,
:Description:
This will take a starting folder (e.g. Downloads folder), and move any
files found in the directory, to a different folder
(e.g. Sorted_Downloads), and organize by file types (based off extensions).
Any file type not identified by a file type will be placed into a folder
that is dated in the mm-dd-yyyy format.
This allows better organization, and groups together files downloaded
(generally) in the same day.
Under MOSX, I use launchd to run this script, any time my download folder
is updated.
**Modules Used (Batteries Included)**:
* os
* sys
* datetime
* time
* shutil
* logging
**Required 3rd Party Modules**:
* None
"""
import os, os.path
import sys
import datetime
import shutil
import logging
INBOUND_DIR = r'/Volumes/3TBDrive/support/incoming_downloads'
SORTED_DIRECTORY = r'/Volumes/4TB_Drive/sorted_downloads'
def return_datestamp(include_time=None):
"""
Return the formatted time date string
"""
datestamp = datetime.datetime.now()
if not include_time:
datestamp = str(datestamp).split(" ")(0)
else:
datestamp = str(datestamp).replace(":", "-")
return datestamp
LOOKUP_TABLE = {'.TORRENT' : "Torrents",
'.DOWNLOAD' : None,
'.DMG' : "Disk Images",
'.ISO' : "Disk Images",
'.ZIP' : "Zip Files",
'.JAR' : "Java",
'.SWF' : "Flash",
'.PDF' : "PDF",
'.PY' : "Python",
'.PYC' : "Python",
'.WEBLOC' : "BookMarks",
'.EPUB' : "Ebooks",
'.RAR' : "RAR",
'.7Z' : "7Z",
'.TXT' : "Text",
'.PAGES' : "Pages",
'.HTM' : "HTML",
'.HTML' : "HTML",
'.CSS' : "StyleSheet",
'.JS' : "JavaScript",
'.CSV' : "CSV",
'.MPG' : "Movie",
'.MPEG' : "Movie",
'.M4V' : "Movie",
'.MOV' : "Movie",
'.AVI' : "Movie",
'.MP4' : "Movie",
'.EXE' : "Windows",
'.MSI' : "Windows",
'.DOC' : "MS Word",
'.DOCX' : "MS Word",
'.XLS' : "Excel",
'.XLSX' : "Excel",
'.PKG' : "Macintosh",
'.APP' : "Macintosh",
}
def return_new_path(filename):
"""
Args:
filename - the Fully qualified filename
Returns:
The name of the folder to place the file in
"""
# print(filename)
output = None
if os.path.isfile(filename):
extension = os.path.splitext(filename)(1)
if extension.upper() in LOOKUP_TABLE:
output = LOOKUP_TABLE(extension.upper())
else:
output = None
# print(output)
if output == None:
output = return_datestamp() #+ os.sep + os.path.split(filename)(1)
return output
def main():
"""
Args:
None
Returns:
None
"""
logger = logging.getLogger("FVS")
loghandler = logging.FileHandler(sys.argv(0) + ".log")
formatter = logging.Formatter("%(asctime)s %(levelname)s %(message)s")
loghandler.setFormatter(formatter)
logger.addHandler(loghandler)
logger.setLevel(logging.WARNING)
#
# Get the contents of the inbound_directory
#
contents_of_inbound = os.listdir(INBOUND_DIR)
for file_x in contents_of_inbound:
complete_filename = os.path.join(INBOUND_DIR, file_x.strip())
if os.path.isfile(complete_filename) and not file_x.startswith(".") and
not file_x.lower().endswith(".part"):
# print return_new_path ( complete_filename )
if os.path.getsize(complete_filename) <= 0:
# if Filesize is zero or less, skip. Incomplete file.
continue
new_path = SORTED_DIRECTORY +
r"/%s" % return_new_path(complete_filename)
logger.info("Moving ... %s to %s", file_x, new_path)
if not os.path.exists(new_path):
logger.warning("Making sorted directory - %s", new_path)
os.mkdir(new_path)
if os.path.exists(os.path.join(new_path, file_x)):
#
# File Already exists, rename it to prevent naming conflicts
#
dstamp = return_datestamp(include_time=True)
logger.warning(
"%s already exists, renaming to %s-%s",
file_x, file_x, dstamp)
fname, extension = os.path.splitext(complete_filename)
new_filename = "%s-%s%s" % (fname, dstamp, extension)
os.rename(complete_filename, new_filename)
shutil.move(os.path.join(INBOUND_DIR, new_filename), new_path)
else:
# Move the file, as is.
if new_path.strip().upper() != SORTED_DIRECTORY.strip().upper():
shutil.move(complete_filename, new_path)
if os.path.exists(INBOUND_DIR + os.sep + ".DS_Store"):
os.remove(INBOUND_DIR + os.sep + ".DS_Store")
if __name__ == "__main__":
main()#