From 4d4ef08ef7e6273746d5d5f2a559a878320098e9 Mon Sep 17 00:00:00 2001 From: Andrew Williams Date: Tue, 26 Jan 2010 10:51:04 +0000 Subject: [PATCH] Reorganised files, changed tagging to tvorganise. Start of fork. --- checkFilms.py | 138 -------------- checkTvEps.py | 326 --------------------------------- filename_config.py | 2 +- setup.py | 14 +- autoPathTv.py => tvorganise.py | 10 +- 5 files changed, 10 insertions(+), 480 deletions(-) delete mode 100755 checkFilms.py delete mode 100755 checkTvEps.py rename autoPathTv.py => tvorganise.py (97%) diff --git a/checkFilms.py b/checkFilms.py deleted file mode 100755 index 8bd75bc..0000000 --- a/checkFilms.py +++ /dev/null @@ -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'] diff --git a/checkTvEps.py b/checkTvEps.py deleted file mode 100755 index a98aedf..0000000 --- a/checkTvEps.py +++ /dev/null @@ -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() \ No newline at end of file diff --git a/filename_config.py b/filename_config.py index 61b8a48..0e9ec8a 100644 --- a/filename_config.py +++ b/filename_config.py @@ -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 = {} diff --git a/setup.py b/setup.py index bb8cbb5..5468d6c 100644 --- a/setup.py +++ b/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' ] }, @@ -27,4 +25,4 @@ classifiers=[ "Topic :: Multimedia", "Topic :: Utilities" ] -) \ No newline at end of file +) diff --git a/autoPathTv.py b/tvorganise.py similarity index 97% rename from autoPathTv.py rename to tvorganise.py index b074820..57b7bf4 100755 --- a/autoPathTv.py +++ b/tvorganise.py @@ -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={}