From e25b07e5987bd7a2b70b57e21b0eed6607f1b2d9 Mon Sep 17 00:00:00 2001 From: Přemysl Eric Janouch Date: Sat, 23 Dec 2023 23:03:31 +0100 Subject: Implement orphans --- main.go | 85 +++++++++++++++++++++++++++++++++++++++++++++++++++++-- public/gallery.js | 36 +++++++++++++++++++++-- public/style.css | 7 +++-- 3 files changed, 119 insertions(+), 9 deletions(-) diff --git a/main.go b/main.go index 5275c26..0ea4ab6 100644 --- a/main.go +++ b/main.go @@ -667,7 +667,7 @@ func handleAPIDuplicates(w http.ResponseWriter, r *http.Request) { } var ( - result [][]webDuplicateImage + result = [][]webDuplicateImage{} err error ) if result, err = getDuplicates1(result); err != nil { @@ -686,6 +686,81 @@ func handleAPIDuplicates(w http.ResponseWriter, r *http.Request) { // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +type webOrphanImage struct { + SHA1 string `json:"sha1"` + ThumbW int64 `json:"thumbW"` + ThumbH int64 `json:"thumbH"` + Tags int64 `json:"tags"` +} + +type webOrphan struct { + webOrphanImage + LastPath string `json:"lastPath"` + Replacement *webOrphanImage `json:"replacement"` +} + +func getOrphanReplacement(webPath string) (*webOrphanImage, error) { + tx, err := db.Begin() + if err != nil { + return nil, err + } + defer tx.Rollback() + + path := decodeWebPath(webPath) + if len(path) == 0 { + return nil, nil + } + + parent, err := idForPath(tx, path[:len(path)-1], false) + if err != nil { + return nil, err + } + + var image webOrphanImage + err = db.QueryRow(`SELECT i.sha1, + IFNULL(i.thumbw, 0), IFNULL(i.thumbh, 0), COUNT(*) AS tags + FROM node AS n + JOIN image AS i ON n.sha1 = i.sha1 + JOIN tag_assignment AS ta ON n.sha1 = ta.sha1 + WHERE n.parent = ? AND n.name = ? + GROUP BY ta.sha1`, parent, path[len(path)-1]).Scan( + &image.SHA1, &image.ThumbW, &image.ThumbH, &image.Tags) + if err != nil { + return nil, err + } + return &image, nil +} + +func getOrphans() (result []webOrphan, err error) { + rows, err := db.Query(`SELECT o.sha1, o.path, + IFNULL(i.thumbw, 0), IFNULL(i.thumbh, 0), COUNT(*) AS tags + FROM orphan AS o + JOIN image AS i ON o.sha1 = i.sha1 + JOIN tag_assignment AS ta ON o.sha1 = ta.sha1 + GROUP BY ta.sha1`) + if err != nil { + return nil, err + } + defer rows.Close() + + result = []webOrphan{} + for rows.Next() { + var orphan webOrphan + if err = rows.Scan(&orphan.SHA1, &orphan.LastPath, + &orphan.ThumbW, &orphan.ThumbH, &orphan.Tags); err != nil { + return nil, err + } + + orphan.Replacement, err = getOrphanReplacement(orphan.LastPath) + if err != nil { + return nil, err + } + + result = append(result, orphan) + } + return result, rows.Err() +} + func handleAPIOrphans(w http.ResponseWriter, r *http.Request) { var params struct{} if err := json.NewDecoder(r.Body).Decode(¶ms); err != nil { @@ -693,8 +768,12 @@ func handleAPIOrphans(w http.ResponseWriter, r *http.Request) { return } - // TODO - result := false + result, err := getOrphans() + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + if err := json.NewEncoder(w).Encode(result); err != nil { log.Println(err) } diff --git a/public/gallery.js b/public/gallery.js index 222bde5..96f0216 100644 --- a/public/gallery.js +++ b/public/gallery.js @@ -371,15 +371,45 @@ let OrphansModel = { }, } +let OrphansReplacement = { + view(node) { + const info = vnode.attrs.info + if (!info) + return [] + + return [ + ` → `, + m(m.route.Link, {href: `/view/${info.sha1}`}, + m('img.thumbnail', {src: `/thumb/${info.sha1}`, + width: info.thumbW, height: info.thumbH, loading})), + `${info.tags} tags`, + ] + }, +} + +let OrphansRow = { + view(node) { + const info = vnode.attrs.info + return m('.row', [ + m('img.thumbnail', {src: `/thumb/${info.sha1}`, + width: info.thumbW, height: info.thumbH, loading}), + `${info.tags} tags`, + m(OrphansReplacement, {info: info.replacement}), + ]) + }, +} + let OrphansList = { // See BrowseView. oncreate(vnode) { vnode.dom.focus() }, view(vnode) { - let children = (DuplicatesModel.entries.length == 0) + let children = (OrphansModel.entries.length == 0) ? "No orphans" - : OrphansModel.entries.map(group => - m('.row', "TODO")) + : OrphansModel.entries.map(info => [ + m("h3", info.lastPath), + m(OrphansRow, {info}), + ]) return m('.orphans[tabindex=0]', {}, children) }, } diff --git a/public/style.css b/public/style.css index 978e01b..0276e43 100644 --- a/public/style.css +++ b/public/style.css @@ -59,6 +59,7 @@ img.thumbnail { display: block; box-shadow: 0 0 3px rgba(0, 0, 0, 0.75); .similar .row { display: flex; margin: .5rem 0; } .similar .row ul { margin: 0; padding: 0 0 0 1.25em; list-style-type: "- "; } -.duplicates { padding: .5rem; flex-grow: 1; overflow: auto; } -.duplicates .row { display: flex; margin: .5rem 0; - align-items: center; gap: 3px; } +.duplicates, +.orphans { padding: .5rem; flex-grow: 1; overflow: auto; } +.duplicates .row, +.orphans .row { display: flex; margin: .5rem 0; align-items: center; gap: 3px; } -- cgit v1.2.3-70-g09d2