public async Task PostAsync(TestNotification request) { DiscordOptions options = GetOptions(request.UserID); string footerText; if (options.ServerNameOverride) { footerText = $"From {_serverConfiguration.Configuration.ServerName}"; } else { footerText = "From Emby Server"; } DiscordMessage discordMessage = new DiscordMessage() { avatar_url = options.AvatarUrl, username = options.Username, embeds = new List <DiscordEmbed>() { new DiscordEmbed() { color = int.Parse(options.EmbedColor.Substring(1, 6), System.Globalization.NumberStyles.HexNumber), description = "This is a test notification from Emby", title = "It worked!", footer = new Footer { icon_url = options.AvatarUrl, text = footerText }, timestamp = DateTime.Now } } }; switch (options.MentionType) { case MentionTypes.Everyone: discordMessage.content = "@everyone"; break; case MentionTypes.Here: discordMessage.content = "@here"; break; } try { await DiscordWebhookHelper.ExecuteWebhook(discordMessage, options.DiscordWebhookURI, _jsonSerializer); } catch (System.Exception e) { _logger.ErrorException("Failed to execute webhook", e); throw new ArgumentException(); } }
/// <inheritdoc /> public Task SendNotification(UserNotification request, CancellationToken cancellationToken) { var options = GetOptions(request.User); if ((!options.MediaAddedOverride || request.Name.Contains(_localizationManager.GetLocalizedString("ValueHasBeenAddedToLibrary").Replace("{0} ", string.Empty, StringComparison.OrdinalIgnoreCase).Replace(" {1}", string.Empty, StringComparison.OrdinalIgnoreCase), StringComparison.OrdinalIgnoreCase)) && options.MediaAddedOverride) { return(Task.CompletedTask); } var serverName = _serverConfiguration.Configuration.ServerName; string footerText; string requestName; if (options.ServerNameOverride) { footerText = $"From {serverName}"; requestName = request.Name.Replace("Jellyfin Server", serverName, StringComparison.OrdinalIgnoreCase); } else { requestName = request.Name; footerText = "From Jellyfin Server"; } var discordMessage = new DiscordMessage(); discordMessage.AvatarUrl = options.AvatarUrl; discordMessage.Username = options.Username; discordMessage.Embeds.Add( new DiscordEmbed { Color = DiscordWebhookHelper.FormatColorCode(options.EmbedColor), Title = requestName, Description = request.Description, Footer = new Footer { IconUrl = options.AvatarUrl, Text = footerText }, Timestamp = DateTime.Now }); discordMessage.Content = options.MentionType switch { MentionType.Everyone => "@everyone", MentionType.Here => "@here", _ => string.Empty }; _pendingSendQueue.Add(discordMessage, options); return(Task.CompletedTask); }
/// <summary> /// Post test notification async. /// </summary> /// <param name="request">The test notification request.</param> /// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns> public async Task PostAsync(TestNotification request) { var options = GetOptions(request.UserId); var footerText = options.ServerNameOverride ? $"From {_serverConfiguration.Configuration.ServerName}" : "From Jellyfin Server"; var discordMessage = new DiscordMessage(); discordMessage.AvatarUrl = options.AvatarUrl; discordMessage.Username = options.Username; discordMessage.Embeds.Add( new DiscordEmbed { Color = int.Parse(options.EmbedColor.Substring(1, 6), NumberStyles.HexNumber, CultureInfo.InvariantCulture), Description = "This is a test notification from Jellyfin", Title = "It worked!", Footer = new Footer { IconUrl = options.AvatarUrl, Text = footerText }, Timestamp = DateTime.Now }); discordMessage.Content = options.MentionType switch { MentionType.Everyone => "@everyone", MentionType.Here => "@here", _ => string.Empty }; try { await DiscordWebhookHelper.ExecuteWebhook(_httpClient, _logger, discordMessage, options.DiscordWebhookUri, _jsonSerializerOptions) .ConfigureAwait(false); } catch (Exception e) { _logger.LogError(e, "Failed to execute webhook", e); throw; } } }
private async void QueuedMessageSender(object sender, ElapsedEventArgs eventArgs) { try { if (_pendingSendQueue.Count > 0) { var message = _pendingSendQueue.First().Key; var options = _pendingSendQueue.First().Value; await DiscordWebhookHelper.ExecuteWebhook(_httpClient, _logger, message, options.DiscordWebhookUri, _jsonSerializerOptions).ConfigureAwait(false); if (_pendingSendQueue.ContainsKey(message)) { _pendingSendQueue.Remove(message); } } } catch (Exception e) { _logger.LogError(e, "Failed to execute webhook"); } }
private void CheckForMetadata(object sender, ElapsedEventArgs eventArgs) { try { var queueCount = _queuedUpdateCheck.Count; if (queueCount > 0) { _logger.LogDebug("Item in queue : {0}", queueCount); } _queuedUpdateCheck.ToList().ForEach(queuedItem => { // sometimes an update check might execute while another one is hanging and causes crash ! if (_queuedUpdateCheck.ContainsKey(queuedItem.Key)) { var options = queuedItem.Value.Configuration; var itemId = queuedItem.Value.ItemId; _logger.LogDebug("{0} queued for recheck", itemId.ToString()); var item = _libraryManager.GetItemById(itemId); var itemLibraryOptions = _libraryManager.GetLibraryOptions(item); // var sysInfo = await _applicationHost.GetPublicSystemInfo(CancellationToken.None); var serverConfig = _serverConfiguration.Configuration; var libraryType = item.GetType().Name; var serverName = options.ServerNameOverride ? serverConfig.ServerName : "Jellyfin Server"; serverName ??= "Jellyfin Server"; // for whatever reason if you have extraction on during library scans then it waits for the extraction to finish before populating the metadata.... I don't get why the f**k it goes in that order // its basically impossible to make a prediction on how long it could take as its dependent on the bitrate, duration, codec, and processing power of the system var localMetadataFallback = _queuedUpdateCheck[queuedItem.Key].Retries >= (itemLibraryOptions.ExtractChapterImagesDuringLibraryScan ? Constants.MaxRetriesBeforeFallback * 5.5 : Constants.MaxRetriesBeforeFallback); if (item.ProviderIds.Count > 0 || localMetadataFallback) { _logger.LogDebug("{0}[{1}] has metadata (Local fallback: {2}), adding to queue", item.Id, item.Name, localMetadataFallback, options.UserId); if (_queuedUpdateCheck.ContainsKey(queuedItem.Key)) { // remove it beforehand because if some operation takes any longer amount of time it might allow enough time for another notification to slip through _queuedUpdateCheck.Remove(queuedItem.Key); } // build primary info var mediaAddedEmbed = new DiscordMessage(); mediaAddedEmbed.Username = options.Username; mediaAddedEmbed.AvatarUrl = options.AvatarUrl; mediaAddedEmbed.Embeds.Add( new DiscordEmbed { Color = DiscordWebhookHelper.FormatColorCode(options.EmbedColor), Footer = new Footer { Text = $"From {serverName}", IconUrl = options.AvatarUrl }, Timestamp = DateTime.Now }); // populate title string titleText; if (libraryType == "Episode") { titleText = $"{item.Parent.Parent.Name}{(item.ParentIndexNumber.HasValue ? $" S{item.ParentIndexNumber:00}" : string.Empty)}{(item.IndexNumber.HasValue ? $"E{item.IndexNumber:00}" : string.Empty)} {item.Name}"; } else if (libraryType == "Season") { titleText = $"{item.Parent.Name} {item.Name}"; } else { titleText = $"{item.Name}{(item.ProductionYear.HasValue ? $" ({item.ProductionYear.ToString()})" : string.Empty)}"; } mediaAddedEmbed.Embeds[0].Title = $"{titleText} has been added to {serverName.Trim()}"; // populate description if (libraryType == "Audio") { var artists = _libraryManager.GetAllArtists(new InternalItemsQuery { ItemIds = new[] { itemId } }); var artistsFormat = artists.Items.Select(baseItem => { var artist = baseItem.Item1; var formattedArtist = artist.Name; if (artist.ProviderIds.Count != 0) { var(key, value) = artist.ProviderIds.FirstOrDefault(); var providerUrl = key == "MusicBrainzArtist" ? $"https://musicbrainz.org/artist/{value}" : $"https://theaudiodb.com/artist/{value}"; formattedArtist += $" [(Music Brainz)]({providerUrl})"; } if (serverConfig.EnableRemoteAccess && !options.ExcludeExternalServerLinks) { formattedArtist += $" [(Jellyfin)]({options.ServerUrl}/web/index.html#!/details?id={itemId}&serverId={_applicationHost.SystemId})"; } return(formattedArtist); }); if (artists.Items.Count != 0) { mediaAddedEmbed.Embeds[0].Description = $"By {string.Join(", ", artistsFormat)}"; } } else { if (!string.IsNullOrEmpty(item.Overview)) { mediaAddedEmbed.Embeds[0].Description = item.Overview; } } // populate title URL if (serverConfig.EnableRemoteAccess && !options.ExcludeExternalServerLinks) { mediaAddedEmbed.Embeds[0].Url = $"{options.ServerUrl}/web/index.html#!/details?id={itemId}&serverId={_applicationHost.SystemId}"; } // populate images if (item.HasImage(ImageType.Primary)) { var imageUrl = string.Empty; if (!item.GetImageInfo(ImageType.Primary, 0).IsLocalFile) { imageUrl = item.GetImagePath(ImageType.Primary); } else if (serverConfig.EnableRemoteAccess && !options.ExcludeExternalServerLinks) // in the future we can proxy images through memester server if people want to hide their server address { imageUrl = $"{options.ServerUrl}/Items/{itemId}/Images/Primary"; } else { var localPath = item.GetImagePath(ImageType.Primary); try { var response = MemesterServiceHelper.UploadImage(localPath); imageUrl = response.FilePath; } catch (Exception e) { _logger.LogError(e, "Failed to proxy image"); } } mediaAddedEmbed.Embeds[0].Thumbnail = new Thumbnail { Url = imageUrl }; } mediaAddedEmbed.Content = options.MentionType switch { MentionType.Everyone => "@everyone", MentionType.Here => "@here", _ => string.Empty }; // populate external URLs var providerFields = new List <Field>(); if (!localMetadataFallback) { item.ProviderIds.ToList().ForEach(provider => { var field = new Field { Name = "External Links" }; var didPopulate = true; switch (provider.Key.ToLower(CultureInfo.InvariantCulture)) { case "imdb": field.Value = $"[IMDb](https://www.imdb.com/title/{provider.Value}/)"; break; case "tmdb": field.Value = $"[TMDb](https://www.themoviedb.org/{(libraryType == "Movie" ? "movie" : "tv")}/{provider.Value})"; break; case "musicbrainztrack": field.Value = $"[MusicBrainz Track](https://musicbrainz.org/track/{provider.Value})"; break; case "musicbrainzalbum": field.Value = $"[MusicBrainz Album](https://musicbrainz.org/release/{provider.Value})"; break; case "theaudiodbalbum": field.Value = $"[TADb Album](https://theaudiodb.com/album/{provider.Value})"; break; default: didPopulate = false; break; } if (didPopulate) { providerFields.Add(field); } }); if (providerFields.Count > 0) { mediaAddedEmbed.Embeds[0].Fields.AddRange(providerFields); } } _pendingSendQueue.Add(mediaAddedEmbed, options); } else { if (_queuedUpdateCheck.ContainsKey(queuedItem.Key)) { _queuedUpdateCheck[queuedItem.Key].Retries++; } } } }); } catch (Exception e) { _logger.LogError(e, "Something unexpected happened in the item update checker"); } }