diff options
Diffstat (limited to 'main.go')
-rw-r--r-- | main.go | 214 |
1 files changed, 115 insertions, 99 deletions
@@ -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 }{ |