Exemplo n.º 1
0
    def _move_files_safe(self, src_web_path, dst_web_path):
        """
        Move file in collection from path1 to path2. Also move associated thumbnail and preview file, and any files
        with same prefix in collection folder (mainly RAWS)
        """
        src_file_phys_path = locations.collection_phys_path(src_web_path)
        dst_file_phys_path = locations.collection_phys_path(dst_web_path)

        # create list of modifications files will be moved in loop at the end of method
        renames = [(src_file_phys_path, dst_file_phys_path)]

        # query generators and add all generated miniatures to renames
        for generator in MINIATURE_GENERATORS:
            if generator.will_output_file(src_web_path):
                src_miniature_phys_path = generator.miniature_phys_path(src_file_phys_path)
                dst_miniature_phys_path = self._calculate_dst_path_after_move(src_web_path, dst_web_path,
                                                                              src_miniature_phys_path)
                renames.append((src_miniature_phys_path, dst_miniature_phys_path))

        # add move of "other files in group" in collection folder
        self._add_similar_files_modifications(src_file_phys_path, dst_file_phys_path, renames)

        # move files in batch
        # TODO: rollback changes (move files back to their original positions) on error
        for (src, dst) in renames:
            move_without_overwriting(src, dst,
                                     # allow creating destination folders only in trash
                                     create_destination_dir=locations.web_path_in_trash(dst_web_path))
Exemplo n.º 2
0
    def remove_old_trash_files():
        month_ago = localized_time(datetime.now() - timedelta(days=30))

        # select images from trash that were moved month before or earlier
        old_images_in_trash = Image.objects.filter(
            Q(directory__path__startswith="Trash/") | Q(directory__path__exact="Trash")
        ).filter(trash_time__lte=month_ago)

        # remove file in collection
        # thumbnails and database object will be removed by Thumbnailer and Indexer respectively
        for image in old_images_in_trash:
            image_phys_path = locations.collection_phys_path(image.path)
            all_files_with_prefix = set(glob.glob(os.path.splitext(image_phys_path)[0] + ".*"))
            logging.info("Removing outdated files in trash: " + " ".join(all_files_with_prefix))
            for file_name in all_files_with_prefix:
                os.unlink(file_name)

        # remove directory in trash if empty
        trash_dir_phys_path = locations.collection_phys_path(locations.TRASH_DIR_NAME)
        for (root, dirs, files) in os.walk(trash_dir_phys_path, topdown=False):
            for directory in dirs:
                try:
                    dir_path = os.path.join(root, directory)
                    os.rmdir(dir_path)
                    logging.info("Removing empty directory in trash: " + dir_path)
                except IOError as e:
                    # directory isn't empty - skipping
                    pass
Exemplo n.º 3
0
    def _try_copying_existing_miniature(cls, original_phys_path, miniature_phys_path, generator):
        """
        When original in collection is moved to new directory, copy existing miniature instead of creating a new one.
        """
        original_mtime = get_mtime_datetime(original_phys_path)
        original_basename = os.path.basename(original_phys_path)

        # originals with same basename and modification time are considered as identical
        # therefore if there exists thumbnail it can be used instead of creating new one
        same_original_query = File.objects.filter(name=original_basename, modification_time=original_mtime)

        for same_original in same_original_query.all():
            same_original_phys_path = locations.collection_phys_path(same_original.path)

            same_original_miniature_phys_path = generator.miniature_phys_path(same_original_phys_path)
            copy_args = (same_original_miniature_phys_path, miniature_phys_path)

            # underlying thumbnail exists - thumbnails can be copied
            if os.path.exists(same_original_miniature_phys_path):
                logger.info(
                    "there exists already original with same name and mtime: copying {} -> {}".format(*copy_args))
                shutil.copy(*copy_args)
                return True

        # there was no thumbnail yet
        # this could happen when two exact copies are added and no thumbnail was created for any of them
        return False
