Reorganised files, changed tagging to tvorganise. Start of fork.

This commit is contained in:
2010-01-26 10:51:04 +00:00
parent f18d5aca10
commit 4d4ef08ef7
5 changed files with 10 additions and 480 deletions

View File

@@ -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']

View File

@@ -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()

View File

@@ -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 = {}

View File

@@ -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'
]
},

View File

@@ -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={}