diff options
| -rw-r--r-- | main.go | 109 | 
1 files changed, 99 insertions, 10 deletions
@@ -17,6 +17,7 @@ import (  	"os/exec"  	"path/filepath"  	"regexp" +	"strconv"  	"strings"  	"time" @@ -53,11 +54,11 @@ func dbCollectStrings(query string) ([]string, error) {  	var result []string  	for rows.Next() { -		var sha1 string -		if err := rows.Scan(&sha1); err != nil { +		var s string +		if err := rows.Scan(&s); err != nil {  			return nil, err  		} -		result = append(result, sha1) +		result = append(result, s)  	}  	if err := rows.Err(); err != nil {  		return nil, err @@ -103,6 +104,74 @@ func (dm *directoryManager) IDForDirectoryPath(path string) (int64, error) {  	return parent.Int64, nil  } +// XXX: This is preliminary. +type entry struct { +	Parent int64 +	Name   string +	Mtime  int64 +	Sha1   string + +	Thumbw int +	Thumbh int +	Dhash  int64 +} + +// XXX: This is preliminary. +type directory struct { +	Id       int64 +	Name     string +	Parent   int64 +	Children []int64 +	Entries  []entry +} + +func dbCollectDirectory(id int64) (directory, error) { +	d := directory{Id: id} +	dbID := sql.NullInt64{Int64: id, Valid: id != 0} +	if id != 0 { +		err := db.QueryRow(`SELECT name, IFNULL(parent, 0) +			FROM directory WHERE id IS ?`, dbID).Scan(&d.Name, &d.Parent) +		if err != nil { +			return d, err +		} +	} + +	rows1, err := db.Query(`SELECT id FROM directory WHERE parent IS ?`, dbID) +	if err != nil { +		return d, err +	} +	defer rows1.Close() +	for rows1.Next() { +		var child int64 +		if err := rows1.Scan(&child); err != nil { +			return d, err +		} +		d.Children = append(d.Children, child) +	} +	if err := rows1.Err(); err != nil { +		return d, err +	} + +	rows2, err := db.Query(`SELECT IFNULL(entry.parent, 0), +		entry.name, entry.mtime, entry.sha1, +		IFNULL(image.thumbw, 0), IFNULL(image.thumbh, 0), IFNULL(image.dhash, 0) +		FROM entry JOIN image ON entry.sha1 = image.sha1 +		WHERE entry.parent IS ?`, dbID) +	if err != nil { +		return d, err +	} +	defer rows2.Close() +	for rows2.Next() { +		var e entry +		if err := rows2.Scan(&e.Parent, &e.Name, &e.Mtime, &e.Sha1, +			&e.Thumbw, &e.Thumbh, &e.Dhash); err != nil { +			return d, err +		} +		d.Entries = append(d.Entries, e) +	} +	return d, rows2.Err() +} +  // cmdInit initializes a "gallery directory" that contains gallery.sqlite,  // images, thumbs.  func cmdInit(args []string) error { @@ -137,8 +206,21 @@ var page = template.Must(template.New("/").Parse(`<!DOCTYPE html><html><head>  	<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) { @@ -147,10 +229,14 @@ func handleRequest(w http.ResponseWriter, r *http.Request) {  		return  	} -	// TODO: Include the most elementary contents first. - -	if err := page.Execute(w, "Hello world"); err != nil { +	id, _ := strconv.ParseInt(r.URL.Query().Get("id"), 10, 64) +	d, err := dbCollectDirectory(id) +	if err != nil {  		http.Error(w, err.Error(), 500) +		return +	} +	if err := page.Execute(w, d); err != nil { +		log.Println(err)  	}  } @@ -186,8 +272,8 @@ func cmdRun(args []string) error {  	staticHandler = http.FileServer(http.Dir("public"))  	http.HandleFunc("/", handleRequest) -	http.HandleFunc("/images/", handleImages) -	http.HandleFunc("/thumbs/", handleThumbs) +	http.HandleFunc("/image/", handleImages) +	http.HandleFunc("/thumb/", handleThumbs)  	// TODO: Add a few API endpoints.  	host, port, err := net.SplitHostPort(address) @@ -357,11 +443,14 @@ func makeThumbnail(pathImage, pathThumb string) (int, int, error) {  	//  - https://www.imagemagick.org/Usage/thumbnails/  	//  - https://imagemagick.org/script/command-line-options.php#layers  	// +	// "info:" output is written for each frame, which is why we delete +	// all of them but the first one beforehands. +	//  	// TODO: See if we can optimize resulting WebP animations.  	// (Do -layers optimize* apply to this format at all?)  	cmd := exec.Command("convert", pathImage, "-coalesce", "-colorspace", "RGB",  		"-auto-orient", "-strip", "-resize", "256x128>", "-colorspace", "sRGB", -		"-format", "%w %h", "+write", "info:", pathThumb) +		"-format", "%w %h", "+write", pathThumb, "-delete", "1--1", "info:")  	stdout, err := cmd.StdoutPipe()  	if err != nil {  | 
