Improve Twitter/X link handling and text formatting

- Use FxTwitter API for full note tweet text (with syndication API fallback)
- Save Twitter posts based on media content:
  - Videos → embed type (proxied video)
  - Images → image type (gallery)
  - Text-only → quote type
- Add granular preview badges: 'X VIDEO', 'X GALLERY', 'X POST'
- Preserve formatting/spacing with white-space: pre-wrap for quotes and descriptions
- Rename VideoInfo to EmbedInfo for better semantic clarity
This commit is contained in:
soup 2026-01-18 00:03:30 -05:00
parent 8a046728ef
commit 4a2cb341fa
Signed by: soup
SSH key fingerprint: SHA256:GYxje8eQkJ6HZKzVWDdyOUF1TyDiprruGhE0Ym8qYDY
7 changed files with 249 additions and 137 deletions

View file

@ -28,10 +28,9 @@ type itemPageData struct {
EmbedVideoURL *string
Tags []string
CreatedAt string
ThumbnailID *int64
MediaID *int64
MediaIsVideo bool
GalleryIDs []int64 // Additional images for multi-image embeds
ImageIDs []int64 // Fetched images (from URLs/embeds)
}
func (c itemPageContent) Render(sw *ssr.Writer) error {
@ -51,37 +50,22 @@ func (c itemPageContent) Render(sw *ssr.Writer) error {
<source src="/media/{{.Item.MediaID}}" type="video/mp4">
</video>
</div>
{{else if eq .Item.ItemType "embed"}}
{{if .Item.EmbedVideoURL}}
{{else if .Item.EmbedVideoURL}}
<div class="video-container">
<video loop muted playsinline poster="{{if .Item.ThumbnailID}}/media/{{.Item.ThumbnailID}}{{end}}">
<video loop muted playsinline {{if .Item.ImageIDs}}poster="/media/{{index .Item.ImageIDs 0}}"{{end}}>
<source src="/proxy/video/{{.Item.ID}}" type="video/mp4">
</video>
<div class="video-overlay" onclick="playVideo(this)">
<span class="play-button">&#9654;</span>
</div>
</div>
{{else if .Item.GalleryIDs}}
<div class="image-gallery">
{{if .Item.ThumbnailID}}<a href="/media/{{.Item.ThumbnailID}}"><img src="/media/{{.Item.ThumbnailID}}" alt="{{if .Item.Title}}{{.Item.Title}}{{else}}Image{{end}}"></a>{{end}}
{{range .Item.GalleryIDs}}<a href="/media/{{.}}"><img src="/media/{{.}}" alt="Image"></a>{{end}}
</div>
{{else if .Item.ThumbnailID}}
<div class="image-container">
<a href="/media/{{.Item.ThumbnailID}}"><img src="/media/{{.Item.ThumbnailID}}" alt="{{if .Item.Title}}{{.Item.Title}}{{else}}Embed{{end}}"></a>
{{else if .Item.ImageIDs}}
<div class="image-container{{if gt (len .Item.ImageIDs) 1}} image-gallery{{end}}">
{{range .Item.ImageIDs}}<a href="/media/{{.}}"><img src="/media/{{.}}" alt="Image"></a>{{end}}
</div>
{{else if .Item.MediaID}}
<div class="image-container">
<a href="/media/{{.Item.MediaID}}"><img src="/media/{{.Item.MediaID}}" alt="{{if .Item.Title}}{{.Item.Title}}{{else}}Embed{{end}}"></a>
</div>
{{end}}
{{else if .Item.MediaID}}
<div class="image-container">
<a href="/media/{{.Item.MediaID}}"><img src="/media/{{.Item.MediaID}}" alt="{{if .Item.Title}}{{.Item.Title}}{{else}}Image{{end}}"></a>
</div>
{{else if .Item.ThumbnailID}}
<div class="image-container">
<a href="/media/{{.Item.ThumbnailID}}"><img src="/media/{{.Item.ThumbnailID}}" alt="{{if .Item.Title}}{{.Item.Title}}{{else}}Image{{end}}"></a>
<a href="/media/{{.Item.MediaID}}"><img src="/media/{{.Item.MediaID}}" alt="Image"></a>
</div>
{{end}}
@ -179,26 +163,19 @@ func HandleItemPage(rc *RequestContext, w http.ResponseWriter, r *http.Request)
}
// Get media
// Media is ordered by ID, so first "image" is the thumbnail, rest are gallery
var thumbnailID, mediaID *int64
var mediaID *int64
var mediaIsVideo bool
var galleryIDs []int64
var imageIDs []int64
mediaList, err := media.QFindByItemID(ctx, rc.DB, it.ID)
if err != nil {
return err
}
firstImage := true
for _, m := range mediaList {
if m.MediaType == "original" {
mediaID = &m.ID
mediaIsVideo = strings.HasPrefix(m.ContentType, "video/")
} else if m.MediaType == "image" {
if firstImage {
thumbnailID = &m.ID
firstImage = false
} else {
galleryIDs = append(galleryIDs, m.ID)
}
imageIDs = append(imageIDs, m.ID)
}
}
@ -212,10 +189,9 @@ func HandleItemPage(rc *RequestContext, w http.ResponseWriter, r *http.Request)
EmbedVideoURL: item.Ptr(it.EmbedVideoURL),
Tags: tagNames,
CreatedAt: it.CreatedAt.Format("Jan 2, 2006"),
ThumbnailID: thumbnailID,
MediaID: mediaID,
MediaIsVideo: mediaIsVideo,
GalleryIDs: galleryIDs,
ImageIDs: imageIDs,
}
w.Header().Set("Content-Type", "text/html; charset=utf-8")