diff --git a/MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj b/MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj index dfe7d70eee..1688fac8bd 100644 --- a/MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj +++ b/MediaBrowser.Common.Implementations/MediaBrowser.Common.Implementations.csproj @@ -92,7 +92,6 @@ - @@ -105,6 +104,7 @@ + diff --git a/MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/StatisticsTask.cs b/MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/StatisticsTask.cs deleted file mode 100644 index 9c0fe165d4..0000000000 --- a/MediaBrowser.Common.Implementations/ScheduledTasks/Tasks/StatisticsTask.cs +++ /dev/null @@ -1,127 +0,0 @@ -using MediaBrowser.Common.Net; -using MediaBrowser.Common.ScheduledTasks; -using MediaBrowser.Model.Logging; -using System; -using System.Collections.Generic; -using System.Threading; -using System.Threading.Tasks; - -namespace MediaBrowser.Common.Implementations.ScheduledTasks.Tasks -{ - /// - /// Class ReloadLoggerFileTask - /// - public class StatisticsTask : IScheduledTask, IConfigurableScheduledTask - { - /// - /// Gets or sets the log manager. - /// - /// The log manager. - private ILogManager LogManager { get; set; } - /// - /// Gets or sets the app host - /// - /// The application host. - private IApplicationHost ApplicationHost { get; set; } - - /// - /// The network manager - /// - private INetworkManager NetworkManager { get; set; } - - /// - /// The http client - /// - private IHttpClient HttpClient { get; set; } - - /// - /// Initializes a new instance of the class. - /// - /// The logManager. - /// - /// - public StatisticsTask(ILogManager logManager, IApplicationHost appHost, INetworkManager networkManager, IHttpClient httpClient) - { - LogManager = logManager; - ApplicationHost = appHost; - NetworkManager = networkManager; - HttpClient = httpClient; - } - - /// - /// Gets the default triggers. - /// - /// IEnumerable{BaseTaskTrigger}. - public IEnumerable GetDefaultTriggers() - { - var trigger = new DailyTrigger { TimeOfDay = TimeSpan.FromHours(20) }; //8pm - when the system is most likely to be active - var trigger2 = new StartupTrigger(); //and also at system start - - return new ITaskTrigger[] { trigger, trigger2 }; - } - - /// - /// Executes the internal. - /// - /// The cancellation token. - /// The progress. - /// Task. - public async Task Execute(CancellationToken cancellationToken, IProgress progress) - { - cancellationToken.ThrowIfCancellationRequested(); - - progress.Report(0); - var mac = NetworkManager.GetMacAddress(); - - var data = new Dictionary - { - { "feature", ApplicationHost.Name }, - { "mac", mac }, - { "ver", ApplicationHost.ApplicationVersion.ToString() }, - { "platform", Environment.OSVersion.VersionString }, - { "isservice", ApplicationHost.IsRunningAsService.ToString().ToLower()} - }; - - await HttpClient.Post(Constants.Constants.MbAdminUrl + "service/registration/ping", data, CancellationToken.None).ConfigureAwait(false); - progress.Report(100); - - } - - /// - /// Gets the name. - /// - /// The name. - public string Name - { - get { return "Collect anonymous usage stats"; } - } - - /// - /// Gets the description. - /// - /// The description. - public string Description - { - get { return "Pings the admin site just so we know how many folks are out there and what version they are on."; } - } - - /// - /// Gets the category. - /// - /// The category. - public string Category - { - get { return "Application"; } - } - - public bool IsHidden - { - get { return true; } - } - - public bool IsEnabled - { - get { return true; } - } - } -} diff --git a/MediaBrowser.Common.Implementations/Security/UsageReporter.cs b/MediaBrowser.Common.Implementations/Security/UsageReporter.cs new file mode 100644 index 0000000000..e32940be9b --- /dev/null +++ b/MediaBrowser.Common.Implementations/Security/UsageReporter.cs @@ -0,0 +1,40 @@ +using MediaBrowser.Common.Net; +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; + +namespace MediaBrowser.Common.Implementations.Security +{ + public class UsageReporter + { + private readonly IApplicationHost _applicationHost; + private readonly INetworkManager _networkManager; + private readonly IHttpClient _httpClient; + + public UsageReporter(IApplicationHost applicationHost, INetworkManager networkManager, IHttpClient httpClient) + { + _applicationHost = applicationHost; + _networkManager = networkManager; + _httpClient = httpClient; + } + + public Task ReportUsage(CancellationToken cancellationToken) + { + cancellationToken.ThrowIfCancellationRequested(); + + var mac = _networkManager.GetMacAddress(); + + var data = new Dictionary + { + { "feature", _applicationHost.Name }, + { "mac", mac }, + { "ver", _applicationHost.ApplicationVersion.ToString() }, + { "platform", Environment.OSVersion.VersionString }, + { "isservice", _applicationHost.IsRunningAsService.ToString().ToLower()} + }; + + return _httpClient.Post(Constants.Constants.MbAdminUrl + "service/registration/ping", data, cancellationToken); + } + } +} diff --git a/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs b/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs index e68790e61f..2583450a3b 100644 --- a/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs +++ b/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs @@ -142,7 +142,7 @@ namespace MediaBrowser.Controller.Entities.Audio // Refresh songs foreach (var item in songs) { - if (tasks.Count >= 2) + if (tasks.Count >= 3) { await Task.WhenAll(tasks).ConfigureAwait(false); tasks.Clear(); @@ -166,7 +166,8 @@ namespace MediaBrowser.Controller.Entities.Audio } }); - tasks.Add(RefreshItem(item, refreshOptions, innerProgress, cancellationToken)); + var taskChild = item; + tasks.Add(Task.Run(async () => await RefreshItem(taskChild, refreshOptions, innerProgress, cancellationToken).ConfigureAwait(false), cancellationToken)); } await Task.WhenAll(tasks).ConfigureAwait(false); @@ -178,7 +179,7 @@ namespace MediaBrowser.Controller.Entities.Audio // Refresh all non-songs foreach (var item in others) { - if (tasks.Count > 4) + if (tasks.Count > 3) { await Task.WhenAll(tasks).ConfigureAwait(false); tasks.Clear(); diff --git a/MediaBrowser.Controller/Entities/IHasImages.cs b/MediaBrowser.Controller/Entities/IHasImages.cs index d53eba11a1..e07db88c4e 100644 --- a/MediaBrowser.Controller/Entities/IHasImages.cs +++ b/MediaBrowser.Controller/Entities/IHasImages.cs @@ -142,6 +142,12 @@ namespace MediaBrowser.Controller.Entities /// /// true if [supports local metadata]; otherwise, false. bool SupportsLocalMetadata { get; } + + /// + /// Gets a value indicating whether this instance is in mixed folder. + /// + /// true if this instance is in mixed folder; otherwise, false. + bool IsInMixedFolder { get; } } public static class HasImagesExtensions diff --git a/MediaBrowser.Controller/Providers/IProviderManager.cs b/MediaBrowser.Controller/Providers/IProviderManager.cs index 691a5add63..4aeb86a6a0 100644 --- a/MediaBrowser.Controller/Providers/IProviderManager.cs +++ b/MediaBrowser.Controller/Providers/IProviderManager.cs @@ -34,7 +34,7 @@ namespace MediaBrowser.Controller.Providers /// Index of the image. /// The cancellation token. /// Task. - Task SaveImage(BaseItem item, string url, SemaphoreSlim resourcePool, ImageType type, int? imageIndex, CancellationToken cancellationToken); + Task SaveImage(IHasImages item, string url, SemaphoreSlim resourcePool, ImageType type, int? imageIndex, CancellationToken cancellationToken); /// /// Saves the image. @@ -46,7 +46,7 @@ namespace MediaBrowser.Controller.Providers /// Index of the image. /// The cancellation token. /// Task. - Task SaveImage(BaseItem item, Stream source, string mimeType, ImageType type, int? imageIndex, CancellationToken cancellationToken); + Task SaveImage(IHasImages item, Stream source, string mimeType, ImageType type, int? imageIndex, CancellationToken cancellationToken); /// /// Adds the metadata providers. diff --git a/MediaBrowser.Providers/Manager/ImageSaver.cs b/MediaBrowser.Providers/Manager/ImageSaver.cs index bac90ae379..0e184d1632 100644 --- a/MediaBrowser.Providers/Manager/ImageSaver.cs +++ b/MediaBrowser.Providers/Manager/ImageSaver.cs @@ -62,14 +62,14 @@ namespace MediaBrowser.Providers.Manager /// The cancellation token. /// Task. /// mimeType - public async Task SaveImage(BaseItem item, Stream source, string mimeType, ImageType type, int? imageIndex, CancellationToken cancellationToken) + public async Task SaveImage(IHasImages item, Stream source, string mimeType, ImageType type, int? imageIndex, CancellationToken cancellationToken) { if (string.IsNullOrEmpty(mimeType)) { throw new ArgumentNullException("mimeType"); } - var saveLocally = item.IsSaveLocalMetadataEnabled() && item.Parent != null && !(item is Audio); + var saveLocally = item.SupportsLocalMetadata && item.IsSaveLocalMetadataEnabled() && !item.IsOwnedItem && !(item is Audio); if (item is IItemByName || item is User) { @@ -93,7 +93,7 @@ namespace MediaBrowser.Providers.Manager { var series = season.Series; - if (series != null && series.SupportsLocalMetadata) + if (series != null && series.SupportsLocalMetadata && series.IsSaveLocalMetadataEnabled()) { saveLocally = true; } @@ -224,7 +224,7 @@ namespace MediaBrowser.Providers.Manager /// Type of the MIME. /// if set to true [save locally]. /// IEnumerable{System.String}. - private string[] GetSavePaths(BaseItem item, ImageType type, int? imageIndex, string mimeType, bool saveLocally) + private string[] GetSavePaths(IHasImages item, ImageType type, int? imageIndex, string mimeType, bool saveLocally) { if (_config.Configuration.ImageSavingConvention == ImageSavingConvention.Legacy || !saveLocally) { @@ -261,7 +261,7 @@ namespace MediaBrowser.Providers.Manager /// imageIndex /// or /// imageIndex - private void SetImagePath(BaseItem item, ImageType type, int? imageIndex, string path) + private void SetImagePath(IHasImages item, ImageType type, int? imageIndex, string path) { item.SetImagePath(type, imageIndex ?? 0, new FileInfo(path)); } @@ -280,7 +280,7 @@ namespace MediaBrowser.Providers.Manager /// or /// imageIndex /// - private string GetStandardSavePath(BaseItem item, ImageType type, int? imageIndex, string mimeType, bool saveLocally) + private string GetStandardSavePath(IHasImages item, ImageType type, int? imageIndex, string mimeType, bool saveLocally) { string filename; @@ -378,7 +378,7 @@ namespace MediaBrowser.Providers.Manager /// Type of the MIME. /// IEnumerable{System.String}. /// imageIndex - private string[] GetCompatibleSavePaths(BaseItem item, ImageType type, int? imageIndex, string mimeType) + private string[] GetCompatibleSavePaths(IHasImages item, ImageType type, int? imageIndex, string mimeType) { var season = item as Season; @@ -405,13 +405,13 @@ namespace MediaBrowser.Providers.Manager return new[] { GetSavePathForItemInMixedFolder(item, type, "fanart", extension) }; } - if (season != null && item.IndexNumber.HasValue) + if (season != null && season.IndexNumber.HasValue) { var seriesFolder = season.SeriesPath; - var seasonMarker = item.IndexNumber.Value == 0 + var seasonMarker = season.IndexNumber.Value == 0 ? "-specials" - : item.IndexNumber.Value.ToString("00", UsCulture); + : season.IndexNumber.Value.ToString("00", UsCulture); var imageFilename = "season" + seasonMarker + "-fanart" + extension; @@ -442,13 +442,13 @@ namespace MediaBrowser.Providers.Manager if (type == ImageType.Primary) { - if (season != null && item.IndexNumber.HasValue) + if (season != null && season.IndexNumber.HasValue) { var seriesFolder = season.SeriesPath; - var seasonMarker = item.IndexNumber.Value == 0 + var seasonMarker = season.IndexNumber.Value == 0 ? "-specials" - : item.IndexNumber.Value.ToString("00", UsCulture); + : season.IndexNumber.Value.ToString("00", UsCulture); var imageFilename = "season" + seasonMarker + "-poster" + extension; @@ -479,13 +479,13 @@ namespace MediaBrowser.Providers.Manager if (type == ImageType.Banner) { - if (season != null && item.IndexNumber.HasValue) + if (season != null && season.IndexNumber.HasValue) { var seriesFolder = season.SeriesPath; - var seasonMarker = item.IndexNumber.Value == 0 + var seasonMarker = season.IndexNumber.Value == 0 ? "-specials" - : item.IndexNumber.Value.ToString("00", UsCulture); + : season.IndexNumber.Value.ToString("00", UsCulture); var imageFilename = "season" + seasonMarker + "-banner" + extension; @@ -495,13 +495,13 @@ namespace MediaBrowser.Providers.Manager if (type == ImageType.Thumb) { - if (season != null && item.IndexNumber.HasValue) + if (season != null && season.IndexNumber.HasValue) { var seriesFolder = season.SeriesPath; - var seasonMarker = item.IndexNumber.Value == 0 + var seasonMarker = season.IndexNumber.Value == 0 ? "-specials" - : item.IndexNumber.Value.ToString("00", UsCulture); + : season.IndexNumber.Value.ToString("00", UsCulture); var imageFilename = "season" + seasonMarker + "-landscape" + extension; diff --git a/MediaBrowser.Providers/Manager/ProviderManager.cs b/MediaBrowser.Providers/Manager/ProviderManager.cs index 119ab0c667..ced9e48680 100644 --- a/MediaBrowser.Providers/Manager/ProviderManager.cs +++ b/MediaBrowser.Providers/Manager/ProviderManager.cs @@ -172,7 +172,7 @@ namespace MediaBrowser.Providers.Manager /// Index of the image. /// The cancellation token. /// Task. - public async Task SaveImage(BaseItem item, string url, SemaphoreSlim resourcePool, ImageType type, int? imageIndex, CancellationToken cancellationToken) + public async Task SaveImage(IHasImages item, string url, SemaphoreSlim resourcePool, ImageType type, int? imageIndex, CancellationToken cancellationToken) { var response = await _httpClient.GetResponse(new HttpRequestOptions { @@ -196,7 +196,7 @@ namespace MediaBrowser.Providers.Manager /// Index of the image. /// The cancellation token. /// Task. - public Task SaveImage(BaseItem item, Stream source, string mimeType, ImageType type, int? imageIndex, CancellationToken cancellationToken) + public Task SaveImage(IHasImages item, Stream source, string mimeType, ImageType type, int? imageIndex, CancellationToken cancellationToken) { return new ImageSaver(ConfigurationManager, _libraryMonitor, _fileSystem, _logger).SaveImage(item, source, mimeType, type, imageIndex, cancellationToken); } diff --git a/MediaBrowser.Server.Implementations/EntryPoints/UsageEntryPoint.cs b/MediaBrowser.Server.Implementations/EntryPoints/UsageEntryPoint.cs new file mode 100644 index 0000000000..3ab47f51b9 --- /dev/null +++ b/MediaBrowser.Server.Implementations/EntryPoints/UsageEntryPoint.cs @@ -0,0 +1,63 @@ +using MediaBrowser.Common; +using MediaBrowser.Common.Implementations.Security; +using MediaBrowser.Common.Net; +using MediaBrowser.Controller.Plugins; +using MediaBrowser.Model.Logging; +using System; +using System.Threading; + +namespace MediaBrowser.Server.Implementations.EntryPoints +{ + /// + /// Class UsageEntryPoint + /// + public class UsageEntryPoint : IServerEntryPoint + { + private readonly IApplicationHost _applicationHost; + private readonly INetworkManager _networkManager; + private readonly IHttpClient _httpClient; + private readonly ILogger _logger; + + private Timer _timer; + private readonly TimeSpan _frequency = TimeSpan.FromHours(24); + + public UsageEntryPoint(ILogger logger, IApplicationHost applicationHost, INetworkManager networkManager, IHttpClient httpClient) + { + _logger = logger; + _applicationHost = applicationHost; + _networkManager = networkManager; + _httpClient = httpClient; + } + + public void Run() + { + _timer = new Timer(OnTimerFired, null, TimeSpan.FromMilliseconds(5000), _frequency); + } + + /// + /// Called when [timer fired]. + /// + /// The state. + private async void OnTimerFired(object state) + { + try + { + await new UsageReporter(_applicationHost, _networkManager, _httpClient).ReportUsage(CancellationToken.None) + .ConfigureAwait(false); + } + catch (Exception ex) + { + _logger.ErrorException("Error sending anonymous usage statistics.", ex); + } + } + + public void Dispose() + { + if (_timer != null) + { + _timer.Dispose(); + _timer = null; + } + } + } +} diff --git a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj index 050af69d08..5060dbed3b 100644 --- a/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj +++ b/MediaBrowser.Server.Implementations/MediaBrowser.Server.Implementations.csproj @@ -117,6 +117,7 @@ +