albums: basic support (json array using contented/album mime-type)

This commit is contained in:
mappu 2023-05-17 18:52:13 +12:00
parent 156e2ab540
commit 4294738337
3 changed files with 114 additions and 13 deletions

View File

@ -22,6 +22,8 @@ var SERVER_HEADER string = `contented/0.0.0-dev`
const DEFAULT_MAX_CONCURRENT_THUMBS = 16 const DEFAULT_MAX_CONCURRENT_THUMBS = 16
const ALBUM_MIMETYPE = `contented/album`
type ServerPublicProperties struct { type ServerPublicProperties struct {
AppTitle string AppTitle string
MaxUploadBytes int64 MaxUploadBytes int64

View File

@ -1,11 +1,13 @@
package contented package contented
import ( import (
"encoding/json"
"fmt" "fmt"
"html" "html"
"log" "log"
"net/http" "net/http"
"os" "os"
"path/filepath"
"strings" "strings"
"time" "time"
) )
@ -56,6 +58,19 @@ html, body {
line-height: 0; line-height: 0;
width: 340px; width: 340px;
text-align: center; text-align: center;
position: relative;
}
.thumbnail-overlay {
position: absolute;
bottom: 4px;
right: 4px;
padding: 4px 8px;
line-height: 1.5em;
pointer-events: none;
background: red;
color: white;
} }
.properties { .properties {
background: #000; background: #000;
@ -82,6 +97,48 @@ html, body {
return return
} }
if m.MimeType == ALBUM_MIMETYPE {
// Special handling for albums
f, err := os.Open(filepath.Join(this.opts.DataDirectory, m.FileHash))
if err != nil {
log.Printf("Opening file '%s' for preview of album '%s': %s", m.FileHash, fileID, err.Error())
http.Error(w, "Internal error", 500)
return
}
var childIDs []string
err = json.NewDecoder(f).Decode(&childIDs)
f.Close()
if err != nil {
log.Printf("Failed to parse album '%s': %s", fileID, err)
http.Error(w, "Internal error", 500)
return
}
if len(childIDs) == 0 {
log.Printf("Failed to parse album '%s': no entries in album", fileID)
http.Error(w, "Internal error", 500)
return
}
tmpl += `
<div class="entry">
<div class="thumbnail">
<a href="` + html.EscapeString(`/p/`+strings.Join(childIDs, `-`)) + `"><img src="` + html.EscapeString(`/thumb/m/`+childIDs[0]) + `"></a>
<div class="thumbnail-overlay">` + fmt.Sprintf("%d", len(childIDs)) + ` image(s)</div>
</div>
<div class="properties">
<b>Name:</b> ` + html.EscapeString(m.Filename) + `<br>
<b>Hash:</b> <span title="` + html.EscapeString(m.FileHash) + `">hover</span><br>
<b>File type:</b> Album<br>
<b>Size:</b> ` + fmt.Sprintf("%d", len(childIDs)) + ` image(s)<br>
<b>Uploader:</b> ` + html.EscapeString(m.UploadIP) + `<br>
<b>Uploaded at:</b> ` + html.EscapeString(m.UploadTime.Format(time.RFC3339)) + `<br>
</div>
</div>
`
} else {
tmpl += ` tmpl += `
<div class="entry"> <div class="entry">
<div class="thumbnail"> <div class="thumbnail">
@ -98,6 +155,7 @@ html, body {
</div> </div>
` `
} }
}
if this.opts.EnableHomepage { if this.opts.EnableHomepage {
tmpl += ` tmpl += `

View File

@ -178,6 +178,12 @@
<path fill="#000000" d="M16.84,2.73C16.45,2.73 16.07,2.88 15.77,3.17L13.65,5.29L18.95,10.6L21.07,8.5C21.67,7.89 21.67,6.94 21.07,6.36L17.9,3.17C17.6,2.88 17.22,2.73 16.84,2.73M12.94,6L4.84,14.11L7.4,14.39L7.58,16.68L9.86,16.85L10.15,19.41L18.25,11.3M4.25,15.04L2.5,21.73L9.2,19.94L8.96,17.78L6.65,17.61L6.47,15.29" /> <path fill="#000000" d="M16.84,2.73C16.45,2.73 16.07,2.88 15.77,3.17L13.65,5.29L18.95,10.6L21.07,8.5C21.67,7.89 21.67,6.94 21.07,6.36L17.9,3.17C17.6,2.88 17.22,2.73 16.84,2.73M12.94,6L4.84,14.11L7.4,14.39L7.58,16.68L9.86,16.85L10.15,19.41L18.25,11.3M4.25,15.04L2.5,21.73L9.2,19.94L8.96,17.78L6.65,17.61L6.47,15.29" />
</svg> </svg>
</div> </div>
<div class="contented-upload-type" data-upload-type="album" title="Album">
<svg viewBox="0 0 24 24">
<path fill="#000000" d="M3,3H21V7H3V3M4,8H20V21H4V8M9.5,11A0.5,0.5 0 0,0 9,11.5V13H15V11.5A0.5,0.5 0 0,0 14.5,11H9.5Z" />
</svg>
</div>
</div> </div>
<div class="contented-content-area"> <div class="contented-content-area">
@ -204,6 +210,15 @@
<label>...</label> <label>...</label>
<div class="contented-progress-bar"><div class="contented-progress-element"></div></div> <div class="contented-progress-bar"><div class="contented-progress-element"></div></div>
</div> </div>
<div class="contented-upload-if contented-if-album">
<label>
Type a list of short IDs, separated with commas:<br>
<input class="contented-album-input" type="text">
</label>
<br><br>
<button class="contented-album-upload">Make album &raquo;</button>
</div>
</div> </div>
</div> </div>
`; `;
@ -307,6 +322,32 @@
handleUploadFrom([blob]); handleUploadFrom([blob]);
}); });
// Album
$f.find(".contented-album-upload").on("click", function(e) {
e.preventDefault();
e.stopPropagation();
var childIDs = $(".contented-album-input").val().split(",");
for (var i = 0; i < childIDs.length; ++i) {
childIDs[i] = childIDs[i].trim(); // Basic validation - can't really perform full validation here
if (childIDs[i].length == 0) {
alert("Entry " + (i+1) + " is too short, expected non-zero length");
return;
}
if (! childIDs[i].match(/^[a-zA-Z0-9]+$/)) {
alert("Entry " + (i+1) + " contains unexpected character");
return;
}
}
var blob = new Blob([JSON.stringify(childIDs)], {type : 'contented/album'});
handleUploadFrom([blob]);
});
// Ctrl+V uploads // Ctrl+V uploads
var pasteHandler = function(e) { var pasteHandler = function(e) {