Exemplo n.º 4
0
    def _move_files(self, src_web_path, dst_web_path):
        src_phys_path = locations.collection_phys_path(src_web_path)

        if not os.path.isfile(src_phys_path):
            raise BadRequestException("Source file doesn't exist: " + src_phys_path)

        self._move_files_safe(src_web_path, dst_web_path)
Exemplo n.º 5
0
    def _create_links(file):
        video_generator = VideoGenerator()
        original_phys_path = locations.collection_phys_path(file.path)
        new_original_phys_path = os.path.splitext(original_phys_path)[0] + video_generator.extension()

        miniature_phys_path = video_generator.miniature_phys_path(original_phys_path)
        if not os.path.exists(miniature_phys_path):
            logger.warn("Miniature doesn't exist, skipping: {}".format(miniature_phys_path))
            return

        if os.path.islink(miniature_phys_path):
            logger.warn("Miniature is already symbolic link, skipping: {}".format(miniature_phys_path))
            file.substitute_original = False
            file.save()
            return

        logger.info("Swapping original with miniature: {}".format(original_phys_path))

        poster_generator = FirstFrameGenerator()
        # poster phys path has to be calculated before original is overwritten
        poster_phys_path = poster_generator.miniature_phys_path(original_phys_path)

        Linker._move_miniature_to_collection(original_phys_path, new_original_phys_path, video_generator)

        Linker._create_symlink(video_generator, new_original_phys_path)

        Linker._remove_original(original_phys_path, new_original_phys_path)

        Linker._move_poster(poster_phys_path, poster_generator, new_original_phys_path)

        Linker._update_file_information(file, new_original_phys_path)
Exemplo n.º 6
0
 def _update_mtime_if_needed(cls, file_object):
     file_phys_path = collection_phys_path(file_object.path)
     mtime = get_mtime_datetime(file_phys_path)
     if file_object.modification_time != mtime:
         logger.info("updating file mtime (and possibly: aspect_ratio): " + file_object.path)
         file_object.modification_time = mtime
         if is_jpeg(file_phys_path):
             file_object.aspect_ratio = cls.get_image_aspect_ratio(file_phys_path)
         file_object.save()
Exemplo n.º 7
0
def find_or_create_directory(web_path, parent=None, update_modification_time=True):
    directory_mtime = get_mtime_datetime(locations.collection_phys_path(web_path))
    directory, created = Directory.objects.get_or_create(path=web_path,
                                                defaults={'modification_time': directory_mtime, 'parent': parent})
    if update_modification_time and directory.modification_time != directory_mtime:
        logger.info("updating directory mtime: " + directory.path)
        directory.modification_time = directory_mtime
        directory.save()

    return directory
Exemplo n.º 8
0
    def post(self, request, *args, **kwargs):
        media_file = self.get_object()
        destination = self.request.data.get('destination', None)
        if destination is None:
            return Response({'reason': 'Required "destination" param is missing'}, status=status.HTTP_400_BAD_REQUEST)

        dst_folder_phys_path = locations.collection_phys_path(destination)
        move_to_trash = locations.web_path_in_trash(destination)
        # destination directory should exists unless media_file is moved to trash (directory tree should be created then)
        if not move_to_trash and not os.path.isdir(dst_folder_phys_path):
            return Response({'reason': 'Invalid destination directory'}, status=status.HTTP_404_NOT_FOUND)

        dst_file_web_path = normpath_join(destination, media_file.name)
        return self._handle_move_request(media_file.path, dst_file_web_path)
Exemplo n.º 9
0
    def perform_requested_rotations(cls):
        for rotated_image in Image.objects.filter(~Q(orientation='up')):
            image_phys_path = locations.collection_phys_path(rotated_image.path)

            cls._rotate_by_jpegtran(image_phys_path, rotated_image)
Exemplo n.º 10
0
 def _update_directory_mtime(new_directory):
     new_directory.modification_time = get_mtime_datetime(collection_phys_path(new_directory.path))
     new_directory.save()