From bc037315470431ac1f1ba2c7365ca634895e113f Mon Sep 17 00:00:00 2001 From: Přemysl Eric Janouch Date: Mon, 25 Dec 2023 02:44:30 +0100 Subject: Shuffle code --- main.go | 412 ++++++++++++++++++++++++++++++++-------------------------------- 1 file changed, 206 insertions(+), 206 deletions(-) (limited to 'main.go') diff --git a/main.go b/main.go index 29b08d3..53c7e22 100644 --- a/main.go +++ b/main.go @@ -453,212 +453,6 @@ func handleAPITags(w http.ResponseWriter, r *http.Request) { // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -func getImageDimensions(sha1 string) (w int64, h int64, err error) { - err = db.QueryRow(`SELECT width, height FROM image WHERE sha1 = ?`, - sha1).Scan(&w, &h) - return -} - -func getImagePaths(sha1 string) (paths []string, err error) { - rows, err := db.Query(`WITH RECURSIVE paths(parent, path) AS ( - SELECT parent, name AS path FROM node WHERE sha1 = ? - UNION ALL - SELECT n.parent, n.name || '/' || p.path - FROM node AS n JOIN paths AS p ON n.id = p.parent - ) SELECT path FROM paths WHERE parent IS NULL`, sha1) - if err != nil { - return nil, err - } - defer rows.Close() - - paths = []string{} - for rows.Next() { - var path string - if err := rows.Scan(&path); err != nil { - return nil, err - } - paths = append(paths, path) - } - return paths, rows.Err() -} - -func getImageTags(sha1 string) (map[string]map[string]float32, error) { - rows, err := db.Query(` - SELECT ts.name, t.name, ta.weight FROM tag_assignment AS ta - JOIN tag AS t ON t.id = ta.tag - JOIN tag_space AS ts ON ts.id = t.space - WHERE ta.sha1 = ?`, sha1) - if err != nil { - return nil, err - } - defer rows.Close() - - result := make(map[string]map[string]float32) - for rows.Next() { - var ( - space, tag string - weight float32 - ) - if err := rows.Scan(&space, &tag, &weight); err != nil { - return nil, err - } - - tags := result[space] - if tags == nil { - tags = make(map[string]float32) - result[space] = tags - } - tags[tag] = weight - } - return result, rows.Err() -} - -func handleAPIInfo(w http.ResponseWriter, r *http.Request) { - var params struct { - SHA1 string - } - if err := json.NewDecoder(r.Body).Decode(¶ms); err != nil { - http.Error(w, err.Error(), http.StatusBadRequest) - return - } - - var result struct { - Width int64 `json:"width"` - Height int64 `json:"height"` - Paths []string `json:"paths"` - Tags map[string]map[string]float32 `json:"tags"` - } - - var err error - result.Width, result.Height, err = getImageDimensions(params.SHA1) - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - result.Paths, err = getImagePaths(params.SHA1) - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - result.Tags, err = getImageTags(params.SHA1) - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - if err := json.NewEncoder(w).Encode(result); err != nil { - log.Println(err) - } -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -type webSimilarImage struct { - SHA1 string `json:"sha1"` - PixelsRatio float32 `json:"pixelsRatio"` - ThumbW int64 `json:"thumbW"` - ThumbH int64 `json:"thumbH"` - Paths []string `json:"paths"` -} - -func getSimilar(sha1 string, dhash int64, pixels int64, distance int) ( - result []webSimilarImage, err error) { - // For distance ∈ {0, 1}, this query is quite inefficient. - // In exchange, it's generic. - // - // If there's a dhash, there should also be thumbnail dimensions, - // so not bothering with IFNULL on them. - rows, err := db.Query(` - SELECT sha1, width * height, IFNULL(thumbw, 0), IFNULL(thumbh, 0) - FROM image WHERE sha1 <> ? AND dhash IS NOT NULL - AND hamming(dhash, ?) = ?`, sha1, dhash, distance) - if err != nil { - return nil, err - } - defer rows.Close() - - result = []webSimilarImage{} - for rows.Next() { - var ( - match webSimilarImage - matchPixels int64 - ) - if err = rows.Scan(&match.SHA1, - &matchPixels, &match.ThumbW, &match.ThumbH); err != nil { - return nil, err - } - if match.Paths, err = getImagePaths(match.SHA1); err != nil { - return nil, err - } - match.PixelsRatio = float32(matchPixels) / float32(pixels) - result = append(result, match) - } - return result, rows.Err() -} - -func getSimilarGroups(sha1 string, dhash int64, pixels int64, - output map[string][]webSimilarImage) error { - var err error - for distance := 0; distance <= 1; distance++ { - output[fmt.Sprintf("Perceptual distance %d", distance)], err = - getSimilar(sha1, dhash, pixels, distance) - if err != nil { - return err - } - } - return nil -} - -func handleAPISimilar(w http.ResponseWriter, r *http.Request) { - var params struct { - SHA1 string - } - if err := json.NewDecoder(r.Body).Decode(¶ms); err != nil { - http.Error(w, err.Error(), http.StatusBadRequest) - return - } - - var result struct { - Info webSimilarImage `json:"info"` - Groups map[string][]webSimilarImage `json:"groups"` - } - - result.Info = webSimilarImage{SHA1: params.SHA1, PixelsRatio: 1} - if paths, err := getImagePaths(params.SHA1); err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } else { - result.Info.Paths = paths - } - - var ( - width, height int64 - dhash sql.NullInt64 - ) - err := db.QueryRow(` - SELECT width, height, dhash, IFNULL(thumbw, 0), IFNULL(thumbh, 0) - FROM image WHERE sha1 = ?`, params.SHA1).Scan(&width, &height, &dhash, - &result.Info.ThumbW, &result.Info.ThumbH) - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - - result.Groups = make(map[string][]webSimilarImage) - if dhash.Valid { - if err := getSimilarGroups( - params.SHA1, dhash.Int64, width*height, result.Groups); err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - } - - if err := json.NewEncoder(w).Encode(result); err != nil { - log.Println(err) - } -} - -// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - type webDuplicateImage struct { SHA1 string `json:"sha1"` ThumbW int64 `json:"thumbW"` @@ -899,6 +693,212 @@ func handleAPIOrphans(w http.ResponseWriter, r *http.Request) { // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +func getImageDimensions(sha1 string) (w int64, h int64, err error) { + err = db.QueryRow(`SELECT width, height FROM image WHERE sha1 = ?`, + sha1).Scan(&w, &h) + return +} + +func getImagePaths(sha1 string) (paths []string, err error) { + rows, err := db.Query(`WITH RECURSIVE paths(parent, path) AS ( + SELECT parent, name AS path FROM node WHERE sha1 = ? + UNION ALL + SELECT n.parent, n.name || '/' || p.path + FROM node AS n JOIN paths AS p ON n.id = p.parent + ) SELECT path FROM paths WHERE parent IS NULL`, sha1) + if err != nil { + return nil, err + } + defer rows.Close() + + paths = []string{} + for rows.Next() { + var path string + if err := rows.Scan(&path); err != nil { + return nil, err + } + paths = append(paths, path) + } + return paths, rows.Err() +} + +func getImageTags(sha1 string) (map[string]map[string]float32, error) { + rows, err := db.Query(` + SELECT ts.name, t.name, ta.weight FROM tag_assignment AS ta + JOIN tag AS t ON t.id = ta.tag + JOIN tag_space AS ts ON ts.id = t.space + WHERE ta.sha1 = ?`, sha1) + if err != nil { + return nil, err + } + defer rows.Close() + + result := make(map[string]map[string]float32) + for rows.Next() { + var ( + space, tag string + weight float32 + ) + if err := rows.Scan(&space, &tag, &weight); err != nil { + return nil, err + } + + tags := result[space] + if tags == nil { + tags = make(map[string]float32) + result[space] = tags + } + tags[tag] = weight + } + return result, rows.Err() +} + +func handleAPIInfo(w http.ResponseWriter, r *http.Request) { + var params struct { + SHA1 string + } + if err := json.NewDecoder(r.Body).Decode(¶ms); err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + + var result struct { + Width int64 `json:"width"` + Height int64 `json:"height"` + Paths []string `json:"paths"` + Tags map[string]map[string]float32 `json:"tags"` + } + + var err error + result.Width, result.Height, err = getImageDimensions(params.SHA1) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + result.Paths, err = getImagePaths(params.SHA1) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + result.Tags, err = getImageTags(params.SHA1) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + if err := json.NewEncoder(w).Encode(result); err != nil { + log.Println(err) + } +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +type webSimilarImage struct { + SHA1 string `json:"sha1"` + PixelsRatio float32 `json:"pixelsRatio"` + ThumbW int64 `json:"thumbW"` + ThumbH int64 `json:"thumbH"` + Paths []string `json:"paths"` +} + +func getSimilar(sha1 string, dhash int64, pixels int64, distance int) ( + result []webSimilarImage, err error) { + // For distance ∈ {0, 1}, this query is quite inefficient. + // In exchange, it's generic. + // + // If there's a dhash, there should also be thumbnail dimensions, + // so not bothering with IFNULL on them. + rows, err := db.Query(` + SELECT sha1, width * height, IFNULL(thumbw, 0), IFNULL(thumbh, 0) + FROM image WHERE sha1 <> ? AND dhash IS NOT NULL + AND hamming(dhash, ?) = ?`, sha1, dhash, distance) + if err != nil { + return nil, err + } + defer rows.Close() + + result = []webSimilarImage{} + for rows.Next() { + var ( + match webSimilarImage + matchPixels int64 + ) + if err = rows.Scan(&match.SHA1, + &matchPixels, &match.ThumbW, &match.ThumbH); err != nil { + return nil, err + } + if match.Paths, err = getImagePaths(match.SHA1); err != nil { + return nil, err + } + match.PixelsRatio = float32(matchPixels) / float32(pixels) + result = append(result, match) + } + return result, rows.Err() +} + +func getSimilarGroups(sha1 string, dhash int64, pixels int64, + output map[string][]webSimilarImage) error { + var err error + for distance := 0; distance <= 1; distance++ { + output[fmt.Sprintf("Perceptual distance %d", distance)], err = + getSimilar(sha1, dhash, pixels, distance) + if err != nil { + return err + } + } + return nil +} + +func handleAPISimilar(w http.ResponseWriter, r *http.Request) { + var params struct { + SHA1 string + } + if err := json.NewDecoder(r.Body).Decode(¶ms); err != nil { + http.Error(w, err.Error(), http.StatusBadRequest) + return + } + + var result struct { + Info webSimilarImage `json:"info"` + Groups map[string][]webSimilarImage `json:"groups"` + } + + result.Info = webSimilarImage{SHA1: params.SHA1, PixelsRatio: 1} + if paths, err := getImagePaths(params.SHA1); err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } else { + result.Info.Paths = paths + } + + var ( + width, height int64 + dhash sql.NullInt64 + ) + err := db.QueryRow(` + SELECT width, height, dhash, IFNULL(thumbw, 0), IFNULL(thumbh, 0) + FROM image WHERE sha1 = ?`, params.SHA1).Scan(&width, &height, &dhash, + &result.Info.ThumbW, &result.Info.ThumbH) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + result.Groups = make(map[string][]webSimilarImage) + if dhash.Valid { + if err := getSimilarGroups( + params.SHA1, dhash.Int64, width*height, result.Groups); err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + } + + if err := json.NewEncoder(w).Encode(result); err != nil { + log.Println(err) + } +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + // cmdWeb runs a web UI against GD on ADDRESS. func cmdWeb(args []string) error { if len(args) != 2 { -- cgit v1.2.3-70-g09d2