summaryrefslogtreecommitdiff
path: root/raphodo/thumbnaildaemon.py
diff options
context:
space:
mode:
Diffstat (limited to 'raphodo/thumbnaildaemon.py')
-rwxr-xr-xraphodo/thumbnaildaemon.py191
1 files changed, 191 insertions, 0 deletions
diff --git a/raphodo/thumbnaildaemon.py b/raphodo/thumbnaildaemon.py
new file mode 100755
index 0000000..3552e3f
--- /dev/null
+++ b/raphodo/thumbnaildaemon.py
@@ -0,0 +1,191 @@
+#!/usr/bin/env python3
+
+# Copyright (C) 2015-2016 Damon Lynch <damonlynch@gmail.com>
+
+# This file is part of Rapid Photo Downloader.
+#
+# 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 3 of the License, or
+# (at your option) any later version.
+#
+# Rapid Photo Downloader 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 Rapid Photo Downloader. If not,
+# see <http://www.gnu.org/licenses/>.
+
+"""
+Generates thumbnails for files that have already been downloaded, and
+writes out FDO thumbnails for files of the type where that makes sense
+e.g. RAW files
+
+See cache.py for definitions of various caches used by Rapid Photo Downloader.
+
+Runs as a single instance daemon process, i.e. for the lifetime of the program.
+"""
+
+__author__ = 'Damon Lynch'
+__copyright__ = "Copyright 2015-2016, Damon Lynch"
+
+import logging
+import pickle
+import sys
+import os
+from typing import Set, Dict
+
+from gettext import gettext as _
+import zmq
+
+from raphodo.constants import (FileType, ThumbnailSize, ThumbnailCacheStatus,
+ ThumbnailCacheDiskStatus, ExtractionTask,
+ ExtractionProcessing,
+ ThumbnailCacheOrigin)
+from raphodo.interprocess import (ThumbnailDaemonData, GenerateThumbnailsResults, DaemonProcess,
+ ThumbnailExtractorArgument)
+from raphodo.rpdfile import RPDFile
+from raphodo.thumbnailpara import GetThumbnailFromCache, preprocess_thumbnail_from_disk
+from raphodo.cache import FdoCacheLarge, FdoCacheNormal
+
+
+class DameonThumbnailWorker(DaemonProcess):
+ """
+ Generates thumbnails for files that have already been downloaded, and
+ writes out FDO thumbnails for files of the type where that makes sense
+ e.g. RAW files
+ """
+
+ def __init__(self):
+ super().__init__('Thumbnail Daemon')
+
+ def run(self):
+ """
+ Set up process and then process thumbnail requests one by one
+ """
+
+ # Always set use_thumbnail_cache to True, because this is a daemon
+ # process that runs for the lifetime of the program. User can
+ # change the program preferences.
+ # Whether to actually use it will be determined at the time the
+ # thumbnail is sought, using the user's preference at that moment.
+ thumbnail_caches = GetThumbnailFromCache(use_thumbnail_cache=True)
+
+ self.frontend = self.context.socket(zmq.PUSH)
+
+ directive, content = self.receiver.recv_multipart()
+
+ self.check_for_command(directive, content)
+
+ data = pickle.loads(content) # type: ThumbnailDaemonData
+ assert data.frontend_port is not None
+ self.frontend.connect("tcp://localhost:{}".format(data.frontend_port))
+
+ # handle freedesktop.org cache files directly
+ fdo_cache_large = FdoCacheLarge()
+ fdo_cache_normal = FdoCacheNormal()
+
+ while True:
+ directive, content = self.receiver.recv_multipart()
+
+ self.check_for_command(directive, content)
+
+ data = pickle.loads(content) # type: ThumbnailDaemonData
+ rpd_file = data.rpd_file
+ if data.backup_full_file_names is not None:
+ # File has been backed up, and an extractor has already generated a FDO thumbnail
+ # for it.
+ # Copy and modify the existing FDO thumbnail
+
+ # MD5 name of the existing FDO thumbnail
+ md5_name = data.fdo_name
+ assert md5_name
+
+ for backup_full_file_name in data.backup_full_file_names:
+
+ # Check to see if existing thumbnail in FDO cache can be
+ # modified and renamed to reflect new URI
+ try:
+ mtime = os.path.getmtime(backup_full_file_name)
+ except OSError:
+ logging.debug("Backup file does not exist: %s", backup_full_file_name)
+ else:
+ logging.debug("Copying and modifying existing FDO 128 thumbnail for %s",
+ backup_full_file_name)
+ fdo_cache_normal.modify_existing_thumbnail_and_save_copy(
+ existing_cache_thumbnail=md5_name,
+ full_file_name=backup_full_file_name,
+ size=rpd_file.size,
+ modification_time=mtime,
+ error_on_missing_thumbnail=True)
+
+ logging.debug("Copying and modifying existing FDO 256 thumbnail for %s",
+ backup_full_file_name)
+ fdo_cache_large.modify_existing_thumbnail_and_save_copy(
+ existing_cache_thumbnail=md5_name,
+ full_file_name=backup_full_file_name,
+ size=rpd_file.size,
+ modification_time=mtime,
+ error_on_missing_thumbnail=False)
+ else:
+ # file has just been downloaded and renamed
+ rpd_file.modified_via_daemon_process = True
+ try:
+
+ # Check the download source to see if it's in the caches, not the file
+ # we've just downloaded
+
+ use_thumbnail_cache = (data.use_thumbnail_cache and not
+ (data.write_fdo_thumbnail and rpd_file.should_write_fdo()))
+ cache_search = thumbnail_caches.get_from_cache(
+ rpd_file=rpd_file,
+ use_thumbnail_cache=use_thumbnail_cache)
+ task, thumbnail_bytes, full_file_name_to_work_on, origin = cache_search
+ processing = set() # type: Set[ExtractionProcessing]
+
+ if task == ExtractionTask.undetermined:
+ # Thumbnail was not found in any cache: extract it
+
+ task = preprocess_thumbnail_from_disk(rpd_file=rpd_file,
+ processing=processing)
+ if task != ExtractionTask.bypass:
+ if rpd_file.thm_full_name is not None:
+ full_file_name_to_work_on = rpd_file.download_thm_full_name
+ else:
+ full_file_name_to_work_on = rpd_file.download_full_file_name
+
+ if task == ExtractionTask.bypass:
+ self.content = pickle.dumps(GenerateThumbnailsResults(
+ rpd_file=rpd_file, thumbnail_bytes=thumbnail_bytes),
+ pickle.HIGHEST_PROTOCOL)
+ self.send_message_to_sink()
+
+ elif task != ExtractionTask.undetermined:
+ # Send data to load balancer, which will send to one of its
+ # workers
+
+ self.content = pickle.dumps(ThumbnailExtractorArgument(
+ rpd_file=rpd_file,
+ task=task,
+ processing=processing,
+ full_file_name_to_work_on=full_file_name_to_work_on,
+ secondary_full_file_name='',
+ exif_buffer=None,
+ thumbnail_bytes=thumbnail_bytes,
+ use_thumbnail_cache=data.use_thumbnail_cache,
+ file_to_work_on_is_temporary=False,
+ write_fdo_thumbnail=data.write_fdo_thumbnail,
+ send_thumb_to_main=True),
+ pickle.HIGHEST_PROTOCOL)
+ self.frontend.send_multipart([b'data', self.content])
+ except SystemExit as e:
+ sys.exit(e)
+ except:
+ logging.error("Exception working on file %s", rpd_file.full_file_name)
+ logging.exception("Traceback:")
+
+if __name__ == '__main__':
+ generate_thumbnails = DameonThumbnailWorker()
+ generate_thumbnails.run() \ No newline at end of file