summaryrefslogtreecommitdiff
path: root/rapid
diff options
context:
space:
mode:
authorJulien Valroff <julien@kirya.net>2010-01-17 09:40:26 +0100
committerJulien Valroff <julien@kirya.net>2010-01-17 09:40:26 +0100
commit8da6d6d0c1c89aca3fb075062f0c65f608212ca7 (patch)
tree3ef8276ab1f9697deb21ec50d011b520931f1ecd /rapid
parentbea7f6b674c60af316ef7d213f158dea089d19da (diff)
parent49ac3995b9f840580322d4bf6feb27506f07f7ed (diff)
Merge commit 'upstream/0.1.2'
Diffstat (limited to 'rapid')
-rw-r--r--rapid/ChangeLog37
-rw-r--r--rapid/config.py4
-rw-r--r--rapid/glade3/rapid.glade16
-rwxr-xr-xrapid/rapid.py250
-rw-r--r--rapid/renamesubfolderprefs.py17
5 files changed, 253 insertions, 71 deletions
diff --git a/rapid/ChangeLog b/rapid/ChangeLog
index f9093dc..f700e80 100644
--- a/rapid/ChangeLog
+++ b/rapid/ChangeLog
@@ -1,3 +1,40 @@
+Version 0.1.2
+-------------
+
+2010-01-16
+
+New feature: photographers using RAW + JPEG mode now have the option to
+synchronize sequence numbers for the matching pair of images. This option is
+useful if you use the RAW + JPEG feature on your camera and you use sequence
+numbers or letters in your image renaming. Enabling this option will cause the
+program to detect matching pairs of RAW and JPEG images, and when they are
+detected, the same sequence numbers and letters will be applied to both image
+names. Furthermore, sequences will be updated as if the images were one. For
+example, if 200 RAW images and 200 matching JPEG images are downloaded, the
+value of Downloads today will be incremented by 200, and not 400. The same goes
+for the rest of the sequence values, including the Stored number sequence
+number. Images are detected by comparing filename, as well as the exif value for
+the date and time the image was created (including subseconds when the camera
+records this value). This option will take effect regardless of whether the RAW
+and JPEG images are stored on different memory cards or the same memory card.
+Furthermore, if they are stored on separate memory cards, you can download from
+them simultaneously or one after the other. The only requirement is to download
+the images in the same session--in other words, for the feature to work, use as
+many memory cards as you need, but do not exit the program between downloads of
+the matching sets of images.
+
+Increased maximum sequence number length to seven digits by user request.
+
+Fixed bug #503704: changes in values for downloads today and stored number not
+updated when changed via program preferences while a download is ready to begin.
+
+Fixed a rare startup bug, where the program could crash when starting a thread.
+
+Added Serbian translation by Milos Popovic. Updated Czech, Dutch, Finnish,
+French, German, Hungarian, Italian, Polish, Russian, Slovak, Spanish and
+Swedish translations.
+
+
Version 0.1.1
-------------
diff --git a/rapid/config.py b/rapid/config.py
index f70aef1..615fda3 100644
--- a/rapid/config.py
+++ b/rapid/config.py
@@ -1,5 +1,5 @@
# -*- coding: latin1 -*-
-### Copyright (C) 2007, 2008, 2009 Damon Lynch <damonlynch@gmail.com>
+### 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
@@ -15,7 +15,7 @@
### along with this program; if not, write to the Free Software
### Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-version = '0.1.1'
+version = '0.1.2'
GCONF_KEY="/apps/rapid-photo-downloader"
GLADE_FILE = "glade3/rapid.glade"
diff --git a/rapid/glade3/rapid.glade b/rapid/glade3/rapid.glade
index 79ceee1..41387c7 100644
--- a/rapid/glade3/rapid.glade
+++ b/rapid/glade3/rapid.glade
@@ -774,6 +774,19 @@
<property name="position">1</property>
</packing>
</child>
+ <child>
+ <widget class="GtkCheckButton" id="synchronize_raw_jpg_checkbutton">
+ <property name="label" translatable="yes">Synchronize RAW + JPEG sequence numbers</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="draw_indicator">True</property>
+ <signal name="toggled" handler="on_synchronize_raw_jpg_checkbutton_toggled"/>
+ </widget>
+ <packing>
+ <property name="position">2</property>
+ </packing>
+ </child>
</widget>
<packing>
<property name="position">1</property>
@@ -2368,7 +2381,7 @@ You can download photos from multiple image devices simultaneously.
<property name="icon">rapid-photo-downloader-about.png</property>
<property name="type_hint">normal</property>
<property name="program_name">Rapid Photo Downloader</property>
- <property name="copyright" translatable="yes">Copyright Damon Lynch 2007-09</property>
+ <property name="copyright" translatable="yes">Copyright Damon Lynch 2007-10</property>
<property name="comments" translatable="yes">Import your images efficiently and reliably</property>
<property name="website">http://www.damonlynch.net/rapid</property>
<property name="license" translatable="yes">Rapid Photo Downloader 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.
@@ -2387,6 +2400,7 @@ Tomas Novak &lt;kuvaly@seznam.cz&gt;
Abel O'Rian &lt;abel.orian@gmail.com&gt;
Balazs Oveges &lt;ovegesb@freemail.hu&gt;
Daniel Paessler &lt;daniel@paessler.org&gt;
+Milo&#x161; Popovi&#x107; &lt;gpopac@gmail.com&gt;
Michal Predotka &lt;mpredotka@googlemail.com&gt;
Luca Reverberi &lt;thereve@gmail.com&gt;
Mikko Ruohola &lt;polarfox@polarfox.net&gt;
diff --git a/rapid/rapid.py b/rapid/rapid.py
index ae7394c..4a137e2 100755
--- a/rapid/rapid.py
+++ b/rapid/rapid.py
@@ -1,7 +1,7 @@
#!/usr/bin/python
# -*- coding: latin1 -*-
-### Copyright (C) 2007, 2008, 2009 Damon Lynch <damonlynch@gmail.com>
+### 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
@@ -213,7 +213,9 @@ class ThreadManager:
def startWorkers(self):
for w in self.getReadyToStartWorkers():
- w.start()
+ #for some reason, very occassionally a thread that has been started shows up in this list, so must filter them out
+ if not w.isAlive():
+ w.start()
def startDownloadingWorkers(self):
for w in self.getReadyToDownloadWorkers():
@@ -373,12 +375,13 @@ class RapidPreferences(prefs.Preferences):
"show_log_dialog": prefs.Value(prefs.BOOL, False),
"day_start": prefs.Value(prefs.STRING, "03:00"),
"downloads_today": prefs.ListValue(prefs.STRING_LIST, [today(), '0']),
- "stored_sequence_no": prefs.Value(prefs.INT, 0),
- "job_codes": prefs.ListValue(prefs.STRING_LIST, [_('New York'),
+ "stored_sequence_no": prefs.Value(prefs.INT, 0),
+ "job_codes": prefs.ListValue(prefs.STRING_LIST, [_('New York'),
_('Manila'), _('Prague'), _('Helsinki'), _('Wellington'),
_('Tehran'), _('Kampala'), _('Paris'), _('Berlin'), _('Sydney'),
_('Budapest'), _('Rome'), _('Moscow'), _('Delhi'), _('Warsaw'),
- _('Jakarta'), _('Madrid'), _('Stockholm')])
+ _('Jakarta'), _('Madrid'), _('Stockholm')]),
+ "synchronize_raw_jpg": prefs.Value(prefs.BOOL, False),
}
def __init__(self):
@@ -816,6 +819,9 @@ class PreferencesDialog(gnomeglade.Component):
self.hour_spinbutton.set_value(float(hour))
self.minute_spinbutton.set_value(float(minute))
+ self.synchronize_raw_jpg_checkbutton.set_active(
+ self.prefs.synchronize_raw_jpg)
+
#compatibility
self.strip_characters_checkbutton.set_active(
self.prefs.strip_characters)
@@ -998,8 +1004,10 @@ class PreferencesDialog(gnomeglade.Component):
self.on_downloads_today_entry_changed(self.downloads_today_entry)
def on_downloads_today_entry_changed(self, entry):
- if workers.noRunningWorkers() == 0:
- # do not update value if a download is occurring - it will mess it up!
+ # do not update value if a download is occurring - it will mess it up!
+ if workers.noDownloadingWorkers() <> 0:
+ cmd_line(_("Downloads today value not updated, as a download is currently occurring"))
+ else:
v = entry.get_text()
try:
v = int(v)
@@ -1012,8 +1020,10 @@ class PreferencesDialog(gnomeglade.Component):
self.updateImageRenameExample()
def on_stored_number_entry_changed(self, entry):
- if workers.noRunningWorkers() == 0:
- # do not update value if a download is occurring - it will mess it up!
+ # do not update value if a download is occurring - it will mess it up!
+ if workers.noDownloadingWorkers() <> 0:
+ cmd_line(_("Stored number value not updated, as a download is currently occurring"))
+ else:
v = entry.get_text()
try:
# the displayed value of stored sequence no 1 more than actual value
@@ -1165,6 +1175,8 @@ class PreferencesDialog(gnomeglade.Component):
path, column = tree.get_cursor()
self.notebook.set_current_page(path[0])
+ def on_synchronize_raw_jpg_checkbutton_toggled(self, check_button):
+ self.prefs.synchronize_raw_jpg = check_button.get_active()
def on_strip_characters_checkbutton_toggled(self, check_button):
self.prefs.strip_characters = check_button.get_active()
@@ -1263,7 +1275,9 @@ class PreferencesDialog(gnomeglade.Component):
class CopyPhotos(Thread):
"""Copies photos from source to destination, backing up if needed"""
- def __init__(self, thread_id, parentApp, fileRenameLock, fileSequenceLock, statsLock, downloadStats, autoStart = False, cardMedia = None):
+ def __init__(self, thread_id, parentApp, fileRenameLock, fileSequenceLock,
+ statsLock, downloadedFilesLock,
+ downloadStats, autoStart = False, cardMedia = None):
self.parentApp = parentApp
self.thread_id = thread_id
self.ctrl = True
@@ -1279,6 +1293,7 @@ class CopyPhotos(Thread):
self.fileRenameLock = fileRenameLock
self.fileSequenceLock = fileSequenceLock
self.statsLock = statsLock
+ self.downloadedFilesLock = downloadedFilesLock
self.downloadStats = downloadStats
@@ -1493,10 +1508,47 @@ class CopyPhotos(Thread):
_("Image filename could not be properly generated. Check to ensure there is sufficient image metadata."),
_("Source: %(source)s\nDestination: %(destination)s\nProblem: %(problem)s") %
{'source': image, 'destination': newName, 'problem': problem})
-
+
+
+ def imageAlreadyExists(source, destination=None, identifier=None):
+ """ Notify the user that the image could not be downloaded because it already exists"""
+ if self.prefs.indicate_download_error:
+ if source and destination and identifier:
+ logError(config.SERIOUS_ERROR, IMAGE_ALREADY_EXISTS,
+ _("Source: %(source)s\nDestination: %(destination)s")
+ % {'source': image, 'destination': newFile},
+ _("Unique identifier '%s' added") % identifier)
+ elif source and destination:
+ logError(config.SERIOUS_ERROR, IMAGE_ALREADY_EXISTS,
+ _("Source: %(source)s\nDestination: %(destination)s")
+ % {'source': source, 'destination': destination},
+ IMAGE_SKIPPED)
+ else:
+ logError(config.SERIOUS_ERROR, IMAGE_ALREADY_EXISTS,
+ _("Source: %(source)s")
+ % {'source': source},
+ IMAGE_SKIPPED)
+
+
+ def downloadCopyingError(source, destination, errno, strerror):
+ """Notify the user that an error occurred when coyping an image"""
+ logError(config.SERIOUS_ERROR, _('Download copying error'),
+ _("Source: %(source)s\nDestination: %(destination)s\nError: %(errorno)s %(strerror)s")
+ % {'source': source, 'destination': destination, 'errorno': errno, 'strerror': strerror},
+ _('The image was not copied.'))
+
+ def sameFileNameDifferentExif(image1, image1_date_time, image1_subseconds, image2, image2_date_time, image2_subseconds):
+ logError(config.WARNING, _('Images detected with the same filenames, but taken at different times:'),
+ _("First image: %(image1)s %(image1_date_time)s:%(image1_subseconds)s\nSecond image: %(image2)s %(image2_date_time)s:%(image2_subseconds)s") %
+ {'image1': image1, 'image1_date_time': image1_date_time, 'image1_subseconds': image1_subseconds,
+ 'image2': image2, 'image2_date_time': image2_date_time, 'image2_subseconds': image2_subseconds})
+
+
+
def generateSubfolderAndFileName(image, name, needMetaDataToCreateUniqueImageName,
needMetaDataToCreateUniqueSubfolderName):
- skipImage = False
+ skipImage = alreadyDownloaded = False
+ sequence_to_use = None
try:
imageMetadata = metadata.MetaData(image)
except IOError:
@@ -1534,23 +1586,43 @@ class CopyPhotos(Thread):
_("Subfolder: %(subfolder)s\nImage: %(image)s\nProblem: %(problem)s") %
{'subfolder': subfolder, 'image': image, 'problem': problem})
+ if self.prefs.synchronize_raw_jpg and usesSequenceElements:
+ image_name, image_ext = os.path.splitext(name)
+ with self.downloadedFilesLock:
+ i, sequence_to_use = downloaded_files.matching_pair(image_name, image_ext, imageMetadata.dateTime(), imageMetadata.subSeconds())
+ if i == -1:
+ # this exact file has already been downloaded (same extension, same filename, and same exif date time subsecond info)
+ if not addUniqueIdentifier:
+ # there is no point to download it, as there is no way a unique filename will be generated
+ alreadyDownloaded = skipImage = True
+ elif i == -99:
+ i1_ext, i1_date_time, i1_subseconds = downloaded_files.extExifDateTime(image_name)
+ sameFileNameDifferentExif("%s%s" % (image_name, i1_ext), i1_date_time, i1_subseconds, name, imageMetadata.dateTime(), imageMetadata.subSeconds())
+
+
# pass the subfolder the image will go into, as this is needed to determine subfolder sequence numbers
# indicate that sequences chosen should be queued
- newName, problem = self.imageRenamePrefsFactory.generateNameUsingPreferences(
- imageMetadata, name, self.stripCharacters, subfolder,
- sequencesPreliminary = True)
-
- path = os.path.join(baseDownloadDir, subfolder)
- newFile = os.path.join(path, newName)
+ if not skipImage or alreadyDownloaded:
+ newName, problem = self.imageRenamePrefsFactory.generateNameUsingPreferences(
+ imageMetadata, name, self.stripCharacters, subfolder,
+ sequencesPreliminary = True,
+ sequence_to_use = sequence_to_use)
+
+ path = os.path.join(baseDownloadDir, subfolder)
+ newFile = os.path.join(path, newName)
if not newName:
skipImage = True
- checkProblemWithImageNameGeneration(newName, image, problem)
+ if not alreadyDownloaded:
+ checkProblemWithImageNameGeneration(newName, image, problem)
+ else:
+ imageAlreadyExists(image, newFile)
+ newName = newFile = path = subfolder = None
- return (skipImage, imageMetadata, newName, newFile, path, subfolder)
+ return (skipImage, imageMetadata, newName, newFile, path, subfolder, sequence_to_use)
- def downloadImage(path, newFile, newName, originalName, image, imageMetadata, subfolder):
+ def downloadImage(path, newFile, newName, originalName, image, imageMetadata, subfolder, sequence_to_use):
try:
imageDownloaded = False
if not os.path.isdir(path):
@@ -1565,7 +1637,7 @@ class CopyPhotos(Thread):
nameUniqueBeforeCopy = False
if not addUniqueIdentifier:
downloadNonUniqueFile = False
- if usesSequenceElements:
+ if usesSequenceElements and not self.prefs.synchronize_raw_jpg:
# potentially, a unique image name could still be generated
# investigate this possibility
with self.fileSequenceLock:
@@ -1580,11 +1652,8 @@ class CopyPhotos(Thread):
break
- if self.prefs.indicate_download_error and not downloadNonUniqueFile:
- logError(config.SERIOUS_ERROR, IMAGE_ALREADY_EXISTS,
- _("Source: %(source)s\nDestination: %(destination)s") %
- {'source': image, 'destination': newFile},
- IMAGE_SKIPPED)
+ if not downloadNonUniqueFile:
+ imageAlreadyExists(image, newFile)
if nameUniqueBeforeCopy or downloadNonUniqueFile:
tempWorkingfile = os.path.join(tempWorkingDir, newName)
@@ -1595,9 +1664,21 @@ class CopyPhotos(Thread):
if usesSequenceElements:
with self.fileSequenceLock:
# get a filename and use this as the "real" filename
+ if sequence_to_use is None and self.prefs.synchronize_raw_jpg:
+ # must check again, just in case the matching pair has been downloaded in the meantime
+ image_name, image_ext = os.path.splitext(originalName)
+ with self.downloadedFilesLock:
+ i, sequence_to_use = downloaded_files.matching_pair(image_name, image_ext, imageMetadata.dateTime(), imageMetadata.subSeconds())
+ if i == -99:
+ i1_ext, i1_date_time, i1_subseconds = downloaded_files.extExifDateTime(image_name)
+ sameFileNameDifferentExif("%s%s" % (image_name, i1_ext), i1_date_time, i1_subseconds, originalName, imageMetadata.dateTime(), imageMetadata.subSeconds())
+
+
+
newName, problem = self.imageRenamePrefsFactory.generateNameUsingPreferences(
imageMetadata, originalName, self.stripCharacters, subfolder,
- sequencesPreliminary = False)
+ sequencesPreliminary = False,
+ sequence_to_use = sequence_to_use)
checkProblemWithImageNameGeneration(newName, image, problem)
if not newName:
# there was a serious error generating the filename
@@ -1608,11 +1689,7 @@ class CopyPhotos(Thread):
if os.path.exists(newFile):
if not addUniqueIdentifier:
doRename = False
- if self.prefs.indicate_download_error:
- logError(config.SERIOUS_ERROR, IMAGE_ALREADY_EXISTS,
- _("Source: %(source)s\nDestination: %(destination)s")
- % {'source': image, 'destination': newFile},
- IMAGE_SKIPPED)
+ imageAlreadyExists(image, newFile)
else:
# add basic suffix to make the filename unique
name = os.path.splitext(newName)
@@ -1627,46 +1704,50 @@ class CopyPhotos(Thread):
possibleNewFile = os.path.join(path, newName)
suffixAlreadyUsed = os.path.exists(possibleNewFile)
- if self.prefs.indicate_download_error:
- logError(config.SERIOUS_ERROR, IMAGE_ALREADY_EXISTS,
- _("Source: %(source)s\nDestination: %(destination)s")
- % {'source': image, 'destination': newFile},
- _("Unique identifier '%s' added") % identifier)
-
+ imageAlreadyExists(image, newFile, identifier)
newFile = possibleNewFile
if doRename:
os.rename(tempWorkingfile, newFile)
+
imageDownloaded = True
if usesSequenceElements:
+ if self.prefs.synchronize_raw_jpg:
+ name, ext = os.path.splitext(originalName)
+ if sequence_to_use is None:
+ with self.fileSequenceLock:
+ seq = self.imageRenamePrefsFactory.sequences.getFinalSequence()
+ else:
+ seq = sequence_to_use
+ with self.downloadedFilesLock:
+ downloaded_files.add_download(name, ext, imageMetadata.dateTime(), imageMetadata.subSeconds(), seq)
+
+
with self.fileSequenceLock:
- self.imageRenamePrefsFactory.sequences.imageCopySucceeded()
- if usesStoredSequenceNo:
- self.prefs.stored_sequence_no += 1
+ if sequence_to_use is None:
+ self.imageRenamePrefsFactory.sequences.imageCopySucceeded()
+ if usesStoredSequenceNo:
+ self.prefs.stored_sequence_no += 1
with self.fileSequenceLock:
- if self.prefs.incrementDownloadsToday():
- # A new day, according the user's preferences of what time a day begins, has started
- cmd_line(_("New day has started - resetting 'Downloads Today' sequence number"))
-
- sequences.setDownloadsToday(0)
+ if sequence_to_use is None:
+ if self.prefs.incrementDownloadsToday():
+ # A new day, according the user's preferences of what time a day begins, has started
+ cmd_line(_("New day has started - resetting 'Downloads Today' sequence number"))
+
+ sequences.setDownloadsToday(0)
except IOError, (errno, strerror):
- logError(config.SERIOUS_ERROR, _('Download copying error'),
- _("Source: %(source)s\nDestination: %(destination)s\nError: %(errorno)s %(strerror)s")
- % {'source': image, 'destination': newFile, 'errorno': errno, 'strerror': strerror},
- _('The image was not copied.'))
+ downloadCopyingError(image, newFile, errno, strerror)
except OSError, (errno, strerror):
- logError(config.CRITICAL_ERROR, _('Download copying error'),
- "Source: %(source)s\nDestination: %(destination)s\nError: %(errorno)s %(strerror)s"
- % {'source': image, 'destination': newFile, 'errorno': errno, 'strerror': strerror},
- )
+ downloadCopyingError(image, newFile, errno, strerror)
if usesSequenceElements:
- if not imageDownloaded:
+ if not imageDownloaded and sequence_to_use is None:
self.imageRenamePrefsFactory.sequences.imageCopyFailed()
+
return (imageDownloaded, newName, newFile)
@@ -1901,7 +1982,7 @@ class CopyPhotos(Thread):
name, root, size, modificationTime = self.cardMedia.images[i]
image = os.path.join(root, name)
- skipImage, imageMetadata, newName, newFile, path, subfolder = generateSubfolderAndFileName(
+ skipImage, imageMetadata, newName, newFile, path, subfolder, sequence_to_use = generateSubfolderAndFileName(
image, name, needMetaDataToCreateUniqueImageName,
needMetaDataToCreateUniqueSubfolderName)
@@ -1909,7 +1990,7 @@ class CopyPhotos(Thread):
noImagesSkipped += 1
else:
imageDownloaded, newName, newFile = downloadImage(path, newFile, newName, name, image,
- imageMetadata, subfolder)
+ imageMetadata, subfolder, sequence_to_use)
if self.prefs.backup_images:
backupImage(subfolder, newName, imageDownloaded, newFile, image)
@@ -2473,6 +2554,9 @@ class RapidApp(gnomeglade.GnomeApp, dbus.service.Object):
#track files that should have a suffix added to them
global duplicate_files
+ #track files that have been downloaded in this session
+ global downloaded_files
+
# control sequence numbers and letters
global sequences
@@ -2480,6 +2564,7 @@ class RapidApp(gnomeglade.GnomeApp, dbus.service.Object):
global need_job_code
duplicate_files = {}
+ downloaded_files = DownloadedFiles()
downloadsToday = self.prefs.getAndMaybeResetDownloadsToday()
sequences = rn.Sequences(downloadsToday, self.prefs.stored_sequence_no)
@@ -2493,6 +2578,7 @@ class RapidApp(gnomeglade.GnomeApp, dbus.service.Object):
self.fileRenameLock = Lock()
self.fileSequenceLock = Lock()
self.statsLock = Lock()
+ self.downloadedFilesLock = Lock()
# log window, in dialog format
# used for displaying download information to the user
@@ -2716,7 +2802,7 @@ class RapidApp(gnomeglade.GnomeApp, dbus.service.Object):
else:
cmd_line(_("This version of the program is newer than the previously run version. Checking preferences."))
-# if True:
+
if rn.checkPreferencesForValidity(self.prefs.image_rename, self.prefs.subfolder, previousVersion):
upgraded, imageRename, subfolder = rn.upgradePreferencesToCurrent(self.prefs.image_rename, self.prefs.subfolder, previousVersion)
if upgraded:
@@ -2877,9 +2963,10 @@ class RapidApp(gnomeglade.GnomeApp, dbus.service.Object):
cardMedia = CardMedia(path, volume, True)
i = workers.getNextThread_id()
- workers.append(CopyPhotos(i, self, self.fileRenameLock, self.fileSequenceLock, self.statsLock,
- self.downloadStats, autostart,
- cardMedia))
+ workers.append(CopyPhotos(i, self, self.fileRenameLock,
+ self.fileSequenceLock, self.statsLock,
+ self.downloadedFilesLock, self.downloadStats,
+ autostart, cardMedia))
self.setDownloadButtonSensitivity()
@@ -2972,7 +3059,7 @@ class RapidApp(gnomeglade.GnomeApp, dbus.service.Object):
else:
cmd_line(_("Automatically start download is false") )
- def setupAvailableImageAndBackupMedia(self, onStartup, onPreferenceChange, doNotAllowAutoStart):
+ def setupAvailableImageAndBackupMedia(self, onStartup, onPreferenceChange, doNotAllowAutoStart):
"""
Sets up volumes for downloading from and backing up to
@@ -3205,6 +3292,7 @@ class RapidApp(gnomeglade.GnomeApp, dbus.service.Object):
self.downloadStats.clear()
self._resetDownloadInfo()
self.speed_label.set_text(' ')
+
def exitOnDownloadComplete(self):
if self.downloadComplete():
@@ -3478,7 +3566,43 @@ class DownloadStats:
self.downloadSize = 0
self.noWarnings = self.noErrors = 0
+class DownloadedFiles:
+ def __init__(self):
+ self.images = {}
+
+ def add_download(self, name, extension, date_time, sub_seconds, sequence_number_used):
+ if name not in self.images:
+ self.images[name] = ([extension], date_time, sub_seconds, sequence_number_used)
+ else:
+ if extension not in self.images[name][0]:
+ self.images[name][0].append(extension)
+
+
+ def matching_pair(self, name, extension, date_time, sub_seconds):
+ """Checks to see if the image matches an image that has already been downloaded.
+ Image name (minus extension), exif date time, and exif subseconds are checked.
+
+ Returns -1 and a sequence number if the name, extension, and exif values match (i.e. it has already been downloaded)
+ Returns 0 and a sequence number if name and exif values match, but the extension is different (i.e. a matching RAW + JPG image)
+ Returns -99 and a sequence number of None if images detected with the same filenames, but taken at different times
+ Returns 1 and a sequence number of None if no match"""
+
+ if name in self.images:
+ if self.images[name][1] == date_time and self.images[name][2] == sub_seconds:
+ if extension in self.images[name][0]:
+ return (-1, self.images[name][3])
+ else:
+ return (0, self.images[name][3])
+ else:
+ return (-99, None)
+ return (1, None)
+
+ def extExifDateTime(self, name):
+ """Returns first extension, exif date time and subseconds data for the already downloaded image"""
+ return (self.images[name][0][0], self.images[name][1], self.images[name][2])
+
class TimeForDownload:
+ # used to store variables, see below
pass
class TimeRemaining:
diff --git a/rapid/renamesubfolderprefs.py b/rapid/renamesubfolderprefs.py
index 71f9089..a449fd7 100644
--- a/rapid/renamesubfolderprefs.py
+++ b/rapid/renamesubfolderprefs.py
@@ -1,7 +1,7 @@
#!/usr/bin/python
# -*- coding: latin1 -*-
-### Copyright (C) 2007, 2008, 2009 Damon Lynch <damonlynch@gmail.com>
+### 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
@@ -147,6 +147,7 @@ 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.
@@ -247,6 +248,7 @@ class i18TranslateMeThanks:
_("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
@@ -322,6 +324,7 @@ LIST_SEQUENCE_NUMBERS_L2 = [
SEQUENCE_NUMBER_4,
SEQUENCE_NUMBER_5,
SEQUENCE_NUMBER_6,
+ SEQUENCE_NUMBER_7,
]
@@ -757,7 +760,7 @@ class Comboi18n(gtk.ComboBox):
return model[active][0]
class ImageRenamePreferences:
- def __init__(self, prefList, parent, fileSequenceLock=None, sequences=None):
+ def __init__(self, prefList, parent, fileSequenceLock=None, sequences=None):
"""
Exception raised if preferences are invalid.
@@ -1126,7 +1129,8 @@ class ImageRenamePreferences:
def generateNameUsingPreferences(self, photo, existingFilename=None,
stripCharacters = False, subfolder=None,
stripInitialPeriodFromExtension=False,
- sequencesPreliminary = True):
+ sequencesPreliminary = True,
+ sequence_to_use = None):
"""
Generate a filename for the photo in string format based on user prefs.
@@ -1136,7 +1140,9 @@ class ImageRenamePreferences:
"""
if self.sequences:
- if sequencesPreliminary:
+ if sequence_to_use is not None:
+ sequence = sequence_to_use
+ elif sequencesPreliminary:
sequence = self.sequences.getPrelimSequence()
else:
sequence = self.sequences.getFinalSequence()
@@ -1470,10 +1476,11 @@ class Sequences:
def imageCopySucceeded(self):
self.increment()
- def increment(self, subfolder=None):
+ def increment(self):
assert(self.assignedSequenceCounter == self.pool[0])
self.assignedSequenceCounter += 1
self.pool = self.pool[1:]
+ #assert(len(self.pool) > 0)