|
import shutil |
|
import os |
|
import subprocess |
|
import re |
|
|
|
ALLOWED_TYPES = ['avi', 'mkv', 'mov', 'mp4'] |
|
PREPARE_FOLDER = r"D:\XBMC-prepare\%s" % eg.globals.mediaType |
|
CLEANSED_FOLDER = r"D:\XBMC\%s" % eg.globals.mediaType |
|
THE_RENAMER = r"C:\\Program Files (x86)\\theRenamer\\theRenamer.exe" |
|
MOVIE_MINIMUM_FILESIZE = 25 * 1024 * 1024 # 25mb |
|
|
|
""" |
|
No editing below this line unless you know what you're doing. |
|
|
|
v1.4 15/11/2016 |
|
- Added MOVIE_MINIMUM_FILESIZE to prevent samples from being copied |
|
- Update anime so it adds CRC32 checksum if missing to improve Kodi scans |
|
- Recursively create target_folder structure |
|
- Added target_filename which allows for customised renaming |
|
- ignore files with 'rarbg.com' and 'sample' in the filename |
|
- rename "Greys Anatomy to "Grey's Anatomy" |
|
|
|
|
|
v1.3 10/01/2016 |
|
- Anime now copies directly to CLEANSED_FOLDER rather than interim prepare folder |
|
- Renamed DESTINATION_FOLDER to PREPARE_FOLDER |
|
|
|
v1.2 18/11/2015 |
|
- Now supports anime to destination folder |
|
(requires source to be in the form of SOURCE_FOLDER\Anime\Show Name\Episode.ext) |
|
""" |
|
#print "PREPARE_FOLDER", PREPARE_FOLDER |
|
|
|
|
|
def should_copy_file(filename): |
|
isFolder = os.path.isdir(filename) |
|
|
|
if isFolder: |
|
return False |
|
|
|
#print "not folder" |
|
bits, fileExtension = os.path.splitext(filename.lower()) |
|
fileExtension = fileExtension.split(os.path.extsep)[1] |
|
|
|
#print "bits", bits |
|
#print "ext", fileExtension |
|
|
|
if fileExtension not in ALLOWED_TYPES: |
|
return False |
|
|
|
if 'sample' in filename.lower() or 'rarbg.com' in filename.lower(): |
|
return False |
|
|
|
if eg.globals.mediaType == "Movies": |
|
if os.path.getsize(filename) <= MOVIE_MINIMUM_FILESIZE: |
|
print "file too small" |
|
return False |
|
|
|
#print "allowed" |
|
return True |
|
|
|
|
|
|
|
def copy_file(filename): |
|
f = None |
|
print "copy_file", filename |
|
|
|
if not os.path.exists(filename): |
|
print "File doesn't exist", filename |
|
return |
|
|
|
target_folder = PREPARE_FOLDER |
|
target_filename = None |
|
mediaType = eg.globals.mediaType |
|
|
|
if mediaType == "Movies": |
|
# Create a fake folder |
|
real_filename = filename.split(os.path.sep)[-1] |
|
target_folder = os.path.join(target_folder, real_filename) |
|
|
|
elif mediaType == "TV Shows": |
|
if 'greys.anatomy' in filename.lower(): |
|
file_parts = filename.split(os.path.sep) |
|
# The folder is correctly labelled + file extension |
|
target_filename = file_parts[-2].lower().replace('greys.anatomy', "grey's.anatomy") + '.' + filename.split('.')[-1] |
|
#print "target_filename", target_filename |
|
|
|
elif mediaType == "Anime": |
|
# No auto-renaming scripts/utilities |
|
target_folder = CLEANSED_FOLDER |
|
|
|
# C:\Downloads\Anime\Show Name\episode.ext |
|
# C:\Downloads\Anime\whatever_ova.ext |
|
file_parts = filename.split(os.path.sep) |
|
real_filename = file_parts.pop() |
|
show_name = file_parts.pop() |
|
|
|
# Append show name if it's available |
|
# (Assuming source folder structure is like the mediaType structure) |
|
if show_name.lower() != mediaType.lower(): |
|
# READY\Anime\<show_name>\ |
|
target_folder = os.path.join(target_folder, show_name) |
|
|
|
# Adding [CRC32SUM] ensures it's scannable by XBMC/Kodi |
|
if not re.search(r"\[[a-fA-F0-9]{8}\]", real_filename): |
|
filename_bits = real_filename.split(os.path.extsep) |
|
filename_bits[0] += " [abcd1234]" |
|
target_filename = os.path.extsep.join(filename_bits) |
|
print "target_filename", target_filename |
|
|
|
# Destination file already exists |
|
if os.path.exists(os.path.join(target_folder, os.path.basename(filename))): |
|
print "Destination file already exists", os.path.basename(filename) |
|
return |
|
|
|
try: |
|
# Attempt to open the file for writing. |
|
# If it's still copying, then this will fail |
|
f = open(filename, 'rb') |
|
f.close() |
|
f = None |
|
|
|
if not os.path.exists(target_folder): |
|
print "Creating missing target folder:", target_folder |
|
os.makedirs(target_folder) |
|
|
|
if target_filename is not None: |
|
target_folder = os.path.join(target_folder, target_filename) |
|
|
|
shutil.copy(filename, target_folder) |
|
print "*** Copied", os.path.basename(filename) |
|
|
|
# Rename files |
|
args = [ THE_RENAMER ] |
|
|
|
if mediaType == "TV Shows": |
|
args.append("-fetch") |
|
|
|
elif mediaType == "Movies": |
|
args.append("-fetchmovie") |
|
# Use the target folder, because it'll be removed when it finishes (theRenamer -fetchmovie bug) |
|
args.append(r'-ff="%s"' % target_folder) |
|
|
|
elif mediaType == "Anime": |
|
# No need for anime autorename |
|
return |
|
|
|
else: |
|
raise Exception("Unsupported media type %s" % mediaType) |
|
|
|
# print "subprocess call", args |
|
subprocess.call(args) |
|
|
|
# print "DONE!" |
|
|
|
except IOError, e: |
|
if f: |
|
f.close() |
|
f = None |
|
|
|
# Error opening file, wait and try again; 30s |
|
print "file open failed", str(e) |
|
eg.scheduler.AddTask(10.0, copy_file, filename) |
|
|
|
|
|
|
|
def is_file_in_schedule(filename): |
|
# Files that are currently being checked |
|
current_files = [item[2][0] for item in eg.scheduler.__dict__['heap'] if item[1] and item[1].__name__ == 'copy_file'] |
|
return (filename in current_files) |
|
|
|
|
|
|
|
def prepare_file(item): |
|
if is_file_in_schedule(item): |
|
return |
|
elif not should_copy_file(item): |
|
return |
|
else: |
|
# Don't start immediately; 60s |
|
eg.scheduler.AddTask(10.0, copy_file, item) |
|
|
|
|
|
# Could be more than one file in this event |
|
for item in eg.event.payload: |
|
#print dir(eg) |
|
|
|
isFolder = os.path.isdir(item) |
|
|
|
# Check every file in folder |
|
if isFolder: |
|
for dir, subdirs, files in os.walk(item): |
|
if len(files) == 0: |
|
continue |
|
|
|
for file in files: |
|
prepare_file(os.path.join(dir, file)) |
|
|
|
# Prepare it for copying |
|
else: |
|
prepare_file(item) |