 |
Peters Flexible RenAmiNg Kit (PFrank) Support and Discussion Site for the PFrank File/Folder Renaming Tool (***NEW HOME PAGE*** "http://pfrank.atwebpages.com")
|
View previous topic :: View next topic |
Author |
Message |
nharding
Joined: 19 Nov 2007 Posts: 11
|
Posted: Sun Nov 25, 2007 3:58 am Post subject: Flexible Date Formatter |
|
|
There doesn't seem to be anyway of doing an attachment, so I've got a cut down version of PfrankUser.py below in the code section.
I tested it with a variety of date formats from files I downloaded from the net. It is VERY flexible on recognising dates, all the following dates are handled correctly (as well as many more).
"Date 2nd July 1967 test",
"Date July-2-1967 test",
"Date Jul 1967 test",
"september-5-43",
"sep 1943",
"5 sept 43",
"Date 17-12-2007 test",
"(1967-07-02) # What the end result should be",
"171207",
"1943 # Not a valid date",
"1943 until 1945-11 # Not a valid date, followed by valid one",
"198507 #YYYYMM",
"July 1st 1961 to 2nd July 1967 # Multiple dates",
You can change the output format by selecting the View \ Options \ Date Formatter. I have added a few small extensions, the month can be a season, or a two month span. So the following are valid dates.
"Christmas 2001",
"Fall 2000",
"March-April 1999",
On outputting the dates if you use month names then the extended forms are used, so format string of %Y %b for the last item in the list above would give 1999 Mar-Apr, and %B %y would give March-April 99. For the extended form of months there is no day field. The extended months have default numeric value associated with them so Christmas 2001 would be 2001-12, Fall 2000 gives 2000-09 and March-April 1999 gives 1999-03 if you are using a numeric format.
Sometimes the day is not available and so there is an extension in the output, and you can use ~ to only display that if day is present. So using an output of Y%-%m~-%d with an input of July 2 1967 would give 1967-07-02, but for an input of July 1967 it would give 1967-07.
Code: |
#!/usr/bin/python
PFrankUserTemplateVersion = 0.2
##########################################
# list your imported modules here.
# If you get import errors, then the modules are not
# present in the environment. In this case you will have to
# insert the required module in the PFrank install folder.
##########################################
# start of user imported modules
import re
import string
import datetime
# end of user imported modules.
##########################################
# The following modules must always be imported
##########################################
# start of required imported modules
try :
from SearchRep_init import configurator
from SearchRepBase import SearchRepBase
from SearchRepConstants import *
except :
from SearchRep_initStubs import configurator
from SearchRepBaseStubs import SearchRepBase
# end of required imported modules
class DateRenamer (SearchRepBase) :
""" This is a date renamer class. The SearchRepLower base class is
mandatory.
"""
def __init__ (self) :
# call base class initializer. This is mandatory
SearchRepBase.__init__(self)
# This is the ID string that will appear in the pre-defined command
# pull down list. It will also appear in the custom list when
# inserted. The id will also be used in the scan summary
# The name 'self.idstring' must not change. Set the assigned string
# on the right-hand side of the assignment statement to whatever
# name you want.
self.idstring = "Convert dates using date formatter"
# This regular expression is "weak", it will let some non dates in
# this is fine, because we do "strong" checks in code
self.date = re.compile(r"""
(?i)^(.*?)
(\d\dst|\d\dnd|\d\drd|\d\dth|\d\d|\dst|\dnd|\drd|\dth|
Jan[-uary. ]+Feb[ruary]*|Feb[-ruary. ]+Mar[ch]*|
Mar[-ch. ]+Apr[il]*|Apr[-il. ]+May|May[-. ]+Jun[e]*|
Jun[-e. ]+Jul[y]*|Jul[-y. ]+Aug[ust]*|
Aug[-ust. ]+Sep[tember]*|Sep[-tember. ]+Oct[ober]*|
Oct[-ober. ]+Nov[ember]*|Nov[-ember. ]+Dec[ember]*|
Dec[-ember. ]+Jan[uary]*|
Jan[uary]*|Feb[ruary]*|Mar[ch]*|Apr[il]*|May|Jun[e]*|
Jul[y]*|Aug[ust]*|Sep[tember]*|Oct[ober]*|Nov[ember]*|
Dec[ember]*|Spring[-. ]*Special*|Easter[-. ]*Special|
Summer[-. ]*Special|Fall[-. ]*Special|Autumn[-. ]*Special|
Winter[-. ]*Special|Christmas[-. ]*Special|
X[-. ]*mas[-. ]*Special|Holiday[-. ]*Special|Spr[ing]*|Eas[ter]*|
Sum[mer]*|Fall|Aut[-mn]*|Win[ter]*|Christmas|X[-. ]*mas|\d)
([-., ]*)
(\d\dst|\d\dnd|\d\drd|\d\dth|\d\d|\dst|\dnd|\drd|\dth|
Jan[-uary. ]+Feb[ruary]*|Feb[-ruary. ]+Mar[ch]*|
Mar[-ch. ]+Apr[il]*|Apr[-il. ]+May|May[-. ]+Jun[e]*|
Jun[-e. ]+Jul[y]*|Jul[-y. ]+Aug[ust]*|
Aug[-ust. ]+Sep[tember]*|Sep[-tember. ]+Oct[ober]*|
Oct[-ober. ]+Nov[ember]*|Nov[-ember. ]+Dec[ember]*|
Dec[-ember. ]+Jan[uary]*|
Jan[uary]*|Feb[ruary]*|Mar[ch]*|Apr[il]*|May|Jun[e]*|
Jul[y]*|Aug[ust]*|Sep[tember]*|Oct[ober]*|Nov[ember]*|
Dec[ember]*|Spring[-. ]*Special*|Easter[-. ]*Special|
Summer[-. ]*Special|Fall[-. ]*Special|Autumn[-. ]*Special|
Winter[-. ]*Special|Christmas[-. ]*Special|
X[-. ]*mas[-. ]*Special|Holiday[-. ]*Special|Spr[ing]*|Eas[ter]*|
Sum[mer]*|Fall|Aut[-mn]*|Win[ter]*|Christmas|X[-. ]*mas|\d)
([-., ]*)
(\d\dst|\d\dnd|\d\drd|\d\dth|\d\d|\dst|\dnd|\drd|\dth|
Jan[-uary. ]+Feb[ruary]*|Feb[-ruary. ]+Mar[ch]*|
Mar[-ch. ]+Apr[il]*|Apr[-il. ]+May|May[-. ]+Jun[e]*|
Jun[-e. ]+Jul[y]*|Jul[-y. ]+Aug[ust]*|
Aug[-ust. ]+Sep[tember]*|Sep[-tember. ]+Oct[ober]*|
Oct[-ober. ]+Nov[ember]*|Nov[-ember. ]+Dec[ember]*|
Dec[-ember. ]+Jan[uary]*|
Jan[uary]*|Feb[ruary]*|Mar[ch]*|Apr[il]*|May|Jun[e]*|
Jul[y]*|Aug[ust]*|Sep[tember]*|Oct[ober]*|Nov[ember]*|
Dec[ember]*|Spring[-. ]*Special*|Easter[-. ]*Special|
Summer[-. ]*Special|Fall[-. ]*Special|Autumn[-. ]*Special|
Winter[-. ]*Special|Christmas[-. ]*Special|
X[-. ]*mas[-. ]*Special|Holiday[-. ]*Special|Spr[ing]*|Eas[ter]*|
Sum[mer]*|Fall|Aut[-mn]*|Win[ter]*|Christmas|X[-. ]*mas|\d)
([-., ]*)
(\d\dst|\d\dnd|\d\drd|\d\dth|\d\d|\dst|\dnd|\drd|\dth|
Jan[-uary. ]+Feb[ruary]*|Feb[-ruary. ]+Mar[ch]*|
Mar[-ch. ]+Apr[il]*|Apr[-il. ]+May|May[-. ]+Jun[e]*|
Jun[-e. ]+Jul[y]*|Jul[-y. ]+Aug[ust]*|
Aug[-ust. ]+Sep[tember]*|Sep[-tember. ]+Oct[ober]*|
Oct[-ober. ]+Nov[ember]*|Nov[-ember. ]+Dec[ember]*|
Dec[-ember. ]+Jan[uary]*|
Jan[uary]*|Feb[ruary]*|Mar[ch]*|Apr[il]*|May|Jun[e]*|
Jul[y]*|Aug[ust]*|Sep[tember]*|Oct[ober]*|Nov[ember]*|
Dec[ember]*|Spring[-. ]*Special*|Easter[-. ]*Special|
Summer[-. ]*Special|Fall[-. ]*Special|Autumn[-. ]*Special|
Winter[-. ]*Special|Christmas[-. ]*Special|
X[-. ]*mas[-. ]*Special|Holiday[-. ]*Special|Spr[ing]*|Eas[ter]*|
Sum[mer]*|Fall|Aut[-mn]*|Win[ter]*|Chr[istmas]*|X[-. ]*mas|\d)?
($|[^0-9]+.*)$ # look for six or 8 digit number in middle of string
# if ends with p, then it is page count and not date
""", re.VERBOSE)
self.number = re.compile(r"(\d\d\d\d|\d\d|\d).*")
self.invalidSeperator = re.compile(r"\w.*")
self.ordinal = re.compile(r"(.*[stndrdth]+.*)")
self.prefixEnd = re.compile(r"[a-zA-Z#]")
self.months = [
re.compile(r"(?i)^Jan[uary]*$"),
re.compile(r"(?i)^Feb[ruary]*$"),
re.compile(r"(?i)^Mar[ch]*$"),
re.compile(r"(?i)^Apr[il]*$"),
re.compile(r"(?i)^May$"),
re.compile(r"(?i)^Jun[e]*$"),
re.compile(r"(?i)^Jul[y]*$"),
re.compile(r"(?i)^Aug[ust]*$"),
re.compile(r"(?i)^Sep[tember]*$"),
re.compile(r"(?i)^Oct[ober]*$"),
re.compile(r"(?i)^Nov[ember]*$"),
re.compile(r"(?i)^Dec[ember]*$"),
re.compile(r"(?i)^Jan[-uary. ]+Feb[ruary]*$"),
re.compile(r"(?i)^Feb[-ruary. ]+Mar[ch]*$"),
re.compile(r"(?i)^Mar[-ch. ]+Apr[il]*$"),
re.compile(r"(?i)^Apr[-il. ]+May$"),
re.compile(r"(?i)^May[-. ]+Jun$"),
re.compile(r"(?i)^Jun[-e. ]+Jul[y]*$"),
re.compile(r"(?i)^Jul[-y. ]+Aug[ust]*$"),
re.compile(r"(?i)^Aug[-ust. ]+Sep[tember]*$"),
re.compile(r"(?i)^Sep[-tember. ]+Oct[ober]*$"),
re.compile(r"(?i)^Oct[-ober. ]+Nov[ember]*$"),
re.compile(r"(?i)^Nov[-ember. ]+Dec[ember]*$"),
re.compile(r"(?i)^Dec[-ember. ]+Jan[uary]*$"),
re.compile(r"(?i)^Spr[ing]*$"),
re.compile(r"(?i)^Eas[ter]*$"),
re.compile(r"(?i)^Sum[mer]*$"),
re.compile(r"(?i)^Fall$|Aut[umn]*$"),
re.compile(r"(?i)^Win[ter]*$"),
re.compile(r"(?i)^Chr[istmas-]*$|X[-]*mas$"),
re.compile(r"(?i)^Spring[-. ]*Special$"),
re.compile(r"(?i)^Easter[-. ]*Special$"),
re.compile(r"(?i)^Summer[-. ]*Special$"),
re.compile(r"(?i)^Fall[-. ]*Special$|Autumn[-. ]Special$"),
re.compile(r"(?i)^Winter[-. ]*Special$"),
re.compile(r"(?i)^Christmas[-. ]*Special$|X[-]*mas[-. ]Special$"),
re.compile(r"(?i)^Holiday[-. ]*Special$"),
]
self.monthValues = [
0,1,2,3,4,5,6,7,8,9,10,11,
0,1,2,3,4,5,6,7,8,9,10,11,
2,3,6,8,10,11,
2,3,6,8,10,11,
]
self.monthNamesShort = [
"Jan","Feb","Mar","Apr","May","Jun",
"Jul","Aug","Sep","Oct","Nov","Dec",
"Jan-Feb","Feb-Mar","Mar-Apr","Apr-May","May-Jun","Jun-Jul",
"Jul-Aug","Aug-Sep","Sep-Oct","Oct-Nov","Nov-Dec","Dec-Jan",
"Spring","Easter","Summer","Fall","Winter","Xmas",
"Spring Special","Easter Special","Summer Special",
"Fall Special","Winter Special","Xmas Special","Holiday Special"
]
self.monthNames = [
"January","February","March","April","May","June",
"July","August","September","October","November","December",
"January-February","February-March","March-April",
"April-May","May-June","June-July","July-August",
"August-September","September-October","October-November",
"November-December","December-January",
"Spring","Easter","Summer","Fall","Winter","Christmas",
"Spring Special","Easter Special","Summer Special",
"Fall Special","Winter Special","Christmas Special",
"Holiday Special"
]
self.dayNamesShort = [
"Mon","Tue","Wed","Thu","Fri","Sat","Sun"
]
self.dayNames = [
"Monday","Tuesday","Wednesday","Thursday",
"Friday","Saturday","Sunday"
]
self.standardFormatFullYear = re.compile(r"YYYY")
self.standardFormatYear = re.compile(r"YY")
self.standardFormatMonth = re.compile(r"MM")
self.standardFormatDay = re.compile(r"DD")
# I have extended custom format, ? means ignore next field IF day is not defined
self.customFormatRemove = re.compile(r"~[-. ]*[%]?.")
self.customFormatClean = re.compile(r"~")
self.customFormatEscape = re.compile(r"%%")
self.customFormatWeekday = re.compile(r"%a")
self.customFormatFullWeekday = re.compile(r"%A")
self.customFormatRemoveExtendedMonth = re.compile(r"[- .]*%[bB]x")
self.customFormatExtendedMonthNamesShort = re.compile(r"%bx")
self.customFormatMonthNamesShort = re.compile(r"%b")
self.customFormatExtendedMonthNames = re.compile(r"%Bx")
self.customFormatMonthNames = re.compile(r"%B")
self.customFormatDay = re.compile(r"%d")
self.customFormatMonth = re.compile(r"%m")
self.customFormatYear = re.compile(r"%y")
self.customFormatFullYear = re.compile(r"%Y")
self.customFormatWeek = re.compile(r"%W")
def initforscan(self, VerificationTest=False) :
"""
This function is called whenever a new scan or rescan is made. Use it to
reset anything that needs to be reinitialized before a scan.
This function is mandatory.
"""
pass
def getInt(self,val) :
"""
This returns val as int or -1, if it isn't valid
It allows for suffix, so 2nd, gives 2
"""
num = self.number.findall(val)
if num == [] :
return -1
return int (num[0])
def getMonthDay(self,month,day) :
"""
Return month and day, if month > 12 then it must be day
"""
if month > 12 :
return day-1,month
else :
return month-1,day
def ZeroPadded(self,num) :
"""
Return 08 rather than 8
"""
if num < 0 :
return "01"
if num < 10 :
return "0" + str(num)
else :
return str(num)
def reformatDate(self,day,month,year) :
"""
Format date according to rename rules
For now just use (YYYY-MM-DD)
"""
dayStr = self.ZeroPadded(day)
monthStr = self.ZeroPadded(self.monthValues[month]+1)
yearStr = self.ZeroPadded(year % 100)
fullYearStr = str(year)
if useCustomDate :
currDay = day
if day <= 0 :
currDay = 1
useDate = datetime.date(year,self.monthValues[month]+1,currDay)
ignoreYear, week, dow = useDate.isocalendar()
newDate = self.customFormatEscape.sub("%",customDateFormat)
if day <0> 11:
newDate = self.customFormatExtendedMonthNamesShort.sub(self.monthNamesShort[month],newDate)
else :
newDate = self.customFormatRemoveExtendedMonth.sub("",newDate)
newDate = self.customFormatMonthNamesShort.sub(self.monthNamesShort[month],newDate)
if month > 11:
newDate = self.customFormatExtendedMonthNames.sub(self.monthNames[month],newDate)
newDate = self.customFormatMonthNames.sub(self.monthNames[month],newDate)
newDate = self.customFormatDay.sub(dayStr,newDate)
newDate = self.customFormatMonth.sub(monthStr,newDate)
newDate = self.customFormatYear.sub(yearStr,newDate)
newDate = self.customFormatFullYear.sub(fullYearStr,newDate)
newDate = self.customFormatWeek.sub(self.ZeroPadded(week),newDate)
else :
newDate = self.standardFormatFullYear.sub(fullYearStr,standardDateFormat)
newDate = self.standardFormatYear.sub(yearStr,newDate)
newDate = self.standardFormatDay.sub(dayStr,newDate)
newDate = self.standardFormatMonth.sub(monthStr,newDate)
newDate = self.standardFormatMonth.sub(monthStr,newDate)
return newDate
def checkIfMonth(self,month) :
"""
Gets index for the month
Input: string to check to see if it is a month (or season)
Output: index of the month (0-11,or season), -1 if not found
"""
if self.number.match(month) != None :
return -1
for curr in range(len(self.months)) :
if self.months[curr].match(month) :
return curr
return -1
def fixnames(self, filename,VerificationTest=False) :
try :
return self.doFixnames(filename,VerificationTest)
except:
print "<Error> in DateRenamer :",filename
return False, filename
def doFixnames(self, filename,VerificationTest=False) :
"""
This function converts name of file to a new name.
Input: string representing the old filename or portion (either All, Prefix, or Extension)
The name does not include the path to the file.
Output: change indicator
True if change to input string occurred, otherwise False
string representing the new filename
When the old filename string is passed into this routine, then depending
on where this user command is placed in the custom list, the string could
be in the middle of a transformation.
e.g. if the original filename was ABCDEF.jpg, and the first command of the
custom list inserted a counter in front of the name, and the second command
was this user command, then the filename string that is passed in could be
something like 0010-ABCDEF.jpg.
This name of course no longer looks like the original name.
If you needed to extract meta data from the file, then you would not be able to
use the passed in string. Therefore the global variable 'configurator.filename' is
provided which has the full path to the filename. You can then just open that name,
extract the meta data, and then close the file.
"""
# full path to original filename
fullPathForFile = configurator.filename
#########################################################################
# Insert code to modify the filename here
#########################################################################
day = 0
year = -1
month = -1
skip = False
append2nd = False
newname = filename
groups = self.date.findall(filename)
eightDigit = False
if groups != [] :
prefix = groups[0][0]
postfix = groups[0][8]
arg1 = groups[0][1]
sep1 = groups[0][2]
arg2 = groups[0][3]
sep2 = groups[0][4]
arg3 = groups[0][5]
sep3 = groups[0][6]
arg4 = groups[0][7]
if postfix == filename :
return False, filename
if self.invalidSeperator.match(postfix) != None :
if (arg4 == '') & (sep3 == '') :
postfix = arg3 + sep3 + arg4 + postfix
arg3 = ''
else :
postfix = arg4 + postfix
arg4 = ''
if self.prefixEnd.match(prefix[-1:]) != None:
if (len(arg1) == 2) & (len(arg2) == 2) & (len(arg3) == 2) & (len(arg4) == 2) & (sep1 == '') & (sep2 == '') & (sep3 == '') :
eightDigit = True
else :
prefix = prefix + arg1 + sep1
arg1 = ''
sep1 = ''
# Ok, it is potential date to get past regular expression
# [0] group is prepender, it used only on replacement
# [1-7] groups are either YY,MM,DD or seperators
# First we want to find the month (for named months & seasons)
month = self.checkIfMonth(arg1)
#if it starts with month, next is either, year or day
if month >= 0 :
day = self.getInt (arg2)
# if day is more than 31, it must be a year
if day > 31 :
year = 1900 + day
day = 0
# if group 4 is [] then there is no seperator between
# digits and it is year, unless day is ordinal (1st,2nd,3rd, etc)
if (sep2 == '') & (self.ordinal.match(arg2) == None) :
year = day * 100 + int (arg3)
day = 0
else :
year = int (arg3)
if arg4 != '' :
year = year * 100 + int (arg4)
elif year <20>= 0:
if (sep2 != sep1) & (self.ordinal.match(arg1) == None) :
append2nd = True
else :
day = self.getInt (arg1)
year = int (arg3)
if arg4 != '' :
year = year * 100 + int (arg4)
elif year < 20 :
year = 2000 + year
else :
year = 1900 + year
else :
#It's either numeric, or YYYY Month
#OR not valid
if (len(sep1) > 0 ) & (len(sep2) > 0) & (sep1 != sep2) :
skip = True
if (eightDigit == False) & (self.prefixEnd.match(prefix[-1:]) != None) :
skip = True
if skip == False :
first = self.getInt(arg1)
second = self.getInt(arg2)
third = self.getInt(arg3)
fourth = self.getInt(arg4)
month = self.checkIfMonth(arg3)
if month >= 0 :
skip = True
if (second > 31) | ((first == 20) & (second < 10)) :
year = first * 100 + second
day = fourth
else :
day = first
if second <10> 11) & (day > 0) :
month = -1
skip = False
#it must be numeric format then, lets do sanity tests
#1943 for example can appear as valid
if (len(arg2) == 1) & (sep2 == '') :
skip = True
# if (sep1 == '') & (sep2 == '-') & (sep3 == '') :
# skip = True
if (len(arg2) == 1) | (len(arg3) == 1) | (len(arg4) == 1) :
skip = True
if skip == False :
if first > 31 :
#Ok, we have YYMMDD, or YYDDMM, assume YYMMDD
#unless month is >= 12
year = 1900 + first
month , day = self.getMonthDay(second,third)
#if month <0>= 19) & (first <20> 31 :
year = 1900 + first
month , day = self.getMonthDay(second,third)
elif third > 31 :
year = 1900 + third
month , day = self.getMonthDay(first,second)
elif (second > 31) | ((second <10> 12
if month > 12 :
month = -1
#Process all the other rules
ignore, tailend = self.fixnames(postfix)
#if we have a valid month, then assume date is valid
if month >= 0 :
if arg4 == '' :
tailend = sep3 + tailend
if append2nd :
newname = prefix + arg1 + sep1 + self.reformatDate(day,month,year) + tailend
else :
newname = prefix + self.reformatDate(day,month,year) + tailend
else :
newname = prefix + arg1 + sep1 + arg2 + sep2 + arg3 + sep3 + arg4 + tailend
#########################################################################
# these statements are mandatory
#########################################################################
change = False
if filename != newname :
change = True
return change, newname
# end of the class definition for DateRenamer
###################################################################
# Create the Renamer Objects in a list. The list is mandatory.
# The name of the list must not change.
# You can list as many names in the list as you like. PFrank will try to
# load all of them. Each name in the list must correspond to the
# name of a user command renaming class. A name can only appear
# once in the list.
#
# User Command Objects are created with the following syntax:
# ClassName()
# i.e. the name of the class followed by ()
###################################################################
UserRenamerList = [
DateRenamer(), # format date as YYYY-MM-DD
]
if __name__ != '__main__' :
standardDateFormat = configurator.optionlist[SEARCHREP_OPTIONDATEFORMAT_ID]
customDateFormat = configurator.optionlist[SEARCHREP_OPTIONCUSTOMDATE_ID]
useCustomDate = configurator.optionlist[SEARCHREP_CUSTOMORFIXEDDATE_ID] == "Custom Format"
######################################
# Code for testing the renamer objects
######################################
if __name__ == '__main__' :
"""
This is some test code to test the renaming objects. Test the code using
the python IDLE tool to verify that things work. Then try importing the file
to PFrank
"""
import os
userpath = os.getcwd()
userpath = os.path.normpath(userpath)
print "Initializing Local Stubs"
###################################################################
# Stubs for Local Testing. These are in addition to the
# stubs imported earlier.
standardDateFormat = "YYYYMMDD"
customDateFormat = "(%Y-%m~-%d %Bx)"
useCustomDate = True
print "Testing User Defined Renaming Classes"
# this is a table of sample filenames for testing
# Assume that the files are in the current folder.
nameTable = [
# Test Date Formating
"Date 2nd July 1967 test",
"Date July-2-1967 test",
"Date Jul 1967 test",
"september-5-43",
"sep 1943",
"5 sept 43",
"Date 17-12-2007 test",
"(1967-07-02) # What the end result should be",
"171207",
"1943 # Not a valid date",
"1943 until 1945-11 # Not a valid date, followed by valid one",
"198507 #YYYYMM",
"July 1st 1961 to 2nd July 1967 # Multiple dates",
"dilbert20060205",
# Now we test padding
# Now we test volume splitting (seperate directories)
# and directories based on Title name
]
# run all the initializers
for renamer in UserRenamerList :
renamer.initforscan()
# run all name fixers
for renamer in UserRenamerList :
print "*************Testing Renamer: ", renamer.idstring
for name in nameTable :
fullpath = os.path.join(os.getcwd(), name)
configurator.filename = os.path.normpath(fullpath)
change, newname = renamer.fixnames(name)
print "Oldname is: ", name
print "Newname is: ", newname
assert (change == (not name == newname))
print ""
|
|
|
Back to top |
|
 |
admin Site Admin
Joined: 09 Mar 2007 Posts: 448 Location: Canada
|
Posted: Mon Nov 26, 2007 7:50 am Post subject: |
|
|
I tried loading the PFrankUser.py excerpt that you provided and it doesn't compile due to these lines:
=====================
else :
year = int (arg3)
if arg4 != '' :
year = year * 100 + int (arg4)
elif year <20>= 0:
if (sep2 != sep1) & (self.ordinal.match(arg1) == None) :
append2nd = True
else :
day = self.getInt (arg1)
year = int (arg3)
if arg4 != '' :
year = year * 100 + int (arg4)
elif year < 20 :
year = 2000 + year
else :
year = 1900 + year
else :
=========================
I would like to try out the file. Would you please send me a copy via email.
Thanks,
Peter. |
|
Back to top |
|
 |
nharding
Joined: 19 Nov 2007 Posts: 11
|
Posted: Sun Dec 02, 2007 1:14 am Post subject: |
|
|
Did you get chance to look at my modified file? If you want to modify it, or include it feel free. (You might want to tidy it up though )
And what do you think of my idea of 2 pass renaming, so that you can see all the files to be processed and then come up with a naming scheme for that. |
|
Back to top |
|
 |
admin Site Admin
Joined: 09 Mar 2007 Posts: 448 Location: Canada
|
Posted: Sun Dec 02, 2007 8:42 am Post subject: |
|
|
I didn't receive any modified file.
Yes - I would like to try it and save it. If other people send me their User files, then I can make those available for all in the future.
Don't know what you mean by the 2 pass renaming. Each row of the custom renaming panel already acts like a renaming pass.
Peter. |
|
Back to top |
|
 |
nharding
Joined: 19 Nov 2007 Posts: 11
|
Posted: Sun Dec 02, 2007 9:55 pm Post subject: |
|
|
I sent another email to you (to the other email address).
When I was talking about 2 pass renaming I was talking about the following.
If I have a selection of files, that when processed give Photo 17, Photo 21, Photo 100, Music 1, Music 10, I would like it to rename them to Photo 017, Photo 021, and Photo 100, Music 01, Music 10. I know how to do a rule to rename n digits to m digits, but I want to write a user command that automatically detects the highest value used for each name, and then pads the other names to match.
Another thing that will use the same code is to automatically move files into subdirectories, so that in the example above it would create Photo and Music directories and move the files into those directories (but only if more than a certain threshold of files was reached).
I also plan on adding something to allow you to automatically prepend then directory name to all the files (and another to move them up in the directory structure). So you could have music\Beetles\Hard Days Night.mp3 and the first command would rename Hard Days Night.mp3 to Beetles - Hard Days Night.mp3, and then the other command would move that file into the music directory. |
|
Back to top |
|
 |
admin Site Admin
Joined: 09 Mar 2007 Posts: 448 Location: Canada
|
Posted: Mon Dec 03, 2007 5:37 am Post subject: |
|
|
Thanks - I received the email.
If I understand your 2-pass renaming idea correctly I think it is already there. i.e. Each row of the custom renaming list is like a pass of renaming.
For example you can insert your user-defined DateFormatter command into row 1 of the list. You can then insert your upcoming user-defined command which move files to Photo and Music folders into row2. Both of those commands can be coded into the PFrankUser.py file and appear as separate commands in the pre-defined drop-down list.
You could add another command into the PFrankUser.py file to prepend folder names; that command can be inserted into row 3. If you weren't looking for the threshold, you could instead add the existing pre-defined command for inserting folder names into row 3. There is also a pathbuilder option for regular expressions which can be used to move the files into different folders (could insert into row 4).
More rows with predefined ocmmand or regex search/replace could be used to do final tweaking like removing uinwanted characters, removing excess blank characters, fixing capitalizations, etc.
Hope this helps,
Peter. |
|
Back to top |
|
 |
nharding
Joined: 19 Nov 2007 Posts: 11
|
Posted: Mon Dec 03, 2007 6:13 am Post subject: |
|
|
You can almost do what I want. But I want it to find all the titles with numbers in them and decide how many digits are needed for each title individually. You need a 2nd pass to do that. Ie Photos (1967) 1, Photos 10 (1973) , Photos_100. After processing through some rules you get Photos 1 (1967), Photos 10 (1973), Photos 100. I want it to say I need 3 digits for the number so that it would become Photos 001 (1967), Photos 010 (1973), Photos 100. If there were just those three files in the directory, it would also know that it doesn't need to move them to a subdirectory. But if you also had Music 1, Music 2, Music 3 then it would decide to create 2 subdirectories, one called Photos and one called Music, it would move the files into the appropriate subdirectories. I want to make it as automated as possible rather than selecting and deselecting rules (I already have a rule to change 3 digit number to 4 digit number) which I select before running the rules. |
|
Back to top |
|
 |
admin Site Admin
Joined: 09 Mar 2007 Posts: 448 Location: Canada
|
Posted: Mon Dec 03, 2007 7:25 am Post subject: |
|
|
OK - I see what you are after.
There is already a post-processing flag for a regex row.
Not sure if there is an easy way to add this functionality for user-defined (or predefined) commands. I'll have to think about it.
One alternative is to use 2 renaming lists. Use the first list to do the post-processing which uses a user-defined command to determine how many digits you need and store that info using a variable in PFrankUser.py. Then use the second list to call the remaining commands, the first of which would use the variable to convert numbers to their required number of digits.
Peter. |
|
Back to top |
|
 |
admin Site Admin
Joined: 09 Mar 2007 Posts: 448 Location: Canada
|
Posted: Tue Dec 04, 2007 6:40 am Post subject: |
|
|
I've had alook at this and have 2 possible solutions.
1)
I adapted the postprocessing available for regex lines to also be available for pre-defined commands (which includes user-defined commands). I still have to test it and decide on a syntax for pre-defined flags. This will be available sometime in the future. However, this is really meant to do post-processing after all the duplication checking. What you really need is preprocessing.
2)
For preprocessing you can use the already available initforscan function which is defined for all user-defined commands. This is currently called once before the scanning starts. I am going to rearrange the scanner so that this function is called just after obtaining the initial list of names using the name filters. The name list will be made available as a global variable which you can access.
Then in the initforscan for your user-defined dateformatter (or perhaps some new user command), you can prescan all the names and determine how large a number field you will need and how many names would be changed. then the regular processing would commence with all the new information.
Does that sound like it could work for you?
If so, I can have a beta program ready tomorrow.
Peter. |
|
Back to top |
|
 |
