fix: claude hat bugs im Kopf
All checks were successful
Create Release PR / Create Release PR (push) Successful in 10s
All checks were successful
Create Release PR / Create Release PR (push) Successful in 10s
This commit is contained in:
@@ -254,7 +254,12 @@ public class SmartNotifyBackgroundService : IHostedService, IDisposable
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_logger.LogDebug("Processing {Count} pending notifications", pendingNotifications.Count);
|
_logger.LogInformation(
|
||||||
|
"Processing {Count} pending notifications (delay={Delay}min, grouping={Grouping}min, cutoff={Cutoff})",
|
||||||
|
pendingNotifications.Count,
|
||||||
|
delayMinutes,
|
||||||
|
groupingWindowMinutes,
|
||||||
|
cutoff);
|
||||||
|
|
||||||
// Group episodes by series
|
// Group episodes by series
|
||||||
var episodesBySeries = pendingNotifications
|
var episodesBySeries = pendingNotifications
|
||||||
@@ -262,6 +267,17 @@ public class SmartNotifyBackgroundService : IHostedService, IDisposable
|
|||||||
.GroupBy(n => n.SeriesId!)
|
.GroupBy(n => n.SeriesId!)
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
|
// Log unmatched notifications (neither episode with series nor movie)
|
||||||
|
var unmatchedCount = pendingNotifications.Count
|
||||||
|
- pendingNotifications.Count(n => n.ItemType == "Episode" && !string.IsNullOrEmpty(n.SeriesId))
|
||||||
|
- pendingNotifications.Count(n => n.ItemType == "Movie");
|
||||||
|
if (unmatchedCount > 0)
|
||||||
|
{
|
||||||
|
_logger.LogWarning(
|
||||||
|
"{Count} notifications are neither episodes (with SeriesId) nor movies and will be skipped",
|
||||||
|
unmatchedCount);
|
||||||
|
}
|
||||||
|
|
||||||
// Process each series group
|
// Process each series group
|
||||||
foreach (var seriesGroup in episodesBySeries)
|
foreach (var seriesGroup in episodesBySeries)
|
||||||
{
|
{
|
||||||
@@ -271,19 +287,34 @@ public class SmartNotifyBackgroundService : IHostedService, IDisposable
|
|||||||
// Only process if the oldest notification is outside the grouping window
|
// Only process if the oldest notification is outside the grouping window
|
||||||
if (oldestInGroup > groupingCutoff)
|
if (oldestInGroup > groupingCutoff)
|
||||||
{
|
{
|
||||||
_logger.LogDebug(
|
_logger.LogInformation(
|
||||||
"Waiting for grouping window for series {SeriesId}, oldest: {Oldest}",
|
"Waiting for grouping window for series {SeriesName} ({SeriesId}), oldest queued: {Oldest}, grouping cutoff: {Cutoff}",
|
||||||
|
seriesGroup.First().SeriesName,
|
||||||
seriesGroup.Key,
|
seriesGroup.Key,
|
||||||
oldestInGroup);
|
oldestInGroup,
|
||||||
|
groupingCutoff);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
await _discordService.SendGroupedEpisodeNotificationAsync(
|
_logger.LogInformation(
|
||||||
|
"Sending grouped notification for {SeriesName}: {Count} episodes",
|
||||||
|
seriesGroup.First().SeriesName,
|
||||||
|
seriesGroup.Count());
|
||||||
|
|
||||||
|
var success = await _discordService.SendGroupedEpisodeNotificationAsync(
|
||||||
seriesGroup,
|
seriesGroup,
|
||||||
CancellationToken.None);
|
CancellationToken.None);
|
||||||
|
|
||||||
|
if (success)
|
||||||
|
{
|
||||||
var idsToRemove = seriesGroup.Select(n => n.Id).ToList();
|
var idsToRemove = seriesGroup.Select(n => n.Id).ToList();
|
||||||
_historyService.RemoveNotifications(idsToRemove);
|
_historyService.RemoveNotifications(idsToRemove);
|
||||||
|
_logger.LogInformation("Removed {Count} processed episode notifications from queue", idsToRemove.Count);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_logger.LogWarning("Discord send failed for {SeriesName}, keeping notifications in queue for retry", seriesGroup.First().SeriesName);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Process movies
|
// Process movies
|
||||||
@@ -293,8 +324,19 @@ public class SmartNotifyBackgroundService : IHostedService, IDisposable
|
|||||||
|
|
||||||
foreach (var movie in movies)
|
foreach (var movie in movies)
|
||||||
{
|
{
|
||||||
await _discordService.SendMovieNotificationAsync(movie, CancellationToken.None);
|
_logger.LogInformation("Sending movie notification for: {Name}", movie.Name);
|
||||||
|
|
||||||
|
var success = await _discordService.SendMovieNotificationAsync(movie, CancellationToken.None);
|
||||||
|
|
||||||
|
if (success)
|
||||||
|
{
|
||||||
_historyService.RemoveNotifications(new[] { movie.Id });
|
_historyService.RemoveNotifications(new[] { movie.Id });
|
||||||
|
_logger.LogInformation("Removed processed movie notification from queue: {Name}", movie.Name);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_logger.LogWarning("Discord send failed for movie {Name}, keeping in queue for retry", movie.Name);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
|
|||||||
@@ -38,8 +38,8 @@ public class DiscordNotificationService
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="notifications">The notifications to group and send.</param>
|
/// <param name="notifications">The notifications to group and send.</param>
|
||||||
/// <param name="cancellationToken">The cancellation token.</param>
|
/// <param name="cancellationToken">The cancellation token.</param>
|
||||||
/// <returns>A task representing the async operation.</returns>
|
/// <returns>True if the notification was sent successfully.</returns>
|
||||||
public async Task SendGroupedEpisodeNotificationAsync(
|
public async Task<bool> SendGroupedEpisodeNotificationAsync(
|
||||||
IEnumerable<PendingNotification> notifications,
|
IEnumerable<PendingNotification> notifications,
|
||||||
CancellationToken cancellationToken)
|
CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
@@ -47,13 +47,13 @@ public class DiscordNotificationService
|
|||||||
if (config == null || string.IsNullOrEmpty(config.DiscordWebhookUrl))
|
if (config == null || string.IsNullOrEmpty(config.DiscordWebhookUrl))
|
||||||
{
|
{
|
||||||
_logger.LogWarning("Discord webhook URL not configured");
|
_logger.LogWarning("Discord webhook URL not configured");
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
var notificationList = notifications.ToList();
|
var notificationList = notifications.ToList();
|
||||||
if (notificationList.Count == 0)
|
if (notificationList.Count == 0)
|
||||||
{
|
{
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
var first = notificationList.First();
|
var first = notificationList.First();
|
||||||
@@ -70,7 +70,7 @@ public class DiscordNotificationService
|
|||||||
var title = $"📺 {seriesName}";
|
var title = $"📺 {seriesName}";
|
||||||
var description = $"Neue Episoden hinzugefügt:\n{episodeDescription}";
|
var description = $"Neue Episoden hinzugefügt:\n{episodeDescription}";
|
||||||
|
|
||||||
await SendDiscordWebhookAsync(
|
return await SendDiscordWebhookAsync(
|
||||||
config,
|
config,
|
||||||
title,
|
title,
|
||||||
description,
|
description,
|
||||||
@@ -153,7 +153,8 @@ public class DiscordNotificationService
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="notification">The notification.</param>
|
/// <param name="notification">The notification.</param>
|
||||||
/// <param name="cancellationToken">The cancellation token.</param>
|
/// <param name="cancellationToken">The cancellation token.</param>
|
||||||
public async Task SendMovieNotificationAsync(
|
/// <returns>True if the notification was sent successfully.</returns>
|
||||||
|
public async Task<bool> SendMovieNotificationAsync(
|
||||||
PendingNotification notification,
|
PendingNotification notification,
|
||||||
CancellationToken cancellationToken)
|
CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
@@ -161,7 +162,7 @@ public class DiscordNotificationService
|
|||||||
if (config == null || string.IsNullOrEmpty(config.DiscordWebhookUrl))
|
if (config == null || string.IsNullOrEmpty(config.DiscordWebhookUrl))
|
||||||
{
|
{
|
||||||
_logger.LogWarning("Discord webhook URL not configured");
|
_logger.LogWarning("Discord webhook URL not configured");
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
var title = $"🎬 {notification.Name}";
|
var title = $"🎬 {notification.Name}";
|
||||||
@@ -176,7 +177,7 @@ public class DiscordNotificationService
|
|||||||
description = description.Substring(0, 297) + "...";
|
description = description.Substring(0, 297) + "...";
|
||||||
}
|
}
|
||||||
|
|
||||||
await SendDiscordWebhookAsync(
|
return await SendDiscordWebhookAsync(
|
||||||
config,
|
config,
|
||||||
title,
|
title,
|
||||||
description,
|
description,
|
||||||
@@ -236,7 +237,8 @@ public class DiscordNotificationService
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sends the actual Discord webhook request, with optional image attachment.
|
/// Sends the actual Discord webhook request, with optional image attachment.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private async Task SendDiscordWebhookAsync(
|
/// <returns>True if the webhook was sent successfully.</returns>
|
||||||
|
private async Task<bool> SendDiscordWebhookAsync(
|
||||||
PluginConfiguration config,
|
PluginConfiguration config,
|
||||||
string title,
|
string title,
|
||||||
string description,
|
string description,
|
||||||
@@ -260,7 +262,16 @@ public class DiscordNotificationService
|
|||||||
|
|
||||||
if (!string.IsNullOrEmpty(externalLinks))
|
if (!string.IsNullOrEmpty(externalLinks))
|
||||||
{
|
{
|
||||||
embed["footer"] = new Dictionary<string, string> { ["text"] = externalLinks };
|
var fields = new List<Dictionary<string, object>>
|
||||||
|
{
|
||||||
|
new Dictionary<string, object>
|
||||||
|
{
|
||||||
|
["name"] = "Links",
|
||||||
|
["value"] = externalLinks,
|
||||||
|
["inline"] = false
|
||||||
|
}
|
||||||
|
};
|
||||||
|
embed["fields"] = fields;
|
||||||
}
|
}
|
||||||
|
|
||||||
embed["timestamp"] = DateTime.UtcNow.ToString("o");
|
embed["timestamp"] = DateTime.UtcNow.ToString("o");
|
||||||
@@ -272,7 +283,7 @@ public class DiscordNotificationService
|
|||||||
};
|
};
|
||||||
|
|
||||||
var json = JsonSerializer.Serialize(payload);
|
var json = JsonSerializer.Serialize(payload);
|
||||||
_logger.LogDebug("Sending Discord webhook: {Json}", json);
|
_logger.LogInformation("Sending Discord webhook for: {Title}", title);
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -281,6 +292,7 @@ public class DiscordNotificationService
|
|||||||
|
|
||||||
if (hasImage)
|
if (hasImage)
|
||||||
{
|
{
|
||||||
|
_logger.LogInformation("Attaching image from: {Path}", imagePath);
|
||||||
// Send as multipart/form-data with image attachment
|
// Send as multipart/form-data with image attachment
|
||||||
using var form = new MultipartFormDataContent();
|
using var form = new MultipartFormDataContent();
|
||||||
form.Add(new StringContent(json, Encoding.UTF8, "application/json"), "payload_json");
|
form.Add(new StringContent(json, Encoding.UTF8, "application/json"), "payload_json");
|
||||||
@@ -306,15 +318,16 @@ public class DiscordNotificationService
|
|||||||
"Discord webhook failed with status {Status}: {Body}",
|
"Discord webhook failed with status {Status}: {Body}",
|
||||||
response.StatusCode,
|
response.StatusCode,
|
||||||
responseBody);
|
responseBody);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
_logger.LogInformation("Discord notification sent successfully: {Title}", title);
|
_logger.LogInformation("Discord notification sent successfully: {Title}", title);
|
||||||
}
|
return true;
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
_logger.LogError(ex, "Failed to send Discord webhook");
|
_logger.LogError(ex, "Failed to send Discord webhook");
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user