mirror of
https://github.com/truewhile/MeBox.git
synced 2026-10-05 21:06:38 +08:00
split telegram notification formatting
This commit is contained in:
@@ -4,7 +4,6 @@ package service
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"regexp"
|
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
"unicode/utf8"
|
"unicode/utf8"
|
||||||
@@ -140,289 +139,3 @@ func formatTelegramNotification(event NotifyEvent) string {
|
|||||||
|
|
||||||
return strings.TrimSpace(sb.String())
|
return strings.TrimSpace(sb.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
|
||||||
telegramMediaTemplateHeader = "🐈⬛🐈⬛ MediaStationGo 更新啦 🐈⬛🐈⬛"
|
|
||||||
telegramMediaTemplateSeparator = "--------------------------------"
|
|
||||||
)
|
|
||||||
|
|
||||||
var telegramSeasonEpisodePattern = regexp.MustCompile(`(?i)S\d{1,2}E\d{1,3}(?:[\-.~_ ]?E?\d{1,3})?`)
|
|
||||||
|
|
||||||
func formatTelegramMediaNotification(event NotifyEvent) string {
|
|
||||||
tag := telegramMediaTag(event.Data)
|
|
||||||
if tag == "" {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
title := telegramFirstValue(event.Data, "chinese_title", "title", "name", "media_title")
|
|
||||||
if title == "" {
|
|
||||||
title = telegramMessageFieldValue(event.Message, "任务", "订阅", "媒体", "资源")
|
|
||||||
}
|
|
||||||
originalTitle := telegramFirstValue(event.Data, "original_title", "original_name")
|
|
||||||
originalLanguage := telegramLanguageName(telegramFirstValue(event.Data, "original_language", "language", "languages"))
|
|
||||||
year := telegramFirstValue(event.Data, "year", "release_year")
|
|
||||||
category := telegramMediaCategory(event.Data)
|
|
||||||
seasonEpisode := telegramSeasonEpisodeValue(event)
|
|
||||||
size := telegramSizeValue(event.Data)
|
|
||||||
version := telegramVersionValue(event, seasonEpisode)
|
|
||||||
rating := telegramFirstValue(event.Data, "rating", "score")
|
|
||||||
genres := telegramGenresValue(telegramFirstValue(event.Data, "genres", "genre", "type"))
|
|
||||||
overview := telegramFirstValue(event.Data, "overview", "summary", "description")
|
|
||||||
links := telegramExternalLinks(event.Data)
|
|
||||||
|
|
||||||
topFields := []string{}
|
|
||||||
if title != "" {
|
|
||||||
topFields = append(topFields, "📺 中文片名:"+escapeHTML(title))
|
|
||||||
}
|
|
||||||
if originalTitle != "" && !strings.EqualFold(originalTitle, title) {
|
|
||||||
topFields = append(topFields, "🧿 原始片名:"+escapeHTML(originalTitle))
|
|
||||||
}
|
|
||||||
if originalLanguage != "" {
|
|
||||||
topFields = append(topFields, "🌐 原始语言:"+escapeHTML(originalLanguage))
|
|
||||||
}
|
|
||||||
if year != "" && year != "0" {
|
|
||||||
topFields = append(topFields, "📅 发行年份:"+escapeHTML(year))
|
|
||||||
}
|
|
||||||
|
|
||||||
mediaFields := []string{}
|
|
||||||
if category != "" {
|
|
||||||
mediaFields = append(mediaFields, "🐈⬛ 类别:"+escapeHTML(category))
|
|
||||||
}
|
|
||||||
if seasonEpisode != "" {
|
|
||||||
mediaFields = append(mediaFields, "🫧 季集:"+escapeHTML(seasonEpisode))
|
|
||||||
}
|
|
||||||
if size != "" {
|
|
||||||
mediaFields = append(mediaFields, "🔎 大小:"+escapeHTML(size))
|
|
||||||
}
|
|
||||||
if version != "" {
|
|
||||||
mediaFields = append(mediaFields, "📁 版本:"+escapeHTML(version))
|
|
||||||
}
|
|
||||||
|
|
||||||
infoFields := []string{}
|
|
||||||
if rating != "" && rating != "0" {
|
|
||||||
infoFields = append(infoFields, "⭐️ 评分:"+escapeHTML(rating))
|
|
||||||
}
|
|
||||||
if genres != "" {
|
|
||||||
infoFields = append(infoFields, "💎 类型:"+escapeHTML(genres))
|
|
||||||
}
|
|
||||||
if overview != "" {
|
|
||||||
infoFields = append(infoFields, "🪬 简介:\n"+escapeHTML(overview))
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(topFields) == 0 && len(mediaFields) == 0 && len(infoFields) == 0 && links == "" {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
lines := []string{telegramMediaTemplateHeader, telegramMediaTemplateSeparator, tag}
|
|
||||||
lines = append(lines, topFields...)
|
|
||||||
if len(mediaFields) > 0 {
|
|
||||||
if len(topFields) > 0 {
|
|
||||||
lines = append(lines, "")
|
|
||||||
}
|
|
||||||
lines = append(lines, mediaFields...)
|
|
||||||
}
|
|
||||||
if len(infoFields) > 0 {
|
|
||||||
if len(topFields) > 0 || len(mediaFields) > 0 {
|
|
||||||
lines = append(lines, "")
|
|
||||||
}
|
|
||||||
lines = append(lines, infoFields...)
|
|
||||||
}
|
|
||||||
if links != "" {
|
|
||||||
lines = append(lines, "", telegramMediaTemplateSeparator, links)
|
|
||||||
}
|
|
||||||
return strings.TrimSpace(strings.Join(lines, "\n"))
|
|
||||||
}
|
|
||||||
|
|
||||||
func telegramShouldShowEventHeading(event NotifyEvent) bool {
|
|
||||||
if telegramMediaTag(event.Data) != "" {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
switch strings.TrimSpace(event.Type) {
|
|
||||||
case EventSubscriptionHit, EventDownloadComplete:
|
|
||||||
return false
|
|
||||||
default:
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func telegramEventTag(event NotifyEvent) string {
|
|
||||||
if tag := telegramMediaTag(event.Data); tag != "" {
|
|
||||||
return tag
|
|
||||||
}
|
|
||||||
switch strings.TrimSpace(event.Type) {
|
|
||||||
case EventSubscriptionHit:
|
|
||||||
return "#订阅"
|
|
||||||
case EventDownloadComplete:
|
|
||||||
return "#下载完成"
|
|
||||||
case EventScrapeFailed:
|
|
||||||
return "#刮削失败"
|
|
||||||
case EventSystemAlert:
|
|
||||||
return "#系统提醒"
|
|
||||||
case EventLibraryIngest:
|
|
||||||
return "#入库"
|
|
||||||
default:
|
|
||||||
title := strings.TrimSpace(strings.TrimPrefix(event.Title, "MediaStationGo "))
|
|
||||||
if title == "" {
|
|
||||||
return "#MediaStationGo"
|
|
||||||
}
|
|
||||||
return "#" + escapeHTML(strings.ReplaceAll(title, " ", ""))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func telegramMediaTag(data map[string]interface{}) string {
|
|
||||||
for _, key := range []string{"media_category", "category", "media_type"} {
|
|
||||||
value := strings.TrimSpace(telegramDataString(data, key))
|
|
||||||
if value == "" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
lower := strings.ToLower(value)
|
|
||||||
switch {
|
|
||||||
case strings.Contains(value, "电影") || lower == "movie":
|
|
||||||
return "#电影"
|
|
||||||
case strings.Contains(value, "剧") || lower == "tv" || lower == "series" || lower == "show":
|
|
||||||
return "#剧集"
|
|
||||||
case strings.Contains(value, "动漫") || strings.Contains(value, "动画") || lower == "anime":
|
|
||||||
return "#动漫"
|
|
||||||
case strings.Contains(value, "综艺") || lower == "variety":
|
|
||||||
return "#综艺"
|
|
||||||
case strings.Contains(value, "纪录") || lower == "documentary":
|
|
||||||
return "#纪录片"
|
|
||||||
default:
|
|
||||||
return "#" + escapeHTML(strings.ReplaceAll(value, " ", ""))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func telegramEventHeading(event NotifyEvent) string {
|
|
||||||
title := strings.TrimSpace(event.Title)
|
|
||||||
title = strings.TrimSpace(strings.TrimPrefix(title, "MediaStationGo "))
|
|
||||||
if title == "" {
|
|
||||||
title = "MediaStationGo 通知"
|
|
||||||
}
|
|
||||||
icon := "🔔"
|
|
||||||
switch strings.TrimSpace(event.Type) {
|
|
||||||
case EventSubscriptionHit:
|
|
||||||
icon = "🎯"
|
|
||||||
case EventDownloadComplete:
|
|
||||||
icon = "✅"
|
|
||||||
case EventScrapeFailed:
|
|
||||||
icon = "⚠️"
|
|
||||||
case EventSystemAlert:
|
|
||||||
icon = "🚨"
|
|
||||||
case EventLibraryIngest:
|
|
||||||
icon = "📚"
|
|
||||||
}
|
|
||||||
return fmt.Sprintf("%s <b>%s</b>", icon, escapeHTML(title))
|
|
||||||
}
|
|
||||||
|
|
||||||
func formatTelegramBody(message string) string {
|
|
||||||
lines := strings.Split(message, "\n")
|
|
||||||
out := make([]string, 0, len(lines))
|
|
||||||
for _, line := range lines {
|
|
||||||
line = strings.TrimSpace(line)
|
|
||||||
if line == "" {
|
|
||||||
out = append(out, "")
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if strings.HasPrefix(line, "- ") {
|
|
||||||
out = append(out, "- "+escapeHTML(strings.TrimSpace(strings.TrimPrefix(line, "- "))))
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if key, ok := trimTelegramEmptyField(line); ok {
|
|
||||||
out = append(out, fmt.Sprintf("%s <b>%s</b>:", telegramFieldIcon(telegramFieldLabel(key)), escapeHTML(telegramFieldLabel(key))))
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if key, value, ok := splitTelegramField(line); ok {
|
|
||||||
out = append(out, formatTelegramField(key, value))
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
out = append(out, escapeHTML(line))
|
|
||||||
}
|
|
||||||
return strings.TrimSpace(strings.Join(out, "\n"))
|
|
||||||
}
|
|
||||||
|
|
||||||
func trimTelegramEmptyField(line string) (string, bool) {
|
|
||||||
line = strings.TrimSpace(line)
|
|
||||||
for _, suffix := range []string{":", ":"} {
|
|
||||||
if strings.HasSuffix(line, suffix) {
|
|
||||||
key := strings.TrimSpace(strings.TrimSuffix(line, suffix))
|
|
||||||
if key != "" && len([]rune(key)) <= 16 {
|
|
||||||
return key, true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return "", false
|
|
||||||
}
|
|
||||||
|
|
||||||
func splitTelegramField(line string) (string, string, bool) {
|
|
||||||
idx := strings.Index(line, ":")
|
|
||||||
sepLen := len(":")
|
|
||||||
if idx < 0 {
|
|
||||||
idx = strings.Index(line, ":")
|
|
||||||
sepLen = len(":")
|
|
||||||
}
|
|
||||||
if idx <= 0 {
|
|
||||||
return "", "", false
|
|
||||||
}
|
|
||||||
key := strings.TrimSpace(line[:idx])
|
|
||||||
value := strings.TrimSpace(line[idx+sepLen:])
|
|
||||||
if key == "" || value == "" || len([]rune(key)) > 16 {
|
|
||||||
return "", "", false
|
|
||||||
}
|
|
||||||
return key, value, true
|
|
||||||
}
|
|
||||||
|
|
||||||
func formatTelegramField(key, value string) string {
|
|
||||||
key = telegramFieldLabel(key)
|
|
||||||
escapedValue := escapeHTML(strings.TrimSpace(value))
|
|
||||||
if telegramCodeField(key) {
|
|
||||||
escapedValue = "<code>" + escapedValue + "</code>"
|
|
||||||
}
|
|
||||||
return fmt.Sprintf("%s <b>%s</b>:%s", telegramFieldIcon(key), escapeHTML(key), escapedValue)
|
|
||||||
}
|
|
||||||
|
|
||||||
func telegramCodeField(key string) bool {
|
|
||||||
key = strings.ToLower(strings.TrimSpace(key))
|
|
||||||
return strings.Contains(key, "hash") ||
|
|
||||||
strings.Contains(key, "路径") ||
|
|
||||||
strings.Contains(key, "path") ||
|
|
||||||
strings.Contains(key, "id")
|
|
||||||
}
|
|
||||||
|
|
||||||
func telegramFieldIcon(key string) string {
|
|
||||||
switch strings.ToLower(strings.TrimSpace(key)) {
|
|
||||||
case "中文片名", "标题", "任务", "媒体", "资源":
|
|
||||||
return "📺"
|
|
||||||
case "原始片名":
|
|
||||||
return "🧿"
|
|
||||||
case "原始语言", "语言":
|
|
||||||
return "🌐"
|
|
||||||
case "发行年份", "年份":
|
|
||||||
return "📅"
|
|
||||||
case "类别", "分类", "媒体类型":
|
|
||||||
return "🐈⬛"
|
|
||||||
case "季集", "集数":
|
|
||||||
return "🫧"
|
|
||||||
case "大小", "质量", "规格":
|
|
||||||
return "🔎"
|
|
||||||
case "版本", "保存路径":
|
|
||||||
return "📁"
|
|
||||||
case "评分":
|
|
||||||
return "⭐️"
|
|
||||||
case "类型":
|
|
||||||
return "💎"
|
|
||||||
case "简介":
|
|
||||||
return "🪬"
|
|
||||||
case "订阅":
|
|
||||||
return "🎯"
|
|
||||||
case "新增资源":
|
|
||||||
return "✨"
|
|
||||||
case "Hash":
|
|
||||||
return "🧿"
|
|
||||||
case "错误":
|
|
||||||
return "⚠️"
|
|
||||||
default:
|
|
||||||
return "•"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -0,0 +1,175 @@
|
|||||||
|
package service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func telegramShouldShowEventHeading(event NotifyEvent) bool {
|
||||||
|
if telegramMediaTag(event.Data) != "" {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
switch strings.TrimSpace(event.Type) {
|
||||||
|
case EventSubscriptionHit, EventDownloadComplete:
|
||||||
|
return false
|
||||||
|
default:
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func telegramEventTag(event NotifyEvent) string {
|
||||||
|
if tag := telegramMediaTag(event.Data); tag != "" {
|
||||||
|
return tag
|
||||||
|
}
|
||||||
|
switch strings.TrimSpace(event.Type) {
|
||||||
|
case EventSubscriptionHit:
|
||||||
|
return "#订阅"
|
||||||
|
case EventDownloadComplete:
|
||||||
|
return "#下载完成"
|
||||||
|
case EventScrapeFailed:
|
||||||
|
return "#刮削失败"
|
||||||
|
case EventSystemAlert:
|
||||||
|
return "#系统提醒"
|
||||||
|
case EventLibraryIngest:
|
||||||
|
return "#入库"
|
||||||
|
default:
|
||||||
|
title := strings.TrimSpace(strings.TrimPrefix(event.Title, "MediaStationGo "))
|
||||||
|
if title == "" {
|
||||||
|
return "#MediaStationGo"
|
||||||
|
}
|
||||||
|
return "#" + escapeHTML(strings.ReplaceAll(title, " ", ""))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func telegramEventHeading(event NotifyEvent) string {
|
||||||
|
title := strings.TrimSpace(event.Title)
|
||||||
|
title = strings.TrimSpace(strings.TrimPrefix(title, "MediaStationGo "))
|
||||||
|
if title == "" {
|
||||||
|
title = "MediaStationGo 通知"
|
||||||
|
}
|
||||||
|
icon := "🔔"
|
||||||
|
switch strings.TrimSpace(event.Type) {
|
||||||
|
case EventSubscriptionHit:
|
||||||
|
icon = "🎯"
|
||||||
|
case EventDownloadComplete:
|
||||||
|
icon = "✅"
|
||||||
|
case EventScrapeFailed:
|
||||||
|
icon = "⚠️"
|
||||||
|
case EventSystemAlert:
|
||||||
|
icon = "🚨"
|
||||||
|
case EventLibraryIngest:
|
||||||
|
icon = "📚"
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("%s <b>%s</b>", icon, escapeHTML(title))
|
||||||
|
}
|
||||||
|
|
||||||
|
func formatTelegramBody(message string) string {
|
||||||
|
lines := strings.Split(message, "\n")
|
||||||
|
out := make([]string, 0, len(lines))
|
||||||
|
for _, line := range lines {
|
||||||
|
line = strings.TrimSpace(line)
|
||||||
|
if line == "" {
|
||||||
|
out = append(out, "")
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if strings.HasPrefix(line, "- ") {
|
||||||
|
out = append(out, "- "+escapeHTML(strings.TrimSpace(strings.TrimPrefix(line, "- "))))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if key, ok := trimTelegramEmptyField(line); ok {
|
||||||
|
out = append(out, fmt.Sprintf("%s <b>%s</b>:", telegramFieldIcon(telegramFieldLabel(key)), escapeHTML(telegramFieldLabel(key))))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if key, value, ok := splitTelegramField(line); ok {
|
||||||
|
out = append(out, formatTelegramField(key, value))
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
out = append(out, escapeHTML(line))
|
||||||
|
}
|
||||||
|
return strings.TrimSpace(strings.Join(out, "\n"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func trimTelegramEmptyField(line string) (string, bool) {
|
||||||
|
line = strings.TrimSpace(line)
|
||||||
|
for _, suffix := range []string{":", ":"} {
|
||||||
|
if strings.HasSuffix(line, suffix) {
|
||||||
|
key := strings.TrimSpace(strings.TrimSuffix(line, suffix))
|
||||||
|
if key != "" && len([]rune(key)) <= 16 {
|
||||||
|
return key, true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return "", false
|
||||||
|
}
|
||||||
|
|
||||||
|
func splitTelegramField(line string) (string, string, bool) {
|
||||||
|
idx := strings.Index(line, ":")
|
||||||
|
sepLen := len(":")
|
||||||
|
if idx < 0 {
|
||||||
|
idx = strings.Index(line, ":")
|
||||||
|
sepLen = len(":")
|
||||||
|
}
|
||||||
|
if idx <= 0 {
|
||||||
|
return "", "", false
|
||||||
|
}
|
||||||
|
key := strings.TrimSpace(line[:idx])
|
||||||
|
value := strings.TrimSpace(line[idx+sepLen:])
|
||||||
|
if key == "" || value == "" || len([]rune(key)) > 16 {
|
||||||
|
return "", "", false
|
||||||
|
}
|
||||||
|
return key, value, true
|
||||||
|
}
|
||||||
|
|
||||||
|
func formatTelegramField(key, value string) string {
|
||||||
|
key = telegramFieldLabel(key)
|
||||||
|
escapedValue := escapeHTML(strings.TrimSpace(value))
|
||||||
|
if telegramCodeField(key) {
|
||||||
|
escapedValue = "<code>" + escapedValue + "</code>"
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("%s <b>%s</b>:%s", telegramFieldIcon(key), escapeHTML(key), escapedValue)
|
||||||
|
}
|
||||||
|
|
||||||
|
func telegramCodeField(key string) bool {
|
||||||
|
key = strings.ToLower(strings.TrimSpace(key))
|
||||||
|
return strings.Contains(key, "hash") ||
|
||||||
|
strings.Contains(key, "路径") ||
|
||||||
|
strings.Contains(key, "path") ||
|
||||||
|
strings.Contains(key, "id")
|
||||||
|
}
|
||||||
|
|
||||||
|
func telegramFieldIcon(key string) string {
|
||||||
|
switch strings.ToLower(strings.TrimSpace(key)) {
|
||||||
|
case "中文片名", "标题", "任务", "媒体", "资源":
|
||||||
|
return "📺"
|
||||||
|
case "原始片名":
|
||||||
|
return "🧿"
|
||||||
|
case "原始语言", "语言":
|
||||||
|
return "🌐"
|
||||||
|
case "发行年份", "年份":
|
||||||
|
return "📅"
|
||||||
|
case "类别", "分类", "媒体类型":
|
||||||
|
return "🐈⬛"
|
||||||
|
case "季集", "集数":
|
||||||
|
return "🫧"
|
||||||
|
case "大小", "质量", "规格":
|
||||||
|
return "🔎"
|
||||||
|
case "版本", "保存路径":
|
||||||
|
return "📁"
|
||||||
|
case "评分":
|
||||||
|
return "⭐️"
|
||||||
|
case "类型":
|
||||||
|
return "💎"
|
||||||
|
case "简介":
|
||||||
|
return "🪬"
|
||||||
|
case "订阅":
|
||||||
|
return "🎯"
|
||||||
|
case "新增资源":
|
||||||
|
return "✨"
|
||||||
|
case "Hash":
|
||||||
|
return "🧿"
|
||||||
|
case "错误":
|
||||||
|
return "⚠️"
|
||||||
|
default:
|
||||||
|
return "•"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,170 @@
|
|||||||
|
package service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"net/url"
|
||||||
|
"sort"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
type telegramDataField struct {
|
||||||
|
key string
|
||||||
|
value string
|
||||||
|
}
|
||||||
|
|
||||||
|
func telegramDisplayData(data map[string]interface{}) []telegramDataField {
|
||||||
|
if len(data) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
keys := make([]string, 0, len(data))
|
||||||
|
for key := range data {
|
||||||
|
if telegramHiddenDataKey(key) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
keys = append(keys, key)
|
||||||
|
}
|
||||||
|
sort.Strings(keys)
|
||||||
|
fields := make([]telegramDataField, 0, len(keys))
|
||||||
|
for _, key := range keys {
|
||||||
|
value := strings.TrimSpace(fmt.Sprint(data[key]))
|
||||||
|
if value == "" || value == "<nil>" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
fields = append(fields, telegramDataField{key: key, value: value})
|
||||||
|
}
|
||||||
|
return fields
|
||||||
|
}
|
||||||
|
|
||||||
|
func telegramHiddenDataKey(key string) bool {
|
||||||
|
switch strings.ToLower(strings.TrimSpace(key)) {
|
||||||
|
case "photo_url", "poster_url", "poster", "image_url", "backdrop_url",
|
||||||
|
"tmdb_url", "imdb_url", "douban_url", "detail_url", "external_url",
|
||||||
|
"resource_title", "torrent_title", "release_title":
|
||||||
|
return true
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func telegramFieldLabel(key string) string {
|
||||||
|
switch strings.ToLower(strings.TrimSpace(key)) {
|
||||||
|
case "title", "name":
|
||||||
|
return "标题"
|
||||||
|
case "original_title":
|
||||||
|
return "原始片名"
|
||||||
|
case "original_language":
|
||||||
|
return "原始语言"
|
||||||
|
case "year", "release_year":
|
||||||
|
return "发行年份"
|
||||||
|
case "save_path":
|
||||||
|
return "保存路径"
|
||||||
|
case "hash":
|
||||||
|
return "Hash"
|
||||||
|
case "media_type":
|
||||||
|
return "媒体类型"
|
||||||
|
case "media_category":
|
||||||
|
return "类别"
|
||||||
|
case "season_episode":
|
||||||
|
return "季集"
|
||||||
|
case "size", "bitrate":
|
||||||
|
return "大小"
|
||||||
|
case "version", "release_group":
|
||||||
|
return "版本"
|
||||||
|
case "rating":
|
||||||
|
return "评分"
|
||||||
|
case "genres":
|
||||||
|
return "类型"
|
||||||
|
case "overview":
|
||||||
|
return "简介"
|
||||||
|
case "subscription":
|
||||||
|
return "订阅"
|
||||||
|
case "queued":
|
||||||
|
return "新增资源"
|
||||||
|
default:
|
||||||
|
return strings.TrimSpace(key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func telegramExternalLinks(data map[string]interface{}) string {
|
||||||
|
if len(data) == 0 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
links := []string{}
|
||||||
|
for _, item := range []struct {
|
||||||
|
key string
|
||||||
|
name string
|
||||||
|
}{
|
||||||
|
{key: "tmdb_url", name: "TMDB"},
|
||||||
|
{key: "imdb_url", name: "IMDB"},
|
||||||
|
{key: "douban_url", name: "豆瓣"},
|
||||||
|
} {
|
||||||
|
value := telegramDataString(data, item.key)
|
||||||
|
if isTelegramRemotePhotoURL(value) {
|
||||||
|
links = append(links, fmt.Sprintf(`<a href="%s">%s</a>`, escapeHTML(value), escapeHTML(item.name)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(links) == 0 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return "🔗 外链:" + strings.Join(links, " / ")
|
||||||
|
}
|
||||||
|
|
||||||
|
func telegramEventPhotoURL(event NotifyEvent) string {
|
||||||
|
for _, key := range []string{"photo_url", "poster_url", "poster", "image_url", "backdrop_url"} {
|
||||||
|
value := telegramDataString(event.Data, key)
|
||||||
|
if isTelegramRemotePhotoURL(value) {
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func telegramDataString(data map[string]interface{}, key string) string {
|
||||||
|
if len(data) == 0 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
for k, value := range data {
|
||||||
|
if strings.EqualFold(strings.TrimSpace(k), key) {
|
||||||
|
return telegramValueString(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func telegramValueString(value interface{}) string {
|
||||||
|
switch v := value.(type) {
|
||||||
|
case nil:
|
||||||
|
return ""
|
||||||
|
case string:
|
||||||
|
return strings.TrimSpace(v)
|
||||||
|
case []string:
|
||||||
|
return strings.TrimSpace(strings.Join(v, ","))
|
||||||
|
case []interface{}:
|
||||||
|
out := make([]string, 0, len(v))
|
||||||
|
for _, item := range v {
|
||||||
|
if s := telegramValueString(item); s != "" {
|
||||||
|
out = append(out, s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return strings.Join(out, ",")
|
||||||
|
case float32:
|
||||||
|
return strings.TrimRight(strings.TrimRight(fmt.Sprintf("%.1f", v), "0"), ".")
|
||||||
|
case float64:
|
||||||
|
return strings.TrimRight(strings.TrimRight(fmt.Sprintf("%.1f", v), "0"), ".")
|
||||||
|
default:
|
||||||
|
text := strings.TrimSpace(fmt.Sprint(value))
|
||||||
|
if text == "<nil>" {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return text
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func isTelegramRemotePhotoURL(raw string) bool {
|
||||||
|
raw = strings.TrimSpace(raw)
|
||||||
|
if raw == "" {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
u, err := url.Parse(raw)
|
||||||
|
return err == nil && (u.Scheme == "http" || u.Scheme == "https") && u.Host != ""
|
||||||
|
}
|
||||||
@@ -2,8 +2,6 @@ package service
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/url"
|
|
||||||
"sort"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
@@ -226,165 +224,3 @@ func telegramGenresValue(raw string) string {
|
|||||||
}
|
}
|
||||||
return strings.Join(out, "、")
|
return strings.Join(out, "、")
|
||||||
}
|
}
|
||||||
|
|
||||||
type telegramDataField struct {
|
|
||||||
key string
|
|
||||||
value string
|
|
||||||
}
|
|
||||||
|
|
||||||
func telegramDisplayData(data map[string]interface{}) []telegramDataField {
|
|
||||||
if len(data) == 0 {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
keys := make([]string, 0, len(data))
|
|
||||||
for key := range data {
|
|
||||||
if telegramHiddenDataKey(key) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
keys = append(keys, key)
|
|
||||||
}
|
|
||||||
sort.Strings(keys)
|
|
||||||
fields := make([]telegramDataField, 0, len(keys))
|
|
||||||
for _, key := range keys {
|
|
||||||
value := strings.TrimSpace(fmt.Sprint(data[key]))
|
|
||||||
if value == "" || value == "<nil>" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
fields = append(fields, telegramDataField{key: key, value: value})
|
|
||||||
}
|
|
||||||
return fields
|
|
||||||
}
|
|
||||||
|
|
||||||
func telegramHiddenDataKey(key string) bool {
|
|
||||||
switch strings.ToLower(strings.TrimSpace(key)) {
|
|
||||||
case "photo_url", "poster_url", "poster", "image_url", "backdrop_url",
|
|
||||||
"tmdb_url", "imdb_url", "douban_url", "detail_url", "external_url",
|
|
||||||
"resource_title", "torrent_title", "release_title":
|
|
||||||
return true
|
|
||||||
default:
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func telegramFieldLabel(key string) string {
|
|
||||||
switch strings.ToLower(strings.TrimSpace(key)) {
|
|
||||||
case "title", "name":
|
|
||||||
return "标题"
|
|
||||||
case "original_title":
|
|
||||||
return "原始片名"
|
|
||||||
case "original_language":
|
|
||||||
return "原始语言"
|
|
||||||
case "year", "release_year":
|
|
||||||
return "发行年份"
|
|
||||||
case "save_path":
|
|
||||||
return "保存路径"
|
|
||||||
case "hash":
|
|
||||||
return "Hash"
|
|
||||||
case "media_type":
|
|
||||||
return "媒体类型"
|
|
||||||
case "media_category":
|
|
||||||
return "类别"
|
|
||||||
case "season_episode":
|
|
||||||
return "季集"
|
|
||||||
case "size", "bitrate":
|
|
||||||
return "大小"
|
|
||||||
case "version", "release_group":
|
|
||||||
return "版本"
|
|
||||||
case "rating":
|
|
||||||
return "评分"
|
|
||||||
case "genres":
|
|
||||||
return "类型"
|
|
||||||
case "overview":
|
|
||||||
return "简介"
|
|
||||||
case "subscription":
|
|
||||||
return "订阅"
|
|
||||||
case "queued":
|
|
||||||
return "新增资源"
|
|
||||||
default:
|
|
||||||
return strings.TrimSpace(key)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func telegramExternalLinks(data map[string]interface{}) string {
|
|
||||||
if len(data) == 0 {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
links := []string{}
|
|
||||||
for _, item := range []struct {
|
|
||||||
key string
|
|
||||||
name string
|
|
||||||
}{
|
|
||||||
{key: "tmdb_url", name: "TMDB"},
|
|
||||||
{key: "imdb_url", name: "IMDB"},
|
|
||||||
{key: "douban_url", name: "豆瓣"},
|
|
||||||
} {
|
|
||||||
value := telegramDataString(data, item.key)
|
|
||||||
if isTelegramRemotePhotoURL(value) {
|
|
||||||
links = append(links, fmt.Sprintf(`<a href="%s">%s</a>`, escapeHTML(value), escapeHTML(item.name)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if len(links) == 0 {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
return "🔗 外链:" + strings.Join(links, " / ")
|
|
||||||
}
|
|
||||||
|
|
||||||
func telegramEventPhotoURL(event NotifyEvent) string {
|
|
||||||
for _, key := range []string{"photo_url", "poster_url", "poster", "image_url", "backdrop_url"} {
|
|
||||||
value := telegramDataString(event.Data, key)
|
|
||||||
if isTelegramRemotePhotoURL(value) {
|
|
||||||
return value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func telegramDataString(data map[string]interface{}, key string) string {
|
|
||||||
if len(data) == 0 {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
for k, value := range data {
|
|
||||||
if strings.EqualFold(strings.TrimSpace(k), key) {
|
|
||||||
return telegramValueString(value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func telegramValueString(value interface{}) string {
|
|
||||||
switch v := value.(type) {
|
|
||||||
case nil:
|
|
||||||
return ""
|
|
||||||
case string:
|
|
||||||
return strings.TrimSpace(v)
|
|
||||||
case []string:
|
|
||||||
return strings.TrimSpace(strings.Join(v, ","))
|
|
||||||
case []interface{}:
|
|
||||||
out := make([]string, 0, len(v))
|
|
||||||
for _, item := range v {
|
|
||||||
if s := telegramValueString(item); s != "" {
|
|
||||||
out = append(out, s)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return strings.Join(out, ",")
|
|
||||||
case float32:
|
|
||||||
return strings.TrimRight(strings.TrimRight(fmt.Sprintf("%.1f", v), "0"), ".")
|
|
||||||
case float64:
|
|
||||||
return strings.TrimRight(strings.TrimRight(fmt.Sprintf("%.1f", v), "0"), ".")
|
|
||||||
default:
|
|
||||||
text := strings.TrimSpace(fmt.Sprint(value))
|
|
||||||
if text == "<nil>" {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
return text
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func isTelegramRemotePhotoURL(raw string) bool {
|
|
||||||
raw = strings.TrimSpace(raw)
|
|
||||||
if raw == "" {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
u, err := url.Parse(raw)
|
|
||||||
return err == nil && (u.Scheme == "http" || u.Scheme == "https") && u.Host != ""
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -0,0 +1,123 @@
|
|||||||
|
package service
|
||||||
|
|
||||||
|
import (
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
telegramMediaTemplateHeader = "🐈⬛🐈⬛ MediaStationGo 更新啦 🐈⬛🐈⬛"
|
||||||
|
telegramMediaTemplateSeparator = "--------------------------------"
|
||||||
|
)
|
||||||
|
|
||||||
|
var telegramSeasonEpisodePattern = regexp.MustCompile(`(?i)S\d{1,2}E\d{1,3}(?:[\-.~_ ]?E?\d{1,3})?`)
|
||||||
|
|
||||||
|
func formatTelegramMediaNotification(event NotifyEvent) string {
|
||||||
|
tag := telegramMediaTag(event.Data)
|
||||||
|
if tag == "" {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
title := telegramFirstValue(event.Data, "chinese_title", "title", "name", "media_title")
|
||||||
|
if title == "" {
|
||||||
|
title = telegramMessageFieldValue(event.Message, "任务", "订阅", "媒体", "资源")
|
||||||
|
}
|
||||||
|
originalTitle := telegramFirstValue(event.Data, "original_title", "original_name")
|
||||||
|
originalLanguage := telegramLanguageName(telegramFirstValue(event.Data, "original_language", "language", "languages"))
|
||||||
|
year := telegramFirstValue(event.Data, "year", "release_year")
|
||||||
|
category := telegramMediaCategory(event.Data)
|
||||||
|
seasonEpisode := telegramSeasonEpisodeValue(event)
|
||||||
|
size := telegramSizeValue(event.Data)
|
||||||
|
version := telegramVersionValue(event, seasonEpisode)
|
||||||
|
rating := telegramFirstValue(event.Data, "rating", "score")
|
||||||
|
genres := telegramGenresValue(telegramFirstValue(event.Data, "genres", "genre", "type"))
|
||||||
|
overview := telegramFirstValue(event.Data, "overview", "summary", "description")
|
||||||
|
links := telegramExternalLinks(event.Data)
|
||||||
|
|
||||||
|
topFields := []string{}
|
||||||
|
if title != "" {
|
||||||
|
topFields = append(topFields, "📺 中文片名:"+escapeHTML(title))
|
||||||
|
}
|
||||||
|
if originalTitle != "" && !strings.EqualFold(originalTitle, title) {
|
||||||
|
topFields = append(topFields, "🧿 原始片名:"+escapeHTML(originalTitle))
|
||||||
|
}
|
||||||
|
if originalLanguage != "" {
|
||||||
|
topFields = append(topFields, "🌐 原始语言:"+escapeHTML(originalLanguage))
|
||||||
|
}
|
||||||
|
if year != "" && year != "0" {
|
||||||
|
topFields = append(topFields, "📅 发行年份:"+escapeHTML(year))
|
||||||
|
}
|
||||||
|
|
||||||
|
mediaFields := []string{}
|
||||||
|
if category != "" {
|
||||||
|
mediaFields = append(mediaFields, "🐈⬛ 类别:"+escapeHTML(category))
|
||||||
|
}
|
||||||
|
if seasonEpisode != "" {
|
||||||
|
mediaFields = append(mediaFields, "🫧 季集:"+escapeHTML(seasonEpisode))
|
||||||
|
}
|
||||||
|
if size != "" {
|
||||||
|
mediaFields = append(mediaFields, "🔎 大小:"+escapeHTML(size))
|
||||||
|
}
|
||||||
|
if version != "" {
|
||||||
|
mediaFields = append(mediaFields, "📁 版本:"+escapeHTML(version))
|
||||||
|
}
|
||||||
|
|
||||||
|
infoFields := []string{}
|
||||||
|
if rating != "" && rating != "0" {
|
||||||
|
infoFields = append(infoFields, "⭐️ 评分:"+escapeHTML(rating))
|
||||||
|
}
|
||||||
|
if genres != "" {
|
||||||
|
infoFields = append(infoFields, "💎 类型:"+escapeHTML(genres))
|
||||||
|
}
|
||||||
|
if overview != "" {
|
||||||
|
infoFields = append(infoFields, "🪬 简介:\n"+escapeHTML(overview))
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(topFields) == 0 && len(mediaFields) == 0 && len(infoFields) == 0 && links == "" {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
lines := []string{telegramMediaTemplateHeader, telegramMediaTemplateSeparator, tag}
|
||||||
|
lines = append(lines, topFields...)
|
||||||
|
if len(mediaFields) > 0 {
|
||||||
|
if len(topFields) > 0 {
|
||||||
|
lines = append(lines, "")
|
||||||
|
}
|
||||||
|
lines = append(lines, mediaFields...)
|
||||||
|
}
|
||||||
|
if len(infoFields) > 0 {
|
||||||
|
if len(topFields) > 0 || len(mediaFields) > 0 {
|
||||||
|
lines = append(lines, "")
|
||||||
|
}
|
||||||
|
lines = append(lines, infoFields...)
|
||||||
|
}
|
||||||
|
if links != "" {
|
||||||
|
lines = append(lines, "", telegramMediaTemplateSeparator, links)
|
||||||
|
}
|
||||||
|
return strings.TrimSpace(strings.Join(lines, "\n"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func telegramMediaTag(data map[string]interface{}) string {
|
||||||
|
for _, key := range []string{"media_category", "category", "media_type"} {
|
||||||
|
value := strings.TrimSpace(telegramDataString(data, key))
|
||||||
|
if value == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
lower := strings.ToLower(value)
|
||||||
|
switch {
|
||||||
|
case strings.Contains(value, "电影") || lower == "movie":
|
||||||
|
return "#电影"
|
||||||
|
case strings.Contains(value, "剧") || lower == "tv" || lower == "series" || lower == "show":
|
||||||
|
return "#剧集"
|
||||||
|
case strings.Contains(value, "动漫") || strings.Contains(value, "动画") || lower == "anime":
|
||||||
|
return "#动漫"
|
||||||
|
case strings.Contains(value, "综艺") || lower == "variety":
|
||||||
|
return "#综艺"
|
||||||
|
case strings.Contains(value, "纪录") || lower == "documentary":
|
||||||
|
return "#纪录片"
|
||||||
|
default:
|
||||||
|
return "#" + escapeHTML(strings.ReplaceAll(value, " ", ""))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user