mirror of
https://github.com/nikdoof/tvorganise.git
synced 2025-12-13 06:42:16 +00:00
Reorganised files, changed tagging to tvorganise. Start of fork.
This commit is contained in:
138
checkFilms.py
138
checkFilms.py
@@ -1,138 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
#encoding:utf-8
|
||||
import os,re,sys
|
||||
|
||||
###################################
|
||||
# Configs
|
||||
###################################
|
||||
|
||||
# Import shared filename pattern config
|
||||
from filename_config import film_regex
|
||||
|
||||
# Location to process
|
||||
loc = "." # Runs from the current path
|
||||
|
||||
###################################
|
||||
# Helper functions
|
||||
###################################
|
||||
|
||||
def colour(text,colour="red"):
|
||||
nocolour=False
|
||||
if nocolour: # Colour no supported, return plain text
|
||||
return text
|
||||
#end if
|
||||
|
||||
c = {'red':'[31m',
|
||||
'green':'[32m',
|
||||
'blue':'[34m',
|
||||
}
|
||||
CLR=chr(27)+'[0m'
|
||||
if not colour in c.keys():
|
||||
raise ValueError("Invalid colour")
|
||||
else:
|
||||
return chr(27)+c[colour] + text + CLR
|
||||
#end if
|
||||
#end colour
|
||||
|
||||
def getError(invalid,errorno):
|
||||
"""Gets all invalid files with supplied error number"""
|
||||
ret = []
|
||||
for cur in invalid:
|
||||
if cur['errorno'] == errorno:
|
||||
ret.append(cur)
|
||||
return ret
|
||||
#end searchError
|
||||
|
||||
###################################
|
||||
# Find all valid files
|
||||
###################################
|
||||
allfiles=[]
|
||||
for (path,dirs,files) in os.walk(loc):
|
||||
for file in files:
|
||||
filename = os.path.join(os.path.abspath(path),file)
|
||||
allfiles.append( str(filename) )
|
||||
#end for f
|
||||
|
||||
# Strip out dotfiles/folder.jpg
|
||||
for current_file in allfiles:
|
||||
current_file_path,current_file_name = os.path.split(current_file)
|
||||
for cur_decrap in film_regex['decrappify']:
|
||||
if cur_decrap.match(current_file_name):
|
||||
allfiles.remove(current_file)
|
||||
#end for file
|
||||
|
||||
# Warn if no files are found, then exit
|
||||
if allfiles.__len__() == 0:
|
||||
print colour('No files found','red')
|
||||
sys.exit(0)
|
||||
|
||||
|
||||
errors = {
|
||||
1:'malformed name',
|
||||
2:'missing year',
|
||||
3:'path is incorrect'
|
||||
}
|
||||
###################################
|
||||
# Validate filenames
|
||||
###################################
|
||||
|
||||
valid = []
|
||||
invalid = []
|
||||
|
||||
for cur in allfiles:
|
||||
cpath,cfile = os.path.split(cur)
|
||||
cfile,cext = os.path.splitext(cfile)
|
||||
|
||||
for cur_checker in film_regex['valid_path']:
|
||||
# Check if path is valid
|
||||
check = cur_checker.findall(cpath)
|
||||
if check:
|
||||
break
|
||||
else:
|
||||
print cpath, "doesnt match"
|
||||
invalid.append({'errorno':3, 'path':cpath,'filename':cfile,
|
||||
'cext':cext})
|
||||
#end for cur_checker
|
||||
|
||||
for cur_checker in film_regex['with_year']:
|
||||
# Check if filename is valid (with ep name)
|
||||
check = cur_checker.findall(cfile)
|
||||
if check:
|
||||
# Valid file name
|
||||
valid.append({'path':cpath,'filename':cfile,
|
||||
'cext':cext})
|
||||
break # Found valid episode, skip to the next one
|
||||
#end if
|
||||
else:
|
||||
for cur_checker in film_regex['missing_year']:
|
||||
# Check for valid name with missing episode name
|
||||
check = cur_checker.findall(cfile)
|
||||
if check:
|
||||
invalid.append({'errorno':2, 'path':cpath,'filename':cfile,
|
||||
'cext':cext})
|
||||
break
|
||||
#end if check
|
||||
else:
|
||||
# Doesn't match valid-name or missing-ep-name regexs, it's invalid
|
||||
invalid.append({'errorno':1, 'path':cpath,'filename':cfile,
|
||||
'cext':cext})
|
||||
#end for cur_checker
|
||||
#end for cur_checker
|
||||
#end for
|
||||
|
||||
###################################
|
||||
# Show invalid names
|
||||
###################################
|
||||
for errorno,errordescr in errors.items():
|
||||
errors = getError(invalid,errorno)
|
||||
if len(errors) == 0: continue
|
||||
|
||||
errmsg = "# %s (error code: %s)" % (errordescr,errorno)
|
||||
|
||||
print
|
||||
print "#"*len(errmsg)
|
||||
print errmsg
|
||||
print "#"*len(errmsg)
|
||||
|
||||
for c in errors:
|
||||
print c['filename']
|
||||
326
checkTvEps.py
326
checkTvEps.py
@@ -1,326 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
#encoding:utf-8
|
||||
import os, sys
|
||||
|
||||
# Import shared filename pattern config
|
||||
from filename_config import tv_regex
|
||||
|
||||
def colour(text, colour="red"):
|
||||
nocolour = False
|
||||
if nocolour: # Colour no supported, return plain text
|
||||
return text
|
||||
#end if
|
||||
|
||||
c = {'red':'[31m',
|
||||
'green':'[32m',
|
||||
'blue':'[34m',
|
||||
}
|
||||
CLR=chr(27)+'[0m'
|
||||
if not colour in c.keys():
|
||||
raise ValueError("Invalid colour")
|
||||
else:
|
||||
return chr(27)+c[colour] + text + CLR
|
||||
#end if
|
||||
#end colour
|
||||
|
||||
def getError(invalid,errorno):
|
||||
"""Gets all invalid files with supplied error number"""
|
||||
ret = []
|
||||
for cur in invalid:
|
||||
if cur['errorno'] == errorno:
|
||||
ret.append(cur)
|
||||
return ret
|
||||
#end searchError
|
||||
|
||||
###################################
|
||||
# Output-helper to convert array of
|
||||
# numbers (episode numbers) to human-readable string
|
||||
###################################
|
||||
|
||||
def seq_display(x):
|
||||
"""
|
||||
Takes an array of numbers, returns a more readable string representation of them
|
||||
|
||||
>>> seq_display( [1,2,3, 5,6,7, 10, 20,21,22] )
|
||||
'1->3, 5->7, 10, 20->22'
|
||||
"""
|
||||
is_int=[]
|
||||
non_int=[]
|
||||
for cur_x in x:
|
||||
if cur_x.find("-") != -1:
|
||||
for tmp_split in cur_x.split("-"):
|
||||
try:
|
||||
tmp_conv = int(tmp_split)
|
||||
is_int.append(tmp_conv)
|
||||
except ValueError:
|
||||
non_int.append(cur_x)
|
||||
#end try
|
||||
#end for tmp_split
|
||||
try:
|
||||
tmp_conv = int(cur_x)
|
||||
is_int.append(tmp_conv)
|
||||
except ValueError:
|
||||
non_int.append(cur_x)
|
||||
#end try
|
||||
#end for cur_x
|
||||
|
||||
if len(is_int) == 0: return x # return original input, no numbers!
|
||||
|
||||
start = min(is_int)
|
||||
end = max(is_int)
|
||||
|
||||
if end == start: return start
|
||||
if end - start > 999: return ", ".join([str(y) for y in x]) # too long, return list
|
||||
|
||||
break_start = False
|
||||
|
||||
out = ""
|
||||
|
||||
for i in xrange(start, end + 1):
|
||||
try:
|
||||
is_int.index(i)
|
||||
if not break_start:
|
||||
break_start = i
|
||||
except ValueError:
|
||||
if break_start:
|
||||
if break_start == i - 1: # start and end are same, its one number
|
||||
out += "%d, " % (break_start)
|
||||
else:
|
||||
out += "%d->%d, " % (break_start, i - 1)
|
||||
break_start = False
|
||||
#end try
|
||||
if break_start == i:
|
||||
out += "%d" % (break_start)
|
||||
else:
|
||||
out += "%d->%d" % (break_start, i) # last value
|
||||
|
||||
return out
|
||||
#end seq_display
|
||||
|
||||
|
||||
###################################
|
||||
# Classes to abstract show data
|
||||
###################################
|
||||
class ShowContainer:
|
||||
def __init__(self):
|
||||
self.shows = {}
|
||||
#end __init__
|
||||
|
||||
def __getitem__(self, show_name):
|
||||
if not self.shows.has_key(show_name):
|
||||
self.shows[show_name] = Show(show_name)
|
||||
return dict.__getitem__(self.shows, show_name)
|
||||
#end __getitem__
|
||||
|
||||
def __str__(self):
|
||||
out=""
|
||||
for current_show_name, current_show in sorted( self.shows.items() ):
|
||||
out += str(current_show) + "\n"
|
||||
return out
|
||||
|
||||
class Show:
|
||||
def __init__(self, name):
|
||||
self.show_name = name
|
||||
self.seasons = {}
|
||||
#end __init__
|
||||
|
||||
def __getitem__(self,season_number):
|
||||
if not self.seasons.has_key(season_number):
|
||||
self.seasons[season_number] = Season(season_number)
|
||||
|
||||
return dict.__getitem__(self.seasons, season_number)
|
||||
#end __getattr__
|
||||
|
||||
def __setitem__(self,season_number, season):
|
||||
if not self.seasons.has_key(season_number):
|
||||
self.seasons[season_number] = Season(season_number)
|
||||
|
||||
self.seasons[season_number] = season
|
||||
#end __setitem__
|
||||
|
||||
def __str__(self):
|
||||
out = self.show_name + "\n"
|
||||
for cur_season_no, cur_season in sorted( self.seasons.items() ):
|
||||
out += str(cur_season) + "\n"
|
||||
return out
|
||||
#end __str__
|
||||
#end Show
|
||||
|
||||
class Season:
|
||||
def __init__(self, number):
|
||||
self.season_number = number
|
||||
self.episodes = {}
|
||||
#end __init__
|
||||
|
||||
def __getitem__(self, episode_number):
|
||||
if not self.episodes.has_key(episode_number):
|
||||
self.episodes[episode_number] = Episode(number = episode_number)
|
||||
|
||||
return dict.__getitem__(self.episodes, episode_number)
|
||||
#end __getitem__
|
||||
|
||||
def __setitem__(self,episode_number, episode):
|
||||
if not self.episodes.has_key(episode_number):
|
||||
self.episodes[episode_number] = Episode()
|
||||
|
||||
self.episodes[episode_number] = episode
|
||||
#end __setitem__
|
||||
|
||||
def __str__(self):
|
||||
out = "\tSeason %s\n" % (self.season_number)
|
||||
out += "\t\t"
|
||||
all_ep_nums = [cur_ep_num for cur_ep_num in self.episodes.keys() ]
|
||||
out += "Episodes " + str(seq_display(all_ep_nums))
|
||||
return out
|
||||
#end __str__
|
||||
#end Season
|
||||
|
||||
class Episode:
|
||||
def __init__(self, number):
|
||||
self.episode_number = number
|
||||
self.episode={}
|
||||
#end __init__
|
||||
|
||||
def __getitem__(self,attr):
|
||||
return dict.__getitem__(self.episode, attr)
|
||||
#end __getitem__
|
||||
|
||||
def __setitem__(self,attr,name):
|
||||
dict.__setitem__(self.episode, attr, name)
|
||||
#end __setitem__
|
||||
#end Episode
|
||||
|
||||
|
||||
def find_files(loc):
|
||||
"""Recursivly finds files in a directory
|
||||
"""
|
||||
allfiles=[]
|
||||
for (path,dirs,files) in os.walk(loc):
|
||||
for file in files:
|
||||
filename = os.path.join(os.path.abspath(path), file)
|
||||
allfiles.append( str(filename) )
|
||||
return allfiles
|
||||
#end find_files
|
||||
|
||||
|
||||
|
||||
def main():
|
||||
# Error-code to error-description mapping
|
||||
errors = {
|
||||
1:'malformed name',
|
||||
2:'missing epsiode name',
|
||||
3:'path is incorrect'
|
||||
}
|
||||
|
||||
# Location to process
|
||||
loc = "." # Runs from the current path
|
||||
|
||||
###################################
|
||||
# Find all valid files
|
||||
###################################
|
||||
allfiles = find_files(loc)
|
||||
|
||||
# Strip out dotfiles/folder.jpg
|
||||
decrappified = []
|
||||
for current_file in allfiles:
|
||||
current_file_path,current_file_name = os.path.split(current_file)
|
||||
crappy = False
|
||||
for cur_decrap in tv_regex['decrappify']:
|
||||
if cur_decrap.match(current_file_name):
|
||||
crappy = True
|
||||
break
|
||||
if not crappy: decrappified.append(current_file)
|
||||
#end for current_file
|
||||
allfiles = decrappified
|
||||
|
||||
# Warn if no files are found, then exit
|
||||
if len(allfiles) == 0:
|
||||
print colour('No files found','red')
|
||||
sys.exit(1)
|
||||
|
||||
###################################
|
||||
# Validate filenames
|
||||
###################################
|
||||
|
||||
valid = []
|
||||
invalid = []
|
||||
|
||||
for cur in allfiles:
|
||||
cpath,cfile = os.path.split(cur)
|
||||
cfile,cext = os.path.splitext(cfile)
|
||||
|
||||
for cur_checker in tv_regex['valid_path']:
|
||||
# Check if path is valid
|
||||
check = cur_checker.findall(cpath)
|
||||
if check:
|
||||
break
|
||||
else:
|
||||
invalid.append({'errorno':3, 'path':cpath,'filename':cfile,
|
||||
'cext':cext})
|
||||
#end for cur_checker
|
||||
|
||||
for cur_checker in tv_regex['with_ep_name']:
|
||||
# Check if filename is valid (with ep name)
|
||||
check = cur_checker.findall(cfile)
|
||||
if check:
|
||||
# Valid file name
|
||||
valid.append({'path':cpath,'filename':cfile,
|
||||
'cext':cext, 'match':check[0]})
|
||||
break # Found valid episode, skip to the next one
|
||||
#end if
|
||||
else:
|
||||
for cur_checker in tv_regex['missing_ep_name']:
|
||||
# Check for valid name with missing episode name
|
||||
check = cur_checker.findall(cfile)
|
||||
if check:
|
||||
invalid.append({'errorno':2, 'path':cpath,'filename':cfile,
|
||||
'cext':cext})
|
||||
break
|
||||
#end if check
|
||||
else:
|
||||
# Doesn't match valid-name or missing-ep-name regexs, it's invalid
|
||||
invalid.append({'errorno':1, 'path':cpath,'filename':cfile,
|
||||
'cext':cext})
|
||||
#end for cur_checker
|
||||
#end for cur_checker
|
||||
#end for
|
||||
|
||||
###################################
|
||||
# Show invalid names
|
||||
###################################
|
||||
if len(invalid) > 0:
|
||||
print colour('WARNING', 'red'), ': Invalid file-names found'
|
||||
|
||||
for errorno,errordescr in errors.items():
|
||||
errors = getError(invalid,errorno)
|
||||
if len(errors) == 0: continue
|
||||
|
||||
errormsg = "# %s (error code %d) #" % (errordescr, errorno)
|
||||
print "#"*len(errormsg)
|
||||
print errormsg
|
||||
print "#"*len(errormsg)
|
||||
|
||||
for c in errors:
|
||||
cur_path = os.path.join(c['path'], c['filename'] + c['cext'])
|
||||
print cur_path
|
||||
|
||||
###################################
|
||||
# Show valid names
|
||||
###################################
|
||||
if len(valid) > 0:
|
||||
print colour('INFO','green'), ': Valid file-names found:'
|
||||
allepisodes = ShowContainer()
|
||||
|
||||
for cur in valid:
|
||||
if len(cur['match']) == 4:
|
||||
showname,seasno,epno,title = cur['match']
|
||||
elif len(cur['match']) == 3:
|
||||
seasno = 1
|
||||
showname,epno,title = cur['match']
|
||||
|
||||
allepisodes[showname][seasno][epno]['name'] = title
|
||||
#end for cur in valid
|
||||
print allepisodes
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -8,7 +8,7 @@ regex_config={}
|
||||
|
||||
# Character class for valid episode/show names.
|
||||
# Example: [a-zA-Z0-9\-'\ ]
|
||||
regex_config['valid_in_names'] = "[\w\(\).,\[\]'\ \-?!#]"
|
||||
regex_config['valid_in_names'] = "[\w\(\).,\[\]'\ \-?!#:]"
|
||||
|
||||
|
||||
tv_regex = {}
|
||||
|
||||
12
setup.py
12
setup.py
@@ -1,19 +1,17 @@
|
||||
from setuptools import setup, find_packages
|
||||
setup(
|
||||
name = 'checkTvEps',
|
||||
name = 'tvorganise',
|
||||
version='0.1',
|
||||
|
||||
author='dbr/Ben',
|
||||
description='A collection of utilties to verify TV episodes match a naming scheme',
|
||||
author='Andrew Williams',
|
||||
description='Utilities to verify TV episode filenames and move them into a organise tree. Forked from dbr/Bens checkTvEps toolset',
|
||||
url='http://github.com/dbr/checktveps/tree/master',
|
||||
license='GPLv2',
|
||||
|
||||
py_modules = ['filename_config', 'checkTvEps', 'checkFilms', 'autoPathTv'],
|
||||
py_modules = ['filename_config', 'tvorganise'],
|
||||
entry_points = {
|
||||
'console_scripts':[
|
||||
'checkTvEps = checkTvEps:main',
|
||||
'checkFilms = checkFilms:main',
|
||||
'autoPathTv = autoPathTv:main'
|
||||
'tvorganise = tvOrganise:main'
|
||||
]
|
||||
},
|
||||
|
||||
|
||||
@@ -1,21 +1,17 @@
|
||||
#!/usr/bin/env python
|
||||
#encoding:utf-8
|
||||
"""
|
||||
autoPathTv.py
|
||||
Use at your own risk. "It works for me".
|
||||
tvorganise.py
|
||||
|
||||
This parses "Show Name - [01x23] - Episode Name.avi"
|
||||
filenames and automatically copies them to
|
||||
/Volumes/aodDrive/video/tv/Show Name/season 1/
|
||||
|
||||
(obviously the path is changable, as is in the input
|
||||
format if you change the reges)
|
||||
the location format defined in the configuration file.
|
||||
"""
|
||||
|
||||
import os, sys, re
|
||||
from optparse import OptionParser
|
||||
import shutil
|
||||
|
||||
|
||||
config = {}
|
||||
regex_config={}
|
||||
|
||||
Reference in New Issue
Block a user