aboutsummaryrefslogtreecommitdiff
path: root/MediaBrowser.Controller
diff options
context:
space:
mode:
Diffstat (limited to 'MediaBrowser.Controller')
-rw-r--r--MediaBrowser.Controller/Channels/Channel.cs3
-rw-r--r--MediaBrowser.Controller/Dto/DtoOptions.cs3
-rw-r--r--MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs2
-rw-r--r--MediaBrowser.Controller/Entities/Audio/MusicArtist.cs2
-rw-r--r--MediaBrowser.Controller/Entities/BaseItem.cs38
-rw-r--r--MediaBrowser.Controller/Entities/CollectionFolder.cs30
-rw-r--r--MediaBrowser.Controller/Entities/Folder.cs196
-rw-r--r--MediaBrowser.Controller/Entities/TV/Series.cs2
-rw-r--r--MediaBrowser.Controller/Library/ILibraryManager.cs4
-rw-r--r--MediaBrowser.Controller/MediaBrowser.Controller.csproj1
-rw-r--r--MediaBrowser.Controller/Providers/IProviderManager.cs19
-rw-r--r--MediaBrowser.Controller/Providers/ProviderRefreshStatus.cs22
12 files changed, 208 insertions, 114 deletions
diff --git a/MediaBrowser.Controller/Channels/Channel.cs b/MediaBrowser.Controller/Channels/Channel.cs
index 862c8e5ac..8e2faa20e 100644
--- a/MediaBrowser.Controller/Channels/Channel.cs
+++ b/MediaBrowser.Controller/Channels/Channel.cs
@@ -6,6 +6,7 @@ using System.Linq;
using MediaBrowser.Model.Serialization;
using System.Threading;
using System.Threading.Tasks;
+using MediaBrowser.Common.Progress;
namespace MediaBrowser.Controller.Channels
{
@@ -51,7 +52,7 @@ namespace MediaBrowser.Controller.Channels
SortBy = query.SortBy,
SortOrder = query.SortOrder
- }, new Progress<double>(), CancellationToken.None).Result;
+ }, new SimpleProgress<double>(), CancellationToken.None).Result;
}
catch
{
diff --git a/MediaBrowser.Controller/Dto/DtoOptions.cs b/MediaBrowser.Controller/Dto/DtoOptions.cs
index b9d9d7dda..098ba558f 100644
--- a/MediaBrowser.Controller/Dto/DtoOptions.cs
+++ b/MediaBrowser.Controller/Dto/DtoOptions.cs
@@ -10,7 +10,8 @@ namespace MediaBrowser.Controller.Dto
{
private static readonly List<ItemFields> DefaultExcludedFields = new List<ItemFields>
{
- ItemFields.SeasonUserData
+ ItemFields.SeasonUserData,
+ ItemFields.RefreshState
};
public List<ItemFields> Fields { get; set; }
diff --git a/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs b/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs
index e9eca19cf..516ab5053 100644
--- a/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs
+++ b/MediaBrowser.Controller/Entities/Audio/MusicAlbum.cs
@@ -235,8 +235,6 @@ namespace MediaBrowser.Controller.Entities.Audio
{
await RefreshArtists(refreshOptions, cancellationToken).ConfigureAwait(false);
}
-
- progress.Report(100);
}
private async Task RefreshArtists(MetadataRefreshOptions refreshOptions, CancellationToken cancellationToken)
diff --git a/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs b/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs
index 4b232de49..ebd83205e 100644
--- a/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs
+++ b/MediaBrowser.Controller/Entities/Audio/MusicArtist.cs
@@ -250,8 +250,6 @@ namespace MediaBrowser.Controller.Entities.Audio
percent /= totalItems;
progress.Report(percent * 100);
}
-
- progress.Report(100);
}
public ArtistInfo GetLookupInfo()
diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs
index 4efea94d8..b4a3d89ea 100644
--- a/MediaBrowser.Controller/Entities/BaseItem.cs
+++ b/MediaBrowser.Controller/Entities/BaseItem.cs
@@ -1058,6 +1058,16 @@ namespace MediaBrowser.Controller.Entities
return RefreshMetadata(new MetadataRefreshOptions(new DirectoryService(Logger, FileSystem)), cancellationToken);
}
+ protected virtual void TriggerOnRefreshStart()
+ {
+
+ }
+
+ protected virtual void TriggerOnRefreshComplete()
+ {
+
+ }
+
/// <summary>
/// Overrides the base implementation to refresh metadata for local trailers
/// </summary>
@@ -1066,6 +1076,8 @@ namespace MediaBrowser.Controller.Entities
/// <returns>true if a provider reports we changed</returns>
public async Task<ItemUpdateType> RefreshMetadata(MetadataRefreshOptions options, CancellationToken cancellationToken)
{
+ TriggerOnRefreshStart();
+
var locationType = LocationType;
var requiresSave = false;
@@ -1091,14 +1103,21 @@ namespace MediaBrowser.Controller.Entities
}
}
- var refreshOptions = requiresSave
- ? new MetadataRefreshOptions(options)
- {
- ForceSave = true
- }
- : options;
+ try
+ {
+ var refreshOptions = requiresSave
+ ? new MetadataRefreshOptions(options)
+ {
+ ForceSave = true
+ }
+ : options;
- return await ProviderManager.RefreshSingleItem(this, refreshOptions, cancellationToken).ConfigureAwait(false);
+ return await ProviderManager.RefreshSingleItem(this, refreshOptions, cancellationToken).ConfigureAwait(false);
+ }
+ finally
+ {
+ TriggerOnRefreshComplete();
+ }
}
[IgnoreDataMember]
@@ -2421,5 +2440,10 @@ namespace MediaBrowser.Controller.Entities
{
return new List<ExternalUrl>();
}
+
+ public virtual double? GetRefreshProgress()
+ {
+ return null;
+ }
}
} \ No newline at end of file
diff --git a/MediaBrowser.Controller/Entities/CollectionFolder.cs b/MediaBrowser.Controller/Entities/CollectionFolder.cs
index 8bc23a581..0bd8606b9 100644
--- a/MediaBrowser.Controller/Entities/CollectionFolder.cs
+++ b/MediaBrowser.Controller/Entities/CollectionFolder.cs
@@ -10,6 +10,7 @@ using System.Threading.Tasks;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Model.Configuration;
+using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Extensions;
using MediaBrowser.Model.IO;
using MediaBrowser.Model.Serialization;
@@ -199,6 +200,30 @@ namespace MediaBrowser.Controller.Entities
return changed;
}
+ public override double? GetRefreshProgress()
+ {
+ var folders = GetPhysicalFolders(true).ToList();
+ double totalProgresses = 0;
+ var foldersWithProgress = 0;
+
+ foreach (var folder in folders)
+ {
+ var progress = ProviderManager.GetRefreshProgress(folder.Id);
+ if (progress.HasValue)
+ {
+ totalProgresses += progress.Value;
+ foldersWithProgress++;
+ }
+ }
+
+ if (foldersWithProgress == 0)
+ {
+ return null;
+ }
+
+ return (totalProgresses / foldersWithProgress);
+ }
+
protected override bool RefreshLinkedChildren(IEnumerable<FileSystemMetadata> fileSystemChildren)
{
return RefreshLinkedChildrenInternal(true);
@@ -321,6 +346,11 @@ namespace MediaBrowser.Controller.Entities
return GetPhysicalFolders(true).SelectMany(c => c.Children);
}
+ public IEnumerable<Folder> GetPhysicalFolders()
+ {
+ return GetPhysicalFolders(true);
+ }
+
private IEnumerable<Folder> GetPhysicalFolders(bool enableCache)
{
if (enableCache)
diff --git a/MediaBrowser.Controller/Entities/Folder.cs b/MediaBrowser.Controller/Entities/Folder.cs
index 727b7dbeb..34b33fde0 100644
--- a/MediaBrowser.Controller/Entities/Folder.cs
+++ b/MediaBrowser.Controller/Entities/Folder.cs
@@ -271,6 +271,11 @@ namespace MediaBrowser.Controller.Entities
return GetCachedChildren();
}
+ public override double? GetRefreshProgress()
+ {
+ return ProviderManager.GetRefreshProgress(Id);
+ }
+
public Task ValidateChildren(IProgress<double> progress, CancellationToken cancellationToken)
{
return ValidateChildren(progress, cancellationToken, new MetadataRefreshOptions(new DirectoryService(Logger, FileSystem)));
@@ -318,6 +323,14 @@ namespace MediaBrowser.Controller.Entities
return current.IsValidFromResolver(newItem);
}
+ protected override void TriggerOnRefreshStart()
+ {
+ }
+
+ protected override void TriggerOnRefreshComplete()
+ {
+ }
+
/// <summary>
/// Validates the children internal.
/// </summary>
@@ -328,7 +341,27 @@ namespace MediaBrowser.Controller.Entities
/// <param name="refreshOptions">The refresh options.</param>
/// <param name="directoryService">The directory service.</param>
/// <returns>Task.</returns>
- protected async virtual Task ValidateChildrenInternal(IProgress<double> progress, CancellationToken cancellationToken, bool recursive, bool refreshChildMetadata, MetadataRefreshOptions refreshOptions, IDirectoryService directoryService)
+ protected virtual async Task ValidateChildrenInternal(IProgress<double> progress, CancellationToken cancellationToken, bool recursive, bool refreshChildMetadata, MetadataRefreshOptions refreshOptions, IDirectoryService directoryService)
+ {
+ if (recursive)
+ {
+ ProviderManager.OnRefreshStart(this);
+ }
+
+ try
+ {
+ await ValidateChildrenInternal2(progress, cancellationToken, recursive, refreshChildMetadata, refreshOptions, directoryService).ConfigureAwait(false);
+ }
+ finally
+ {
+ if (recursive)
+ {
+ ProviderManager.OnRefreshComplete(this);
+ }
+ }
+ }
+
+ private async Task ValidateChildrenInternal2(IProgress<double> progress, CancellationToken cancellationToken, bool recursive, bool refreshChildMetadata, MetadataRefreshOptions refreshOptions, IDirectoryService directoryService)
{
var locationType = LocationType;
@@ -360,6 +393,11 @@ namespace MediaBrowser.Controller.Entities
progress.Report(5);
+ if (recursive)
+ {
+ ProviderManager.OnRefreshProgress(this, 5);
+ }
+
//build a dictionary of the current children we have now by Id so we can compare quickly and easily
var currentChildren = GetActualChildrenDictionary();
@@ -424,76 +462,99 @@ namespace MediaBrowser.Controller.Entities
await LibraryManager.CreateItems(newItems, cancellationToken).ConfigureAwait(false);
}
}
+ else
+ {
+ if (recursive || refreshChildMetadata)
+ {
+ // used below
+ validChildren = Children.ToList();
+ }
+ }
progress.Report(10);
- cancellationToken.ThrowIfCancellationRequested();
-
if (recursive)
{
- await ValidateSubFolders(Children.ToList().OfType<Folder>().ToList(), directoryService, progress, cancellationToken).ConfigureAwait(false);
+ ProviderManager.OnRefreshProgress(this, 10);
}
- progress.Report(20);
+ cancellationToken.ThrowIfCancellationRequested();
- if (refreshChildMetadata)
+ if (recursive)
{
- var container = this as IMetadataContainer;
+ using (var innerProgress = new ActionableProgress<double>())
+ {
+ var folder = this;
+ innerProgress.RegisterAction(p =>
+ {
+ double newPct = .70 * p + 10;
+ progress.Report(newPct);
+ ProviderManager.OnRefreshProgress(folder, newPct);
+ });
- var innerProgress = new ActionableProgress<double>();
+ await ValidateSubFolders(validChildren.OfType<Folder>().ToList(), directoryService, innerProgress, cancellationToken).ConfigureAwait(false);
+ }
+ }
- innerProgress.RegisterAction(p => progress.Report(.80 * p + 20));
+ if (refreshChildMetadata)
+ {
+ progress.Report(80);
- if (container != null)
+ if (recursive)
{
- await container.RefreshAllMetadata(refreshOptions, innerProgress, cancellationToken).ConfigureAwait(false);
+ ProviderManager.OnRefreshProgress(this, 80);
}
- else
+
+ var container = this as IMetadataContainer;
+
+ using (var innerProgress = new ActionableProgress<double>())
{
- await RefreshMetadataRecursive(refreshOptions, recursive, innerProgress, cancellationToken);
+ var folder = this;
+ innerProgress.RegisterAction(p =>
+ {
+ double newPct = .20 * p + 80;
+ progress.Report(newPct);
+ if (recursive)
+ {
+ ProviderManager.OnRefreshProgress(folder, newPct);
+ }
+ });
+
+ if (container != null)
+ {
+ await container.RefreshAllMetadata(refreshOptions, innerProgress, cancellationToken).ConfigureAwait(false);
+ }
+ else
+ {
+ await RefreshMetadataRecursive(validChildren, refreshOptions, recursive, innerProgress, cancellationToken);
+ }
}
}
-
- progress.Report(100);
}
- private async Task RefreshMetadataRecursive(MetadataRefreshOptions refreshOptions, bool recursive, IProgress<double> progress, CancellationToken cancellationToken)
+ private async Task RefreshMetadataRecursive(List<BaseItem> children, MetadataRefreshOptions refreshOptions, bool recursive, IProgress<double> progress, CancellationToken cancellationToken)
{
- var children = Children.ToList();
-
- var percentages = new Dictionary<Guid, double>(children.Count);
var numComplete = 0;
var count = children.Count;
+ double currentPercent = 0;
foreach (var child in children)
{
cancellationToken.ThrowIfCancellationRequested();
- if (child.IsFolder)
+ using (var innerProgress = new ActionableProgress<double>())
{
- var innerProgress = new ActionableProgress<double>();
-
// Avoid implicitly captured closure
- var currentChild = child;
+ var currentInnerPercent = currentPercent;
+
innerProgress.RegisterAction(p =>
{
- lock (percentages)
- {
- percentages[currentChild.Id] = p / 100;
-
- var innerPercent = percentages.Values.Sum();
- innerPercent /= count;
- innerPercent *= 100;
- progress.Report(innerPercent);
- }
+ double innerPercent = currentInnerPercent;
+ innerPercent += p / (count);
+ progress.Report(innerPercent);
});
- await RefreshChildMetadata(child, refreshOptions, recursive, innerProgress, cancellationToken)
- .ConfigureAwait(false);
- }
- else
- {
- await RefreshChildMetadata(child, refreshOptions, false, new Progress<double>(), cancellationToken)
+ await RefreshChildMetadata(child, refreshOptions, recursive && child.IsFolder, innerProgress, cancellationToken)
.ConfigureAwait(false);
}
@@ -501,11 +562,10 @@ namespace MediaBrowser.Controller.Entities
double percent = numComplete;
percent /= count;
percent *= 100;
+ currentPercent = percent;
progress.Report(percent);
}
-
- progress.Report(100);
}
private async Task RefreshChildMetadata(BaseItem child, MetadataRefreshOptions refreshOptions, bool recursive, IProgress<double> progress, CancellationToken cancellationToken)
@@ -526,11 +586,10 @@ namespace MediaBrowser.Controller.Entities
if (folder != null)
{
- await folder.RefreshMetadataRecursive(refreshOptions, true, progress, cancellationToken);
+ await folder.RefreshMetadataRecursive(folder.Children.ToList(), refreshOptions, true, progress, cancellationToken);
}
}
}
- progress.Report(100);
}
/// <summary>
@@ -543,47 +602,40 @@ namespace MediaBrowser.Controller.Entities
/// <returns>Task.</returns>
private async Task ValidateSubFolders(IList<Folder> children, IDirectoryService directoryService, IProgress<double> progress, CancellationToken cancellationToken)
{
- var list = children;
- var childCount = list.Count;
-
- var percentages = new Dictionary<Guid, double>(list.Count);
+ var numComplete = 0;
+ var count = children.Count;
+ double currentPercent = 0;
- foreach (var item in list)
+ foreach (var child in children)
{
cancellationToken.ThrowIfCancellationRequested();
- var child = item;
-
- var innerProgress = new ActionableProgress<double>();
-
- innerProgress.RegisterAction(p =>
+ using (var innerProgress = new ActionableProgress<double>())
{
- lock (percentages)
+ // Avoid implicitly captured closure
+ var currentInnerPercent = currentPercent;
+
+ innerProgress.RegisterAction(p =>
{
- percentages[child.Id] = p / 100;
+ double innerPercent = currentInnerPercent;
+ innerPercent += p / (count);
+ progress.Report(innerPercent);
+ });
- var percent = percentages.Values.Sum();
- percent /= childCount;
+ await child.ValidateChildrenInternal(innerProgress, cancellationToken, true, false, null, directoryService)
+ .ConfigureAwait(false);
+ }
- progress.Report(10 * percent + 10);
- }
- });
+ numComplete++;
+ double percent = numComplete;
+ percent /= count;
+ percent *= 100;
+ currentPercent = percent;
- await child.ValidateChildrenInternal(innerProgress, cancellationToken, true, false, null, directoryService)
- .ConfigureAwait(false);
+ progress.Report(percent);
}
}
- /// <summary>
- /// Determines whether the specified path is offline.
- /// </summary>
- /// <param name="path">The path.</param>
- /// <returns><c>true</c> if the specified path is offline; otherwise, <c>false</c>.</returns>
- public static bool IsPathOffline(string path)
- {
- return IsPathOffline(path, LibraryManager.GetVirtualFolders().SelectMany(i => i.Locations).ToList());
- }
-
public static bool IsPathOffline(string path, List<string> allLibraryPaths)
{
if (FileSystem.FileExists(path))
@@ -926,7 +978,7 @@ namespace MediaBrowser.Controller.Entities
SortBy = query.SortBy,
SortOrder = query.SortOrder
- }, new Progress<double>(), CancellationToken.None).Result;
+ }, new SimpleProgress<double>(), CancellationToken.None).Result;
}
catch
{
diff --git a/MediaBrowser.Controller/Entities/TV/Series.cs b/MediaBrowser.Controller/Entities/TV/Series.cs
index 0b9662450..1e4b3fdad 100644
--- a/MediaBrowser.Controller/Entities/TV/Series.cs
+++ b/MediaBrowser.Controller/Entities/TV/Series.cs
@@ -414,8 +414,6 @@ namespace MediaBrowser.Controller.Entities.TV
refreshOptions = new MetadataRefreshOptions(refreshOptions);
refreshOptions.IsPostRecursiveRefresh = true;
await ProviderManager.RefreshSingleItem(this, refreshOptions, cancellationToken).ConfigureAwait(false);
-
- progress.Report(100);
}
public IEnumerable<Episode> GetSeasonEpisodes(Season parentSeason, User user, DtoOptions options)
diff --git a/MediaBrowser.Controller/Library/ILibraryManager.cs b/MediaBrowser.Controller/Library/ILibraryManager.cs
index 5a702b4f0..b726c267c 100644
--- a/MediaBrowser.Controller/Library/ILibraryManager.cs
+++ b/MediaBrowser.Controller/Library/ILibraryManager.cs
@@ -132,7 +132,9 @@ namespace MediaBrowser.Controller.Library
/// Gets the default view.
/// </summary>
/// <returns>IEnumerable{VirtualFolderInfo}.</returns>
- IEnumerable<VirtualFolderInfo> GetVirtualFolders();
+ List<VirtualFolderInfo> GetVirtualFolders();
+
+ List<VirtualFolderInfo> GetVirtualFolders(bool includeRefreshState);
/// <summary>
/// Gets the item by id.
diff --git a/MediaBrowser.Controller/MediaBrowser.Controller.csproj b/MediaBrowser.Controller/MediaBrowser.Controller.csproj
index 348cfd343..22f94695d 100644
--- a/MediaBrowser.Controller/MediaBrowser.Controller.csproj
+++ b/MediaBrowser.Controller/MediaBrowser.Controller.csproj
@@ -320,7 +320,6 @@
<Compile Include="Plugins\IPluginConfigurationPage.cs" />
<Compile Include="Plugins\IServerEntryPoint.cs" />
<Compile Include="Providers\IImageEnhancer.cs" />
- <Compile Include="Providers\ProviderRefreshStatus.cs" />
<Compile Include="Resolvers\IResolverIgnoreRule.cs" />
<Compile Include="Resolvers\ResolverPriority.cs" />
<Compile Include="Library\TVUtils.cs" />
diff --git a/MediaBrowser.Controller/Providers/IProviderManager.cs b/MediaBrowser.Controller/Providers/IProviderManager.cs
index c0bc90214..0ba573da8 100644
--- a/MediaBrowser.Controller/Providers/IProviderManager.cs
+++ b/MediaBrowser.Controller/Providers/IProviderManager.cs
@@ -9,6 +9,7 @@ using System.Collections.Generic;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
+using MediaBrowser.Model.Events;
namespace MediaBrowser.Controller.Providers
{
@@ -30,7 +31,7 @@ namespace MediaBrowser.Controller.Providers
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task.</returns>
Task RefreshFullItem(IHasMetadata item, MetadataRefreshOptions options, CancellationToken cancellationToken);
-
+
/// <summary>
/// Refreshes the metadata.
/// </summary>
@@ -68,7 +69,7 @@ namespace MediaBrowser.Controller.Providers
/// </summary>
/// <returns>Task.</returns>
Task SaveImage(IHasImages item, string source, string mimeType, ImageType type, int? imageIndex, bool? saveLocallyWithMedia, CancellationToken cancellationToken);
-
+
/// <summary>
/// Adds the metadata providers.
/// </summary>
@@ -128,7 +129,7 @@ namespace MediaBrowser.Controller.Providers
/// <param name="savers">The savers.</param>
/// <returns>Task.</returns>
Task SaveMetadata(IHasMetadata item, ItemUpdateType updateType, IEnumerable<string> savers);
-
+
/// <summary>
/// Gets the metadata options.
/// </summary>
@@ -158,6 +159,18 @@ namespace MediaBrowser.Controller.Providers
/// <param name="cancellationToken">The cancellation token.</param>
/// <returns>Task{HttpResponseInfo}.</returns>
Task<HttpResponseInfo> GetSearchImage(string providerName, string url, CancellationToken cancellationToken);
+
+ Dictionary<Guid, Guid> GetRefreshQueue();
+
+ void OnRefreshStart(BaseItem item);
+ void OnRefreshProgress(BaseItem item, double progress);
+ void OnRefreshComplete(BaseItem item);
+
+ double? GetRefreshProgress(Guid id);
+
+ event EventHandler<GenericEventArgs<BaseItem>> RefreshStarted;
+ event EventHandler<GenericEventArgs<BaseItem>> RefreshCompleted;
+ event EventHandler<GenericEventArgs<Tuple<BaseItem, double>>> RefreshProgress;
}
public enum RefreshPriority
diff --git a/MediaBrowser.Controller/Providers/ProviderRefreshStatus.cs b/MediaBrowser.Controller/Providers/ProviderRefreshStatus.cs
deleted file mode 100644
index 6523dc417..000000000
--- a/MediaBrowser.Controller/Providers/ProviderRefreshStatus.cs
+++ /dev/null
@@ -1,22 +0,0 @@
-
-namespace MediaBrowser.Controller.Providers
-{
- /// <summary>
- /// Enum ProviderRefreshStatus
- /// </summary>
- public enum ProviderRefreshStatus
- {
- /// <summary>
- /// The success
- /// </summary>
- Success = 0,
- /// <summary>
- /// The completed with errors
- /// </summary>
- CompletedWithErrors = 1,
- /// <summary>
- /// The failure
- /// </summary>
- Failure = 2
- }
-}