瀏覽代碼

Album parent, png support

Innocenty Enikeew 10 年之前
父節點
當前提交
d0ea4d3f6b
共有 4 個文件被更改,包括 50 次插入28 次删除
  1. 24 17
      assets/site.js
  2. 11 1
      exif.lisp
  3. 3 1
      photo-store.asd
  4. 12 9
      photo-store.lisp

+ 24 - 17
assets/site.js

@@ -2,10 +2,12 @@ function setAlbums(albums) {
     var dAlbums = document.getElementById('albums');
     dAlbums.innerHTML = '';
     Array.prototype.forEach.call(albums, function(alb, i){
-        var a = addAlbumDom(dAlbums, alb);
+        var a = addAlbumDom(dAlbums, alb, true);
+        a.setAttribute('data-id', alb.id);
+        a.setAttribute('title', alb.cover.src);
         a.addEventListener('click', function() {
             jsonGET('/api/albums/' + alb.id + '/', function (alb) {
-                startGallery(alb.photos);
+                startGallery(alb.photos, 0, alb.id);
             });
         });
     });
@@ -15,10 +17,10 @@ function setIncoming(albums, parent) {
     parent.innerHTML = '';
     Array.prototype.forEach.call(albums, function(alb, i){
         var div = appendElement(parent, 'div', null, 'incoming-album');
-        var a = addAlbumDom(div, alb);
+        var a = addAlbumDom(div, alb, true);
         a.addEventListener('click', function(e) {
             e.preventDefault();
-            startGallery(alb.photos);
+            startGallery(alb.photos, 0, i);
         });
         var form = appendElement(div, 'form', null, null, '<div><p><label>Title</label><input type="text"/></p><p><label>Path</label><input type="text"/></p><p><input type="submit" value="Import"/></p>');
         form[0].value = alb.title;
@@ -42,11 +44,27 @@ function setIncoming(albums, parent) {
     });
 }
 
-function startGallery(items, index) {
+function addAlbumDom(parent, alb, add_count) {
+    var a = appendElement(parent, 'a');
+    var img = appendElement(a, 'img');
+    img.src = alb.cover.src;
+    if (alb.title) {
+        var fig = appendElement(a, 'figure');
+        fig.textContent = alb.title;
+        if (add_count)
+            fig.textContent += ' [' + (alb.count || alb.photos.length) + ']';
+    };
+    return a;
+}
+
+function startGallery(items, index, uid) {
     var pswpElement = document.querySelectorAll('.pswp')[0];
 
     var options = {
-        index: index || 0
+        preload: [1, 3],
+        loadingIndicatorDelay: 300,
+        index: index || 0,
+        galleryUID: uid || 1
     };
 
     // Initializes and opens PhotoSwipe
@@ -56,17 +74,6 @@ function startGallery(items, index) {
     return gallery;
 }
 
-function addAlbumDom(parent, alb) {
-    var a = appendElement(parent, 'a');
-    var img = appendElement(a, 'img');
-    img.src = alb.cover.src;
-    if (alb.title) {
-        var fig = appendElement(a, 'figure');
-        fig.textContent = alb.title;
-    };
-    return a;
-}
-
   function appendElement(parent, tag, id, className, innerHTML) {
     var el = document.createElement(tag);
     if (id) el.id = id;

+ 11 - 1
exif.lisp

@@ -31,6 +31,15 @@
                                 (zpb-exif:exif-value :ImageHeight exif)))))
       (and width height (list width height)))))
 
