diff --git a/BetterGenshinImpact/Service/Notifier/TelegramNotifier.cs b/BetterGenshinImpact/Service/Notifier/TelegramNotifier.cs
index a014e420..b9d7b370 100644
--- a/BetterGenshinImpact/Service/Notifier/TelegramNotifier.cs
+++ b/BetterGenshinImpact/Service/Notifier/TelegramNotifier.cs
@@ -1,4 +1,5 @@
using System;
+using System.IO;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
@@ -7,69 +8,21 @@ using System.Threading.Tasks;
using BetterGenshinImpact.Service.Notification.Model;
using BetterGenshinImpact.Service.Notifier.Exception;
using BetterGenshinImpact.Service.Notifier.Interface;
+using SixLabors.ImageSharp;
+using SixLabors.ImageSharp.PixelFormats;
namespace BetterGenshinImpact.Service.Notifier;
public class TelegramNotifier : INotifier, IDisposable
{
// 默认Telegram API的标准URL前缀
- private const string DEFAULT_TELEGRAM_API_URL = "https://api.telegram.org/bot";
- private readonly bool _createdHttpClient;
+ private const string DefaultApiUrl = "https://api.telegram.org/bot";
+
+ private static readonly JsonSerializerOptions JsonOptions = new()
+ { PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower };
+
private readonly HttpClient _httpClient;
-
- private readonly JsonSerializerOptions _jsonSerializerOptions = new()
- {
- PropertyNamingPolicy = JsonNamingPolicy.SnakeCaseLower
- };
-
- ///
- /// 创建一个新的Telegram通知器实例
- ///
- /// 可选的HttpClient,如果不提供则创建新的
- /// Telegram机器人Token
- /// Telegram聊天ID
- /// 自定义Telegram API基础URL(可以只填写域名,如"xxx.xxx.xxx"),为空则使用默认URL
- public TelegramNotifier(HttpClient httpClient = null, string telegramBotToken = "", string telegramChatId = "",
- string telegramApiBaseUrl = "")
- {
- TelegramBotToken = telegramBotToken;
- TelegramChatId = telegramChatId;
-
- if (httpClient != null)
- {
- _httpClient = httpClient;
- _createdHttpClient = false;
- }
- else
- {
- _httpClient = new HttpClient();
- _createdHttpClient = true;
- _httpClient.Timeout = TimeSpan.FromSeconds(30);
- }
-
- // 使用自定义API URL,如果为空则使用默认Telegram API URL
- if (string.IsNullOrEmpty(telegramApiBaseUrl))
- {
- TelegramApiBaseUrl = DEFAULT_TELEGRAM_API_URL;
- }
- else
- {
- // 格式化用户提供的API URL
- var formattedUrl = telegramApiBaseUrl.Trim();
-
- // 添加协议前缀(如果没有)
- if (!formattedUrl.StartsWith("http://") && !formattedUrl.StartsWith("https://"))
- formattedUrl = "https://" + formattedUrl;
-
- // 确保URL以斜杠结尾
- if (!formattedUrl.EndsWith("/")) formattedUrl += "/";
-
- // 添加bot路径(如果需要)
- if (!formattedUrl.EndsWith("/bot")) formattedUrl += "bot";
-
- TelegramApiBaseUrl = formattedUrl;
- }
- }
+ private readonly bool _ownsHttpClient;
///
/// Telegram机器人Token
@@ -86,44 +39,48 @@ public class TelegramNotifier : INotifier, IDisposable
///
public string TelegramApiBaseUrl { get; set; }
- public void Dispose()
- {
- if (_createdHttpClient)
- {
- _httpClient?.Dispose();
- }
- }
-
///
/// 通知器名称
///
public string Name { get; set; } = "Telegram";
+ ///
+ /// 创建一个新的Telegram通知器实例
+ ///
+ /// 可选的HttpClient,如果不提供则创建新的
+ /// Telegram机器人Token
+ /// Telegram聊天ID
+ /// 自定义Telegram API基础URL(可以只填写域名,如"xxx.xxx.xxx"),为空则使用默认URL
+ public TelegramNotifier(HttpClient? httpClient = null, string telegramBotToken = "", string telegramChatId = "",
+ string telegramApiBaseUrl = "")
+ {
+ TelegramBotToken = telegramBotToken;
+ TelegramChatId = telegramChatId;
+ _httpClient = httpClient ?? new HttpClient { Timeout = TimeSpan.FromSeconds(30) };
+ _ownsHttpClient = httpClient == null;
+ TelegramApiBaseUrl = FormatApiBaseUrl(telegramApiBaseUrl);
+ }
+
+ public void Dispose()
+ {
+ if (_ownsHttpClient) _httpClient.Dispose();
+ }
+
public async Task SendAsync(BaseNotificationData content)
{
- if (string.IsNullOrEmpty(TelegramBotToken))
- {
- throw new NotifierException("Telegram bot token is not set");
- }
-
- if (string.IsNullOrEmpty(TelegramChatId))
- {
- throw new NotifierException("Telegram chat ID is not set");
- }
+ if (string.IsNullOrEmpty(TelegramBotToken)) throw new NotifierException("Telegram bot token is not set");
+ if (string.IsNullOrEmpty(TelegramChatId)) throw new NotifierException("Telegram chat ID is not set");
+ if (string.IsNullOrEmpty(content.Message)) throw new NotifierException("No message content to send");
try
{
- var message = content.Message;
- var fullMessage = !string.IsNullOrEmpty(message) ? message : "";
+ if (content.Screenshot != null)
+ {
+ await SendImageMessageAsync(content.Screenshot, content.Message.Length < 1024 ? content.Message : null);
+ if (content.Message.Length < 1024) return;
+ }
- if (!string.IsNullOrEmpty(fullMessage))
- {
- await SendTextMessageAsync(fullMessage);
- }
- else
- {
- throw new NotifierException("No message content to send");
- }
+ await SendTextMessageAsync(content.Message);
}
catch (HttpRequestException ex)
{
@@ -133,110 +90,93 @@ public class TelegramNotifier : INotifier, IDisposable
{
throw new NotifierException("Telegram API request timed out. Check your internet connection.");
}
- catch (NotifierException)
- {
- throw;
- }
- catch (System.Exception ex)
+ catch (System.Exception ex) when (ex is not NotifierException)
{
throw new NotifierException("Error sending Telegram notification: " + ex.Message);
}
}
+ private async Task SendImageMessageAsync(Image image, string? caption)
+ {
+ var endpoint = $"{TelegramApiBaseUrl}{TelegramBotToken}/sendPhoto";
+ using var memoryStream = new MemoryStream();
+ await image.SaveAsPngAsync(memoryStream);
+ memoryStream.Position = 0;
+
+ var content = new MultipartFormDataContent
+ {
+ { new StreamContent(memoryStream), "photo", "image.png" },
+ { new StringContent(TelegramChatId), "chat_id" }
+ };
+ if (!string.IsNullOrEmpty(caption)) content.Add(new StringContent(caption), "caption");
+
+ await SendRequestAsync(endpoint, content, "image");
+ }
+
private async Task SendTextMessageAsync(string message)
{
- // 构建Telegram API URL - 使用自定义或默认API基础URL
var endpoint = $"{TelegramApiBaseUrl}{TelegramBotToken}/sendMessage";
-
- try
+ var json = JsonSerializer.Serialize(new
{
- var jsonContent = new
- {
- chat_id = TelegramChatId,
- text = message,
- disable_web_page_preview = true
- };
+ chat_id = TelegramChatId,
+ text = message,
+ disable_web_page_preview = true
+ }, JsonOptions);
- var json = JsonSerializer.Serialize(jsonContent, _jsonSerializerOptions);
- var content = new StringContent(json, Encoding.UTF8, "application/json");
+ var content = new StringContent(json, Encoding.UTF8, "application/json");
+ await SendRequestAsync(endpoint, content, "text");
+ }
- var request = new HttpRequestMessage(HttpMethod.Post, endpoint)
- {
- Content = content
- };
+ private async Task SendRequestAsync(string endpoint, HttpContent content, string type)
+ {
+ var request = new HttpRequestMessage(HttpMethod.Post, endpoint) { Content = content };
+ request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
+ request.Headers.UserAgent.Add(new ProductInfoHeaderValue("BetterGenshinImpact", "1.0"));
- request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
- request.Headers.UserAgent.Add(new ProductInfoHeaderValue("BetterGenshinImpact", "1.0"));
+ var response = await _httpClient.SendAsync(request);
+ var responseContent = await response.Content.ReadAsStringAsync();
- var response = await _httpClient.SendAsync(request);
- var responseContent = await response.Content.ReadAsStringAsync();
+ if (!response.IsSuccessStatusCode)
+ throw new NotifierException($"Telegram {type} message failed: {response.StatusCode}, {responseContent}");
- if (!response.IsSuccessStatusCode)
- {
- throw new NotifierException(
- $"Telegram message failed with code: {response.StatusCode}, Error: {responseContent}");
- }
-
- // Check for API errors in the response
- var (isSuccess, errorCode, errorDescription) = ValidateApiResponse(responseContent);
-
- if (!isSuccess)
- {
- if (errorCode == 400)
- {
- throw new NotifierException(
- "Please send a message to the bot first and check that the chat ID is correct.");
- }
-
- if (errorCode == 401)
- {
- throw new NotifierException("Telegram bot token is incorrect.");
- }
-
- if (errorCode == 404)
- throw new NotifierException(
- $"Telegram API not found (404). Please verify your bot token is correct. URL: {endpoint}");
-
- throw new NotifierException($"Telegram API error: {errorDescription} (Code: {errorCode})");
- }
- }
- catch (System.Exception ex) when (!(ex is NotifierException))
+ var (isSuccess, errorCode, errorDescription) = ValidateApiResponse(responseContent);
+ if (!isSuccess)
{
- throw new NotifierException("Error sending Telegram notification: " + ex.Message);
+ var msg = errorCode switch
+ {
+ 400 => "Please send a message to the bot first and check that the chat ID is correct.",
+ 401 => "Telegram bot token is incorrect.",
+ 404 => $"Telegram API not found (404). Please verify your bot token is correct. URL: {endpoint}",
+ _ => $"Telegram API error: {errorDescription} (Code: {errorCode})"
+ };
+ throw new NotifierException(msg);
}
}
- private (bool isSuccess, int errorCode, string errorDescription) ValidateApiResponse(string responseJson)
+ private static string FormatApiBaseUrl(string apiBaseUrl)
+ {
+ if (string.IsNullOrEmpty(apiBaseUrl)) return DefaultApiUrl;
+ var url = apiBaseUrl.Trim();
+ if (!url.StartsWith("http://") && !url.StartsWith("https://")) url = "https://" + url;
+ if (!url.EndsWith("/")) url += "/";
+ if (!url.EndsWith("/bot")) url += "bot";
+ return url;
+ }
+
+ private static (bool isSuccess, int errorCode, string errorDescription) ValidateApiResponse(string responseJson)
{
try
{
- using (var doc = JsonDocument.Parse(responseJson))
- {
- var root = doc.RootElement;
+ using var doc = JsonDocument.Parse(responseJson);
+ var root = doc.RootElement;
+ if (root.TryGetProperty("ok", out var okElement) && okElement.GetBoolean())
+ return (true, 0, string.Empty);
- // Telegram API returns "ok": true for success
- if (root.TryGetProperty("ok", out var okElement))
- {
- var isOk = okElement.GetBoolean();
-
- if (!isOk)
- {
- var errorDescription = "Unknown Telegram API error";
- if (root.TryGetProperty("description", out var descriptionElement))
- errorDescription = descriptionElement.GetString();
-
- var errorCode = 0;
- if (root.TryGetProperty("error_code", out var errorCodeElement))
- errorCode = errorCodeElement.GetInt32();
-
- return (false, errorCode, errorDescription);
- }
-
- return (true, 0, string.Empty);
- }
-
- return (false, 0, "Invalid API response: 'ok' field missing");
- }
+ var errorDescription = root.TryGetProperty("description", out var desc)
+ ? desc.GetString()
+ : "Unknown Telegram API error";
+ var errorCode = root.TryGetProperty("error_code", out var code) ? code.GetInt32() : 0;
+ return (false, errorCode, errorDescription ?? "");
}
catch (JsonException ex)
{