summaryrefslogtreecommitdiffci
path: root/internal
diff options
from:
to:
context:
space:
mode:
Diffstat (limited to 'internal')
-rw-r--r--internal/blog/index.go82
-rw-r--r--internal/blog/s3.go125
2 files changed, 175 insertions, 32 deletions
diff --git a/internal/blog/index.go b/internal/blog/index.go
index 861a90e..6c1a560 100644
--- a/internal/blog/index.go
+++ b/internal/blog/index.go
@@ -1,10 +1,17 @@
package blog
-import "time"
+import (
+ "encoding/json"
+ "fmt"
+ "time"
+
+ "github.com/SayaAndy/saya-today-web/internal/frontmatter"
+)
const IndexFileName = "index.json"
+const MedleysIndexFileName = "medleys.json"
-const IndexSchemaVersion = 1
+const IndexSchemaVersion = 2
type IndexEntry struct {
Link string `json:"link"`
@@ -20,13 +27,76 @@ type IndexEntry struct {
MedleyPart int `json:"medleyPart,omitempty"`
}
-type IndexCategory struct {
+func (e IndexEntry) Metadata() *frontmatter.Metadata {
+ return &frontmatter.Metadata{
+ Title: e.Title,
+ ShortDescription: e.ShortDescription,
+ ActionDate: e.ActionDate,
+ PublishedTime: e.PublishedTime,
+ Thumbnail: e.Thumbnail,
+ Tags: e.Tags,
+ Geolocation: e.Geolocation,
+ Medley: e.Medley,
+ MedleyPart: e.MedleyPart,
+ }
+}
+
+type IndexV2Category struct {
+ GeneratedAt time.Time `json:"generatedAt"`
+ Pages map[string]IndexEntry `json:"pages"`
+}
+
+type IndexV1Category struct {
GeneratedAt time.Time `json:"generatedAt"`
Pages []IndexEntry `json:"pages"`
}
type Index struct {
- SchemaVersion int `json:"schemaVersion"`
- GeneratedAt time.Time `json:"generatedAt"`
- Categories map[string]IndexCategory `json:"categories"`
+ SchemaVersion int `json:"schemaVersion"`
+ GeneratedAt time.Time `json:"generatedAt"`
+ Categories any `json:"categories"`
+}
+
+func (idx *Index) UnmarshalJSON(data []byte) error {
+ var tmp struct {
+ SchemaVersion int `json:"schemaVersion"`
+ GeneratedAt time.Time `json:"generatedAt"`
+ Categories json.RawMessage `json:"categories"`
+ }
+
+ if err := json.Unmarshal(data, &tmp); err != nil {
+ return err
+ }
+
+ idx.SchemaVersion = tmp.SchemaVersion
+ idx.GeneratedAt = tmp.GeneratedAt
+
+ switch tmp.SchemaVersion {
+ case 1:
+ var categories map[string]*IndexV1Category
+ if err := json.Unmarshal(tmp.Categories, &categories); err != nil {
+ return fmt.Errorf("unmarshal map[string]*IndexV1Category: %w", err)
+ }
+ idx.Categories = &categories
+ case 2:
+ var categories map[string]*IndexV2Category
+ if err := json.Unmarshal(tmp.Categories, &categories); err != nil {
+ return fmt.Errorf("unmarshal map[string]*IndexV2Category: %w", err)
+ }
+ idx.Categories = &categories
+ default:
+ return fmt.Errorf("unsupported index version: %d", tmp.SchemaVersion)
+ }
+
+ return nil
+}
+
+type MedleyEntry struct {
+ Codename string `json:"codename"`
+ Content []string `json:"content"`
+}
+
+type MedleyPageEntry struct {
+ Codename string `json:"codename"`
+ Position int `json:"position"`
}
diff --git a/internal/blog/s3.go b/internal/blog/s3.go
index 5ee896a..04fad33 100644
--- a/internal/blog/s3.go
+++ b/internal/blog/s3.go
@@ -1,6 +1,7 @@
package blog
import (
+ "bytes"
"context"
"encoding/json"
"fmt"
@@ -86,34 +87,72 @@ func (c *S3Client) Scan(prefix string) ([]*Page, error) {
fullPrefix := c.prefix + prefix
pages := make([]*Page, 0)
- for catKey, cat := range idx.Categories {
- lang, ok := strings.CutPrefix(catKey, c.prefix)
- if !ok {
- continue
- }
- if wantLang != "" && wantLang != lang {
- continue
+
+ switch idx.SchemaVersion {
+ case 1:
+ for catKey, cat := range *idx.Categories.(*map[string]*IndexV1Category) {
+ lang, ok := strings.CutPrefix(catKey, c.prefix)
+ if !ok {
+ continue
+ }
+ if wantLang != "" && wantLang != lang {
+ continue
+ }
+ for _, e := range cat.Pages {
+ if !strings.HasPrefix(e.Link, fullPrefix) {
+ continue
+ }
+ fileName := e.Link[strings.LastIndex(e.Link, "/")+1 : strings.LastIndex(e.Link, ".")]
+ pages = append(pages, &Page{
+ Link: e.Link,
+ FileName: fileName,
+ Lang: lang,
+ ModifiedTime: e.ModifiedTime,
+ Metadata: &frontmatter.Metadata{
+ Title: e.Title,
+ ShortDescription: e.ShortDescription,
+ ActionDate: e.ActionDate,
+ PublishedTime: e.PublishedTime,
+ Thumbnail: e.Thumbnail,
+ Tags: e.Tags,
+ Geolocation: e.Geolocation,
+ Medley: e.Medley,
+ MedleyPart: e.MedleyPart,
+ },
+ })
+ }
}
- for _, e := range cat.Pages {
- if !strings.HasPrefix(e.Link, fullPrefix) {
+ case 2:
+ for catKey, cat := range *idx.Categories.(*map[string]*IndexV2Category) {
+ lang, ok := strings.CutPrefix(catKey, c.prefix)
+ if !ok {
continue
}
- fileName := e.Link[strings.LastIndex(e.Link, "/")+1 : strings.LastIndex(e.Link, ".")]
- pages = append(pages, &Page{
- Link: e.Link,
- FileName: fileName,
- Lang: lang,
- ModifiedTime: e.ModifiedTime,
- Metadata: &frontmatter.Metadata{
- Title: e.Title,
- ShortDescription: e.ShortDescription,
- ActionDate: e.ActionDate,
- PublishedTime: e.PublishedTime,
- Thumbnail: e.Thumbnail,
- Tags: e.Tags,
- Geolocation: e.Geolocation,
- },
- })
+ if wantLang != "" && wantLang != lang {
+ continue
+ }
+ for codename, e := range cat.Pages {
+ if !strings.HasPrefix(e.Link, fullPrefix) {
+ continue
+ }
+ pages = append(pages, &Page{
+ Link: e.Link,
+ FileName: codename,
+ Lang: lang,
+ ModifiedTime: e.ModifiedTime,
+ Metadata: &frontmatter.Metadata{
+ Title: e.Title,
+ ShortDescription: e.ShortDescription,
+ ActionDate: e.ActionDate,
+ PublishedTime: e.PublishedTime,
+ Thumbnail: e.Thumbnail,
+ Tags: e.Tags,
+ Geolocation: e.Geolocation,
+ Medley: e.Medley,
+ MedleyPart: e.MedleyPart,
+ },
+ })
+ }
}
}
@@ -121,9 +160,13 @@ func (c *S3Client) Scan(prefix string) ([]*Page, error) {
}
func (c *S3Client) ReadAll(path string) ([]byte, error) {
+ return c.readAll(c.prefix + path)
+}
+
+func (c *S3Client) readAll(path string) ([]byte, error) {
output, err := c.s3cl.GetObject(context.Background(), &s3.GetObjectInput{
Bucket: aws.String(c.bucketName),
- Key: aws.String(c.prefix + path),
+ Key: aws.String(path),
})
if err != nil {
return nil, fmt.Errorf("get S3 object: %w", err)
@@ -139,10 +182,40 @@ func (c *S3Client) ReadAll(path string) ([]byte, error) {
}
func (c *S3Client) ReadFrontmatter(path string) (metadata *frontmatter.Metadata, markdown []byte, err error) {
+ idxRaw, err := c.readAll(IndexFileName)
+ if err != nil {
+ return nil, nil, fmt.Errorf("read %s: %w", IndexFileName, err)
+ }
+
+ var idx Index
+ if err := json.Unmarshal(idxRaw, &idx); err != nil {
+ return nil, nil, fmt.Errorf("unmarshal %s: %w", IndexFileName, err)
+ }
+
contentBytes, err := c.ReadAll(path)
if err != nil {
return nil, nil, fmt.Errorf("failed to read file for frontmatter parsing: %w", err)
}
+ switch idx.SchemaVersion {
+ case 1:
+ return frontmatter.ParseFrontmatter(contentBytes)
+ case 2:
+ fullPath := c.prefix + path
+ page := (*idx.Categories.(*map[string]*IndexV2Category))[fullPath[:strings.LastIndex(fullPath, "/")]].Pages[fullPath[strings.LastIndex(fullPath, "/")+1:strings.LastIndex(fullPath, ".")]]
+ metadata = page.Metadata()
+
+ if !bytes.HasPrefix(contentBytes, []byte("---\n")) {
+ return metadata, contentBytes, nil
+ }
+
+ end := bytes.Index(contentBytes[4:], []byte("\n---\n"))
+ if end == -1 {
+ return metadata, contentBytes, nil
+ }
+
+ return metadata, contentBytes[end+9:], nil
+ }
+
return frontmatter.ParseFrontmatter(contentBytes)
}