mirror of
https://github.com/krau/SaveAny-Bot.git
synced 2026-05-19 22:49:32 +08:00
91 lines
2.2 KiB
Go
91 lines
2.2 KiB
Go
package twitter
|
|
|
|
import (
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"net/http"
|
|
"path"
|
|
"regexp"
|
|
"strings"
|
|
|
|
"github.com/krau/SaveAny-Bot/pkg/parser"
|
|
)
|
|
|
|
type TwitterParser struct {
|
|
client http.Client
|
|
}
|
|
|
|
const (
|
|
FxTwitterApi = "api.fxtwitter.com"
|
|
)
|
|
|
|
var _ parser.Parser = (*TwitterParser)(nil)
|
|
|
|
var (
|
|
twitterSourceURLRegexp *regexp.Regexp = regexp.MustCompile(`(?:twitter|x)\.com/([^/]+)/status/(\d+)`)
|
|
)
|
|
|
|
func getTweetID(sourceURL string) string {
|
|
matches := twitterSourceURLRegexp.FindStringSubmatch(sourceURL)
|
|
if len(matches) < 3 {
|
|
return ""
|
|
}
|
|
return matches[2]
|
|
}
|
|
|
|
func (p *TwitterParser) Parse(u string) (*parser.Item, error) {
|
|
id := getTweetID(u)
|
|
if id == "" {
|
|
return nil, errors.New("invalid Twitter URL")
|
|
}
|
|
apiUrl := fmt.Sprintf("https://%s/_/status/%s", FxTwitterApi, id)
|
|
resp, err := p.client.Get(apiUrl)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to fetch Twitter API: %w", err)
|
|
}
|
|
defer resp.Body.Close()
|
|
if resp.StatusCode != http.StatusOK {
|
|
return nil, fmt.Errorf("failed to fetch Twitter API, status code: %d", resp.StatusCode)
|
|
}
|
|
var fxResp FxTwitterApiResp
|
|
if err := json.NewDecoder(resp.Body).Decode(&fxResp); err != nil {
|
|
return nil, fmt.Errorf("failed to decode Twitter API response: %w", err)
|
|
}
|
|
if fxResp.Code != 200 {
|
|
return nil, fmt.Errorf("request twitter API error: %s", fxResp.Message)
|
|
}
|
|
if len(fxResp.Tweet.Media.All) == 0 {
|
|
return nil, errors.New("no media found in the tweet")
|
|
}
|
|
resources := make([]parser.Resource, 0, len(fxResp.Tweet.Media.All))
|
|
for _, media := range fxResp.Tweet.Media.All {
|
|
var size int64
|
|
resp, err := p.client.Get(media.URL)
|
|
if err == nil {
|
|
size = resp.ContentLength
|
|
resp.Body.Close()
|
|
}
|
|
resources = append(resources, parser.Resource{
|
|
URL: media.URL,
|
|
Filename: path.Base(strings.Split(media.URL, "?")[0]),
|
|
Size: size,
|
|
})
|
|
}
|
|
item := &parser.Item{
|
|
Site: "Twitter",
|
|
Title: fmt.Sprintf("Tweet/%s", id),
|
|
URL: fxResp.Tweet.URL,
|
|
Description: fxResp.Tweet.Text,
|
|
Author: fxResp.Tweet.Author.Name,
|
|
Tags: make([]string, 0),
|
|
Extra: make(map[string]any),
|
|
Resources: resources,
|
|
}
|
|
return item, nil
|
|
}
|
|
|
|
func (p *TwitterParser) CanHandle(u string) bool {
|
|
return twitterSourceURLRegexp.MatchString(u)
|
|
}
|