diff options
Diffstat (limited to 'rapid/renamesubfolderprefs.py')
-rw-r--r-- | rapid/renamesubfolderprefs.py | 1693 |
1 files changed, 0 insertions, 1693 deletions
diff --git a/rapid/renamesubfolderprefs.py b/rapid/renamesubfolderprefs.py deleted file mode 100644 index d46a8c1..0000000 --- a/rapid/renamesubfolderprefs.py +++ /dev/null @@ -1,1693 +0,0 @@ -#!/usr/bin/python -# -*- coding: latin1 -*- - -### Copyright (C) 2007, 2008, 2009, 2010 Damon Lynch <damonlynch@gmail.com> - -### This program is free software; you can redistribute it and/or modify -### it under the terms of the GNU General Public License as published by -### the Free Software Foundation; either version 2 of the License, or -### (at your option) any later version. - -### This program is distributed in the hope that it will be useful, -### but WITHOUT ANY WARRANTY; without even the implied warranty of -### MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -### GNU General Public License for more details. - -### You should have received a copy of the GNU General Public License -### along with this program; if not, write to the Free Software -### Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -""" Define and test preferences for use in PlusMinus tables. - -These are displayed to the user as a series of rows in the user -preferences dialog window. - -Preferences for subfolders and image renaming are defined below -in dictionaries and lists. This makes it easier for checking validity and -creating combo boxes. - -There are 3 levels: 0, 1 and 2, which specify the depth of the pref value. -Level 0 is the topmost level, and corresponds to the first entry in the -row of preferences the user sees in the preferences dialog window. - -Custom exceptions are defined to handle invalid preferences. - -The user's actual preferences, on the other hand, are stored in flat lists. -Each list has members which are a multiple of 3 in length. -Each group of 3 members is equal to one line of preferences in the plus minus -table. -""" -#needed for python 2.5, unneeded for python 2.6 -from __future__ import with_statement - -import string - -import os -import re -import sys - -import gtk.gdk as gdk - -try: - import pygtk - pygtk.require("2.0") -except: - pass -try: - import gtk -except: - sys.exit(1) - -from common import Configi18n -global _ -_ = Configi18n._ - -import datetime - -import config - -from common import pythonifyVersion -import problemnotification as pn - - -# Special key in each dictionary which specifies the order of elements. -# It is very important to have a consistent and rational order when displaying -# these prefs to the user, and dictionaries are unsorted. - -ORDER_KEY = "__order__" - -# PLEASE NOTE: these values are duplicated in a dummy class whose function -# is to have them put into the translation template. If you change the values below -# then you MUST change the value in class i18TranslateMeThanks as well!! - -# *** Level 0 -DATE_TIME = 'Date time' -TEXT = 'Text' -FILENAME = 'Filename' -METADATA = 'Metadata' -SEQUENCES = 'Sequences' -JOB_CODE = 'Job code' - -SEPARATOR = os.sep - -# *** Level 1 - -# Date time -IMAGE_DATE = 'Image date' -TODAY = 'Today' -YESTERDAY = 'Yesterday' -VIDEO_DATE = 'Video date' -DOWNLOAD_TIME = 'Download time' - -# File name -NAME_EXTENSION = 'Name + extension' -NAME = 'Name' -EXTENSION = 'Extension' -IMAGE_NUMBER = 'Image number' -VIDEO_NUMBER = 'Video number' - -# Metadata -APERTURE = 'Aperture' -ISO = 'ISO' -EXPOSURE_TIME = 'Exposure time' -FOCAL_LENGTH = 'Focal length' -CAMERA_MAKE = 'Camera make' -CAMERA_MODEL = 'Camera model' -SHORT_CAMERA_MODEL = 'Short camera model' -SHORT_CAMERA_MODEL_HYPHEN = 'Hyphenated short camera model' -SERIAL_NUMBER = 'Serial number' -SHUTTER_COUNT = 'Shutter count' -OWNER_NAME = 'Owner name' - -# Video metadata -CODEC = 'Codec' -WIDTH = 'Width' -HEIGHT = 'Height' -FPS = 'Frames Per Second' -LENGTH = 'Length' - -#Image sequences -DOWNLOAD_SEQ_NUMBER = 'Downloads today' -SESSION_SEQ_NUMBER = 'Session number' -SUBFOLDER_SEQ_NUMBER = 'Subfolder number' -STORED_SEQ_NUMBER = 'Stored number' - -SEQUENCE_LETTER = 'Sequence letter' - - - -# *** Level 2 - -# Image number -IMAGE_NUMBER_ALL = 'All digits' -IMAGE_NUMBER_1 = 'Last digit' -IMAGE_NUMBER_2 = 'Last 2 digits' -IMAGE_NUMBER_3 = 'Last 3 digits' -IMAGE_NUMBER_4 = 'Last 4 digits' - - -# Case -ORIGINAL_CASE = "Original Case" -UPPERCASE = "UPPERCASE" -LOWERCASE = "lowercase" - -# Sequence number -SEQUENCE_NUMBER_1 = "One digit" -SEQUENCE_NUMBER_2 = "Two digits" -SEQUENCE_NUMBER_3 = "Three digits" -SEQUENCE_NUMBER_4 = "Four digits" -SEQUENCE_NUMBER_5 = "Five digits" -SEQUENCE_NUMBER_6 = "Six digits" -SEQUENCE_NUMBER_7 = "Seven digits" - - -# Now, define dictionaries and lists of valid combinations of preferences. - -# Level 2 - -# Date - -SUBSECONDS = 'Subseconds' - -# ****** NOTE 1: if changing LIST_DATE_TIME_L2, you MUST update the default subfolder preference below ***** -# ****** NOTE 2: if changing LIST_DATE_TIME_L2, you MUST update DATE_TIME_CONVERT below ***** -LIST_DATE_TIME_L2 = ['YYYYMMDD', 'YYYY-MM-DD','YYMMDD', 'YY-MM-DD', - 'MMDDYYYY', 'MMDDYY', 'MMDD', - 'DDMMYYYY', 'DDMMYY', 'YYYY', 'YY', - 'MM', 'DD', - 'HHMMSS', 'HHMM', 'HH-MM-SS', 'HH-MM', 'HH', 'MM (minutes)', 'SS'] - - -LIST_IMAGE_DATE_TIME_L2 = LIST_DATE_TIME_L2 + [SUBSECONDS] - -DEFAULT_SUBFOLDER_PREFS = [DATE_TIME, IMAGE_DATE, LIST_DATE_TIME_L2[9], '/', '', '', DATE_TIME, IMAGE_DATE, LIST_DATE_TIME_L2[0]] -DEFAULT_VIDEO_SUBFOLDER_PREFS = [DATE_TIME, VIDEO_DATE, LIST_DATE_TIME_L2[9], '/', '', '', DATE_TIME, VIDEO_DATE, LIST_DATE_TIME_L2[0]] - -class i18TranslateMeThanks: - """ this class is never used in actual running code - It's purpose is to have these values inserted into the program's i18n template file - - """ - def __init__(self): - _('Date time') - _('Text') - _('Filename') - _('Metadata') - _('Sequences') - # Translators: for an explanation of what this means, see http://damonlynch.net/rapid/documentation/index.html#jobcode - _('Job code') - _('Image date') - _('Video date') - _('Today') - _('Yesterday') - # Translators: Download time is the time and date that the download started (when the user clicked the Download button) - _('Download time') - # Translators: for an explanation of what this means, see http://damonlynch.net/rapid/documentation/index.html#renamefilename - _('Name + extension') - # Translators: for an explanation of what this means, see http://damonlynch.net/rapid/documentation/index.html#renamefilename - _('Name') - # Translators: for an explanation of what this means, see http://damonlynch.net/rapid/documentation/index.html#renamefilename - _('Extension') - # Translators: for an explanation of what this means, see http://damonlynch.net/rapid/documentation/index.html#renamefilename - _('Image number') - _('Video number') - # Translators: for an explanation of what this means, see http://damonlynch.net/rapid/documentation/index.html#renamemetadata - _('Aperture') - # Translators: for an explanation of what this means, see http://damonlynch.net/rapid/documentation/index.html#renamemetadata - _('ISO') - # Translators: for an explanation of what this means, see http://damonlynch.net/rapid/documentation/index.html#renamemetadata - _('Exposure time') - # Translators: for an explanation of what this means, see http://damonlynch.net/rapid/documentation/index.html#renamemetadata - _('Focal length') - # Translators: for an explanation of what this means, see http://damonlynch.net/rapid/documentation/index.html#renamemetadata - _('Camera make') - # Translators: for an explanation of what this means, see http://damonlynch.net/rapid/documentation/index.html#renamemetadata - _('Camera model') - # Translators: for an explanation of what this means, see http://damonlynch.net/rapid/documentation/index.html#renamemetadata - _('Short camera model') - # Translators: for an explanation of what this means, see http://damonlynch.net/rapid/documentation/index.html#renamemetadata - _('Hyphenated short camera model') - # Translators: for an explanation of what this means, see http://damonlynch.net/rapid/documentation/index.html#renamemetadata - _('Serial number') - # Translators: for an explanation of what this means, see http://damonlynch.net/rapid/documentation/index.html#renamemetadata - _('Shutter count') - # Translators: for an explanation of what this means, see http://damonlynch.net/rapid/documentation/index.html#renamemetadata - _('Owner name') - _('Codec') - _('Width') - _('Height') - _('Length') - _('Frames Per Second') - # Translators: for an explanation of what this means, see http://damonlynch.net/rapid/documentation/index.html#sequencenumbers - _('Downloads today') - # Translators: for an explanation of what this means, see http://damonlynch.net/rapid/documentation/index.html#sequencenumbers - _('Session number') - # Translators: for an explanation of what this means, see http://damonlynch.net/rapid/documentation/index.html#sequencenumbers - _('Subfolder number') - # Translators: for an explanation of what this means, see http://damonlynch.net/rapid/documentation/index.html#sequencenumbers - _('Stored number') - # Translators: for an explanation of what this means, see http://damonlynch.net/rapid/documentation/index.html#sequenceletters - _('Sequence letter') - # Translators: for an explanation of what this means, see http://damonlynch.net/rapid/documentation/index.html#renamefilename - _('All digits') - # Translators: for an explanation of what this means, see http://damonlynch.net/rapid/documentation/index.html#renamefilename - _('Last digit') - # Translators: for an explanation of what this means, see http://damonlynch.net/rapid/documentation/index.html#renamefilename - _('Last 2 digits') - # Translators: for an explanation of what this means, see http://damonlynch.net/rapid/documentation/index.html#renamefilename - _('Last 3 digits') - # Translators: for an explanation of what this means, see http://damonlynch.net/rapid/documentation/index.html#renamefilename - _('Last 4 digits') - # Translators: please not the capitalization of this text, and keep it the same if your language features capitalization - _("Original Case") - # Translators: please not the capitalization of this text, and keep it the same if your language features capitalization - _("UPPERCASE") - # Translators: please not the capitalization of this text, and keep it the same if your language features capitalization - _("lowercase") - _("One digit") - _("Two digits") - _("Three digits") - _("Four digits") - _("Five digits") - _("Six digits") - _("Seven digits") - # Translators: for an explanation of what this means, see http://damonlynch.net/rapid/documentation/index.html#renamedateandtime - _('Subseconds') - # Translators: for an explanation of what this means, see http://damonlynch.net/rapid/documentation/index.html#renamedateandtime - _('YYYYMMDD') - # Translators: for an explanation of what this means, see http://damonlynch.net/rapid/documentation/index.html#renamedateandtime - _('YYYY-MM-DD') - # Translators: for an explanation of what this means, see http://damonlynch.net/rapid/documentation/index.html#renamedateandtime - _('YYMMDD') - # Translators: for an explanation of what this means, see http://damonlynch.net/rapid/documentation/index.html#renamedateandtime - _('YY-MM-DD') - # Translators: for an explanation of what this means, see http://damonlynch.net/rapid/documentation/index.html#renamedateandtime - _('MMDDYYYY') - # Translators: for an explanation of what this means, see http://damonlynch.net/rapid/documentation/index.html#renamedateandtime - _('MMDDYY') - # Translators: for an explanation of what this means, see http://damonlynch.net/rapid/documentation/index.html#renamedateandtime - _('MMDD') - # Translators: for an explanation of what this means, see http://damonlynch.net/rapid/documentation/index.html#renamedateandtime - _('DDMMYYYY') - # Translators: for an explanation of what this means, see http://damonlynch.net/rapid/documentation/index.html#renamedateandtime - _('DDMMYY') - # Translators: for an explanation of what this means, see http://damonlynch.net/rapid/documentation/index.html#renamedateandtime - _('YYYY') - # Translators: for an explanation of what this means, see http://damonlynch.net/rapid/documentation/index.html#renamedateandtime - _('YY') - # Translators: for an explanation of what this means, see http://damonlynch.net/rapid/documentation/index.html#renamedateandtime - _('MM') - # Translators: for an explanation of what this means, see http://damonlynch.net/rapid/documentation/index.html#renamedateandtime - _('DD') - # Translators: for an explanation of what this means, see http://damonlynch.net/rapid/documentation/index.html#renamedateandtime - _('HHMMSS') - # Translators: for an explanation of what this means, see http://damonlynch.net/rapid/documentation/index.html#renamedateandtime - _('HHMM') - # Translators: for an explanation of what this means, see http://damonlynch.net/rapid/documentation/index.html#renamedateandtime - _('HH-MM-SS') - # Translators: for an explanation of what this means, see http://damonlynch.net/rapid/documentation/index.html#renamedateandtime - _('HH-MM') - # Translators: for an explanation of what this means, see http://damonlynch.net/rapid/documentation/index.html#renamedateandtime - _('HH') - # Translators: for an explanation of what this means, see http://damonlynch.net/rapid/documentation/index.html#renamedateandtime - _('MM (minutes)') - # Translators: for an explanation of what this means, see http://damonlynch.net/rapid/documentation/index.html#renamedateandtime - _('SS') - - -# Convenience values for python datetime conversion using values in -# LIST_DATE_TIME_L2. Obviously the two must remain synchronized. - -DATE_TIME_CONVERT = ['%Y%m%d', '%Y-%m-%d','%y%m%d', '%y-%m-%d', - '%m%d%Y', '%m%d%y', '%m%d', - '%d%m%Y', '%d%m%y', '%Y', '%y', - '%m', '%d', - '%H%M%S', '%H%M', '%H-%M-%S', '%H-%M', - '%H', '%M', '%S'] - - -LIST_IMAGE_NUMBER_L2 = [IMAGE_NUMBER_ALL, IMAGE_NUMBER_1, IMAGE_NUMBER_2, - IMAGE_NUMBER_3, IMAGE_NUMBER_4] - - -LIST_CASE_L2 = [ORIGINAL_CASE, UPPERCASE, LOWERCASE] - -LIST_SEQUENCE_LETTER_L2 = [ - UPPERCASE, - LOWERCASE - ] - - - -LIST_SEQUENCE_NUMBERS_L2 = [ - SEQUENCE_NUMBER_1, - SEQUENCE_NUMBER_2, - SEQUENCE_NUMBER_3, - SEQUENCE_NUMBER_4, - SEQUENCE_NUMBER_5, - SEQUENCE_NUMBER_6, - SEQUENCE_NUMBER_7, - ] - - - -LIST_SHUTTER_COUNT_L2 = [ - SEQUENCE_NUMBER_3, - SEQUENCE_NUMBER_4, - SEQUENCE_NUMBER_5, - SEQUENCE_NUMBER_6, - ] - -# Level 1 -LIST_DATE_TIME_L1 = [IMAGE_DATE, TODAY, YESTERDAY, DOWNLOAD_TIME] -LIST_VIDEO_DATE_TIME_L1 = [VIDEO_DATE, TODAY, YESTERDAY, DOWNLOAD_TIME] - -DICT_DATE_TIME_L1 = { - IMAGE_DATE: LIST_IMAGE_DATE_TIME_L2, - TODAY: LIST_DATE_TIME_L2, - YESTERDAY: LIST_DATE_TIME_L2, - DOWNLOAD_TIME: LIST_DATE_TIME_L2, - ORDER_KEY: LIST_DATE_TIME_L1 - } - -VIDEO_DICT_DATE_TIME_L1 = { - VIDEO_DATE: LIST_IMAGE_DATE_TIME_L2, - TODAY: LIST_DATE_TIME_L2, - YESTERDAY: LIST_DATE_TIME_L2, - DOWNLOAD_TIME: LIST_DATE_TIME_L2, - ORDER_KEY: LIST_VIDEO_DATE_TIME_L1 - } - - -LIST_FILENAME_L1 = [NAME_EXTENSION, NAME, EXTENSION, IMAGE_NUMBER] - -DICT_FILENAME_L1 = { - NAME_EXTENSION: LIST_CASE_L2, - NAME: LIST_CASE_L2, - EXTENSION: LIST_CASE_L2, - IMAGE_NUMBER: LIST_IMAGE_NUMBER_L2, - ORDER_KEY: LIST_FILENAME_L1 - } - -LIST_VIDEO_FILENAME_L1 = [NAME_EXTENSION, NAME, EXTENSION, VIDEO_NUMBER] - -DICT_VIDEO_FILENAME_L1 = { - NAME_EXTENSION: LIST_CASE_L2, - NAME: LIST_CASE_L2, - EXTENSION: LIST_CASE_L2, - VIDEO_NUMBER: LIST_IMAGE_NUMBER_L2, - ORDER_KEY: LIST_VIDEO_FILENAME_L1 - } - - -LIST_SUBFOLDER_FILENAME_L1 = [EXTENSION] - -DICT_SUBFOLDER_FILENAME_L1 = { - EXTENSION: LIST_CASE_L2, - ORDER_KEY: LIST_SUBFOLDER_FILENAME_L1 -} - -LIST_METADATA_L1 = [APERTURE, ISO, EXPOSURE_TIME, FOCAL_LENGTH, - CAMERA_MAKE, CAMERA_MODEL, - SHORT_CAMERA_MODEL, - SHORT_CAMERA_MODEL_HYPHEN, - SERIAL_NUMBER, - SHUTTER_COUNT, - OWNER_NAME] - -LIST_VIDEO_METADATA_L1 = [CODEC, WIDTH, HEIGHT, LENGTH, FPS] - -DICT_METADATA_L1 = { - APERTURE: None, - ISO: None, - EXPOSURE_TIME: None, - FOCAL_LENGTH: None, - CAMERA_MAKE: LIST_CASE_L2, - CAMERA_MODEL: LIST_CASE_L2, - SHORT_CAMERA_MODEL: LIST_CASE_L2, - SHORT_CAMERA_MODEL_HYPHEN: LIST_CASE_L2, - SERIAL_NUMBER: None, - SHUTTER_COUNT: LIST_SHUTTER_COUNT_L2, - OWNER_NAME: LIST_CASE_L2, - ORDER_KEY: LIST_METADATA_L1 - } - -DICT_VIDEO_METADATA_L1 = { - CODEC: LIST_CASE_L2, - WIDTH: None, - HEIGHT: None, - LENGTH: None, - FPS: None, - ORDER_KEY: LIST_VIDEO_METADATA_L1 - } - -LIST_SEQUENCE_L1 = [ - DOWNLOAD_SEQ_NUMBER, - STORED_SEQ_NUMBER, - SESSION_SEQ_NUMBER, - SEQUENCE_LETTER - ] - -DICT_SEQUENCE_L1 = { - DOWNLOAD_SEQ_NUMBER: LIST_SEQUENCE_NUMBERS_L2, - STORED_SEQ_NUMBER: LIST_SEQUENCE_NUMBERS_L2, - SESSION_SEQ_NUMBER: LIST_SEQUENCE_NUMBERS_L2, - SEQUENCE_LETTER: LIST_SEQUENCE_LETTER_L2, - ORDER_KEY: LIST_SEQUENCE_L1 - } - - -# Level 0 - - -LIST_IMAGE_RENAME_L0 = [DATE_TIME, TEXT, FILENAME, METADATA, - SEQUENCES, JOB_CODE] - -LIST_VIDEO_RENAME_L0 = LIST_IMAGE_RENAME_L0 - - -DICT_IMAGE_RENAME_L0 = { - DATE_TIME: DICT_DATE_TIME_L1, - TEXT: None, - FILENAME: DICT_FILENAME_L1, - METADATA: DICT_METADATA_L1, - SEQUENCES: DICT_SEQUENCE_L1, - JOB_CODE: None, - ORDER_KEY: LIST_IMAGE_RENAME_L0 - } - -DICT_VIDEO_RENAME_L0 = { - DATE_TIME: VIDEO_DICT_DATE_TIME_L1, - TEXT: None, - FILENAME: DICT_VIDEO_FILENAME_L1, - METADATA: DICT_VIDEO_METADATA_L1, - SEQUENCES: DICT_SEQUENCE_L1, - JOB_CODE: None, - ORDER_KEY: LIST_VIDEO_RENAME_L0 - } - -LIST_SUBFOLDER_L0 = [DATE_TIME, TEXT, FILENAME, METADATA, JOB_CODE, SEPARATOR] - -DICT_SUBFOLDER_L0 = { - DATE_TIME: DICT_DATE_TIME_L1, - TEXT: None, - FILENAME: DICT_SUBFOLDER_FILENAME_L1, - METADATA: DICT_METADATA_L1, - JOB_CODE: None, - SEPARATOR: None, - ORDER_KEY: LIST_SUBFOLDER_L0 - } - -LIST_VIDEO_SUBFOLDER_L0 = [DATE_TIME, TEXT, FILENAME, METADATA, JOB_CODE, SEPARATOR] - -DICT_VIDEO_SUBFOLDER_L0 = { - DATE_TIME: VIDEO_DICT_DATE_TIME_L1, - TEXT: None, - FILENAME: DICT_SUBFOLDER_FILENAME_L1, - METADATA: DICT_VIDEO_METADATA_L1, - JOB_CODE: None, - SEPARATOR: None, - ORDER_KEY: LIST_VIDEO_SUBFOLDER_L0 - } - -# preference elements that require metadata -# note there is no need to specify lower level elements if a higher level -# element is necessary for them to be present to begin with -METADATA_ELEMENTS = [METADATA, IMAGE_DATE] - -# preference elements that are sequence numbers or letters -SEQUENCE_ELEMENTS = [ - DOWNLOAD_SEQ_NUMBER, - SESSION_SEQ_NUMBER, - SUBFOLDER_SEQ_NUMBER, - STORED_SEQ_NUMBER, - SEQUENCE_LETTER] - -# preference elements that do not require metadata and are not fixed -# as above, there is no need to specify lower level elements if a higher level -# element is necessary for them to be present to begin with -DYNAMIC_NON_METADATA_ELEMENTS = [ - TODAY, YESTERDAY, - FILENAME] + SEQUENCE_ELEMENTS - - - -#the following is what the preferences looked in older versions of the program -#they are here for reference, and for checking the validity of preferences - -USER_INPUT = 'User' - -DOWNLOAD_SEQ_NUMBER_V_0_0_8_B7 = 'Downloads today' -SESSION_SEQ_NUMBER_V_0_0_8_B7 = 'Session sequence number' -SUBFOLDER_SEQ_NUMBER_V_0_0_8_B7 = 'Subfolder sequence number' -STORED_SEQ_NUMBER_V_0_0_8_B7 = 'Stored sequence number' -SEQUENCE_LETTER_V_0_0_8_B7 = 'Sequence letter' - -LIST_SEQUENCE_NUMBERS_L1_L2_V_0_0_8_B7 = [ - SEQUENCE_NUMBER_1, - SEQUENCE_NUMBER_2, - SEQUENCE_NUMBER_3, - SEQUENCE_NUMBER_4, - SEQUENCE_NUMBER_5, - SEQUENCE_NUMBER_6, - ] - -DICT_SEQUENCE_NUMBERS_L1_L2_V_0_0_8_B7 = { - SEQUENCE_NUMBER_1: None, - SEQUENCE_NUMBER_2: None, - SEQUENCE_NUMBER_3: None, - SEQUENCE_NUMBER_4: None, - SEQUENCE_NUMBER_5: None, - SEQUENCE_NUMBER_6: None, - ORDER_KEY: LIST_SEQUENCE_NUMBERS_L1_L2_V_0_0_8_B7 - } - -LIST_SEQUENCE_L1_V_0_0_8_B7 = [USER_INPUT] - -DICT_SEQUENCE_L1_V_0_0_8_B7 = { - USER_INPUT: DICT_SEQUENCE_NUMBERS_L1_L2_V_0_0_8_B7, - ORDER_KEY: LIST_SEQUENCE_L1_V_0_0_8_B7 - } - -LIST_SEQUENCE_LETTER_L1_L1_V_0_0_8_B7 = [ - UPPERCASE, - LOWERCASE - ] - -DICT_SEQUENCE_LETTER_L1_V_0_0_8_B7 = { - UPPERCASE: None, - LOWERCASE: None, - ORDER_KEY: LIST_SEQUENCE_LETTER_L1_L1_V_0_0_8_B7 - } - -LIST_IMAGE_RENAME_L0_V_0_0_8_B7 = [DATE_TIME, TEXT, FILENAME, METADATA, - DOWNLOAD_SEQ_NUMBER_V_0_0_8_B7, - SESSION_SEQ_NUMBER_V_0_0_8_B7, - SEQUENCE_LETTER_V_0_0_8_B7] - -DICT_IMAGE_RENAME_L0_V_0_0_8_B7 = { - DATE_TIME: DICT_DATE_TIME_L1, - TEXT: None, - FILENAME: DICT_FILENAME_L1, - METADATA: DICT_METADATA_L1, - DOWNLOAD_SEQ_NUMBER_V_0_0_8_B7: None, - SESSION_SEQ_NUMBER_V_0_0_8_B7: None, - SEQUENCE_LETTER_V_0_0_8_B7: DICT_SEQUENCE_LETTER_L1_V_0_0_8_B7, - ORDER_KEY: LIST_IMAGE_RENAME_L0_V_0_0_8_B7 - } - -PREVIOUS_IMAGE_RENAME= { - '0.0.8~b7': DICT_IMAGE_RENAME_L0_V_0_0_8_B7, - } - - -# Functions to work with above data - -def _getPrevPrefs(oldDefs, currentDefs, previousVersion): - k = oldDefs.keys() - # if there were other defns, we'd need to figure out which one - # but currently, there are no others - # there will be in future, and this code wil be updated then - version_change = pythonifyVersion(k[0]) - if pythonifyVersion(previousVersion) <= version_change: - return oldDefs[k[0]] - else: - return currentDefs - -def _upgradePreferencesToCurrent(prefs, previousVersion): - """ checks to see if preferences should be upgraded - - returns True if they were upgraded, and the new prefs - - VERY IMPORTANT: the new prefs will be a new list, not an inplace - modification of the existing preferences! Otherwise, the check on - assignment in the prefs.py __setattr__ will not work as expected!! - """ - upgraded = False - # code to upgrade from <= 0.0.8~b7 to >= 0.0.8~b8 - p = [] - for i in range(0, len(prefs), 3): - if prefs[i] in [SEQUENCE_LETTER_V_0_0_8_B7, SESSION_SEQ_NUMBER_V_0_0_8_B7]: - upgraded = True - p.append(SEQUENCES) - if prefs[i] == SEQUENCE_LETTER_V_0_0_8_B7: - p.append(SEQUENCE_LETTER) - p.append(prefs[i+1]) - else: - p.append(SESSION_SEQ_NUMBER) - p.append(prefs[i+2]) - else: - p += prefs[i:i+3] - - assert(len(prefs)==len(p)) - return (upgraded, p) - - -def upgradePreferencesToCurrent(imageRenamePrefs, subfolderPrefs, previousVersion): - """Upgrades user preferences to current version - - returns True if the preferences were upgraded""" - - # only check image rename, for now.... - upgraded, imageRenamePrefs = _upgradePreferencesToCurrent(imageRenamePrefs, previousVersion) - return (upgraded, imageRenamePrefs , subfolderPrefs) - - -def usesJobCode(prefs): - """ Returns True if the preferences contain a job code, else returns False""" - for i in range(0, len(prefs), 3): - if prefs[i] == JOB_CODE: - return True - return False - -def checkPreferencesForValidity(imageRenamePrefs, subfolderPrefs, videoRenamePrefs, videoSubfolderPrefs, version=config.version): - """ - Checks preferences for validity (called at program startup) - - Returns true if the passed in preferences are valid, else returns False - """ - - if version == config.version: - try: - tests = ((imageRenamePrefs, ImageRenamePreferences), - (subfolderPrefs, SubfolderPreferences), - (videoRenamePrefs, VideoRenamePreferences), - (videoSubfolderPrefs, VideoSubfolderPreferences)) - for i, Prefs in tests: - p = Prefs(i, None) - p.checkPrefsForValidity() - except: - return False - return True - else: - defn = _getPrevPrefs(PREVIOUS_IMAGE_RENAME, DICT_IMAGE_RENAME_L0, version) - try: - checkPreferenceValid(defn, imageRenamePrefs) - checkPreferenceValid(DICT_SUBFOLDER_L0, subfolderPrefs) - checkPreferenceValid(DICT_VIDEO_SUBFOLDER_L0, videoSubfolderPrefs) - checkPreferenceValid(DICT_VIDEO_RENAME_L0, videoRenamePrefs) - except: - return False - return True - -def checkPreferenceValid(prefDefinition, prefs, modulo=3): - """ - Checks to see if prefs are valid according to definition. - - prefs is a list of preferences. - prefDefinition is a Dict specifying what is valid. - modulo is how many list elements are equivalent to one line of preferences. - - Returns True if prefs match with prefDefinition, - else raises appropriate error. - """ - - if (len(prefs) % modulo <> 0) or not prefs: - raise PrefLengthError(prefs) - else: - for i in range(0, len(prefs), modulo): - _checkPreferenceValid(prefDefinition, prefs[i:i+modulo]) - - return True - -def _checkPreferenceValid(prefDefinition, prefs): - - key = prefs[0] - value = prefs[1] - - - if prefDefinition.has_key(key): - - nextPrefDefinition = prefDefinition[key] - - if value == None: - # value should never be None, at any time - raise PrefValueInvalidError((None, nextPrefDefinition)) - - if nextPrefDefinition and not value: - raise PrefValueInvalidError((value, nextPrefDefinition)) - - if type(nextPrefDefinition) == type({}): - return _checkPreferenceValid(nextPrefDefinition, prefs[1:]) - else: - if type(nextPrefDefinition) == type([]): - result = value in nextPrefDefinition - if not result: - raise PrefValueInvalidError((value, nextPrefDefinition)) - return True - elif not nextPrefDefinition: - return True - else: - result = nextPrefDefinition == value - if not result: - raise PrefKeyValue((value, nextPrefDefinition)) - return True - else: - raise PrefKeyError((key, prefDefinition[ORDER_KEY])) - -def filterSubfolderPreferences(prefList): - """ - Filters out extraneous preference choices - """ - prefs_changed = False - continueCheck = True - while continueCheck and prefList: - continueCheck = False - if prefList[0] == SEPARATOR: - # Subfolder preferences should not start with a / - prefList = prefList[3:] - prefs_changed = True - continueCheck = True - elif prefList[-3] == SEPARATOR: - # Subfolder preferences should not end with a / - prefList = prefList[:-3] - continueCheck = True - prefs_changed = True - else: - for i in range(0, len(prefList) - 3, 3): - if prefList[i] == SEPARATOR and prefList[i+3] == SEPARATOR: - # Subfolder preferences should not contain two /s side by side - continueCheck = True - prefs_changed = True - # note we are messing with the contents of the pref list, - # must exit loop and try again - prefList = prefList[:i] + prefList[i+3:] - break - - return (prefs_changed, prefList) - - -class PrefError(Exception): - """ base class """ - def unpackList(self, l): - """ - Make the preferences presentable to the user - """ - - s = '' - for i in l: - if i <> ORDER_KEY: - s += "'" + i + "', " - return s[:-2] - - def __str__(self): - return self.msg - -class PrefKeyError(PrefError): - def __init__(self, error): - value = error[0] - expectedValues = self.unpackList(error[1]) - self.msg = _("Preference key '%(key)s' is invalid.\nExpected one of %(value)s") % { - 'key': value, 'value': expectedValues} - - -class PrefValueInvalidError(PrefKeyError): - def __init__(self, error): - value = error[0] - self.msg = _("Preference value '%(value)s' is invalid") % {'value': value} - -class PrefLengthError(PrefError): - def __init__(self, error): - self.msg = _("These preferences are not well formed:") + "\n %s" % self.unpackList(error) - -class PrefValueKeyComboError(PrefError): - def __init__(self, error): - self.msg = error - - -def convertDateForStrftime(dateTimeUserChoice): - try: - return DATE_TIME_CONVERT[LIST_DATE_TIME_L2.index(dateTimeUserChoice)] - except: - raise PrefValueInvalidError(dateTimeUserChoice) - - -class Comboi18n(gtk.ComboBox): - """ very simple i18n version of the venerable combo box - with one column displayed to the user. - - This combo box has two columns: - 1. the first contains the actual value and is invisible - 2. the second contains the translation of the first column, and this is what - the users sees - """ - def __init__(self): - liststore = gtk.ListStore(str, str) - gtk.ComboBox.__init__(self, liststore) - cell = gtk.CellRendererText() - self.pack_start(cell, True) - self.add_attribute(cell, 'text', 1) - - def append_text(self, text): - model = self.get_model() - model.append((text, _(text))) - - def get_active_text(self): - model = self.get_model() - active = self.get_active() - if active < 0: - return None - return model[active][0] - -class ImageRenamePreferences: - def __init__(self, prefList, parent, fileSequenceLock=None, sequences=None): - """ - Exception raised if preferences are invalid. - - This should be caught by calling class.""" - - self.parent = parent - self.prefList = prefList - - # use variables for determining sequence numbers - # there are two possibilities: - # 1. this code is being called while being run from within a copy photos process - # 2. it's being called from within the preferences dialog window - - self.fileSequenceLock = fileSequenceLock - self.sequences = sequences - - self.job_code = '' - - # derived classes will have their own definitions, do not overwrite - if not hasattr(self, "prefsDefnL0"): - self.prefsDefnL0 = DICT_IMAGE_RENAME_L0 - self.defaultPrefs = [FILENAME, NAME_EXTENSION, ORIGINAL_CASE] - self.defaultRow = self.defaultPrefs - self.stripForwardSlash = True - self.L1DateCheck = IMAGE_DATE #used in _getDateComponent() - self.component = pn.FILENAME_COMPONENT - - - def initializeProblem(self, problem): - """ - Set the problem tracker used in name generation - """ - self.problem = problem - - def getProblems(self): - """ - Returns Problem class if there were problems, else returns None. - """ - if self.problem.has_problem(): - return self.problem - else: - return None - - def checkPrefsForValidity(self): - """ - Checks image preferences validity - """ - - return checkPreferenceValid(self.prefsDefnL0, self.prefList) - - def formatPreferencesForPrettyPrint(self): - """ returns a string useful for printing the preferences""" - - v = '' - - for i in range(0, len(self.prefList), 3): - if (self.prefList[i+1] or self.prefList[i+2]): - c = ':' - else: - c = '' - s = "%s%s " % (self.prefList[i], c) - - if self.prefList[i+1]: - s = "%s%s" % (s, self.prefList[i+1]) - if self.prefList[i+2]: - s = "%s (%s)" % (s, self.prefList[i+2]) - - v += s + "\n" - return v - - - def setJobCode(self, job_code): - self.job_code = job_code - - def setDownloadStartTime(self, download_start_time): - self.download_start_time = download_start_time - - def _getDateComponent(self): - """ - Returns portion of new image / subfolder name based on date time. - If the date is missing, will attempt to use the fallback date. - """ - - # step 1: get the correct value from metadata - if self.L1 == self.L1DateCheck: - if self.L2 == SUBSECONDS: - d = self.metadata.subSeconds() - if d == '00': - self.problem.add_problem(self.component, pn.MISSING_METADATA, _(self.L2)) - return '' - else: - return d - else: - d = self.metadata.dateTime(missing=None) - - elif self.L1 == TODAY: - d = datetime.datetime.now() - elif self.L1 == YESTERDAY: - delta = datetime.timedelta(days = 1) - d = datetime.datetime.now() - delta - elif self.L1 == DOWNLOAD_TIME: - d = self.download_start_time - else: - raise("Date options invalid") - - # step 2: handle a missing value - if not d: - if self.fallback_date: - try: - d = datetime.datetime.fromtimestamp(self.fallback_date) - except: - self.problem.add_problem(self.component, pn.INVALID_DATE_TIME, '') - return '' - else: - self.problem.add_problem(self.component, pn.MISSING_METADATA, _(self.L1)) - return '' - - try: - return d.strftime(convertDateForStrftime(self.L2)) - except: - self.problem.add_problem(self.component, pn.INVALID_DATE_TIME, d) - return '' - - def _getFilenameComponent(self): - """ - Returns portion of new image / subfolder name based on the file name - """ - - name, extension = os.path.splitext(self.existingFilename) - - if self.L1 == NAME_EXTENSION: - filename = self.existingFilename - elif self.L1 == NAME: - filename = name - elif self.L1 == EXTENSION: - if extension: - if not self.stripInitialPeriodFromExtension: - # keep the period / dot of the extension, so the user does not - # need to manually specify it - filename = extension - else: - # having the period when this is used as a part of a subfolder name - # is a bad idea! - filename = extension[1:] - else: - self.problem.add_problem(self.component, pn.MISSING_FILE_EXTENSION) - return "" - elif self.L1 == IMAGE_NUMBER or self.L1 == VIDEO_NUMBER: - n = re.search("(?P<image_number>[0-9]+$)", name) - if not n: - self.problem.add_problem(self.component, pn.MISSING_IMAGE_NUMBER) - return '' - else: - image_number = n.group("image_number") - - if self.L2 == IMAGE_NUMBER_ALL: - filename = image_number - elif self.L2 == IMAGE_NUMBER_1: - filename = image_number[-1] - elif self.L2 == IMAGE_NUMBER_2: - filename = image_number[-2:] - elif self.L2 == IMAGE_NUMBER_3: - filename = image_number[-3:] - elif self.L2 == IMAGE_NUMBER_4: - filename = image_number[-4:] - else: - raise TypeError("Incorrect filename option") - - if self.L2 == UPPERCASE: - filename = filename.upper() - elif self.L2 == LOWERCASE: - filename = filename.lower() - - return filename - - def _getMetadataComponent(self): - """ - Returns portion of new image / subfolder name based on the metadata - - Note: date time metadata found in _getDateComponent() - """ - - if self.L1 == APERTURE: - v = self.metadata.aperture() - elif self.L1 == ISO: - v = self.metadata.iso() - elif self.L1 == EXPOSURE_TIME: - v = self.metadata.exposureTime(alternativeFormat=True) - elif self.L1 == FOCAL_LENGTH: - v = self.metadata.focalLength() - elif self.L1 == CAMERA_MAKE: - v = self.metadata.cameraMake() - elif self.L1 == CAMERA_MODEL: - v = self.metadata.cameraModel() - elif self.L1 == SHORT_CAMERA_MODEL: - v = self.metadata.shortCameraModel() - elif self.L1 == SHORT_CAMERA_MODEL_HYPHEN: - v = self.metadata.shortCameraModel(includeCharacters = "\-") - elif self.L1 == SERIAL_NUMBER: - v = self.metadata.cameraSerial() - elif self.L1 == SHUTTER_COUNT: - v = self.metadata.shutterCount() - if v: - v = int(v) - padding = LIST_SHUTTER_COUNT_L2.index(self.L2) + 3 - formatter = '%0' + str(padding) + "i" - v = formatter % v - - elif self.L1 == OWNER_NAME: - v = self.metadata.ownerName() - else: - raise TypeError("Invalid metadata option specified") - if self.L1 in [CAMERA_MAKE, CAMERA_MODEL, SHORT_CAMERA_MODEL, - SHORT_CAMERA_MODEL_HYPHEN, OWNER_NAME]: - if self.L2 == UPPERCASE: - v = v.upper() - elif self.L2 == LOWERCASE: - v = v.lower() - if not v: - self.problem.add_problem(self.component, pn.MISSING_METADATA, _(self.L1)) - return v - - - def _formatSequenceNo(self, value, amountToPad): - padding = LIST_SEQUENCE_NUMBERS_L2.index(amountToPad) + 1 - formatter = '%0' + str(padding) + "i" - return formatter % value - - - def _calculateLetterSequence(self, sequence): - - def _letters(x): - """ - Adapted from algorithm at http://en.wikipedia.org/wiki/Hexavigesimal - """ - v = '' - while x > 25: - r = x % 26 - x= x / 26 - 1 - v = string.lowercase[r] + v - v = string.lowercase[x] + v - - return v - - - v = _letters(sequence) - if self.L2 == UPPERCASE: - v = v.upper() - - return v - - def _getSubfolderSequenceNo(self): - """ - Add a sequence number to the filename - - * Sequence numbering is per subfolder - * Assume the user might actually have a (perhaps odd) reason to have more - than one subfolder sequence number in the same file name - """ - - self.subfolderSeqNoInstanceInFilename += 1 - - if self.downloadSubfolder: - subfolder = self.downloadSubfolder + str(self.subfolderSeqNoInstanceInFilename) - else: - subfolder = "__subfolder__" + str(self.subfolderSeqNoInstanceInFilename) - - if self.fileSequenceLock: - with self.fileSequenceLock: - v = self.sequenceNos.calculate(subfolder) - v = self.formatSequenceNo(v, self.L1) - else: - v = self.sequenceNos.calculate(subfolder) - v = self.formatSequenceNo(v, self.L1) - - return v - - def _getSessionSequenceNo(self): - return self._formatSequenceNo(self.sequences.getSessionSequenceNoUsingCounter(self.sequenceCounter), self.L2) - - def _getDownloadsTodaySequenceNo(self): - return self._formatSequenceNo(self.sequences.getDownloadsTodayUsingCounter(self.sequenceCounter), self.L2) - - - def _getStoredSequenceNo(self): - return self._formatSequenceNo(self.sequences.getStoredSequenceNoUsingCounter(self.sequenceCounter), self.L2) - - def _getSequenceLetter(self): - return self._calculateLetterSequence(self.sequences.getSequenceLetterUsingCounter(self.sequenceCounter)) - - - def _getSequencesComponent(self): - if self.L1 == DOWNLOAD_SEQ_NUMBER: - return self._getDownloadsTodaySequenceNo() - elif self.L1 == SESSION_SEQ_NUMBER: - return self._getSessionSequenceNo() - elif self.L1 == SUBFOLDER_SEQ_NUMBER: - return self._getSubfolderSequenceNo() - elif self.L1 == STORED_SEQ_NUMBER: - return self._getStoredSequenceNo() - elif self.L1 == SEQUENCE_LETTER: - return self._getSequenceLetter() - - def _getComponent(self): - try: - if self.L0 == DATE_TIME: - return self._getDateComponent() - elif self.L0 == TEXT: - return self.L1 - elif self.L0 == FILENAME: - return self._getFilenameComponent() - elif self.L0 == METADATA: - return self._getMetadataComponent() - elif self.L0 == SEQUENCES: - return self._getSequencesComponent() - elif self.L0 == JOB_CODE: - return self.job_code - elif self.L0 == SEPARATOR: - return os.sep - except: - self.problem.add_problem(self.component, pn.ERROR_IN_GENERATION, _(self.L0)) - return '' - - def _getValuesFromList(self): - for i in range(0, len(self.prefList), 3): - yield (self.prefList[i], self.prefList[i+1], self.prefList[i+2]) - - - def _generateName(self, metadata, existingFilename, stripCharacters, subfolder, stripInitialPeriodFromExtension, sequence, fallback_date): - self.metadata = metadata - self.existingFilename = existingFilename - self.stripInitialPeriodFromExtension = stripInitialPeriodFromExtension - self.fallback_date = fallback_date - - name = '' - - #the subfolder in which the image will be downloaded to - self.downloadSubfolder = subfolder - - self.sequenceCounter = sequence - - for self.L0, self.L1, self.L2 in self._getValuesFromList(): - v = self._getComponent() - if v: - name += v - - if stripCharacters: - for c in r'\:*?"<>|': - name = name.replace(c, '') - - if self.stripForwardSlash: - name = name.replace('/', '') - - name = name.strip() - - return name - - def generateNameUsingPreferences(self, metadata, existingFilename=None, - stripCharacters = False, subfolder=None, - stripInitialPeriodFromExtension=False, - sequencesPreliminary = True, - sequence_to_use = None, - fallback_date = None): - """ - Generate a filename for the photo or video in string format based on user preferences. - - Returns the name in string format - - Any problems encountered during the generation of the name can be accessed - through the method getProblems() - """ - - if self.sequences: - if sequence_to_use is not None: - sequence = sequence_to_use - elif sequencesPreliminary: - sequence = self.sequences.getPrelimSequence() - else: - sequence = self.sequences.getFinalSequence() - else: - sequence = 0 - - return self._generateName(metadata, existingFilename, stripCharacters, subfolder, - stripInitialPeriodFromExtension, sequence, fallback_date) - - def generateNameSequencePossibilities(self, metadata, existingFilename, - stripCharacters=False, subfolder=None, - stripInitialPeriodFromExtension=False): - - """ Generates the possible image names using the sequence numbers / letter possibilities""" - - for sequence in self.sequences.getSequencePossibilities(): - yield self._generateName(metadata, existingFilename, stripCharacters, subfolder, - stripInitialPeriodFromExtension, sequence) - - def filterPreferences(self): - """ - Filters out extraneous preference choices - Expected to be implemented in derived classes when needed - """ - pass - - def needImageMetaDataToCreateUniqueName(self): - """ - Returns True if an image's metadata is essential to properly generate a unique image name - - Image names should be unique. Some images may not have metadata. If - only non-dynamic components make up the rest of an image name - (e.g. text specified by the user), then relying on metadata will likely - produce duplicate names. - - File extensions are not considered dynamic. - - This is NOT a general test to see if unique filenames can be generated. It is a test - to see if an image's metadata is needed. - """ - hasMD = hasDynamic = False - - for e in METADATA_ELEMENTS: - if e in self.prefList: - hasMD = True - break - - if hasMD: - for e in DYNAMIC_NON_METADATA_ELEMENTS: - if e in self.prefList: - if e == FILENAME and (NAME_EXTENSION in self.prefList or - NAME in self.prefList or - IMAGE_NUMBER in self.prefList): - hasDynamic = True - break - - if hasMD and not hasDynamic: - return True - else: - return False - - def usesSequenceElements(self): - """ Returns true if any sequence numbers or letters are used to generate the filename """ - - for e in SEQUENCE_ELEMENTS: - if e in self.prefList: - return True - - return False - - def usesTheSequenceElement(self, e): - """ Returns true if a stored sequence number is used to generate the filename """ - return e in self.prefList - - - def _createCombo(self, choices): - combobox = Comboi18n() - for text in choices: - combobox.append_text(text) - return combobox - - def getDefaultRow(self): - """ - returns a list of default widgets - """ - return self.getWidgetsBasedOnUserSelection(self.defaultRow) - - def _getPreferenceWidgets(self, prefDefinition, prefs, widgets): - key = prefs[0] - value = prefs[1] - - # supply a default value if the user has not yet chosen a value! - if not key: - key = prefDefinition[ORDER_KEY][0] - - if not key in prefDefinition: - raise PrefKeyError((key, prefDefinition.keys())) - - - list0 = prefDefinition[ORDER_KEY] - - # the first widget will always be a combo box - widget0 = self._createCombo(list0) - widget0.set_active(list0.index(key)) - - widgets.append(widget0) - - if key == TEXT: - widget1 = gtk.Entry() - widget1.set_text(value) - - widgets.append(widget1) - widgets.append(None) - return - elif key in [SEPARATOR, JOB_CODE]: - widgets.append(None) - widgets.append(None) - return - else: - nextPrefDefinition = prefDefinition[key] - if type(nextPrefDefinition) == type({}): - return self._getPreferenceWidgets(nextPrefDefinition, - prefs[1:], - widgets) - else: - if type(nextPrefDefinition) == type([]): - widget1 = self._createCombo(nextPrefDefinition) - if not value: - value = nextPrefDefinition[0] - try: - widget1.set_active(nextPrefDefinition.index(value)) - except: - raise PrefValueInvalidError((value, nextPrefDefinition)) - - widgets.append(widget1) - else: - widgets.append(None) - - def getWidgetsBasedOnPreferences(self): - """ - Yields a list of widgets and their callbacks based on the users preferences. - - This list is equivalent to one row of preferences when presented to the - user in the Plus Minus Table. - """ - - for L0, L1, L2 in self._getValuesFromList(): - prefs = [L0, L1, L2] - widgets = [] - self._getPreferenceWidgets(self.prefsDefnL0, prefs, widgets) - yield widgets - - - def getWidgetsBasedOnUserSelection(self, selection): - """ - Returns a list of widgets and their callbacks based on what the user has selected. - - Selection is the values the user has chosen thus far in comboboxes. - It determines the contents of the widgets returned. - It should be a list of three values, with None for values not chosen. - For values which are None, the first value in the preferences - definition is chosen. - - """ - widgets = [] - - self._getPreferenceWidgets(self.prefsDefnL0, selection, widgets) - return widgets - -def getVideoMetadataComponent(video): - """ - Returns portion of video / subfolder name based on the metadata - - This is outside of a class definition because of the inheritence - hierarchy. - """ - - problem = None - if video.L1 == CODEC: - v = video.metadata.codec() - elif video.L1 == WIDTH: - v = video.metadata.width() - elif video.L1 == HEIGHT: - v = video.metadata.height() - elif video.L1 == FPS: - v = video.metadata.framesPerSecond() - elif video.L1 == LENGTH: - v = video.metadata.length() - else: - raise TypeError("Invalid metadata option specified") - if video.L1 in [CODEC]: - if video.L2 == UPPERCASE: - v = v.upper() - elif video.L2 == LOWERCASE: - v = v.lower() - if not v: - video.problem.add_problem(video.component, pn.MISSING_METADATA, _(video.L1)) - return v - -class VideoRenamePreferences(ImageRenamePreferences): - def __init__(self, prefList, parent, fileSequenceLock=None, sequences=None): - self.prefsDefnL0 = DICT_VIDEO_RENAME_L0 - self.defaultPrefs = [FILENAME, NAME_EXTENSION, ORIGINAL_CASE] - self.defaultRow = self.defaultPrefs - self.stripForwardSlash = True - self.L1DateCheck = VIDEO_DATE - self.component = pn.FILENAME_COMPONENT - ImageRenamePreferences.__init__(self, prefList, parent, fileSequenceLock, sequences) - - def _getMetadataComponent(self): - """ - Returns portion of video / subfolder name based on the metadata - - Note: date time metadata found in _getDateComponent() - """ - return getVideoMetadataComponent(self) - - -class SubfolderPreferences(ImageRenamePreferences): - def __init__(self, prefList, parent): - self.prefsDefnL0 = DICT_SUBFOLDER_L0 - self.defaultPrefs = DEFAULT_SUBFOLDER_PREFS - self.defaultRow = [DATE_TIME, IMAGE_DATE, LIST_DATE_TIME_L2[0]] - self.stripForwardSlash = False - self.L1DateCheck = IMAGE_DATE - self.component = pn.SUBFOLDER_COMPONENT - ImageRenamePreferences.__init__(self, prefList, parent) - - self.stripExtraneousWhiteSpace = re.compile(r'\s*%s\s*' % os.sep) - - def generateNameUsingPreferences(self, photo, existingFilename=None, - stripCharacters = False, fallback_date = None): - """ - Generate a filename for the photo in string format based on user prefs. - - Returns a tuple of two strings: - - the name - - any problems generating the name. If blank, there were no problems - """ - - subfolders = ImageRenamePreferences.generateNameUsingPreferences( - self, photo, - existingFilename, stripCharacters, - stripInitialPeriodFromExtension=True, - fallback_date=fallback_date) - # subfolder value must never start with a separator, or else any - # os.path.join function call will fail to join a subfolder to its - # parent folder - if subfolders: - if subfolders[0] == os.sep: - subfolders = subfolders[1:] - - # remove any spaces before and after a directory name - if subfolders and stripCharacters: - subfolders = self.stripExtraneousWhiteSpace.sub(os.sep, subfolders) - - return subfolders - - def filterPreferences(self): - filtered, prefList = filterSubfolderPreferences(self.prefList) - if filtered: - self.prefList = prefList - - def needMetaDataToCreateUniqueName(self): - """ - Returns True if metadata is essential to properly generate subfolders - - This will be the case if the only components are metadata and separators - """ - - for e in self.prefList: - if (not e) and ((e not in METADATA_ELEMENTS) or (e <> SEPARATOR)): - return True - - return False - - - - - def checkPrefsForValidity(self): - """ - Checks subfolder preferences validity above and beyond image name checks. - - See parent method for full description. - - Subfolders have additional requirments to that of image names. - """ - v = ImageRenamePreferences.checkPrefsForValidity(self) - if v: - # peform additional checks: - # 1. do not start with a separator - # 2. do not end with a separator - # 3. do not have two separators in a row - # these three rules will ensure something else other than a - # separator is specified - L1s = [] - for i in range(0, len(self.prefList), 3): - L1s.append(self.prefList[i]) - - if L1s[0] == SEPARATOR: - raise PrefValueKeyComboError(_("Subfolder preferences should not start with a %s") % os.sep) - elif L1s[-1] == SEPARATOR: - raise PrefValueKeyComboError(_("Subfolder preferences should not end with a %s") % os.sep) - else: - for i in range(len(L1s) - 1): - if L1s[i] == SEPARATOR and L1s[i+1] == SEPARATOR: - raise PrefValueKeyComboError(_("Subfolder preferences should not contain two %s one after the other") % os.sep) - return v - - - -class VideoSubfolderPreferences(SubfolderPreferences): - def __init__(self, prefList, parent): - SubfolderPreferences.__init__(self, prefList, parent) - self.prefsDefnL0 = DICT_VIDEO_SUBFOLDER_L0 - self.defaultPrefs = DEFAULT_VIDEO_SUBFOLDER_PREFS - self.defaultRow = [DATE_TIME, VIDEO_DATE, LIST_DATE_TIME_L2[0]] - self.L1DateCheck = VIDEO_DATE - self.component = pn.SUBFOLDER_COMPONENT - - def _getMetadataComponent(self): - """ - Returns portion of video / subfolder name based on the metadata - - Note: date time metadata found in _getDateComponent() - """ - return getVideoMetadataComponent(self) - -class Sequences: - """ - Holds sequence numbers and letters used in generating filenames. - The same instance of this class is shared among all threads. - """ - def __init__(self, downloadsToday, storedSequenceNo): - self.subfolderSequenceNo = {} - self.sessionSequenceNo = 1 - self.sequenceLetter = 0 - - self.setUseOfSequenceElements(False, False) - - self.assignedSequenceCounter = 1 - self.reset(downloadsToday, storedSequenceNo) - - def setUseOfSequenceElements(self, usesSessionSequenceNo, usesSequenceLetter): - self.usesSessionSequenceNo = usesSessionSequenceNo - self.usesSequenceLetter = usesSequenceLetter - - def reset(self, downloadsToday, storedSequenceNo): - self.downloadsToday = downloadsToday - self.downloadsTodayOffset = 0 - self.storedSequenceNo = storedSequenceNo - if self.usesSessionSequenceNo: - self.sessionSequenceNo = self.sessionSequenceNo + self.assignedSequenceCounter - 1 - if self.usesSequenceLetter: - self.sequenceLetter = self.sequenceLetter + self.assignedSequenceCounter - 1 - self.doNotAddToPool = False - self.pool = [] - self.poolSequenceCounter = 0 - self.assignedSequenceCounter = 1 - - def getPrelimSequence(self): - if self.doNotAddToPool: - self.doNotAddToPool = False - else: - # increment pool sequence number - self.poolSequenceCounter += 1 - self.pool.append(self.poolSequenceCounter) - - return self.poolSequenceCounter - - def getFinalSequence(self): - # get oldest queue value - # remove from queue or flag it should be removed - - return self.assignedSequenceCounter - - def getSequencePossibilities(self): - for i in self.pool: - yield i - - def getSessionSequenceNo(self): - return self.sessionSequenceNo + self.assignedSequenceCounter - 1 - - def getSessionSequenceNoUsingCounter(self, counter): - return self.sessionSequenceNo + counter - 1 - - def setSessionSequenceNo(self, value): - self.sessionSequenceNo = value - - def setStoredSequenceNo(self, value): - self.storedSequenceNo = value - - def getDownloadsTodayUsingCounter(self, counter): - return self.downloadsToday + counter - self.downloadsTodayOffset - - def setDownloadsToday(self, value): - self.downloadsToday = value - self.downloadsTodayOffset = self.assignedSequenceCounter - 1 - - def getStoredSequenceNoUsingCounter(self, counter): - return self.storedSequenceNo + counter - - def getSequenceLetterUsingCounter(self, counter): - return self.sequenceLetter + counter - 1 - - def imageCopyFailed(self): - self.doNotAddToPool = True - - def imageCopySucceeded(self): - self.increment() - - def increment(self): - assert(self.assignedSequenceCounter == self.pool[0]) - self.assignedSequenceCounter += 1 - self.pool = self.pool[1:] - #assert(len(self.pool) > 0) - - - - -if __name__ == '__main__': - import sys - import os.path - from metadata import MetaData - - if False: - if (len(sys.argv) != 2): - print 'Usage: ' + sys.argv[0] + ' path/to/photo/containing/metadata' - sys.exit(1) - else: - p0 = [FILENAME, NAME_EXTENSION, ORIGINAL_CASE] - p1 = [FILENAME, NAME_EXTENSION, LOWERCASE] - p2 = [METADATA, APERTURE, None] - p3 = [FILENAME, IMAGE_NUMBER, IMAGE_NUMBER_ALL] - p4 = [METADATA, CAMERA_MODEL, ORIGINAL_CASE] - p5 = [TEXT, '-', None] - p6 = [TEXT, 'Job', None] - - p = [p0, p1, p2, p3, p4] - p = [p6 + p5 + p2 + p5 + p3] - - d0 = [DATE_TIME, IMAGE_DATE, 'YYYYMMDD'] - d1 = [DATE_TIME, IMAGE_DATE, 'HHMMSS'] - d2 = [DATE_TIME, IMAGE_DATE, SUBSECONDS] - - d = [d0 + d1 + d2] - - fullpath = sys.argv[1] - path, filename = os.path.split(fullpath) - - m = MetaData(fullpath) - m.readMetadata() - - for pref in p: - i = ImageRenamePreferences(pref, None) - print i.generateNameUsingPreferences(m, filename) - - for pref in d: - i = ImageRenamePreferences(pref, None) - print i.generateNameUsingPreferences(m, filename) - else: - prefs = [SEQUENCES, SESSION_SEQ_NUMBER, SEQUENCE_NUMBER_3] -# prefs = ['Filename2', NAME_EXTENSION, UPPERCASE] - print checkPreferenceValid(DICT_IMAGE_RENAME_L0, prefs) |