Skip to content

Commit

Permalink
feat: support editing photos
Browse files Browse the repository at this point in the history
  • Loading branch information
hacdias committed Feb 9, 2025
1 parent 57182fd commit 57fcc19
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 42 deletions.
8 changes: 7 additions & 1 deletion core/entries.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,12 @@ import (

const moreSeparator = "<!--more-->"

// TODO: update to match https://aaronparecki.com/2017/02/25/9/day-67-image-alt-text
type Photo struct {
URL string `yaml:"url,omitempty"`
Title string `yaml:"title,omitempty"`
}

type FrontMatter struct {
Title string `yaml:"title,omitempty"`
Description string `yaml:"description,omitempty"`
Expand All @@ -28,6 +34,7 @@ type FrontMatter struct {
ExpiryDate time.Time `yaml:"expiryDate,omitempty"`
NoIndex bool `yaml:"noIndex,omitempty"`
NoWebmentions bool `yaml:"noWebmentions,omitempty"`
Photos []Photo `yaml:"photos,omitempty"`
Other map[string]any `yaml:",inline"`
}

Expand All @@ -38,7 +45,6 @@ type Entry struct {
Permalink string
RelPermalink string
Content string
// Photos [][]byte
}

func (e *Entry) Deleted() bool {
Expand Down
99 changes: 59 additions & 40 deletions server/micropub.go
Original file line number Diff line number Diff line change
Expand Up @@ -231,17 +231,12 @@ func (m *micropubServer) update(permalink string, req *micropub.Request, update
func (m *micropubServer) getPhotos(e *core.Entry) ([]Photo, error) {
var photos []Photo

for i, photo := range typed.New(e.Other).Objects("photos") {
for i, photo := range e.Photos {
if i >= 4 {
break
}

photoUrl := photo.String("url")
if photoUrl == "" {
return nil, errors.New("photo has no url")
}

photoUrl, err := m.s.media.GetImageURL(photoUrl, media.FormatJPEG, media.Width1000)
photoUrl, err := m.s.media.GetImageURL(photo.URL, media.FormatJPEG, media.Width1000)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -420,6 +415,12 @@ func (m *micropubServer) entryToMF2(e *core.Entry) map[string]any {
properties["post-status"] = "published"
}

if len(e.Photos) > 0 {
properties["photo"] = lo.Map(e.Photos, func(p core.Photo, i int) string {
return p.URL
})
}

if m.s.c.Micropub.CategoriesTaxonomy != "" {
taxons := e.Taxonomy(m.s.c.Micropub.CategoriesTaxonomy)
if len(taxons) != 0 {
Expand Down Expand Up @@ -549,64 +550,82 @@ func (m *micropubServer) updateEntryWithProps(e *core.Entry, newProps map[string
}

func (m *micropubServer) updateEntryWithPhotos(e *core.Entry, properties typed.Typed) error {
// Define prefix for the photos that will be uploaded
parts := strings.Split(strings.TrimSuffix(e.ID, "/"), "/")
slug := parts[len(parts)-1]
prefix := fmt.Sprintf("%04d-%02d-%s", e.Date.Year(), e.Date.Month(), slug)

photoUrls := []string{}
photoData := map[string][]byte{}
urls := []string{}
cachedData := map[string][]byte{}

if url, ok := properties.StringIf("photo"); ok {
data, ok := m.s.mediaCache.Get(url)
if !ok {
return fmt.Errorf("photo %q not found in cache", url)
}
if strings.HasPrefix(url, "cache:/") {
data, ok := m.s.mediaCache.Get(url)
if !ok {
return fmt.Errorf("photo %q not found in cache", url)
}

photoUrls = append(photoUrls, url)
photoData[url] = data
m.s.mediaCache.Delete(url)
cachedData[url] = data
m.s.mediaCache.Delete(url)
}

urls = append(urls, url)
delete(properties, "photo")
} else if photos, ok := properties.StringsIf("photo"); ok {
for _, url := range photos {
data, ok := m.s.mediaCache.Get(url)
if !ok {
return fmt.Errorf("photo %q not found in cache", url)
if strings.HasPrefix(url, "cache:/") {
data, ok := m.s.mediaCache.Get(url)
if !ok {
return fmt.Errorf("photo %q not found in cache", url)
}

cachedData[url] = data
m.s.mediaCache.Delete(url)
}

photoUrls = append(photoUrls, url)
photoData[url] = data
m.s.mediaCache.Delete(url)
urls = append(urls, url)
}

delete(properties, "photo")
}

if len(photoUrls) == 0 {
if len(urls) == 0 {
e.Photos = nil
return nil
}

photos := []any{}
// Get old titles
titles := lo.Reduce(e.Photos, func(t map[string]string, p core.Photo, i int) map[string]string {
t[p.Title] = p.URL
return t
}, map[string]string{})

for i, url := range photoUrls {
data := photoData[url]
filename := prefix
if len(photoUrls) > 1 {
filename += fmt.Sprintf("-%02d", i+1)
}
e.Photos = []core.Photo{}
for i, url := range urls {
data, isCached := cachedData[url]

ext := filepath.Ext(url)
cdnUrl, err := m.s.media.UploadMedia(filename, ext, bytes.NewBuffer(data))
if err != nil {
return fmt.Errorf("failed to upload photo: %w", err)
}
if isCached {
filename := prefix
if len(urls) > 1 {
filename += fmt.Sprintf("-%02d", i+1)
}

photos = append(photos, map[string]string{
"url": cdnUrl,
})
}
ext := filepath.Ext(url)
cdnUrl, err := m.s.media.UploadMedia(filename, ext, bytes.NewBuffer(data))
if err != nil {
return fmt.Errorf("failed to upload photo: %w", err)
}

e.Other["photos"] = photos
e.Photos = append(e.Photos, core.Photo{
URL: cdnUrl,
})
} else {
e.Photos = append(e.Photos, core.Photo{
URL: url,
Title: titles[url],
})
}
}

return nil
}
2 changes: 1 addition & 1 deletion server/micropub_media.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ func (s *Server) makeMicropubMedia() http.Handler {
ext = mime.Extension()
}

filename := fmt.Sprintf("cache://%x%s", sha256.Sum256(data), ext)
filename := fmt.Sprintf("cache:/%x%s", sha256.Sum256(data), ext)

added := s.mediaCache.Set(filename, data)
if !added {
Expand Down

0 comments on commit 57fcc19

Please sign in to comment.