telegram/replace.go (view raw)
1package telegram
2
3import (
4 "fmt"
5 "regexp"
6
7 tgbotapi "github.com/BiRabittoh/telegram-bot-api/v5"
8)
9
10type Replacer struct {
11 Regex *regexp.Regexp
12 Format string
13}
14
15const (
16 parseMode = "markdown"
17 linkMessage = "[🔗](%s) Da %s."
18 regexFlags = "(?i)(?m)"
19)
20
21var replacers = []Replacer{
22 {
23 Regex: regexp.MustCompile(regexFlags + `(?:(?:https?:)?\/\/)?(?:(?:www|m)\.)?(?:(?:youtube(?:-nocookie)?\.com|youtu.be))(?:\/(?:[\w\-]+\?v=|embed\/|live\/|v\/|shorts\/)?)([\w\-]+)`),
24 Format: "https://y.outube.duckdns.org/%s",
25 },
26 {
27 Regex: regexp.MustCompile(regexFlags + `https?:\/\/(?:www\.)?twitter\.com\/(?:#!\/)?(.*)\/status(?:es)?\/([^\/\?\s]+)`),
28 Format: "https://fxtwitter.com/%s/status/%s",
29 },
30 {
31 Regex: regexp.MustCompile(regexFlags + `(?:https?:\/\/)?(?:www\.)?x\.com\/(?:#!\/)?(.*)\/status(?:es)?\/([^\/\?\s]+)`),
32 Format: "https://fixupx.com/%s/status/%s",
33 },
34 {
35 Regex: regexp.MustCompile(regexFlags + `(?:https?:\/\/)?(?:www\.)?instagram\.com\/(reels?|p)\/([\w\-]{11})[\/\?\w=&]*`),
36 Format: "https://ddinstagram.com/%s/%s",
37 },
38 {
39 Regex: regexp.MustCompile(regexFlags + `https?:\/\/(?:(?:www)|(?:vm))?\.?tiktok\.com\/@([\w.]+)\/(?:video)\/(\d{19,})`),
40 Format: "https://www.tnktok.com/@%s/video/%s",
41 },
42 {
43 Regex: regexp.MustCompile(regexFlags + `(?:https?:\/\/)?(?:(?:www)|(?:vm))?\.?tiktok\.com\/(?:t\/)?([\w]{9})\/?`),
44 Format: "https://vm.tnktok.com/%s/",
45 },
46}
47
48func isInSpoiler(entities []tgbotapi.MessageEntity, offset, length int) bool {
49 for _, s := range entities {
50 if s.Type != "spoiler" {
51 continue
52 }
53
54 if offset < s.Offset+s.Length && offset+length > s.Offset {
55 return true
56 }
57 }
58 return false
59}
60
61func parseText(text string, entities []tgbotapi.MessageEntity) (links []string) {
62 var rawLinks string
63
64 for _, e := range entities {
65 if e.Type == "text_link" {
66 if isInSpoiler(entities, e.Offset, len(e.URL)) {
67 continue
68 }
69 rawLinks += e.URL + "\n"
70 } else if e.Type == "url" {
71 if isInSpoiler(entities, e.Offset, e.Length) {
72 continue
73 }
74
75 rawLinks += text[e.Offset:e.Offset+e.Length] + "\n"
76 }
77 }
78
79 for _, replacer := range replacers {
80 foundMatches := replacer.Regex.FindStringSubmatch(rawLinks)
81 if len(foundMatches) == 0 {
82 continue
83 }
84 captureGroups := foundMatches[1:]
85
86 var formatArgs []interface{}
87 for _, match := range captureGroups {
88 if match != "" {
89 formatArgs = append(formatArgs, match)
90 }
91 }
92
93 formatted := fmt.Sprintf(replacer.Format, formatArgs...)
94 links = append(links, formatted)
95 }
96 return links
97}
98
99func getUserMention(user tgbotapi.User) string {
100 var name string
101 if user.UserName == "" {
102 name = user.FirstName + user.LastName
103 } else {
104 name = "@" + user.UserName
105 }
106 return fmt.Sprintf("[%s](tg://user?id=%d)", name, user.ID)
107}
108
109func handleLinks(bot *tgbotapi.BotAPI, message *tgbotapi.Message) {
110 links := []string{}
111
112 if len(message.Entities) > 0 {
113 textLinks := parseText(message.Text, message.Entities)
114 links = append(links, textLinks...)
115 }
116
117 if len(message.CaptionEntities) > 0 {
118 captionLinks := parseText(message.Caption, message.CaptionEntities)
119 links = append(links, captionLinks...)
120 }
121
122 if len(links) == 0 {
123 return
124 }
125
126 user := getUserMention(*message.From)
127
128 for _, link := range links {
129 text := fmt.Sprintf(linkMessage, link, user)
130 msg := tgbotapi.NewMessage(message.Chat.ID, text)
131 msg.MessageThreadID = message.MessageThreadID
132 msg.ParseMode = parseMode
133 bot.Send(msg)
134 }
135
136}