Handle recordWithMedia, refactor processPost function
All checks were successful
/ build (push) Successful in 2m20s
All checks were successful
/ build (push) Successful in 2m20s
This commit is contained in:
parent
e2faeaac75
commit
e8b6e04239
3 changed files with 249 additions and 117 deletions
233
main.go
233
main.go
|
|
@ -186,6 +186,53 @@ func (h *handler) HandleEvent(ctx context.Context, event *models.Event) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (h *handler) handleVideo(media bsky.ParsedEmbeds) (tgbotapi.InputMedia, error) {
|
||||
url := buildBlobURL(h.bsky.Bluesky.Cfg.PDSURL, h.bsky.Bluesky.Cfg.DID, media.URI)
|
||||
log.Printf("Fetching video: %s\n", url)
|
||||
|
||||
resp, err := http.Get(url)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to fetch video: %w", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
filename := media.URI + ".mp4"
|
||||
f, err := os.Create(filename)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create video file: %w", err)
|
||||
}
|
||||
defer func() {
|
||||
f.Close()
|
||||
os.Remove(filename)
|
||||
}()
|
||||
|
||||
if _, err := io.Copy(f, resp.Body); err != nil {
|
||||
return nil, fmt.Errorf("failed to write video: %w", err)
|
||||
}
|
||||
if _, err := f.Seek(0, 0); err != nil {
|
||||
return nil, fmt.Errorf("failed to seek video: %w", err)
|
||||
}
|
||||
|
||||
mediaAdd := tgbotapi.NewInputMediaVideo(tgbotapi.FileReader{Name: "video.mp4", Reader: f})
|
||||
|
||||
metadata, err := getVideoMetadata(f.Name())
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to read video metadata: %w", err)
|
||||
}
|
||||
|
||||
mediaAdd.SupportsStreaming = true
|
||||
mediaAdd.Height = metadata.Height()
|
||||
mediaAdd.Width = metadata.Width()
|
||||
mediaAdd.Duration = int(metadata.Duration())
|
||||
|
||||
frames, _ := metadata.ReadFrames(0)
|
||||
var buf bytes.Buffer
|
||||
jpeg.Encode(&buf, frames[0], &jpeg.Options{Quality: 90})
|
||||
mediaAdd.Thumb = tgbotapi.FileBytes{Name: "thumb.jpg", Bytes: buf.Bytes()}
|
||||
|
||||
return &mediaAdd, nil
|
||||
}
|
||||
|
||||
func (h *handler) ProcessPost(event *models.Event) error {
|
||||
ps, _ := h.bsky.ParsePost(event.Commit.Record)
|
||||
po := ps.GetEmbeds()
|
||||
|
|
@ -209,42 +256,38 @@ func (h *handler) ProcessPost(event *models.Event) error {
|
|||
aliases := h.bsky.Bluesky.FetchAliases()
|
||||
facets := ps.ProcessFacets(aliases)
|
||||
|
||||
ownHandle, handleErr := h.bsky.GetHandleFromDID(h.bsky.Bluesky.Cfg.DID)
|
||||
if handleErr != nil {
|
||||
ownHandle = h.bsky.Bluesky.Cfg.Handle
|
||||
}
|
||||
|
||||
var captionText string
|
||||
if ps.IsQuotePost() {
|
||||
ownHandle, handleErr := h.bsky.GetHandleFromDID(h.bsky.Bluesky.Cfg.DID)
|
||||
if handleErr != nil {
|
||||
ownHandle = h.bsky.Bluesky.Cfg.Handle
|
||||
var quotedURI string
|
||||
if ps.Embed.Record != nil && ps.Embed.Record.Record != nil && ps.Embed.Record.Record.URI != "" {
|
||||
quotedURI = ps.Embed.Record.Record.URI
|
||||
} else if ps.Embed.Record != nil && ps.Embed.Record.URI != "" {
|
||||
quotedURI = ps.Embed.Record.URI
|
||||
}
|
||||
if ps.Embed.Record.Type == "app.bsky.embed.record" {
|
||||
handle, _ := h.bsky.GetHandleFromDID(strings.Split(ps.Embed.Record.Record.URI, "/")[2])
|
||||
captionText = fmt.Sprintf(
|
||||
quotePostFormat,
|
||||
facets,
|
||||
strings.Split(ps.Embed.Record.Record.URI, "/")[2],
|
||||
strings.Split(ps.Embed.Record.Record.URI, "/")[4],
|
||||
handle,
|
||||
event.Did,
|
||||
event.Commit.RKey,
|
||||
ownHandle)
|
||||
} else {
|
||||
handle, _ := h.bsky.GetHandleFromDID(strings.Split(ps.Embed.Record.URI, "/")[2])
|
||||
captionText = fmt.Sprintf(
|
||||
quotePostFormat,
|
||||
facets,
|
||||
strings.Split(ps.Embed.Record.URI, "/")[2],
|
||||
strings.Split(ps.Embed.Record.URI, "/")[4],
|
||||
handle,
|
||||
event.Did,
|
||||
event.Commit.RKey,
|
||||
ownHandle)
|
||||
|
||||
if quotedURI != "" {
|
||||
parts := strings.Split(quotedURI, "/")
|
||||
if len(parts) >= 5 {
|
||||
handle, _ := h.bsky.GetHandleFromDID(parts[2])
|
||||
captionText = fmt.Sprintf(
|
||||
quotePostFormat,
|
||||
facets,
|
||||
parts[2],
|
||||
parts[4],
|
||||
handle,
|
||||
event.Did,
|
||||
event.Commit.RKey,
|
||||
ownHandle)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if captionText == "" {
|
||||
ownHandle, handleErr := h.bsky.GetHandleFromDID(h.bsky.Bluesky.Cfg.DID)
|
||||
if handleErr != nil {
|
||||
ownHandle = h.bsky.Bluesky.Cfg.Handle
|
||||
}
|
||||
if facets != "" {
|
||||
captionText = fmt.Sprintf(postFormat, facets, h.bsky.Bluesky.Cfg.DID, event.Commit.RKey, ownHandle)
|
||||
} else {
|
||||
|
|
@ -252,16 +295,72 @@ func (h *handler) ProcessPost(event *models.Event) error {
|
|||
}
|
||||
}
|
||||
|
||||
// post has media
|
||||
if len((*po)) != 0 {
|
||||
if len(po) != 0 {
|
||||
mediaGroup := []tgbotapi.InputMedia{}
|
||||
if (*po)[0].Type == "external" {
|
||||
tenorGif := tgbotapi.NewInputMediaVideo(tgbotapi.FileURL((*po)[0].URI)) // is most likely gif from Tenor
|
||||
|
||||
if ps.Embed.Type == "app.bsky.embed.recordWithMedia" {
|
||||
hasExternal := false
|
||||
for _, media := range po {
|
||||
if media.Type == "external" {
|
||||
hasExternal = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if hasExternal && ps.Embed.Media != nil && ps.Embed.Media.External != nil {
|
||||
// Send as text message with webpage preview
|
||||
m := tgbotapi.NewMessage(cid, captionText)
|
||||
m.ParseMode = tgbotapi.ModeHTML
|
||||
m.LinkPreviewOptions = tgbotapi.LinkPreviewOptions{
|
||||
IsDisabled: false,
|
||||
URL: ps.Embed.Media.External.URI,
|
||||
PreferLargeMedia: true,
|
||||
ShowAboveText: false,
|
||||
}
|
||||
resp, _ := h.tg.Send(m)
|
||||
uri, postCid := getLink(event)
|
||||
h.bsky.Bluesky.CommitTelegramResponse(&bsky.TelegramRecord{
|
||||
ChannelID: resp.Chat.ID,
|
||||
MessageID: []int{resp.MessageID},
|
||||
Link: &bsky.Link{
|
||||
Cid: postCid,
|
||||
URI: uri,
|
||||
},
|
||||
}, event.Commit.RKey)
|
||||
return nil
|
||||
}
|
||||
|
||||
// recordWithMedia with images or video (not external) — fall through to normal media handling
|
||||
for _, media := range po {
|
||||
switch media.Type {
|
||||
case "record":
|
||||
continue
|
||||
case "image":
|
||||
mediaAdd := tgbotapi.NewInputMediaPhoto(tgbotapi.FileURL(buildBlobURL(h.bsky.Bluesky.Cfg.PDSURL, h.bsky.Bluesky.Cfg.DID, media.URI)))
|
||||
if len(mediaGroup) == 0 {
|
||||
mediaAdd.Caption = captionText
|
||||
mediaAdd.ParseMode = tgbotapi.ModeHTML
|
||||
}
|
||||
mediaGroup = append(mediaGroup, &mediaAdd)
|
||||
case "video":
|
||||
mediaAdd, err := h.handleVideo(media)
|
||||
if err != nil {
|
||||
log.Printf("Failed to handle video: %s\n", err)
|
||||
break
|
||||
}
|
||||
if len(mediaGroup) == 0 {
|
||||
setCaption(mediaAdd, captionText)
|
||||
}
|
||||
mediaGroup = append(mediaGroup, mediaAdd)
|
||||
}
|
||||
}
|
||||
} else if po[0].Type == "external" {
|
||||
tenorGif := tgbotapi.NewInputMediaVideo(tgbotapi.FileURL(po[0].URI))
|
||||
tenorGif.Caption = captionText
|
||||
tenorGif.ParseMode = tgbotapi.ModeHTML
|
||||
mediaGroup = append(mediaGroup, &tenorGif)
|
||||
} else {
|
||||
for _, media := range *po {
|
||||
for _, media := range po {
|
||||
switch media.Type {
|
||||
case "image":
|
||||
mediaAdd := tgbotapi.NewInputMediaPhoto(tgbotapi.FileURL(buildBlobURL(h.bsky.Bluesky.Cfg.PDSURL, h.bsky.Bluesky.Cfg.DID, media.URI)))
|
||||
|
|
@ -271,37 +370,19 @@ func (h *handler) ProcessPost(event *models.Event) error {
|
|||
}
|
||||
mediaGroup = append(mediaGroup, &mediaAdd)
|
||||
case "video":
|
||||
log.Printf("Fetching video: %s\n", buildBlobURL(h.bsky.Bluesky.Cfg.PDSURL, h.bsky.Bluesky.Cfg.DID, media.URI))
|
||||
resp, _ := http.Get(buildBlobURL(h.bsky.Bluesky.Cfg.PDSURL, h.bsky.Bluesky.Cfg.DID, media.URI))
|
||||
defer resp.Body.Close()
|
||||
f, _ := os.Create(media.URI + ".mp4")
|
||||
defer f.Close()
|
||||
io.Copy(f, resp.Body)
|
||||
f.Seek(0, 0)
|
||||
mediaAdd := tgbotapi.NewInputMediaVideo(tgbotapi.FileReader{Name: "video.mp4", Reader: f})
|
||||
metadata, err := getVideoMetadata(f.Name())
|
||||
mediaAdd, err := h.handleVideo(media)
|
||||
if err != nil {
|
||||
log.Printf("Unable to read video metadata: %s - URL: %s\n", err, buildBlobURL(h.bsky.Bluesky.Cfg.PDSURL, h.bsky.Bluesky.Cfg.DID, media.URI))
|
||||
log.Printf("Failed to handle video: %s\n", err)
|
||||
break
|
||||
}
|
||||
mediaAdd.SupportsStreaming = true
|
||||
mediaAdd.Height = metadata.Height()
|
||||
mediaAdd.Width = metadata.Width()
|
||||
mediaAdd.Duration = int(metadata.Duration())
|
||||
|
||||
frames, _ := metadata.ReadFrames(0)
|
||||
var buf bytes.Buffer
|
||||
jpeg.Encode(&buf, frames[0], &jpeg.Options{Quality: 90})
|
||||
mediaAdd.Thumb = tgbotapi.FileBytes{Name: "thumb.jpg", Bytes: buf.Bytes()}
|
||||
if len(mediaGroup) == 0 {
|
||||
mediaAdd.Caption = captionText
|
||||
mediaAdd.ParseMode = tgbotapi.ModeHTML
|
||||
setCaption(mediaAdd, captionText)
|
||||
}
|
||||
os.Remove(media.URI + ".mp4")
|
||||
mediaGroup = append(mediaGroup, &mediaAdd)
|
||||
mediaGroup = append(mediaGroup, mediaAdd)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(mediaGroup) == 0 {
|
||||
log.Print("No mediaGroup to send, see previous error")
|
||||
} else {
|
||||
|
|
@ -310,7 +391,7 @@ func (h *handler) ProcessPost(event *models.Event) error {
|
|||
fmt.Println(resp, err)
|
||||
} else {
|
||||
resp, _ := h.tg.SendMediaGroup(tgbotapi.NewMediaGroup(cid, mediaGroup))
|
||||
uri, cid := getLink(event)
|
||||
uri, postCid := getLink(event)
|
||||
var messageIDs []int
|
||||
for _, msgID := range resp {
|
||||
messageIDs = append(messageIDs, msgID.MessageID)
|
||||
|
|
@ -319,7 +400,7 @@ func (h *handler) ProcessPost(event *models.Event) error {
|
|||
ChannelID: resp[0].Chat.ID,
|
||||
MessageID: messageIDs,
|
||||
Link: &bsky.Link{
|
||||
Cid: cid,
|
||||
Cid: postCid,
|
||||
URI: uri,
|
||||
},
|
||||
}, event.Commit.RKey)
|
||||
|
|
@ -334,11 +415,19 @@ func (h *handler) ProcessPost(event *models.Event) error {
|
|||
}
|
||||
m.ParseMode = tgbotapi.ModeHTML
|
||||
if ps.IsQuotePost() {
|
||||
m.LinkPreviewOptions = tgbotapi.LinkPreviewOptions{
|
||||
IsDisabled: false,
|
||||
URL: fmt.Sprintf(embedURL,
|
||||
var previewURI string
|
||||
if ps.Embed.Record != nil && ps.Embed.Record.Record != nil {
|
||||
previewURI = fmt.Sprintf(embedURL,
|
||||
strings.Split(ps.Embed.Record.Record.URI, "/")[2],
|
||||
strings.Split(ps.Embed.Record.Record.URI, "/")[4])
|
||||
} else if ps.Embed.Record != nil {
|
||||
previewURI = fmt.Sprintf(embedURL,
|
||||
strings.Split(ps.Embed.Record.URI, "/")[2],
|
||||
strings.Split(ps.Embed.Record.URI, "/")[4]),
|
||||
strings.Split(ps.Embed.Record.URI, "/")[4])
|
||||
}
|
||||
m.LinkPreviewOptions = tgbotapi.LinkPreviewOptions{
|
||||
IsDisabled: false,
|
||||
URL: previewURI,
|
||||
PreferSmallMedia: true,
|
||||
PreferLargeMedia: false,
|
||||
ShowAboveText: true,
|
||||
|
|
@ -346,13 +435,14 @@ func (h *handler) ProcessPost(event *models.Event) error {
|
|||
} else {
|
||||
m.LinkPreviewOptions = tgbotapi.LinkPreviewOptions{IsDisabled: true}
|
||||
}
|
||||
resp, _ := h.tg.Send(m)
|
||||
uri, cid := getLink(event)
|
||||
resp, e := h.tg.Send(m)
|
||||
fmt.Println(resp, e)
|
||||
uri, postCid := getLink(event)
|
||||
h.bsky.Bluesky.CommitTelegramResponse(&bsky.TelegramRecord{
|
||||
ChannelID: resp.Chat.ID,
|
||||
MessageID: []int{resp.MessageID},
|
||||
Link: &bsky.Link{
|
||||
Cid: cid,
|
||||
Cid: postCid,
|
||||
URI: uri,
|
||||
},
|
||||
}, event.Commit.RKey)
|
||||
|
|
@ -360,6 +450,17 @@ func (h *handler) ProcessPost(event *models.Event) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func setCaption(media tgbotapi.InputMedia, caption string) {
|
||||
switch m := media.(type) {
|
||||
case *tgbotapi.InputMediaVideo:
|
||||
m.Caption = caption
|
||||
m.ParseMode = tgbotapi.ModeHTML
|
||||
case *tgbotapi.InputMediaPhoto:
|
||||
m.Caption = caption
|
||||
m.ParseMode = tgbotapi.ModeHTML
|
||||
}
|
||||
}
|
||||
|
||||
func buildBlobURL(server string, did string, cid string) string {
|
||||
return server + "/xrpc/com.atproto.sync.getBlob?did=" + url.QueryEscape(did) + "&cid=" + cid
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue