Add albums: group photos by free-text tags
An album is a tag. Photos carry lowercase free-text tags in their .toml sidecar (`tags = [...]`), parallel to the existing day grouping — no database, all derived at build time. - albums.go: parseTags (lowercase/trim/dedupe, slug via sanitiseSlug), groupByTag mirroring groupByDay, and rendering for album pages, the index, and the JSON API. Slug collisions between distinct names are suffixed and logged. - Routes: /album/<slug>/ (paginated square grid per tag), /albums/ (index with counts), /tags.json (machine-readable tag list, served statically like feed.xml). - POST /upload gains a `tags` field written into the sidecar; the web upload form gains a tags input. - Tags shown on each photo page linking to their album; an Albums link in the timeline/grid header.
This commit is contained in:
1 parent
f33bdd55b1
commit
a42abfab48
11 files changed
+469
-6
No files matched your search
+16
-3
@@ -41,8 +41,9 @@ var ogQualityLadder = []int{85, 78, 70, 62}
|
||||
|
||||
// PhotoMeta is the structure of a .toml sidecar file.
|
||||
type PhotoMeta struct {
|
||||
Caption string `toml:"caption"`
|
||||
Date string `toml:"date"` // YYYY-MM-DD
|
||||
Caption string `toml:"caption"`
|
||||
Date string `toml:"date"` // YYYY-MM-DD
|
||||
Tags []string `toml:"tags,omitempty"` // free-text, lowercased; each tag is an album
|
||||
}
|
||||
|
||||
// Photo is the in-memory representation of one image.
|
||||
@@ -56,6 +57,7 @@ type Photo struct {
|
||||
OGHeight int
|
||||
Caption string
|
||||
Date time.Time
|
||||
Tags []Tag // albums this photo belongs to
|
||||
}
|
||||
|
||||
// DayGroup is a run of photos sharing the same calendar day, for the timeline.
|
||||
@@ -121,7 +123,7 @@ func (g *Generator) Build() error {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, d := range []string{"images", "thumbs", "medium", "og", "photo", "grid", "day", "static"} {
|
||||
for _, d := range []string{"images", "thumbs", "medium", "og", "photo", "grid", "day", "album", "albums", "static"} {
|
||||
if err := os.MkdirAll(filepath.Join(g.outputDir, d), 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -142,6 +144,16 @@ func (g *Generator) Build() error {
|
||||
if err := g.renderDayPages(photos); err != nil {
|
||||
return err
|
||||
}
|
||||
albums := groupByTag(photos)
|
||||
if err := g.renderAlbumPages(albums, len(photos)); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := g.renderAlbumsIndex(albums, len(photos)); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := g.renderTagsJSON(albums); err != nil {
|
||||
return err
|
||||
}
|
||||
for i := range photos {
|
||||
var newer, older *Photo
|
||||
if i > 0 {
|
||||
@@ -209,6 +221,7 @@ func (g *Generator) loadPhotos() ([]Photo, error) {
|
||||
OG: "og/" + slug + ".jpg",
|
||||
Caption: meta.Caption,
|
||||
Date: date,
|
||||
Tags: parseTags(meta.Tags...),
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user