diff --git a/internal/service/notify_telegram.go b/internal/service/notify_telegram.go index 764a842..933da6a 100644 --- a/internal/service/notify_telegram.go +++ b/internal/service/notify_telegram.go @@ -4,7 +4,6 @@ package service import ( "context" "fmt" - "regexp" "strings" "time" "unicode/utf8" @@ -140,289 +139,3 @@ func formatTelegramNotification(event NotifyEvent) 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 %s", 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 %s:", 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 = "" + escapedValue + "" - } - return fmt.Sprintf("%s %s:%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 "•" - } -} diff --git a/internal/service/notify_telegram_body.go b/internal/service/notify_telegram_body.go new file mode 100644 index 0000000..3945438 --- /dev/null +++ b/internal/service/notify_telegram_body.go @@ -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 %s", 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 %s:", 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 = "" + escapedValue + "" + } + return fmt.Sprintf("%s %s:%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 "•" + } +} diff --git a/internal/service/notify_telegram_data.go b/internal/service/notify_telegram_data.go new file mode 100644 index 0000000..adf432c --- /dev/null +++ b/internal/service/notify_telegram_data.go @@ -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 == "" { + 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(`%s`, 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 == "" { + 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 != "" +} diff --git a/internal/service/notify_telegram_fields.go b/internal/service/notify_telegram_fields.go index 43a760d..c7da82c 100644 --- a/internal/service/notify_telegram_fields.go +++ b/internal/service/notify_telegram_fields.go @@ -2,8 +2,6 @@ package service import ( "fmt" - "net/url" - "sort" "strconv" "strings" ) @@ -226,165 +224,3 @@ func telegramGenresValue(raw string) string { } 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 == "" { - 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(`%s`, 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 == "" { - 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 != "" -} diff --git a/internal/service/notify_telegram_media.go b/internal/service/notify_telegram_media.go new file mode 100644 index 0000000..a0be82e --- /dev/null +++ b/internal/service/notify_telegram_media.go @@ -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 "" +}