diff options
Diffstat (limited to 'rapid/generatename.py')
-rw-r--r-- | rapid/generatename.py | 546 |
1 files changed, 0 insertions, 546 deletions
diff --git a/rapid/generatename.py b/rapid/generatename.py deleted file mode 100644 index 446aaf8..0000000 --- a/rapid/generatename.py +++ /dev/null @@ -1,546 +0,0 @@ -#!/usr/bin/python -# -*- coding: latin1 -*- - -### Copyright (C) 2007-2012 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 -### USA - -import os, re, datetime, string, collections - -import multiprocessing -import logging -logger = multiprocessing.get_logger() - -import problemnotification as pn - -from generatenameconfig import * - -from gettext import gettext as _ - - -def convert_date_for_strftime(datetime_user_choice): - try: - return DATE_TIME_CONVERT[LIST_DATE_TIME_L2.index(datetime_user_choice)] - except: - raise PrefValueInvalidError(datetime_user_choice) - - -class PhotoName: - """ - Generate the name of a photo. Used as a base class for generating names - of videos, as well as subfolder names for both file types - """ - - def __init__(self, pref_list): - self.pref_list = pref_list - - - # Some of the next values are overwritten in derived classes - self.strip_initial_period_from_extension = False - self.strip_forward_slash = True - self.L1_date_check = IMAGE_DATE #used in _get_date_component() - self.component = pn.FILENAME_COMPONENT #used in error reporting - - - def _get_values_from_pref_list(self): - for i in range(0, len(self.pref_list), 3): - yield (self.pref_list[i], self.pref_list[i+1], self.pref_list[i+2]) - - def _get_date_component(self): - """ - Returns portion of new file / 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.L1_date_check: - if self.L2 == SUBSECONDS: - d = self.rpd_file.metadata.sub_seconds(missing=None) - if d is None: - self.rpd_file.problem.add_problem(self.component, pn.MISSING_METADATA, _(self.L2)) - return '' - else: - return d - else: - d = self.rpd_file.metadata.date_time(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.rpd_file.download_start_time - else: - raise("Date options invalid") - - # step 2: if have a value, try to convert it to string format - if d: - try: - return d.strftime(convert_date_for_strftime(self.L2)) - except: - logger.warning("Exif date time value appears invalid for file %s", self.rpd_file.full_file_name) - - # step 3: handle a missing value using file modification time - if self.rpd_file.modification_time: - try: - d = datetime.datetime.fromtimestamp(self.rpd_file.modification_time) - except: - self.rpd_file.add_problem(self.component, pn.INVALID_DATE_TIME, '') - logger.error("Both file modification time and metadata date & time are invalid for file %s", self.rpd_file.full_file_name) - return '' - else: - self.rpd_file.add_problem(self.component, pn.MISSING_METADATA, _(self.L1)) - return '' - - try: - return d.strftime(convert_date_for_strftime(self.L2)) - except: - self.rpd_file.add_problem(self.component, pn.INVALID_DATE_TIME, d) - logger.error("Both file modification time and metadata date & time are invalid for file %s", self.rpd_file.full_file_name) - return '' - - def _get_associated_file_extension(self, associate_file): - """ - Generates extensions with correct capitalization for files like - thumbnail or audio files. - """ - if associate_file: - extension = os.path.splitext(associate_file)[1] - if self.L2 == UPPERCASE: - extension = extension.upper() - elif self.L2 == LOWERCASE: - extension = extension.lower() - else: - extension = None - return extension - - - def _get_thm_extension(self): - """ - Generates THM extension with correct capitalization, if needed - """ - self.rpd_file.thm_extension = self._get_associated_file_extension(self.rpd_file.thm_full_name) - - def _get_audio_extension(self): - """ - Generates audio extension with correct capitalization, if needed - e.g. WAV or wav - """ - self.rpd_file.audio_extension = self._get_associated_file_extension(self.rpd_file.audio_file_full_name) - - def _get_xmp_extension(self, extension): - """ - Generates XMP extension with correct capitalization, if needed. - """ - if self.rpd_file.temp_xmp_full_name: - if self.L2 == UPPERCASE: - self.rpd_file.xmp_extension = '.XMP' - elif self.L2 == LOWERCASE: - self.rpd_file.xmp_extension = '.xmp' - else: - # mimic capitalization of extension - if extension.isupper(): - self.rpd_file.xmp_extension = '.XMP' - else: - self.rpd_file.xmp_extension = '.xmp' - else: - self.rpd_file.xmp_extension = None - - - def _get_filename_component(self): - """ - Returns portion of new file / subfolder name based on the file name - """ - - name, extension = os.path.splitext(self.rpd_file.name) - - if self.L1 == NAME_EXTENSION: - filename = self.rpd_file.name - self._get_thm_extension() - self._get_audio_extension() - self._get_xmp_extension(extension) - elif self.L1 == NAME: - filename = name - elif self.L1 == EXTENSION: - self._get_thm_extension() - self._get_audio_extension() - self._get_xmp_extension(extension) - if extension: - if not self.strip_initial_period_from_extension: - # 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 when it is at the start! - filename = extension[1:] - else: - self.rpd_file.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.rpd_file.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 _get_metadata_component(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.rpd_file.metadata.aperture() - elif self.L1 == ISO: - v = self.rpd_file.metadata.iso() - elif self.L1 == EXPOSURE_TIME: - v = self.rpd_file.metadata.exposure_time(alternativeFormat=True) - elif self.L1 == FOCAL_LENGTH: - v = self.rpd_file.metadata.focal_length() - elif self.L1 == CAMERA_MAKE: - v = self.rpd_file.metadata.camera_make() - elif self.L1 == CAMERA_MODEL: - v = self.rpd_file.metadata.camera_model() - elif self.L1 == SHORT_CAMERA_MODEL: - v = self.rpd_file.metadata.short_camera_model() - elif self.L1 == SHORT_CAMERA_MODEL_HYPHEN: - v = self.rpd_file.metadata.short_camera_model(includeCharacters = "\-") - elif self.L1 == SERIAL_NUMBER: - v = self.rpd_file.metadata.camera_serial() - elif self.L1 == SHUTTER_COUNT: - v = self.rpd_file.metadata.shutter_count() - 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 == FILE_NUMBER: - v = self.rpd_file.metadata.file_number() - if v and self.L2 == FILE_NUMBER_FOLDER: - v = v[:3] - elif self.L1 == OWNER_NAME: - v = self.rpd_file.metadata.owner_name() - elif self.L1 == ARTIST: - v = self.rpd_file.metadata.artist() - elif self.L1 == COPYRIGHT: - v = self.rpd_file.metadata.copyright() - else: - raise TypeError("Invalid metadata option specified") - if self.L1 in [CAMERA_MAKE, CAMERA_MODEL, SHORT_CAMERA_MODEL, - SHORT_CAMERA_MODEL_HYPHEN, OWNER_NAME, ARTIST, - COPYRIGHT]: - if self.L2 == UPPERCASE: - v = v.upper() - elif self.L2 == LOWERCASE: - v = v.lower() - if not v: - self.rpd_file.add_problem(self.component, pn.MISSING_METADATA, _(self.L1)) - return v - - def _calculate_letter_sequence(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 _format_sequence_no(self, value, amountToPad): - padding = LIST_SEQUENCE_NUMBERS_L2.index(amountToPad) + 1 - formatter = '%0' + str(padding) + "i" - return formatter % value - - def _get_downloads_today(self): - return self._format_sequence_no(self.rpd_file.sequences.get_downloads_today(), self.L2) - - def _get_session_sequence_no(self): - return self._format_sequence_no(self.rpd_file.sequences.get_session_sequence_no(), self.L2) - - def _get_stored_sequence_no(self): - return self._format_sequence_no(self.rpd_file.sequences.get_stored_sequence_no(), self.L2) - - def _get_sequence_letter(self): - return self._calculate_letter_sequence(self.rpd_file.sequences.get_sequence_letter()) - - def _get_sequences_component(self): - if self.L1 == DOWNLOAD_SEQ_NUMBER: - return self._get_downloads_today() - elif self.L1 == SESSION_SEQ_NUMBER: - return self._get_session_sequence_no() - elif self.L1 == STORED_SEQ_NUMBER: - return self._get_stored_sequence_no() - elif self.L1 == SEQUENCE_LETTER: - return self._get_sequence_letter() - - - #~ elif self.L1 == SUBFOLDER_SEQ_NUMBER: - #~ return self._getSubfolderSequenceNo() - - - - def _get_component(self): - try: - if self.L0 == DATE_TIME: - return self._get_date_component() - elif self.L0 == TEXT: - return self.L1 - elif self.L0 == FILENAME: - return self._get_filename_component() - elif self.L0 == METADATA: - return self._get_metadata_component() - elif self.L0 == SEQUENCES: - return self._get_sequences_component() - elif self.L0 == JOB_CODE: - return self.rpd_file.job_code - elif self.L0 == SEPARATOR: - return os.sep - except: - self.rpd_file.add_problem(self.component, pn.ERROR_IN_GENERATION, _(self.L0)) - return '' - - - def generate_name(self, rpd_file): - self.rpd_file = rpd_file - - name = '' - - for self.L0, self.L1, self.L2 in self._get_values_from_pref_list(): - v = self._get_component() - if v: - name += v - - # remove any null characters - they are bad news in filenames - name = name.replace('\x00', '') - - if self.rpd_file.strip_characters: - for c in r'\:*?"<>|': - name = name.replace(c, '') - - if self.strip_forward_slash: - name = name.replace('/', '') - - name = name.strip() - - return name - - - - -class VideoName(PhotoName): - def __init__(self, pref_list): - PhotoName.__init__(self, pref_list) - self.L1_date_check = VIDEO_DATE #used in _get_date_component() - - def _get_metadata_component(self): - """ - Returns portion of video / subfolder name based on the metadata - - Note: date time metadata found in _getDateComponent() - """ - return get_video_metadata_component(self) - -class PhotoSubfolder(PhotoName): - """ - Generate subfolder names for photo files - """ - - def __init__(self, pref_list): - self.pref_list = pref_list - - self.strip_extraneous_white_space = re.compile(r'\s*%s\s*' % os.sep) - self.strip_initial_period_from_extension = True - self.strip_forward_slash = False - self.L1_date_check = IMAGE_DATE #used in _get_date_component() - self.component = pn.SUBFOLDER_COMPONENT #used in error reporting - - def generate_name(self, rpd_file): - - subfolders = PhotoName.generate_name(self, rpd_file) - - # 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 self.rpd_file.strip_characters: - subfolders = self.strip_extraneous_white_space.sub(os.sep, subfolders) - - return subfolders - - - - -class VideoSubfolder(PhotoSubfolder): - """ - Generate subfolder names for video files - """ - - def __init__(self, pref_list): - PhotoSubfolder.__init__(self, pref_list) - self.L1_date_check = VIDEO_DATE #used in _get_date_component() - - - def _get_metadata_component(self): - """ - Returns portion of video / subfolder name based on the metadata - - Note: date time metadata found in _getDateComponent() - """ - return get_video_metadata_component(self) - -def get_video_metadata_component(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.rpd_file.metadata.codec() - elif video.L1 == WIDTH: - v = video.rpd_file.metadata.width() - elif video.L1 == HEIGHT: - v = video.rpd_file.metadata.height() - elif video.L1 == FPS: - v = video.rpd_file.metadata.frames_per_second() - elif video.L1 == LENGTH: - v = video.rpd_file.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.rpd_file.add_problem(video.component, pn.MISSING_METADATA, _(video.L1)) - return v - -class Sequences: - """ - Holds sequence numbers and letters used in generating filenames. - """ - def __init__(self, downloads_today_tracker, stored_sequence_no): - self.session_sequence_no = 0 - self.sequence_letter = -1 - self.downloads_today_tracker = downloads_today_tracker - self.stored_sequence_no = stored_sequence_no - self.matched_sequences = None - - def set_matched_sequence_value(self, matched_sequences): - self.matched_sequences = matched_sequences - - def get_session_sequence_no(self): - if self.matched_sequences is not None: - return self.matched_sequences.session_sequence_no - else: - return self._get_session_sequence_no() - - def _get_session_sequence_no(self): - return self.session_sequence_no + 1 - - def get_sequence_letter(self): - if self.matched_sequences is not None: - return self.matched_sequences.sequence_letter - else: - return self._get_sequence_letter() - - def _get_sequence_letter(self): - return self.sequence_letter + 1 - - def increment(self, uses_session_sequece_no, uses_sequence_letter): - if uses_session_sequece_no: - self.session_sequence_no += 1 - if uses_sequence_letter: - self.sequence_letter += 1 - - def get_downloads_today(self): - if self.matched_sequences is not None: - return self.matched_sequences.downloads_today - else: - return self._get_downloads_today() - - def _get_downloads_today(self): - v = self.downloads_today_tracker.get_downloads_today() - if v == -1: - return 1 - else: - return v + 1 - - def get_stored_sequence_no(self): - if self.matched_sequences is not None: - return self.matched_sequences.stored_sequence_no - else: - return self._get_stored_sequence_no() - - def _get_stored_sequence_no(self): - # Must add 1 to the value, for historic reasons (that is how it used - # to work) - return self.stored_sequence_no + 1 - - def create_matched_sequences(self): - sequences = collections.namedtuple( - 'AssignedSequences', - 'session_sequence_no sequence_letter downloads_today stored_sequence_no' - ) - sequences.session_sequence_no = self._get_session_sequence_no() - sequences.sequence_letter = self._get_sequence_letter() - sequences.downloads_today = self._get_downloads_today() - sequences.stored_sequence_no = self._get_stored_sequence_no() - return sequences |