From 5dc3874ebdeac26d7be885b9a44ca1321b4b25cf Mon Sep 17 00:00:00 2001 From: Bond_009 Date: Fri, 20 Dec 2019 21:30:51 +0100 Subject: Enable nullable reference types for Emby.Photos and Emby.Notifications * Enable TreatWarningsAsErrors for Emby.Notifications * Add analyzers to Emby.Notifications --- Emby.Notifications/Api/NotificationsService.cs | 115 +------- Emby.Notifications/CoreNotificationTypes.cs | 4 +- Emby.Notifications/Emby.Notifications.csproj | 14 + .../NotificationConfigurationFactory.cs | 5 +- Emby.Notifications/NotificationEntryPoint.cs | 326 +++++++++++++++++++++ Emby.Notifications/NotificationManager.cs | 39 ++- Emby.Notifications/Notifications.cs | 291 ------------------ 7 files changed, 386 insertions(+), 408 deletions(-) create mode 100644 Emby.Notifications/NotificationEntryPoint.cs delete mode 100644 Emby.Notifications/Notifications.cs (limited to 'Emby.Notifications') diff --git a/Emby.Notifications/Api/NotificationsService.cs b/Emby.Notifications/Api/NotificationsService.cs index 83845558a..559180971 100644 --- a/Emby.Notifications/Api/NotificationsService.cs +++ b/Emby.Notifications/Api/NotificationsService.cs @@ -1,3 +1,8 @@ +#pragma warning disable CS1591 +#pragma warning disable SA1402 +#pragma warning disable SA1600 +#pragma warning disable SA1649 + using System; using System.Collections.Generic; using System.Linq; @@ -12,60 +17,6 @@ using MediaBrowser.Model.Services; namespace Emby.Notifications.Api { - [Route("/Notifications/{UserId}", "GET", Summary = "Gets notifications")] - public class GetNotifications : IReturn - { - [ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")] - public string UserId { get; set; } - - [ApiMember(Name = "IsRead", Description = "An optional filter by IsRead", IsRequired = false, DataType = "bool", ParameterType = "query", Verb = "GET")] - public bool? IsRead { get; set; } - - [ApiMember(Name = "StartIndex", Description = "Optional. The record index to start at. All items with a lower index will be dropped from the results.", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")] - public int? StartIndex { get; set; } - - [ApiMember(Name = "Limit", Description = "Optional. The maximum number of records to return", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")] - public int? Limit { get; set; } - } - - public class Notification - { - public string Id { get; set; } - - public string UserId { get; set; } - - public DateTime Date { get; set; } - - public bool IsRead { get; set; } - - public string Name { get; set; } - - public string Description { get; set; } - - public string Url { get; set; } - - public NotificationLevel Level { get; set; } - } - - public class NotificationResult - { - public Notification[] Notifications { get; set; } - public int TotalRecordCount { get; set; } - } - - public class NotificationsSummary - { - public int UnreadCount { get; set; } - public NotificationLevel MaxUnreadNotificationLevel { get; set; } - } - - [Route("/Notifications/{UserId}/Summary", "GET", Summary = "Gets a notification summary for a user")] - public class GetNotificationsSummary : IReturn - { - [ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")] - public string UserId { get; set; } - } - [Route("/Notifications/Types", "GET", Summary = "Gets notification types")] public class GetNotificationTypes : IReturn> { @@ -80,41 +31,21 @@ namespace Emby.Notifications.Api public class AddAdminNotification : IReturnVoid { [ApiMember(Name = "Name", Description = "The notification's name", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "POST")] - public string Name { get; set; } + public string Name { get; set; } = string.Empty; [ApiMember(Name = "Description", Description = "The notification's description", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "POST")] - public string Description { get; set; } + public string Description { get; set; } = string.Empty; [ApiMember(Name = "ImageUrl", Description = "The notification's image url", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "POST")] - public string ImageUrl { get; set; } + public string? ImageUrl { get; set; } [ApiMember(Name = "Url", Description = "The notification's info url", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "POST")] - public string Url { get; set; } + public string? Url { get; set; } [ApiMember(Name = "Level", Description = "The notification level", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "POST")] public NotificationLevel Level { get; set; } } - [Route("/Notifications/{UserId}/Read", "POST", Summary = "Marks notifications as read")] - public class MarkRead : IReturnVoid - { - [ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")] - public string UserId { get; set; } - - [ApiMember(Name = "Ids", Description = "A list of notification ids, comma delimited", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "POST", AllowMultiple = true)] - public string Ids { get; set; } - } - - [Route("/Notifications/{UserId}/Unread", "POST", Summary = "Marks notifications as unread")] - public class MarkUnread : IReturnVoid - { - [ApiMember(Name = "UserId", Description = "User Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "POST")] - public string UserId { get; set; } - - [ApiMember(Name = "Ids", Description = "A list of notification ids, comma delimited", IsRequired = true, DataType = "string", ParameterType = "query", Verb = "POST", AllowMultiple = true)] - public string Ids { get; set; } - } - [Authenticated] public class NotificationsService : IService { @@ -129,30 +60,19 @@ namespace Emby.Notifications.Api public object Get(GetNotificationTypes request) { + _ = request; // Silence unused variable warning return _notificationManager.GetNotificationTypes(); } public object Get(GetNotificationServices request) { + _ = request; // Silence unused variable warning return _notificationManager.GetNotificationServices().ToList(); } - public object Get(GetNotificationsSummary request) - { - return new NotificationsSummary - { - - }; - } - public Task Post(AddAdminNotification request) { // This endpoint really just exists as post of a real with sickbeard - return AddNotification(request); - } - - private Task AddNotification(AddAdminNotification request) - { var notification = new NotificationRequest { Date = DateTime.UtcNow, @@ -165,18 +85,5 @@ namespace Emby.Notifications.Api return _notificationManager.SendNotification(notification, CancellationToken.None); } - - public void Post(MarkRead request) - { - } - - public void Post(MarkUnread request) - { - } - - public object Get(GetNotifications request) - { - return new NotificationResult(); - } } } diff --git a/Emby.Notifications/CoreNotificationTypes.cs b/Emby.Notifications/CoreNotificationTypes.cs index 0f9fc08d9..73e0b0256 100644 --- a/Emby.Notifications/CoreNotificationTypes.cs +++ b/Emby.Notifications/CoreNotificationTypes.cs @@ -1,7 +1,9 @@ +#pragma warning disable CS1591 +#pragma warning disable SA1600 + using System; using System.Collections.Generic; using System.Linq; -using MediaBrowser.Controller; using MediaBrowser.Controller.Notifications; using MediaBrowser.Model.Globalization; using MediaBrowser.Model.Notifications; diff --git a/Emby.Notifications/Emby.Notifications.csproj b/Emby.Notifications/Emby.Notifications.csproj index 004ded77b..e6bf785bf 100644 --- a/Emby.Notifications/Emby.Notifications.csproj +++ b/Emby.Notifications/Emby.Notifications.csproj @@ -4,6 +4,8 @@ netstandard2.1 false true + true + enable @@ -16,4 +18,16 @@ + + + + + + + + + + ../jellyfin.ruleset + + diff --git a/Emby.Notifications/NotificationConfigurationFactory.cs b/Emby.Notifications/NotificationConfigurationFactory.cs index d08475f7d..b168ed221 100644 --- a/Emby.Notifications/NotificationConfigurationFactory.cs +++ b/Emby.Notifications/NotificationConfigurationFactory.cs @@ -1,3 +1,6 @@ +#pragma warning disable CS1591 +#pragma warning disable SA1600 + using System.Collections.Generic; using MediaBrowser.Common.Configuration; using MediaBrowser.Model.Notifications; @@ -13,7 +16,7 @@ namespace Emby.Notifications new ConfigurationStore { Key = "notifications", - ConfigurationType = typeof (NotificationOptions) + ConfigurationType = typeof(NotificationOptions) } }; } diff --git a/Emby.Notifications/NotificationEntryPoint.cs b/Emby.Notifications/NotificationEntryPoint.cs new file mode 100644 index 000000000..ab92822fa --- /dev/null +++ b/Emby.Notifications/NotificationEntryPoint.cs @@ -0,0 +1,326 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using MediaBrowser.Common.Configuration; +using MediaBrowser.Controller; +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Entities.Audio; +using MediaBrowser.Controller.Entities.TV; +using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.Notifications; +using MediaBrowser.Controller.Plugins; +using MediaBrowser.Model.Activity; +using MediaBrowser.Model.Events; +using MediaBrowser.Model.Globalization; +using MediaBrowser.Model.Notifications; +using Microsoft.Extensions.Logging; + +namespace Emby.Notifications +{ + /// + /// Creates notifications for various system events. + /// + public class NotificationEntryPoint : IServerEntryPoint + { + private readonly ILogger _logger; + private readonly IActivityManager _activityManager; + private readonly ILocalizationManager _localization; + private readonly INotificationManager _notificationManager; + private readonly ILibraryManager _libraryManager; + private readonly IServerApplicationHost _appHost; + private readonly IConfigurationManager _config; + + private readonly object _libraryChangedSyncLock = new object(); + private readonly List _itemsAdded = new List(); + + private Timer? _libraryUpdateTimer; + + private string[] _coreNotificationTypes; + + private bool _disposed = false; + + /// + /// Initializes a new instance of the class. + /// + /// The logger. + /// The activity manager. + /// The localization manager. + /// The notification manager. + /// The library manager. + /// The application host. + /// The configuration manager. + public NotificationEntryPoint( + ILogger logger, + IActivityManager activityManager, + ILocalizationManager localization, + INotificationManager notificationManager, + ILibraryManager libraryManager, + IServerApplicationHost appHost, + IConfigurationManager config) + { + _logger = logger; + _activityManager = activityManager; + _localization = localization; + _notificationManager = notificationManager; + _libraryManager = libraryManager; + _appHost = appHost; + _config = config; + + _coreNotificationTypes = new CoreNotificationTypes(localization).GetNotificationTypes().Select(i => i.Type).ToArray(); + } + + /// + public Task RunAsync() + { + _libraryManager.ItemAdded += OnLibraryManagerItemAdded; + _appHost.HasPendingRestartChanged += OnAppHostHasPendingRestartChanged; + _appHost.HasUpdateAvailableChanged += OnAppHostHasUpdateAvailableChanged; + _activityManager.EntryCreated += OnActivityManagerEntryCreated; + + return Task.CompletedTask; + } + + private async void OnAppHostHasPendingRestartChanged(object sender, EventArgs e) + { + var type = NotificationType.ServerRestartRequired.ToString(); + + var notification = new NotificationRequest + { + NotificationType = type, + Name = string.Format( + CultureInfo.InvariantCulture, + _localization.GetLocalizedString("ServerNameNeedsToBeRestarted"), + _appHost.Name) + }; + + await SendNotification(notification, null).ConfigureAwait(false); + } + + private async void OnActivityManagerEntryCreated(object sender, GenericEventArgs e) + { + var entry = e.Argument; + + var type = entry.Type; + + if (string.IsNullOrEmpty(type) || !_coreNotificationTypes.Contains(type, StringComparer.OrdinalIgnoreCase)) + { + return; + } + + var userId = e.Argument.UserId; + + if (!userId.Equals(Guid.Empty) && !GetOptions().IsEnabledToMonitorUser(type, userId)) + { + return; + } + + var notification = new NotificationRequest + { + NotificationType = type, + Name = entry.Name, + Description = entry.Overview + }; + + await SendNotification(notification, null).ConfigureAwait(false); + } + + private NotificationOptions GetOptions() + { + return _config.GetConfiguration("notifications"); + } + + private async void OnAppHostHasUpdateAvailableChanged(object sender, EventArgs e) + { + if (!_appHost.HasUpdateAvailable) + { + return; + } + + var type = NotificationType.ApplicationUpdateAvailable.ToString(); + + var notification = new NotificationRequest + { + Description = "Please see jellyfin.media for details.", + NotificationType = type, + Name = _localization.GetLocalizedString("NewVersionIsAvailable") + }; + + await SendNotification(notification, null).ConfigureAwait(false); + } + + private void OnLibraryManagerItemAdded(object sender, ItemChangeEventArgs e) + { + if (!FilterItem(e.Item)) + { + return; + } + + lock (_libraryChangedSyncLock) + { + if (_libraryUpdateTimer == null) + { + _libraryUpdateTimer = new Timer( + LibraryUpdateTimerCallback, + null, + 5000, + Timeout.Infinite); + } + else + { + _libraryUpdateTimer.Change(5000, Timeout.Infinite); + } + + _itemsAdded.Add(e.Item); + } + } + + private bool FilterItem(BaseItem item) + { + if (item.IsFolder) + { + return false; + } + + if (!item.HasPathProtocol) + { + return false; + } + + if (item is IItemByName) + { + return false; + } + + return item.SourceType == SourceType.Library; + } + + private async void LibraryUpdateTimerCallback(object state) + { + List items; + + lock (_libraryChangedSyncLock) + { + items = _itemsAdded.ToList(); + _itemsAdded.Clear(); + _libraryUpdateTimer!.Dispose(); // Shouldn't be null as it just set off this callback + _libraryUpdateTimer = null; + } + + items = items.Take(10).ToList(); + + foreach (var item in items) + { + var notification = new NotificationRequest + { + NotificationType = NotificationType.NewLibraryContent.ToString(), + Name = string.Format( + CultureInfo.InvariantCulture, + _localization.GetLocalizedString("ValueHasBeenAddedToLibrary"), + GetItemName(item)), + Description = item.Overview + }; + + await SendNotification(notification, item).ConfigureAwait(false); + } + } + + private static string GetItemName(BaseItem item) + { + var name = item.Name; + if (item is Episode episode) + { + if (episode.IndexNumber.HasValue) + { + name = string.Format( + CultureInfo.InvariantCulture, + "Ep{0} - {1}", + episode.IndexNumber.Value, + name); + } + + if (episode.ParentIndexNumber.HasValue) + { + name = string.Format( + CultureInfo.InvariantCulture, + "S{0}, {1}", + episode.ParentIndexNumber.Value, + name); + } + } + + if (item is IHasSeries hasSeries) + { + name = hasSeries.SeriesName + " - " + name; + } + + if (item is IHasAlbumArtist hasAlbumArtist) + { + var artists = hasAlbumArtist.AlbumArtists; + + if (artists.Count > 0) + { + name = artists[0] + " - " + name; + } + } + else if (item is IHasArtist hasArtist) + { + var artists = hasArtist.Artists; + + if (artists.Count > 0) + { + name = artists[0] + " - " + name; + } + } + + return name; + } + + private async Task SendNotification(NotificationRequest notification, BaseItem? relatedItem) + { + try + { + await _notificationManager.SendNotification(notification, relatedItem, CancellationToken.None).ConfigureAwait(false); + } + catch (Exception ex) + { + _logger.LogError(ex, "Error sending notification"); + } + } + + /// + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + /// + /// Releases unmanaged and - optionally - managed resources. + /// + /// true to release both managed and unmanaged resources; false to release only unmanaged resources. + protected virtual void Dispose(bool disposing) + { + if (_disposed) + { + return; + } + + if (disposing) + { + _libraryUpdateTimer?.Dispose(); + } + + _libraryUpdateTimer = null; + + _libraryManager.ItemAdded -= OnLibraryManagerItemAdded; + _appHost.HasPendingRestartChanged -= OnAppHostHasPendingRestartChanged; + _appHost.HasUpdateAvailableChanged -= OnAppHostHasUpdateAvailableChanged; + _activityManager.EntryCreated -= OnActivityManagerEntryCreated; + + _disposed = true; + } + } +} diff --git a/Emby.Notifications/NotificationManager.cs b/Emby.Notifications/NotificationManager.cs index eecbbea07..836aa3e72 100644 --- a/Emby.Notifications/NotificationManager.cs +++ b/Emby.Notifications/NotificationManager.cs @@ -16,20 +16,32 @@ using Microsoft.Extensions.Logging; namespace Emby.Notifications { + /// + /// NotificationManager class. + /// public class NotificationManager : INotificationManager { private readonly ILogger _logger; private readonly IUserManager _userManager; private readonly IServerConfigurationManager _config; - private INotificationService[] _services; - private INotificationTypeFactory[] _typeFactories; - - public NotificationManager(ILoggerFactory loggerFactory, IUserManager userManager, IServerConfigurationManager config) + private INotificationService[] _services = Array.Empty(); + private INotificationTypeFactory[] _typeFactories = Array.Empty(); + + /// + /// Initializes a new instance of the class. + /// + /// The logger. + /// the user manager. + /// The server configuration manager. + public NotificationManager( + ILogger logger, + IUserManager userManager, + IServerConfigurationManager config) { + _logger = logger; _userManager = userManager; _config = config; - _logger = loggerFactory.CreateLogger(GetType().Name); } private NotificationOptions GetConfiguration() @@ -37,12 +49,14 @@ namespace Emby.Notifications return _config.GetConfiguration("notifications"); } + /// public Task SendNotification(NotificationRequest request, CancellationToken cancellationToken) { return SendNotification(request, null, cancellationToken); } - public Task SendNotification(NotificationRequest request, BaseItem relatedItem, CancellationToken cancellationToken) + /// + public Task SendNotification(NotificationRequest request, BaseItem? relatedItem, CancellationToken cancellationToken) { var notificationType = request.NotificationType; @@ -64,7 +78,8 @@ namespace Emby.Notifications return Task.WhenAll(tasks); } - private Task SendNotification(NotificationRequest request, + private Task SendNotification( + NotificationRequest request, INotificationService service, IEnumerable users, string title, @@ -79,7 +94,7 @@ namespace Emby.Notifications return Task.WhenAll(tasks); } - private IEnumerable GetUserIds(NotificationRequest request, NotificationOption options) + private IEnumerable GetUserIds(NotificationRequest request, NotificationOption? options) { if (request.SendToUserMode.HasValue) { @@ -109,7 +124,8 @@ namespace Emby.Notifications return request.UserIds; } - private async Task SendNotification(NotificationRequest request, + private async Task SendNotification( + NotificationRequest request, INotificationService service, string title, string description, @@ -161,12 +177,14 @@ namespace Emby.Notifications return GetConfiguration().IsServiceEnabled(service.Name, notificationType); } + /// public void AddParts(IEnumerable services, IEnumerable notificationTypeFactories) { _services = services.ToArray(); _typeFactories = notificationTypeFactories.ToArray(); } + /// public List GetNotificationTypes() { var list = _typeFactories.Select(i => @@ -180,7 +198,6 @@ namespace Emby.Notifications _logger.LogError(ex, "Error in GetNotificationTypes"); return new List(); } - }).SelectMany(i => i).ToList(); var config = GetConfiguration(); @@ -193,13 +210,13 @@ namespace Emby.Notifications return list; } + /// public IEnumerable GetNotificationServices() { return _services.Select(i => new NameIdPair { Name = i.Name, Id = i.Name.GetMD5().ToString("N", CultureInfo.InvariantCulture) - }).OrderBy(i => i.Name); } } diff --git a/Emby.Notifications/Notifications.cs b/Emby.Notifications/Notifications.cs deleted file mode 100644 index 7aa1e7ae8..000000000 --- a/Emby.Notifications/Notifications.cs +++ /dev/null @@ -1,291 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Globalization; -using System.Linq; -using System.Threading; -using System.Threading.Tasks; -using MediaBrowser.Common.Configuration; -using MediaBrowser.Controller; -using MediaBrowser.Controller.Entities; -using MediaBrowser.Controller.Entities.Audio; -using MediaBrowser.Controller.Entities.TV; -using MediaBrowser.Controller.Library; -using MediaBrowser.Controller.Notifications; -using MediaBrowser.Controller.Plugins; -using MediaBrowser.Model.Activity; -using MediaBrowser.Model.Events; -using MediaBrowser.Model.Globalization; -using MediaBrowser.Model.Notifications; -using Microsoft.Extensions.Logging; - -namespace Emby.Notifications -{ - /// - /// Creates notifications for various system events - /// - public class Notifications : IServerEntryPoint - { - private readonly ILogger _logger; - - private readonly INotificationManager _notificationManager; - - private readonly ILibraryManager _libraryManager; - private readonly IServerApplicationHost _appHost; - - private Timer LibraryUpdateTimer { get; set; } - private readonly object _libraryChangedSyncLock = new object(); - - private readonly IConfigurationManager _config; - private readonly ILocalizationManager _localization; - private readonly IActivityManager _activityManager; - - private string[] _coreNotificationTypes; - - public Notifications( - IActivityManager activityManager, - ILocalizationManager localization, - ILogger logger, - INotificationManager notificationManager, - ILibraryManager libraryManager, - IServerApplicationHost appHost, - IConfigurationManager config) - { - _logger = logger; - _notificationManager = notificationManager; - _libraryManager = libraryManager; - _appHost = appHost; - _config = config; - _localization = localization; - _activityManager = activityManager; - - _coreNotificationTypes = new CoreNotificationTypes(localization).GetNotificationTypes().Select(i => i.Type).ToArray(); - } - - public Task RunAsync() - { - _libraryManager.ItemAdded += _libraryManager_ItemAdded; - _appHost.HasPendingRestartChanged += _appHost_HasPendingRestartChanged; - _appHost.HasUpdateAvailableChanged += _appHost_HasUpdateAvailableChanged; - _activityManager.EntryCreated += _activityManager_EntryCreated; - - return Task.CompletedTask; - } - - private async void _appHost_HasPendingRestartChanged(object sender, EventArgs e) - { - var type = NotificationType.ServerRestartRequired.ToString(); - - var notification = new NotificationRequest - { - NotificationType = type, - Name = string.Format(_localization.GetLocalizedString("ServerNameNeedsToBeRestarted"), _appHost.Name) - }; - - await SendNotification(notification, null).ConfigureAwait(false); - } - - private async void _activityManager_EntryCreated(object sender, GenericEventArgs e) - { - var entry = e.Argument; - - var type = entry.Type; - - if (string.IsNullOrEmpty(type) || !_coreNotificationTypes.Contains(type, StringComparer.OrdinalIgnoreCase)) - { - return; - } - - var userId = e.Argument.UserId; - - if (!userId.Equals(Guid.Empty) && !GetOptions().IsEnabledToMonitorUser(type, userId)) - { - return; - } - - var notification = new NotificationRequest - { - NotificationType = type, - Name = entry.Name, - Description = entry.Overview - }; - - await SendNotification(notification, null).ConfigureAwait(false); - } - - private NotificationOptions GetOptions() - { - return _config.GetConfiguration("notifications"); - } - - private async void _appHost_HasUpdateAvailableChanged(object sender, EventArgs e) - { - if (!_appHost.HasUpdateAvailable) - { - return; - } - - var type = NotificationType.ApplicationUpdateAvailable.ToString(); - - var notification = new NotificationRequest - { - Description = "Please see jellyfin.media for details.", - NotificationType = type, - Name = _localization.GetLocalizedString("NewVersionIsAvailable") - }; - - await SendNotification(notification, null).ConfigureAwait(false); - } - - private readonly List _itemsAdded = new List(); - private void _libraryManager_ItemAdded(object sender, ItemChangeEventArgs e) - { - if (!FilterItem(e.Item)) - { - return; - } - - lock (_libraryChangedSyncLock) - { - if (LibraryUpdateTimer == null) - { - LibraryUpdateTimer = new Timer(LibraryUpdateTimerCallback, null, 5000, - Timeout.Infinite); - } - else - { - LibraryUpdateTimer.Change(5000, Timeout.Infinite); - } - - _itemsAdded.Add(e.Item); - } - } - - private bool FilterItem(BaseItem item) - { - if (item.IsFolder) - { - return false; - } - - if (!item.HasPathProtocol) - { - return false; - } - - if (item is IItemByName) - { - return false; - } - - return item.SourceType == SourceType.Library; - } - - private async void LibraryUpdateTimerCallback(object state) - { - List items; - - lock (_libraryChangedSyncLock) - { - items = _itemsAdded.ToList(); - _itemsAdded.Clear(); - DisposeLibraryUpdateTimer(); - } - - items = items.Take(10).ToList(); - - foreach (var item in items) - { - var notification = new NotificationRequest - { - NotificationType = NotificationType.NewLibraryContent.ToString(), - Name = string.Format(_localization.GetLocalizedString("ValueHasBeenAddedToLibrary"), GetItemName(item)), - Description = item.Overview - }; - - await SendNotification(notification, item).ConfigureAwait(false); - } - } - - public static string GetItemName(BaseItem item) - { - var name = item.Name; - if (item is Episode episode) - { - if (episode.IndexNumber.HasValue) - { - name = string.Format( - CultureInfo.InvariantCulture, - "Ep{0} - {1}", - episode.IndexNumber.Value, - name); - } - if (episode.ParentIndexNumber.HasValue) - { - name = string.Format( - CultureInfo.InvariantCulture, - "S{0}, {1}", - episode.ParentIndexNumber.Value, - name); - } - } - - - if (item is IHasSeries hasSeries) - { - name = hasSeries.SeriesName + " - " + name; - } - - if (item is IHasAlbumArtist hasAlbumArtist) - { - var artists = hasAlbumArtist.AlbumArtists; - - if (artists.Count > 0) - { - name = artists[0] + " - " + name; - } - } - else if (item is IHasArtist hasArtist) - { - var artists = hasArtist.Artists; - - if (artists.Count > 0) - { - name = artists[0] + " - " + name; - } - } - - return name; - } - - private async Task SendNotification(NotificationRequest notification, BaseItem relatedItem) - { - try - { - await _notificationManager.SendNotification(notification, relatedItem, CancellationToken.None).ConfigureAwait(false); - } - catch (Exception ex) - { - _logger.LogError(ex, "Error sending notification"); - } - } - - public void Dispose() - { - DisposeLibraryUpdateTimer(); - - _libraryManager.ItemAdded -= _libraryManager_ItemAdded; - _appHost.HasPendingRestartChanged -= _appHost_HasPendingRestartChanged; - _appHost.HasUpdateAvailableChanged -= _appHost_HasUpdateAvailableChanged; - _activityManager.EntryCreated -= _activityManager_EntryCreated; - } - - private void DisposeLibraryUpdateTimer() - { - if (LibraryUpdateTimer != null) - { - LibraryUpdateTimer.Dispose(); - LibraryUpdateTimer = null; - } - } - } -} -- cgit v1.2.3