From fa1c8e6963f412e06fc92f74287e4a4b50a74a3d Mon Sep 17 00:00:00 2001 From: Balakrishnan Balasubramanian Date: Fri, 2 Aug 2024 23:39:49 -0400 Subject: [PATCH 1/7] implement get-albums --- main.go | 83 +++++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 75 insertions(+), 8 deletions(-) diff --git a/main.go b/main.go index 7442ec0..c976c11 100644 --- a/main.go +++ b/main.go @@ -10,6 +10,7 @@ import ( "io" "io/fs" "net/http" + "net/url" "os" "path" "regexp" @@ -23,12 +24,14 @@ import ( ) var ( - imagesDir string - collageDir string - devMode bool - collageNameGen *nameGen - imagesDirFs fs.FS - listenAddr string + imagesDir string + collageDir string + devMode bool + collageNameGen *nameGen + imagesDirFs fs.FS + listenAddr string + photoPrismURL string + photoPrismToken string //go:embed web webFS embed.FS @@ -39,6 +42,8 @@ func main() { flag.StringVar(&collageDir, "collages-dir", "collages", "Sets the collages dir") flag.BoolVar(&devMode, "dev", false, "Serve local assets during development") flag.StringVar(&listenAddr, "addr", "127.0.0.1:8767", "Web listen address, see https://pkg.go.dev/go.balki.me/anyhttp#readme-address-syntax") + flag.StringVar(&photoPrismURL, "pp-url", "", "Base url for photoprism") + flag.StringVar(&photoPrismToken, "pp-token", "", "API token for photoprism") flag.Parse() @@ -100,16 +105,33 @@ func main() { w.WriteHeader(http.StatusInternalServerError) return } - collageFile, err := MakeCollage(&collageReq) + collageFilePath, err := MakeCollage(&collageReq) if err != nil { slog.Error("failed to make collage", "error", err) w.WriteHeader(http.StatusInternalServerError) return } - if _, err := w.Write([]byte(collageFile)); err != nil { + if _, err := w.Write([]byte(collageFilePath)); err != nil { slog.Error("Failed to write collageFile", "error", err) } }) + + http.HandleFunc("/get-albums", func(w http.ResponseWriter, r *http.Request) { + albums, err := GetAlbums() + if err != nil { + slog.Error("failed to get albums", "error", err) + w.WriteHeader(http.StatusInternalServerError) + return + } + jData, err := json.Marshal(albums) + if err != nil { + slog.Error("failed to marshal albums", "error", err) + w.WriteHeader(http.StatusInternalServerError) + return + } + w.Header().Set("Content-Type", "application/json") + w.Write(jData) + }) addrType, server, done, err := anyhttp.Serve(listenAddr, idle.WrapHandler(nil)) if err != nil { slog.Error("anyhttp Serve failed", "error", err) @@ -141,3 +163,48 @@ func MakeCollage(req *collage.Request) (string, error) { } return collageFile, nil } + +type Album struct { + Title string `json:"Title"` + UID string `json:"UID"` +} + +func GetAlbums() ([]Album, error) { + u, err := url.Parse(photoPrismURL) + if err != nil { + return nil, err + } + + u.Path = "/api/v1/albums" + v := url.Values{} + v.Add("count", "10") + v.Add("type", "album") + u.RawQuery = v.Encode() + + req, err := http.NewRequest("GET", u.String(), nil) + if err != nil { + return nil, err + } + req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", photoPrismToken)) + req.Header.Set("Content-Type", "application/json") + resp, err := http.DefaultClient.Do(req) + if err != nil { + return nil, err + } + + albums := []Album{} + + respBytes, err := io.ReadAll(resp.Body) + if err != nil { + return nil, err + } + + err = json.Unmarshal(respBytes, &albums) + if err != nil { + return nil, err + } + + // List albums + // yq -oc '[.[] | pick(["UID", "Title"])]' albums.json | pandoc -fcsv -tplain + return albums, nil +} -- 2.34.1 From bf6bdf9b726d080e12b20d545113243c192ebba9 Mon Sep 17 00:00:00 2001 From: Balakrishnan Balasubramanian Date: Sat, 3 Aug 2024 00:38:54 -0400 Subject: [PATCH 2/7] frontend for get-albums --- web/choose.html | 19 +++++++++++++++++++ web/choose.js | 45 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+) create mode 100644 web/choose.html create mode 100644 web/choose.js diff --git a/web/choose.html b/web/choose.html new file mode 100644 index 0000000..fa4bd78 --- /dev/null +++ b/web/choose.html @@ -0,0 +1,19 @@ + + + + + + + + + + + +
+
+ + diff --git a/web/choose.js b/web/choose.js new file mode 100644 index 0000000..9e5c238 --- /dev/null +++ b/web/choose.js @@ -0,0 +1,45 @@ +"use strict"; + +// elements + +/** @type {HTMLButtonElement} */ +let loadAlbumsBtn + +/** @type {HTMLButtonElement} */ +let loadPhotosBtn + +/** @type {HTMLSelectElement} */ +let albumSelect + +function main() { + albumSelect = document.getElementById("album_selector") + loadAlbumsBtn = document.getElementById("load_albums_button") + loadPhotosBtn = document.getElementById("load_photos_button") + loadAlbumsBtn.onclick = () => loadAlbums() + loadPhotosBtn.onclick = () => loadPhotos() +} + +function loadAlbums() { + (async () => { + const resp = await fetch("get-albums") + const albums = await resp.json() + albumSelect.replaceChildren() // This empties existing options + for(const album of albums) { + albumSelect.add(new Option(album.Title, album.UID)) + } + })(); +} + +function loadPhotos() { + const selected = albumSelect.selectedOptions + if(selected.length != 1) { + return + } + const [elem] = selected + console.log(elem) + console.log(elem.text) + console.log(elem.value) +} + + +main() -- 2.34.1 From 5fee186dcb307001ff0fffb69291f39fc6850b70 Mon Sep 17 00:00:00 2001 From: Balakrishnan Balasubramanian Date: Sat, 3 Aug 2024 01:47:22 -0400 Subject: [PATCH 3/7] Add a dialog for showing notices --- web/choose.html | 4 ++++ web/choose.js | 41 ++++++++++++++++++++++++++++++++++++----- 2 files changed, 40 insertions(+), 5 deletions(-) diff --git a/web/choose.html b/web/choose.html index fa4bd78..8be1e6e 100644 --- a/web/choose.html +++ b/web/choose.html @@ -6,6 +6,10 @@ + +

+
+
- - -
+ +
+
+ + + +
+
+
1
+
2
+
3
+
4
+
5
+
6
+
7
+
8
+
9
+
10
+
11
+
12
+
+
diff --git a/web/choose.js b/web/choose.js index 3216a04..6b38320 100644 --- a/web/choose.js +++ b/web/choose.js @@ -17,14 +17,38 @@ let noticeP /** @type {HTMLDialogElement} */ let noticeDialog +/** @type {HTMLDivElement} */ +let albumPhotosDiv + +/** @type {HTMLDivElement} */ +let selectedPhotosDiv + +/** @type {HTMLImageElement} */ +let selectedPhotoImg + function main() { albumSelect = document.getElementById("album_selector") loadAlbumsBtn = document.getElementById("load_albums_button") loadPhotosBtn = document.getElementById("load_photos_button") noticeDialog = document.getElementById("notice_dialog") + albumPhotosDiv = document.getElementById("album_photos") + selectedPhotosDiv = document.getElementById("selected_photos") noticeP = document.getElementById("notice_p") loadAlbumsBtn.onclick = () => loadAlbums() loadPhotosBtn.onclick = () => loadPhotos() + + /** + * @type HTMLImageElement[] + */ + const selectedPhotos = selectedPhotosDiv.getElementsByTagName("img") + for (const img of selectedPhotos) { + img.onclick = () => { + selectedPhotoImg?.classList.remove("current") + selectedPhotoImg = img + selectedPhotoImg.classList.add("current") + } + } + selectedPhotos[0].click() } function loadAlbums() { @@ -67,9 +91,38 @@ function loadPhotos() { return } const [elem] = selected - console.log(elem) - console.log(elem.text) - console.log(elem.value) + + (async () => { + try { + const resp = await fetch(`load-photos/${elem.value}`) + /** + * @type String[] + */ + const photos = await resp.json() + if(photos.length == 0) { + showNotice("No Photos found") + return + } + albumPhotosDiv.replaceChildren() + for(const url of photos) { + const img = new Image() + img.src = url + albumPhotosDiv.appendChild(img) + } + + /** + * @type HTMLImageElement[] + */ + const photoImgs = albumPhotosDiv.children + for(const photo of photoImgs) { + photo.onclick = () => { + selectedPhotoImg.src = photo.src + } + } + } catch(e) { + console.log(e) + } + })(); } -- 2.34.1 From e21cc83a5f88dccd05b8446ce83d749e028c679d Mon Sep 17 00:00:00 2001 From: Balakrishnan Balasubramanian Date: Wed, 7 Aug 2024 19:42:43 -0400 Subject: [PATCH 6/7] add stock.svg --- web/choose.html | 24 ++++++++++++------------ web/choose.js | 2 +- web/stock.svg | 4 ++++ 3 files changed, 17 insertions(+), 13 deletions(-) create mode 100644 web/stock.svg diff --git a/web/choose.html b/web/choose.html index 48d3b0b..cfdf18e 100644 --- a/web/choose.html +++ b/web/choose.html @@ -18,18 +18,18 @@
-
1
-
2
-
3
-
4
-
5
-
6
-
7
-
8
-
9
-
10
-
11
-
12
+
1
+
2
+
3
+
4
+
5
+
6
+
7
+
8
+
9
+
10
+
11
+
12
diff --git a/web/choose.js b/web/choose.js index 6b38320..85dcfd9 100644 --- a/web/choose.js +++ b/web/choose.js @@ -90,7 +90,7 @@ function loadPhotos() { showNotice("Select an album to load photos") return } - const [elem] = selected + const [elem] = selected; (async () => { try { diff --git a/web/stock.svg b/web/stock.svg new file mode 100644 index 0000000..7f1c0d2 --- /dev/null +++ b/web/stock.svg @@ -0,0 +1,4 @@ + + + + -- 2.34.1 From 1bf6bf90339388e4f8654ffcee57ec5566cd3e2d Mon Sep 17 00:00:00 2001 From: Balakrishnan Balasubramanian Date: Thu, 8 Aug 2024 12:05:40 -0400 Subject: [PATCH 7/7] Show images from urls --- web/choose.html | 1 + web/choose.js | 24 ++++++++++++++++++++++++ web/index.js | 10 +++++++++- 3 files changed, 34 insertions(+), 1 deletion(-) diff --git a/web/choose.html b/web/choose.html index cfdf18e..08a55ee 100644 --- a/web/choose.html +++ b/web/choose.html @@ -16,6 +16,7 @@ +
1
diff --git a/web/choose.js b/web/choose.js index 85dcfd9..eaa23fb 100644 --- a/web/choose.js +++ b/web/choose.js @@ -8,6 +8,9 @@ let loadAlbumsBtn /** @type {HTMLButtonElement} */ let loadPhotosBtn +/** @type {HTMLButtonElement} */ +let makeCollageBtn + /** @type {HTMLSelectElement} */ let albumSelect @@ -30,12 +33,14 @@ function main() { albumSelect = document.getElementById("album_selector") loadAlbumsBtn = document.getElementById("load_albums_button") loadPhotosBtn = document.getElementById("load_photos_button") + makeCollageBtn = document.getElementById("make_collage_button") noticeDialog = document.getElementById("notice_dialog") albumPhotosDiv = document.getElementById("album_photos") selectedPhotosDiv = document.getElementById("selected_photos") noticeP = document.getElementById("notice_p") loadAlbumsBtn.onclick = () => loadAlbums() loadPhotosBtn.onclick = () => loadPhotos() + makeCollageBtn.onclick = () => gotoCollage() /** * @type HTMLImageElement[] @@ -125,5 +130,24 @@ function loadPhotos() { })(); } +function gotoCollage() { + /** + * @type HTMLImageElement[] + */ + const selectedPhotos = selectedPhotosDiv.getElementsByTagName("img") + /** + * @type String[] + */ + let photoUrls = []; + + for (const img of selectedPhotos) { + if (!img.src.endsWith("stock.svg")) { + photoUrls.push(img.src) + } + } + const encodedURLS = encodeURIComponent(JSON.stringify(photoUrls)) + window.location.href = `index.html?urls=${encodedURLS}` +} + main() diff --git a/web/index.js b/web/index.js index 14f1123..9292913 100644 --- a/web/index.js +++ b/web/index.js @@ -51,7 +51,7 @@ let collageUrlA let crops = []; let pageSize = "letter-landscape"; -const imageUrls = [ +let imageUrls = [ , // images start with index 1 "images/img1.jpg", "images/img2.jpg", @@ -75,6 +75,8 @@ function main() { for(const tmpl of document.getElementsByClassName("template")) { tmpl.onclick = () => applyTemplate(tmpl) } + const queryUrls = loadImageUrlsFromQuery() + imageUrls = [,].concat(queryUrls) applyTemplate(document.getElementById("default_template")) } @@ -210,4 +212,10 @@ function applyTemplate(templateDiv) { initCollage() } +function loadImageUrlsFromQuery() { + const params = new URLSearchParams(window.location.search) + const urlsstr = params.get('urls') + return JSON.parse(urlsstr) +} + main() -- 2.34.1