+(defun get-dims (path)
+  (with-open-file (in path :element-type '(unsigned-byte 8))
+    (case (intern (string-upcase (pathname-type path)) "KEYWORD")
+      (:jpg (multiple-value-bind (h w)
+                (jpeg:decode-stream-height-width in)
+              (list w h)))
+      (:png (let ((png (png-read:read-png-datastream in)))
+              (list (png-read:width png) (png-read:height png)))))))
+
 (defun load-photo-info (path)
   (with-open-file (in path :element-type '(unsigned-byte 8))
     (let ((length (file-length in))
@@ -43,6 +52,7 @@
        (cons :length length)
        (cons :created-at (local-time:universal-to-timestamp
                           (or (exif-to-taken exif) modified)))
-       (cons :dim (exif-to-dim exif))
+       (cons :dim (or (exif-to-dim exif)
+                      (get-dims path)))
        (cons :location (exif-to-point exif))))))
 

+ 3 - 1
photo-store.asd

@@ -3,11 +3,13 @@
   :description "Home photo storage"
   :author "Innokentiy Enikeev <me@enikesha.net>"
   :license "MIT"
-  :depends-on (:cl-json
+  :depends-on (:cl-jpeg
+               :cl-json
                :geo
                :iterate
                :local-time
                :log4cl
+               :png-read
                :restas
                :zpb-exif)
   :serial t

+ 12 - 9
photo-store.lisp

@@ -19,7 +19,7 @@
 (defun db-init ()
   (with-db (db)
     (sqlite:execute-non-query db "create table if not exists photos (id INTEGER PRIMARY KEY, path, size, taken, width, height, lat, lon)")
-    (sqlite:execute-non-query db "create table if not exists albums (id INTEGER PRIMARY KEY, name, description, cover_id REFERENCES photos)")
+    (sqlite:execute-non-query db "create table if not exists albums (id INTEGER PRIMARY KEY, name, description, cover_id REFERENCES photos, parent_id REFERENCES albums)")
     (sqlite:execute-non-query db "create table if not exists album_photos (album_id REFERENCES albums NOT NULL, photo_id REFERENCES photos NOT NULL, description, idx, hidden)")))
 
 (defun db/add-photo (db info)
@@ -66,12 +66,14 @@
                 (cons :cover (find cover-id photos :key (agetter :id)))
                 (cons :photos photos)))))))
 
-(defun db-load-albums ()
+(defun db-load-albums (&optional parent-id)
   (with-db (db)
-    (iter (for (id title cover-path cover-w cover-h)
-               in-sqlite-query "select a.id, a.name, c.path, c.width, c.height from albums a inner join photos c on a.cover_id=c.id order by c.taken" on-database db)
+    (iter (for (id title cover-path cover-w cover-h cover-taken count)
+               in-sqlite-query "select a.id, a.name, c.path, c.width, c.height, c.taken, (select count(photo_id) from album_photos where album_id=a.id) cnt from albums a left join photos c on a.cover_id=c.id where cnt > 0 and ((? is null and parent_id is null) or (parent_id=?)) order by c.taken" on-database db with-parameters (parent-id parent-id))
           (collect (list (cons :id id)
                          (cons :title title)
+                         (cons :count count)
+                         (cons :date cover-taken)
                          (cons :cover (list (cons :src (concatenate 'string
                                                                     *photo-storage-url* cover-path))
                                             (cons :w cover-w)
@@ -97,7 +99,7 @@
   (elt seq (floor (length seq) 2)))
 
 (defun imagep (path)
-  (equal (string-downcase (pathname-type path)) "jpg"))
+  (member (string-downcase (pathname-type path)) '("jpg" "png") :test #'equal))
 
 (defun directory-images (directory)
   (remove-if-not 'imagep (uiop:directory-files directory)))
@@ -154,10 +156,11 @@
       ;; Move all non-image files from original folders if no images left there.
       ;; Do not call after-move-func on them
       (setf after-move-func #'identity)
-      (dolist (dir dirs)
-        (unless (other-images dir files)
-          (move (uiop:directory-files dir) dest)
-          (ignore-errors (uiop:delete-empty-directory dir)))))))
+      (ignore-errors
+        (dolist (dir dirs)
+          (unless (other-images dir files)
+            (move (uiop:directory-files dir) dest)
+            (uiop:delete-empty-directory dir)))))))
 
 (defun import-album (name dest paths)
   (let (added-photos