From 4929366f82339ee2c4727c8a08dda87c60fae1b0 Mon Sep 17 00:00:00 2001 From: Eggbertx Date: Sat, 15 Mar 2025 23:52:13 -0700 Subject: [PATCH] Update templates with embed stuff, add example URL matchers --- examples/configs/gochan.example.json | 20 ++++++++++++-- pkg/building/posts.go | 9 +++++-- pkg/config/config.go | 13 +++++++++ pkg/gctemplates/funcs.go | 40 ++++++++++++++++++++++++++++ pkg/posting/embed.go | 7 ----- pkg/posting/post.go | 14 +++++++++- templates/post.html | 8 +++++- templates/postbox.html | 3 +++ 8 files changed, 101 insertions(+), 13 deletions(-) diff --git a/examples/configs/gochan.example.json b/examples/configs/gochan.example.json index c8da53d3..b8320223 100644 --- a/examples/configs/gochan.example.json +++ b/examples/configs/gochan.example.json @@ -95,10 +95,26 @@ "EnableCyclicThreads": true, "CyclicThreadNumPosts": 500, - "EnableEmbeds": true, "EnableNoFlag": true, "EmbedWidth": 200, - "EmbedHeight": 164, + "EmbedHeight": 200, + "EmbedMatchers": { + "youtube": { + "URLRegex": "^https?://(?:(?:(?:www\\.)?youtube\\.com/watch\\?v=)|(?:youtu\\.be/))([^&]+)", + "EmbedTemplate": "", + "ThumbnailURLTemplate": "https://img.youtube.com/vi/{{.VideoID}}/0.jpg" + }, + "vimeo": { + "URLRegex": "^https?://(?:\\w+\\.)?vimeo\\.com/(\\d{2,10})", + "EmbedTemplate": "", + "ThumbnailURLTemplate": "https://vumbnail.com/{{.VideoID}}.jpg" + }, + "rawvideo": { + "URLRegex": "^https?://\\S+\\.\\S+/\\S+/(\\S+\\.(?:mp4|webm))$", + "EmbedTemplate": "", + "VideoIDSubmatchIndex": 0 + } + }, "ImagesOpenNewTab": true, "NewTabOnOutlinks": true, "DisableBBcode": false, diff --git a/pkg/building/posts.go b/pkg/building/posts.go index b32a7528..864297fb 100644 --- a/pkg/building/posts.go +++ b/pkg/building/posts.go @@ -6,6 +6,7 @@ import ( "net" "path" "strconv" + "strings" "time" "github.com/gochan-org/gochan/pkg/config" @@ -76,8 +77,12 @@ func (p *Post) WebPath() string { return p.ThreadPath() + "#" + strconv.Itoa(p.ID) } +func (p *Post) HasEmbed() bool { + return strings.HasPrefix(p.Filename, "embed:") +} + func (p *Post) ThumbnailPath() string { - if p.Filename == "" { + if p.Filename == "" || p.HasEmbed() { return "" } thumbnail, _ := uploads.GetThumbnailFilenames(p.Filename) @@ -85,7 +90,7 @@ func (p *Post) ThumbnailPath() string { } func (p *Post) UploadPath() string { - if p.Filename == "" { + if p.Filename == "" || p.HasEmbed() { return "" } return config.WebPath(p.BoardDir, "src", p.Filename) diff --git a/pkg/config/config.go b/pkg/config/config.go index d8d825c5..03d0f200 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -664,6 +664,19 @@ func (pc *PostConfig) GetEmbedVideoID(url string) (string, string, error) { return "", "", ErrNoMatchingEmbedHandler } +// GetEmbedTemplates returns the embed and (if it has one) thumbnail URL templates for the given embed ID +func (pc *PostConfig) GetEmbedTemplates(embedID string) (*template.Template, *template.Template, error) { + embedTmpl, ok := pc.embedMatchersEmbedTemplate[embedID] + if !ok { + return nil, nil, ErrNoMatchingEmbedHandler + } + thumbTmpl, ok := pc.embedMatchersThumbnailURLTemplate[embedID] + if !ok { + thumbTmpl = nil + } + return embedTmpl, thumbTmpl, nil +} + func (pc *PostConfig) validateEmbedMatchers() error { if pc.EmbedMatchers == nil { return nil diff --git a/pkg/gctemplates/funcs.go b/pkg/gctemplates/funcs.go index 9385513d..921c5cfd 100644 --- a/pkg/gctemplates/funcs.go +++ b/pkg/gctemplates/funcs.go @@ -1,6 +1,7 @@ package gctemplates import ( + "bytes" "errors" "fmt" "html" @@ -23,6 +24,13 @@ var ( ErrInvalidMap = errors.New("invalid template map call") ) +type EmbedVideo struct { + VideoID string + Handler string + ThumbWidth int + ThumbHeight int +} + var funcMap = template.FuncMap{ // Arithmetic functions "add": func(a, b int) int { @@ -165,6 +173,38 @@ var funcMap = template.FuncMap{ } return dir }, + "embedVideo": func(filename string, videoID string, board string) template.HTML { + filenameParts := strings.SplitN(filename, ":", 2) + if len(filenameParts) != 2 { + return "invalid embed ID" + } + + boardCfg := config.GetBoardConfig(board) + embedTmpl, thumbTmpl, err := boardCfg.GetEmbedTemplates(filenameParts[1]) + if err != nil { + return template.HTML(err.Error()) + } + templateData := EmbedVideo{ + VideoID: videoID, + Handler: filenameParts[1], + ThumbWidth: boardCfg.EmbedWidth, + ThumbHeight: boardCfg.EmbedHeight, + } + + var buf bytes.Buffer + if thumbTmpl != nil { + if err := thumbTmpl.Execute(&buf, templateData); err != nil { + return template.HTML(err.Error()) + } + return template.HTML(`Video thumbnail`) + } + + if err = embedTmpl.Execute(&buf, templateData); err != nil { + return template.HTML(err.Error()) + } + return template.HTML(buf.String()) + }, + // Template convenience functions "makeLoop": func(n int, offset int) []int { loopArr := make([]int, n) diff --git a/pkg/posting/embed.go b/pkg/posting/embed.go index 3dfeec9b..4e3c71e3 100644 --- a/pkg/posting/embed.go +++ b/pkg/posting/embed.go @@ -14,13 +14,6 @@ var ( ErrUnrecognizedEmbed = errors.New("unrecognized embed URL") ) -type EmbedVideo struct { - VideoID string - Handler string - ThumbWidth int - ThumbHeight int -} - // AttachEmbedFromRequest checks if the post contains an embedded media URL from the form (if applicable) and if it is valid. // It returns true if the post contains an embedded media URL, an error if the URL is invalid or some other error occurred. // It attaches the embed as a pseudo-upload in the database if the URL is valid. diff --git a/pkg/posting/post.go b/pkg/posting/post.go index 5496fd06..0d3c9ac6 100644 --- a/pkg/posting/post.go +++ b/pkg/posting/post.go @@ -459,6 +459,18 @@ func MakePost(writer http.ResponseWriter, request *http.Request) { server.ServeError(writer, err.Error(), wantsJSON, nil) return } + + embed, err := AttachEmbedFromRequest(request, boardConfig, warnEv, errEv) + if err != nil { + server.ServeError(writer, err.Error(), wantsJSON, nil) + return + } + if embed != nil { + // CheckAndAttachEmbed verifies that the post does not already have an embed or an upload, so upload + // is guaranteed to be nil here + upload = embed + } + var filePath, thumbPath, catalogThumbPath string documentRoot := config.GetSystemCriticalConfig().DocumentRoot if upload != nil { @@ -478,7 +490,7 @@ func MakePost(writer http.ResponseWriter, request *http.Request) { errEv.Err(err).Caller(). Str("sql", "postInsertion"). Msg("Unable to insert post") - if upload != nil { + if upload != nil && !upload.IsEmbed() { os.Remove(filePath) os.Remove(thumbPath) os.Remove(catalogThumbPath) diff --git a/templates/post.html b/templates/post.html index 3dcbbacc..d243d491 100644 --- a/templates/post.html +++ b/templates/post.html @@ -39,7 +39,13 @@
File removed
{{- else if ne $.post.Filename "" -}} {{- template "uploadinfo" . -}} - {{.post.UploadPath}} + + {{- if $.post.HasEmbed -}} + {{embedVideo .post.Filename .post.OriginalFilename $.board.Dir}} + {{- else -}} + {{.post.UploadPath}} + {{- end -}} + {{- end -}} {{- if $.post.IsTopPost}}{{template "nameline" .}}{{end -}}
{{.post.Message}}
diff --git a/templates/postbox.html b/templates/postbox.html index 4e58f0b3..a866fb5a 100644 --- a/templates/postbox.html +++ b/templates/postbox.html @@ -14,6 +14,9 @@ {{- if $.boardConfig.EnableSpoileredImages -}} {{- end}} + {{- if $.boardConfig.HasEmbedMatchers -}} + Embed + {{- end -}} {{- if or (customFlagsEnabled $.board.Dir) $.boardConfig.EnableGeoIP -}} Flag