all repos — escarbot @ 52c9b07a1684492fa7d561bdc8901ee088d39dcb

Earthbound Café's custom Telegram bot, with lots of cool utilities built-in.

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}