aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--main.go214
1 files changed, 115 insertions, 99 deletions
diff --git a/main.go b/main.go
index a57f3af..1ef03ab 100644
--- a/main.go
+++ b/main.go
@@ -73,62 +73,63 @@ func dbCollectStrings(query string) ([]string, error) {
return result, nil
}
-type directoryManager struct {
- cache map[string]int64 // Unix-style paths to directory.id
-}
-
-func (dm *directoryManager) uncachedIDForPath(
- tx *sql.Tx, path []string) (int64, error) {
- var parent sql.NullInt64
- for _, name := range path {
- if err := tx.QueryRow(
- `SELECT id FROM directory WHERE name = ? AND parent IS ?`,
- name, parent).Scan(&parent); err == nil {
- continue
- } else if !errors.Is(err, sql.ErrNoRows) {
- return 0, err
- }
+// --- Initialization ----------------------------------------------------------
- if result, err := tx.Exec(
- `INSERT INTO directory(name, parent) VALUES (?, ?)`,
- name, parent); err != nil {
- return 0, err
- } else if id, err := result.LastInsertId(); err != nil {
- return 0, err
- } else {
- parent = sql.NullInt64{Int64: id, Valid: true}
- }
+// cmdInit initializes a "gallery directory" that contains gallery.sqlite,
+// images, thumbs.
+func cmdInit(args []string) error {
+ if len(args) != 1 {
+ return errors.New("usage: GD")
}
- return parent.Int64, nil
-}
-func (dm *directoryManager) IDForDirectoryPath(
- tx *sql.Tx, path string) (int64, error) {
- // Relative paths could be handled differently,
- // but right now, they're assumed to start at the root.
- path = filepath.ToSlash(filepath.Clean(path))
- list := strings.Split(path, "/")
- if len(list) > 1 && list[0] == "" {
- list = list[1:]
+ if err := openDB(args[0]); err != nil {
+ return err
}
- if len(list) == 0 {
- return 0, nil
+ if _, err := db.Exec(initializeSQL); err != nil {
+ return err
}
- if dm.cache == nil {
- dm.cache = make(map[string]int64)
- } else if id, ok := dm.cache[path]; ok {
- return id, nil
+ // XXX: There's technically no reason to keep images as symlinks,
+ // we might just keep absolute paths in the database as well.
+ if err := os.MkdirAll(
+ filepath.Join(galleryDirectory, "images"), 0755); err != nil {
+ return err
}
-
- id, err := dm.uncachedIDForPath(tx, list)
- if err != nil {
- return 0, err
+ if err := os.MkdirAll(
+ filepath.Join(galleryDirectory, "thumbs"), 0755); err != nil {
+ return err
}
- dm.cache[path] = id
- return id, nil
+ return nil
}
+// --- Web ---------------------------------------------------------------------
+
+var hashRE = regexp.MustCompile(`^/.*?/([0-9a-f]{40})$`)
+var staticHandler http.Handler
+
+var page = template.Must(template.New("/").Parse(`<!DOCTYPE html><html><head>
+ <title>Gallery</title>
+ <meta charset="utf-8" />
+ <meta name="viewport" content="width=device-width, initial-scale=1">
+ <link rel=stylesheet href=style.css>
+</head><body>
+ <h1>{{ .Name }}</h1>
+ <ul>
+ {{ range .Children }}
+ <li><a href="?id={{ . }}">{{ . }}</a></li>
+ {{ end }}
+ </ul>
+
+ {{ range .Entries }}
+ <a href="/image/{{ .Sha1 }}">
+ <img width={{ .Thumbw }} height={{ .Thumbh }} src="/thumb/{{ .Sha1 }}"
+ title="{{ .Name }}">
+ </a>
+ {{ end }}
+
+ <script src=gallery.js></script>
+</body></html>`))
+
// XXX: This is preliminary.
type entry struct {
Parent int64
@@ -197,59 +198,6 @@ func dbCollectDirectory(id int64) (directory, error) {
return d, rows2.Err()
}
-// cmdInit initializes a "gallery directory" that contains gallery.sqlite,
-// images, thumbs.
-func cmdInit(args []string) error {
- if len(args) != 1 {
- return errors.New("usage: GD")
- }
-
- if err := openDB(args[0]); err != nil {
- return err
- }
- if _, err := db.Exec(initializeSQL); err != nil {
- return err
- }
-
- // XXX: There's technically no reason to keep images as symlinks,
- // we might just keep absolute paths in the database as well.
- if err := os.MkdirAll(
- filepath.Join(galleryDirectory, "images"), 0755); err != nil {
- return err
- }
- if err := os.MkdirAll(
- filepath.Join(galleryDirectory, "thumbs"), 0755); err != nil {
- return err
- }
- return nil
-}
-
-var hashRE = regexp.MustCompile(`^/.*?/([0-9a-f]{40})$`)
-var staticHandler http.Handler
-
-var page = template.Must(template.New("/").Parse(`<!DOCTYPE html><html><head>
- <title>Gallery</title>
- <meta charset="utf-8" />
- <meta name="viewport" content="width=device-width, initial-scale=1">
- <link rel=stylesheet href=style.css>
-</head><body>
- <h1>{{ .Name }}</h1>
- <ul>
- {{ range .Children }}
- <li><a href="?id={{ . }}">{{ . }}</a></li>
- {{ end }}
- </ul>
-
- {{ range .Entries }}
- <a href="/image/{{ .Sha1 }}">
- <img width={{ .Thumbw }} height={{ .Thumbh }} src="/thumb/{{ .Sha1 }}"
- title="{{ .Name }}">
- </a>
- {{ end }}
-
- <script src=gallery.js></script>
-</body></html>`))
-
func handleRequest(w http.ResponseWriter, r *http.Request) {
if r.URL.Path != "/" {
staticHandler.ServeHTTP(w, r)
@@ -321,8 +269,68 @@ func cmdRun(args []string) error {
return s.ListenAndServe()
}
+// --- Import ------------------------------------------------------------------
+
+type directoryManager struct {
+ cache map[string]int64 // Unix-style paths to directory.id
+}
+
+func (dm *directoryManager) uncachedIDForPath(
+ tx *sql.Tx, path []string) (int64, error) {
+ var parent sql.NullInt64
+ for _, name := range path {
+ if err := tx.QueryRow(
+ `SELECT id FROM directory WHERE name = ? AND parent IS ?`,
+ name, parent).Scan(&parent); err == nil {
+ continue
+ } else if !errors.Is(err, sql.ErrNoRows) {
+ return 0, err
+ }
+
+ if result, err := tx.Exec(
+ `INSERT INTO directory(name, parent) VALUES (?, ?)`,
+ name, parent); err != nil {
+ return 0, err
+ } else if id, err := result.LastInsertId(); err != nil {
+ return 0, err
+ } else {
+ parent = sql.NullInt64{Int64: id, Valid: true}
+ }
+ }
+ return parent.Int64, nil
+}
+
+func (dm *directoryManager) IDForDirectoryPath(
+ tx *sql.Tx, path string) (int64, error) {
+ // Relative paths could be handled differently,
+ // but right now, they're assumed to start at the root.
+ path = filepath.ToSlash(filepath.Clean(path))
+ list := strings.Split(path, "/")
+ if len(list) > 1 && list[0] == "" {
+ list = list[1:]
+ }
+ if len(list) == 0 {
+ return 0, nil
+ }
+
+ if dm.cache == nil {
+ dm.cache = make(map[string]int64)
+ } else if id, ok := dm.cache[path]; ok {
+ return id, nil
+ }
+
+ id, err := dm.uncachedIDForPath(tx, list)
+ if err != nil {
+ return 0, err
+ }
+ dm.cache[path] = id
+ return id, nil
+}
+
func isImage(path string) (bool, error) {
cmd := exec.Command("xdg-mime", "query", "filetype", path)
+
+ // XXX: Early returns may leak resources.
stdout, err := cmd.StdoutPipe()
if err != nil {
return false, err
@@ -481,6 +489,8 @@ func cmdSync(args []string) error {
return nil
}
+// --- Check -------------------------------------------------------------------
+
// cmdCheck checks if all files tracked in the DB are accessible.
func cmdCheck(args []string) error {
if len(args) != 1 {
@@ -495,6 +505,8 @@ func cmdCheck(args []string) error {
return nil
}
+// --- Thumbnailing ------------------------------------------------------------
+
func makeThumbnail(pathImage, pathThumb string) (int, int, error) {
thumbDirname, _ := filepath.Split(pathThumb)
if err := os.MkdirAll(thumbDirname, 0755); err != nil {
@@ -597,6 +609,8 @@ func cmdThumbnail(args []string) error {
return nil
}
+// --- Perceptual hash ---------------------------------------------------------
+
func makeDhash(hasher, pathThumb string) (uint64, error) {
cmd := exec.Command(hasher, pathThumb)
@@ -658,6 +672,8 @@ func cmdDhash(args []string) error {
return nil
}
+// --- Main --------------------------------------------------------------------
+
var commands = map[string]struct {
handler func(args []string) error
}{