nharding
Joined: 19 Nov 2007 Posts: 11
|
Posted: Tue Dec 04, 2007 4:14 pm Post subject: |
|
|
That sounds good thanks, I will be making a new command. I'm already working on another new one that will prepend directory name to the file names (it's a LOT more complex than that though). If you have a directory called Music To Die For\ and files called Music To Die For 1.mp3 MTDF 2.mp3, 3.mp3, then it will rename MTDF 2 and 3. |
|
Back to top |
|
 |
admin Site Admin
Joined: 09 Mar 2007 Posts: 448 Location: Canada
|
Posted: Wed Dec 05, 2007 2:49 am Post subject: |
|
|
A beta is available at:
http://www3.telus.net/pfrank/PFrankSetup2.111.exe
It has the global scanlist that you can access in your PFrankUser.py file using the initforscan function. The variable is in 'configurator.scanlist'. The example below prints the list:
===================================
def initforscan(self, VerificationTest=False) :
"""
This function is called whenever a new scan or rescan is made. Use it to
reset anything that needs to be reinitialized before a scan.
This function is mandatory.
"""
print "scan list is: ", configurator.scanlist
===================================
This is the list of names that have passed the name filtering. You should be able to process the list to determine how many digits your numbers need, etc.
Let me know if there are any problems
Peter. |
|
Back to top |
|
 |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
|