Files
rimgo/pages/media.go
orangix 02be603dcc refactor api package comments
* use encoding/json for comment parsing

* refactor by moving loop code to an UnmarshalJSON

* use a preallocated array and indices to maintain order while using
  goroutines again, this was removed a while ago

* use new struct in comment.hbs and contextComment.hbs

* rewriteUrl partial to reduce rimgo-specific code in api

* move RenderError into pages package to avoid import cycle between render and utils
2026-01-25 06:08:28 +01:00

91 lines
2.8 KiB
Go

package pages
import (
"io"
"mime"
"net/http"
"strings"
"codeberg.org/rimgo/rimgo/utils"
)
func HandleMedia(w http.ResponseWriter, r *http.Request) error {
w.Header().Set("Cache-Control", "public,max-age=31557600")
w.Header().Set("Content-Security-Policy", "default-src 'none'; style-src 'self'; img-src 'self'")
splitName := strings.SplitN(r.PathValue("component"), ".", 2)
baseName, extension := splitName[0], splitName[1]
if strings.HasPrefix(r.URL.Path, "/stack") {
return handleMedia(w, r, "https://i.stack.imgur.com/"+strings.ReplaceAll(baseName, "stack/", "")+"."+extension)
} else {
return handleMedia(w, r, "https://i.imgur.com/"+baseName+"."+extension)
}
}
func HandleUserCover(w http.ResponseWriter, r *http.Request) error {
w.Header().Set("Cache-Control", "public,max-age=604800")
w.Header().Set("Content-Security-Policy", "default-src 'none'")
return handleMedia(w, r, "https://imgur.com/user/"+r.PathValue("userID")+"/cover?maxwidth=2560")
}
func HandleUserAvatar(w http.ResponseWriter, r *http.Request) error {
w.Header().Set("Cache-Control", "public,max-age=604800")
w.Header().Set("Content-Security-Policy", "default-src 'none'")
return handleMedia(w, r, "https://imgur.com/user/"+r.PathValue("userID")+"/avatar")
}
func handleMedia(w http.ResponseWriter, r *http.Request, url string) error {
utils.SetHeaders(w)
path := r.URL.Path
if utils.Config.ForceWebp &&
!strings.HasSuffix(path, ".webp") &&
r.Header.Get("Sec-Fetch-Dest") == "image" &&
r.URL.Query().Get("no_webp") == "" &&
utils.Accepts(r, "image/webp") &&
!strings.HasPrefix(path, "/stack") {
url = strings.ReplaceAll(url, ".png", ".webp")
url = strings.ReplaceAll(url, ".jpg", ".webp")
url = strings.ReplaceAll(url, ".jpeg", ".webp")
filename := strings.TrimPrefix(path, "/")
w.Header().Set("Content-Disposition", mime.FormatMediaType("attachment", map[string]string{"filename*": filename}))
}
queryStr := r.URL.Query().Encode()
if strings.HasPrefix(path, "/stack") && queryStr != "" {
url = url + "?" + queryStr
}
req, err := http.NewRequest("GET", url, nil)
if err != nil {
return err
}
utils.SetReqHeaders(req)
rng := r.URL.Query().Get("Range")
if rng != "" {
req.Header.Set("Range", rng)
}
res, err := http.DefaultClient.Do(req)
if err != nil {
return err
}
if res.StatusCode == 404 || strings.Contains(res.Request.URL.String(), "error/404") {
return RenderError(w, r, 404)
} else if res.StatusCode == 429 {
return RenderError(w, r, 429)
}
w.Header().Set("Accept-Ranges", "bytes")
w.Header().Set("Content-Type", res.Header.Get("Content-Type"))
w.Header().Set("Content-Length", res.Header.Get("Content-Length"))
if res.Header.Get("Content-Range") != "" {
w.Header().Set("Content-Range", res.Header.Get("Content-Range"))
}
_, err = io.Copy(w, res.Body)
return err
}