public async Task Run(IProgress<double> progress, CancellationToken cancellationToken) { var users = _userManager.Users .DistinctBy(ChannelDownloadScheduledTask.GetUserDistinctValue) .Select(i => i.Id.ToString("N")) .ToList(); var numComplete = 0; foreach (var user in users) { double percentPerUser = 1; percentPerUser /= users.Count; var startingPercent = numComplete * percentPerUser * 100; var innerProgress = new ActionableProgress<double>(); innerProgress.RegisterAction(p => progress.Report(startingPercent + (percentPerUser * p))); await DownloadContent(user, cancellationToken, innerProgress).ConfigureAwait(false); numComplete++; double percent = numComplete; percent /= users.Count; progress.Report(percent * 100); } progress.Report(100); }
public async Task Execute(CancellationToken cancellationToken, IProgress<double> progress) { CleanChannelContent(cancellationToken); var users = _userManager.Users.Select(i => i.Id.ToString("N")).ToList(); var numComplete = 0; foreach (var user in users) { double percentPerUser = 1; percentPerUser /= users.Count; var startingPercent = numComplete * percentPerUser * 100; var innerProgress = new ActionableProgress<double>(); innerProgress.RegisterAction(p => progress.Report(startingPercent + (.8 * p))); await DownloadContent(user, cancellationToken, innerProgress).ConfigureAwait(false); numComplete++; double percent = numComplete; percent /= users.Count; progress.Report(percent * 100); } progress.Report(100); }
/// <summary> /// Refreshes the children. /// </summary> /// <param name="children">The children.</param> /// <param name="directoryService">The directory service.</param> /// <param name="progress">The progress.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <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); foreach (var item in list) { cancellationToken.ThrowIfCancellationRequested(); var child = item; var innerProgress = new ActionableProgress <double>(); innerProgress.RegisterAction(p => { lock (percentages) { percentages[child.Id] = p / 100; var percent = percentages.Values.Sum(); percent /= childCount; progress.Report((10 * percent) + 10); } }); await child.ValidateChildrenInternal(innerProgress, cancellationToken, true, false, null, directoryService) .ConfigureAwait(false); } }
public async Task Init(IProgress <double> progress) { progress.Report(1); JsonSerializer = CreateJsonSerializer(); OnLoggerLoaded(true); LogManager.LoggerLoaded += (s, e) => OnLoggerLoaded(false); IsFirstRun = !ConfigurationManager.CommonConfiguration.IsStartupWizardCompleted; progress.Report(2); LogManager.LogSeverity = ConfigurationManager.CommonConfiguration.EnableDebugLevelLogging ? LogSeverity.Debug : LogSeverity.Info; progress.Report(3); DiscoverTypes(); progress.Report(14); SetHttpLimit(); progress.Report(15); var innerProgress = new ActionableProgress <double>(); innerProgress.RegisterAction(p => progress.Report(.8 * p + 15)); await RegisterResources(innerProgress).ConfigureAwait(false); FindParts(); progress.Report(95); progress.Report(100); }
public async Task Execute(CancellationToken cancellationToken, IProgress <double> progress) { CleanChannelContent(cancellationToken); var users = _userManager.Users.Select(i => i.Id.ToString("N")).ToList(); var numComplete = 0; foreach (var user in users) { double percentPerUser = 1; percentPerUser /= users.Count; var startingPercent = numComplete * percentPerUser * 100; var innerProgress = new ActionableProgress <double>(); innerProgress.RegisterAction(p => progress.Report(startingPercent + (percentPerUser * p))); await DownloadContent(user, cancellationToken, innerProgress).ConfigureAwait(false); numComplete++; double percent = numComplete; percent /= users.Count; progress.Report(percent * 100); } progress.Report(100); }
public async Task Sync(IProgress <double> progress, CancellationToken cancellationToken) { await EnsureSyncJobs(cancellationToken).ConfigureAwait(false); // If it already has a converting status then is must have been aborted during conversion var result = _syncRepo.GetJobItems(new SyncJobItemQuery { Statuses = new List <SyncJobItemStatus> { SyncJobItemStatus.Queued, SyncJobItemStatus.Converting } }); var jobItems = result.Items; var index = 0; foreach (var item in jobItems) { double percent = index; percent /= result.TotalRecordCount; progress.Report(100 * percent); cancellationToken.ThrowIfCancellationRequested(); var innerProgress = new ActionableProgress <double>(); var job = _syncRepo.GetJob(item.JobId); await ProcessJobItem(job, item, innerProgress, cancellationToken).ConfigureAwait(false); job = _syncRepo.GetJob(item.JobId); await UpdateJobStatus(job).ConfigureAwait(false); index++; } }
/// <summary> /// Refreshes the children. /// </summary> /// <param name="children">The children.</param> /// <param name="progress">The progress.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <param name="recursive">if set to <c>true</c> [recursive].</param> /// <returns>Task.</returns> private Task RefreshChildren(IEnumerable <Tuple <BaseItem, bool> > children, IProgress <double> progress, CancellationToken cancellationToken, bool?recursive) { var list = children.ToList(); var percentages = new ConcurrentDictionary <Guid, double>(list.Select(i => new KeyValuePair <Guid, double>(i.Item1.Id, 0))); var tasks = list.Select(tuple => Task.Run(async() => { cancellationToken.ThrowIfCancellationRequested(); var child = tuple.Item1; //refresh it await child.RefreshMetadata(cancellationToken, resetResolveArgs: child.IsFolder).ConfigureAwait(false); // Refresh children if a folder and the item changed or recursive is set to true var refreshChildren = child.IsFolder && (tuple.Item2 || (recursive.HasValue && recursive.Value)); if (refreshChildren) { // Don't refresh children if explicitly set to false if (recursive.HasValue && recursive.Value == false) { refreshChildren = false; } } if (refreshChildren) { cancellationToken.ThrowIfCancellationRequested(); var innerProgress = new ActionableProgress <double>(); innerProgress.RegisterAction(p => { percentages.TryUpdate(child.Id, p / 100, percentages[child.Id]); var percent = percentages.Values.Sum(); percent /= list.Count; progress.Report((90 * percent) + 10); }); await((Folder)child).ValidateChildren(innerProgress, cancellationToken, recursive).ConfigureAwait(false); } else { percentages.TryUpdate(child.Id, 1, percentages[child.Id]); var percent = percentages.Values.Sum(); percent /= list.Count; progress.Report((90 * percent) + 10); } })); cancellationToken.ThrowIfCancellationRequested(); return(Task.WhenAll(tasks)); }
public async Task Run(IProgress <double> progress, CancellationToken cancellationToken) { var users = _userManager.Users .DistinctBy(GetUserDistinctValue) .Select(i => i.Id.ToString("N")) .ToList(); var numComplete = 0; foreach (var user in users) { double percentPerUser = 1; percentPerUser /= users.Count; var startingPercent = numComplete * percentPerUser * 100; var innerProgress = new ActionableProgress <double>(); innerProgress.RegisterAction(p => progress.Report(startingPercent + percentPerUser * p)); await DownloadContent(user, cancellationToken, innerProgress).ConfigureAwait(false); numComplete++; double percent = numComplete; percent /= users.Count; progress.Report(percent * 100); } await CleanDatabase(cancellationToken).ConfigureAwait(false); progress.Report(100); }
public async Task Sync(IServerSyncProvider provider, ISyncDataProvider dataProvider, SyncTarget target, IProgress<double> progress, CancellationToken cancellationToken) { var serverId = _appHost.SystemId; var serverName = _appHost.FriendlyName; await SyncData(provider, dataProvider, serverId, target, cancellationToken).ConfigureAwait(false); progress.Report(3); var innerProgress = new ActionableProgress<double>(); innerProgress.RegisterAction(pct => { var totalProgress = pct * .97; totalProgress += 1; progress.Report(totalProgress); }); await GetNewMedia(provider, dataProvider, target, serverId, serverName, innerProgress, cancellationToken); // Do the data sync twice so the server knows what was removed from the device await SyncData(provider, dataProvider, serverId, target, cancellationToken).ConfigureAwait(false); progress.Report(100); }
public async Task Execute(CancellationToken cancellationToken, IProgress <double> progress) { // Ensure these objects are lazy loaded. // Without this there is a deadlock that will need to be investigated var rootChildren = _libraryManager.RootFolder.Children.ToList(); rootChildren = _libraryManager.GetUserRootFolder().Children.ToList(); var innerProgress = new ActionableProgress <double>(); innerProgress.RegisterAction(p => { double newPercentCommplete = .45 * p; progress.Report(newPercentCommplete); }); await CleanDeadItems(cancellationToken, innerProgress).ConfigureAwait(false); progress.Report(45); innerProgress = new ActionableProgress <double>(); innerProgress.RegisterAction(p => { double newPercentCommplete = 45 + .55 * p; progress.Report(newPercentCommplete); }); await _itemRepo.UpdateInheritedValues(cancellationToken).ConfigureAwait(false); progress.Report(100); }
public async Task Sync(IServerSyncProvider provider, ISyncDataProvider dataProvider, SyncTarget target, IProgress <double> progress, CancellationToken cancellationToken) { var serverId = _appHost.SystemId; var serverName = _appHost.FriendlyName; await SyncData(provider, dataProvider, serverId, target, cancellationToken).ConfigureAwait(false); progress.Report(3); var innerProgress = new ActionableProgress <double>(); innerProgress.RegisterAction(pct => { var totalProgress = pct * .97; totalProgress += 1; progress.Report(totalProgress); }); await GetNewMedia(provider, dataProvider, target, serverId, serverName, innerProgress, cancellationToken); // Do the data sync twice so the server knows what was removed from the device await SyncData(provider, dataProvider, serverId, target, cancellationToken).ConfigureAwait(false); progress.Report(100); }
/// <summary> /// Validates the people. /// </summary> /// <param name="cancellationToken">The cancellation token.</param> /// <param name="progress">The progress.</param> /// <returns>Task.</returns> public async Task ValidatePeople(CancellationToken cancellationToken, IProgress <double> progress) { var innerProgress = new ActionableProgress <double>(); innerProgress.RegisterAction(pct => progress.Report(pct * .15)); var peopleOptions = _config.Configuration.PeopleMetadataOptions; var people = _libraryManager.GetAllPeople(); var dict = new Dictionary <string, bool>(StringComparer.OrdinalIgnoreCase); foreach (var person in people) { bool current; if (!dict.TryGetValue(person.Name, out current) || !current) { dict[person.Name] = DownloadMetadata(person, peopleOptions); } } var numComplete = 0; foreach (var person in dict) { cancellationToken.ThrowIfCancellationRequested(); try { var item = _libraryManager.GetPerson(person.Key); var options = new MetadataRefreshOptions { MetadataRefreshMode = person.Value ? MetadataRefreshMode.Default : MetadataRefreshMode.ValidationOnly, ImageRefreshMode = person.Value ? ImageRefreshMode.Default : ImageRefreshMode.ValidationOnly }; await item.RefreshMetadata(options, cancellationToken).ConfigureAwait(false); } catch (Exception ex) { _logger.ErrorException("Error validating IBN entry {0}", ex, person); } // Update progress numComplete++; double percent = numComplete; percent /= people.Count; progress.Report(100 * percent); } progress.Report(100); _logger.Info("People validation complete"); // Bad practice, i know. But we keep a lot in memory, unfortunately. GC.Collect(2, GCCollectionMode.Forced, true); GC.Collect(2, GCCollectionMode.Forced, true); }
/// <summary> /// Validates the people. /// </summary> /// <param name="cancellationToken">The cancellation token.</param> /// <param name="progress">The progress.</param> /// <returns>Task.</returns> public async Task ValidatePeople(CancellationToken cancellationToken, IProgress <double> progress) { var innerProgress = new ActionableProgress <double>(); innerProgress.RegisterAction(pct => progress.Report(pct * .15)); var people = _libraryManager.GetPeople(new InternalPeopleQuery()); var dict = new Dictionary <string, bool>(StringComparer.OrdinalIgnoreCase); foreach (var person in people) { dict[person.Name] = true; } var numComplete = 0; _logger.Debug("Will refresh {0} people", dict.Count); var numPeople = dict.Count; foreach (var person in dict) { cancellationToken.ThrowIfCancellationRequested(); try { var item = _libraryManager.GetPerson(person.Key); var options = new MetadataRefreshOptions(_fileSystem) { ImageRefreshMode = ImageRefreshMode.ValidationOnly, MetadataRefreshMode = MetadataRefreshMode.ValidationOnly }; await item.RefreshMetadata(options, cancellationToken).ConfigureAwait(false); } catch (OperationCanceledException) { throw; } catch (Exception ex) { _logger.ErrorException("Error validating IBN entry {0}", ex, person); } // Update progress numComplete++; double percent = numComplete; percent /= numPeople; progress.Report(100 * percent); } progress.Report(100); _logger.Info("People validation complete"); }
public async Task <FFMpegInfo> GetFFMpegInfo(IProgress <double> progress) { var versionedDirectoryPath = Path.Combine(GetMediaToolsPath(true), FFMpegDownloadInfo.Version); var info = new FFMpegInfo { ProbePath = Path.Combine(versionedDirectoryPath, FFMpegDownloadInfo.FFProbeFilename), Path = Path.Combine(versionedDirectoryPath, FFMpegDownloadInfo.FFMpegFilename), Version = FFMpegDownloadInfo.Version }; Directory.CreateDirectory(versionedDirectoryPath); var tasks = new List <Task>(); double ffmpegPercent = 0; double fontPercent = 0; var syncLock = new object(); if (!File.Exists(info.ProbePath) || !File.Exists(info.Path)) { var ffmpegProgress = new ActionableProgress <double>(); ffmpegProgress.RegisterAction(p => { ffmpegPercent = p; lock (syncLock) { progress.Report((ffmpegPercent / 2) + (fontPercent / 2)); } }); tasks.Add(DownloadFFMpeg(info, ffmpegProgress)); } else { ffmpegPercent = 100; progress.Report(50); } var fontProgress = new ActionableProgress <double>(); fontProgress.RegisterAction(p => { fontPercent = p; lock (syncLock) { progress.Report((ffmpegPercent / 2) + (fontPercent / 2)); } }); tasks.Add(DownloadFonts(versionedDirectoryPath, fontProgress)); await Task.WhenAll(tasks).ConfigureAwait(false); return(info); }
public async Task<FFMpegInfo> GetFFMpegInfo(IProgress<double> progress) { var versionedDirectoryPath = Path.Combine(GetMediaToolsPath(true), FFMpegDownloadInfo.Version); var info = new FFMpegInfo { ProbePath = Path.Combine(versionedDirectoryPath, FFMpegDownloadInfo.FFProbeFilename), Path = Path.Combine(versionedDirectoryPath, FFMpegDownloadInfo.FFMpegFilename), Version = FFMpegDownloadInfo.Version }; Directory.CreateDirectory(versionedDirectoryPath); var tasks = new List<Task>(); double ffmpegPercent = 0; double fontPercent = 0; var syncLock = new object(); if (!File.Exists(info.ProbePath) || !File.Exists(info.Path)) { var ffmpegProgress = new ActionableProgress<double>(); ffmpegProgress.RegisterAction(p => { ffmpegPercent = p; lock (syncLock) { progress.Report((ffmpegPercent / 2) + (fontPercent / 2)); } }); tasks.Add(DownloadFFMpeg(info, ffmpegProgress)); } else { ffmpegPercent = 100; progress.Report(50); } var fontProgress = new ActionableProgress<double>(); fontProgress.RegisterAction(p => { fontPercent = p; lock (syncLock) { progress.Report((ffmpegPercent / 2) + (fontPercent / 2)); } }); tasks.Add(DownloadFonts(versionedDirectoryPath, fontProgress)); await Task.WhenAll(tasks).ConfigureAwait(false); return info; }
/// <summary> /// Runs the specified progress. /// </summary> /// <param name="progress">The progress.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns>Task.</returns> public async Task Run(IProgress<double> progress, CancellationToken cancellationToken) { var allItems = _libraryManager.RootFolder.GetRecursiveChildren(); var allSongs = allItems.OfType<Audio>().ToList(); var innerProgress = new ActionableProgress<double>(); innerProgress.RegisterAction(pct => progress.Report(pct * .8)); var allArtists = await GetAllArtists(allSongs, cancellationToken, innerProgress).ConfigureAwait(false); progress.Report(80); var numComplete = 0; var userLibraries = _userManager.Users .Select(i => new Tuple<Guid, List<IHasArtist>>(i.Id, i.RootFolder.GetRecursiveChildren(i).OfType<IHasArtist>().ToList())) .ToList(); var numArtists = allArtists.Count; foreach (var artist in allArtists) { cancellationToken.ThrowIfCancellationRequested(); // Only do this for artists accessed by name. Folder-based artists use ArtistInfoFromSongsProvider if (artist.IsAccessedByName && !artist.LockedFields.Contains(MetadataFields.Genres)) { // Avoid implicitly captured closure var artist1 = artist; artist.Genres = allSongs.Where(i => i.HasArtist(artist1.Name)) .SelectMany(i => i.Genres) .Distinct(StringComparer.OrdinalIgnoreCase) .ToList(); } // Populate counts of items //SetItemCounts(artist, null, allItems.OfType<IHasArtist>()); foreach (var lib in userLibraries) { SetItemCounts(artist, lib.Item1, lib.Item2); } numComplete++; double percent = numComplete; percent /= numArtists; percent *= 20; progress.Report(80 + percent); } progress.Report(100); }
public async Task Execute(CancellationToken cancellationToken, IProgress <double> progress) { var playlists = Plugin.Instance.Configuration.Playlists; await Cleanup(playlists, cancellationToken); // No point going further if we don't have users. if (playlists.Length == 0) { _logger.Info("No internal playlists added"); return; } _logger.Info("Library sync started"); var existingPlaylists = _libraryManager.GetUserRootFolder() .RecursiveChildren.OfType <VodPlaylist>() .Where(p1 => playlists.FirstOrDefault(p2 => p2.IdentifierId == p1.IdentifierId) != null) .ToList(); var i = 1; foreach (PlaylistConfig playlistConfig in playlists) { var playlist = playlistConfig.ToPlaylist(); progress.Report((i / playlists.Length) * 100); var existingPlaylist = existingPlaylists.FirstOrDefault(p1 => p1.IdentifierId == playlist.IdentifierId); if (existingPlaylist != null) { // UPDATE _logger.Debug("{0}: playlist with id {1} and identifier {2} found, updating...", existingPlaylist.Name, existingPlaylist.Id, existingPlaylist.IdentifierId); await existingPlaylist.Merge(existingPlaylist); } else { // CREATE _logger.Debug("{0}: playlist with identifier {1} not found, creating...", playlist.Name, playlist.IdentifierId); playlist.Id = _libraryManager.GetNewItemId(playlist.IdentifierId.ToString(), typeof(VodPlaylist)); await _libraryManager.GetUserRootFolder().AddChild(playlist, cancellationToken).ConfigureAwait(false); } var innerProgress = new ActionableProgress <double>(); // Avoid implicitly captured closure innerProgress.RegisterAction(progress.Report); await SyncMedia(playlist, innerProgress, cancellationToken).ConfigureAwait(false); i++; } progress.Report(100); _libraryManager.QueueLibraryScan(); }
/// <summary> /// Inits this instance. /// </summary> /// <returns>Task.</returns> public virtual async Task Init(IProgress <double> progress) { try { // https://github.com/ServiceStack/ServiceStack/blob/master/tests/ServiceStack.WebHost.IntegrationTests/Web.config#L4 Licensing.RegisterLicense("1001-e1JlZjoxMDAxLE5hbWU6VGVzdCBCdXNpbmVzcyxUeXBlOkJ1c2luZXNzLEhhc2g6UHVNTVRPclhvT2ZIbjQ5MG5LZE1mUTd5RUMzQnBucTFEbTE3TDczVEF4QUNMT1FhNXJMOWkzVjFGL2ZkVTE3Q2pDNENqTkQyUktRWmhvUVBhYTBiekJGUUZ3ZE5aZHFDYm9hL3lydGlwUHI5K1JsaTBYbzNsUC85cjVJNHE5QVhldDN6QkE4aTlvdldrdTgyTk1relY2eis2dFFqTThYN2lmc0JveHgycFdjPSxFeHBpcnk6MjAxMy0wMS0wMX0="); } catch { // Failing under mono } progress.Report(1); JsonSerializer = CreateJsonSerializer(); if (Environment.OSVersion.Platform == PlatformID.Win32NT) { MemoryStreamProvider = new RecyclableMemoryStreamProvider(); } else { MemoryStreamProvider = new MemoryStreamProvider(); } OnLoggerLoaded(true); LogManager.LoggerLoaded += (s, e) => OnLoggerLoaded(false); IsFirstRun = !ConfigurationManager.CommonConfiguration.IsStartupWizardCompleted; progress.Report(2); LogManager.LogSeverity = ConfigurationManager.CommonConfiguration.EnableDebugLevelLogging ? LogSeverity.Debug : LogSeverity.Info; progress.Report(3); DiscoverTypes(); progress.Report(14); SetHttpLimit(); progress.Report(15); var innerProgress = new ActionableProgress <double>(); innerProgress.RegisterAction(p => progress.Report(.8 * p + 15)); await RegisterResources(innerProgress).ConfigureAwait(false); FindParts(); progress.Report(95); await InstallIsoMounters(CancellationToken.None).ConfigureAwait(false); progress.Report(100); }
/// <summary> /// Runs the specified progress. /// </summary> /// <param name="progress">The progress.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns>Task.</returns> public async Task Run(IProgress <double> progress, CancellationToken cancellationToken) { var allItems = _libraryManager.RootFolder.GetRecursiveChildren(); var allSongs = allItems.OfType <Audio>().ToList(); var innerProgress = new ActionableProgress <double>(); innerProgress.RegisterAction(pct => progress.Report(pct * .8)); var allArtists = await GetAllArtists(allSongs, cancellationToken, innerProgress).ConfigureAwait(false); progress.Report(80); var numComplete = 0; var userLibraries = _userManager.Users .Select(i => new Tuple <Guid, List <IHasArtist> >(i.Id, i.RootFolder.GetRecursiveChildren(i).OfType <IHasArtist>().ToList())) .ToList(); var numArtists = allArtists.Count; foreach (var artist in allArtists) { cancellationToken.ThrowIfCancellationRequested(); // Only do this for artists accessed by name. Folder-based artists get it from the normal refresh if (artist.IsAccessedByName && !artist.LockedFields.Contains(MetadataFields.Genres)) { // Avoid implicitly captured closure var artist1 = artist; artist.Genres = allSongs.Where(i => i.HasArtist(artist1.Name)) .SelectMany(i => i.Genres) .Distinct(StringComparer.OrdinalIgnoreCase) .ToList(); } foreach (var lib in userLibraries) { SetItemCounts(artist, lib.Item1, lib.Item2); } numComplete++; double percent = numComplete; percent /= numArtists; percent *= 20; progress.Report(80 + percent); } progress.Report(100); }
private async Task RefreshMetadataRecursive(MetadataRefreshOptions refreshOptions, bool recursive, IProgress <double> progress, CancellationToken cancellationToken) { var children = ActualChildren.ToList(); var percentages = new Dictionary <Guid, double>(children.Count); var tasks = new List <Task>(); foreach (var child in children) { if (tasks.Count >= 3) { await Task.WhenAll(tasks).ConfigureAwait(false); tasks.Clear(); } cancellationToken.ThrowIfCancellationRequested(); var innerProgress = new ActionableProgress <double>(); // Avoid implicitly captured closure var currentChild = child; innerProgress.RegisterAction(p => { lock (percentages) { percentages[currentChild.Id] = p / 100; var percent = percentages.Values.Sum(); percent /= children.Count; percent *= 100; progress.Report(percent); } }); if (child.IsFolder) { await RefreshChildMetadata(child, refreshOptions, recursive, innerProgress, cancellationToken) .ConfigureAwait(false); } else { // Avoid implicitly captured closure var taskChild = child; tasks.Add(Task.Run(async() => await RefreshChildMetadata(taskChild, refreshOptions, false, innerProgress, cancellationToken).ConfigureAwait(false), cancellationToken)); } } await Task.WhenAll(tasks).ConfigureAwait(false); progress.Report(100); }
public async Task RefreshAllMetadata(MetadataRefreshOptions refreshOptions, IProgress <double> progress, CancellationToken cancellationToken) { // Refresh bottom up, children first, then the boxset // By then hopefully the movies within will have Tmdb collection values var items = RecursiveChildren.ToList(); var totalItems = items.Count; var percentages = new Dictionary <Guid, double>(totalItems); var tasks = new List <Task>(); // Refresh songs foreach (var item in items) { if (tasks.Count >= 3) { await Task.WhenAll(tasks).ConfigureAwait(false); tasks.Clear(); } cancellationToken.ThrowIfCancellationRequested(); var innerProgress = new ActionableProgress <double>(); // Avoid implicitly captured closure var currentChild = item; innerProgress.RegisterAction(p => { lock (percentages) { percentages[currentChild.Id] = p / 100; var percent = percentages.Values.Sum(); percent /= totalItems; percent *= 100; progress.Report(percent); } }); // Avoid implicitly captured closure var taskChild = item; tasks.Add(Task.Run(async() => await RefreshItem(taskChild, refreshOptions, innerProgress, cancellationToken).ConfigureAwait(false), cancellationToken)); } await Task.WhenAll(tasks).ConfigureAwait(false); tasks.Clear(); // Refresh current item await RefreshMetadata(refreshOptions, cancellationToken).ConfigureAwait(false); progress.Report(100); }
/// <summary> /// Runs the specified progress. /// </summary> /// <param name="progress">The progress.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns>Task.</returns> public async Task Run(IProgress <double> progress, CancellationToken cancellationToken) { var allItems = _libraryManager.RootFolder.RecursiveChildren.ToList(); var allArtists = await GetAllArtists(allItems).ConfigureAwait(false); progress.Report(10); var allMusicArtists = allItems.OfType <MusicArtist>().ToList(); var allSongs = allItems.OfType <Audio>().ToList(); var numComplete = 0; foreach (var artist in allArtists) { var musicArtist = FindMusicArtist(artist, allMusicArtists); if (musicArtist != null) { artist.Images = new Dictionary <ImageType, string>(musicArtist.Images); artist.BackdropImagePaths = musicArtist.BackdropImagePaths.ToList(); artist.ScreenshotImagePaths = musicArtist.ScreenshotImagePaths.ToList(); artist.SetProviderId(MetadataProviders.Musicbrainz, musicArtist.GetProviderId(MetadataProviders.Musicbrainz)); artist.Genres = musicArtist.Genres.ToList(); } else { // Avoid implicitly captured closure var artist1 = artist; artist.Genres = allSongs.Where(i => i.HasArtist(artist1.Name)) .SelectMany(i => i.Genres) .Distinct(StringComparer.OrdinalIgnoreCase) .ToList(); } numComplete++; double percent = numComplete; percent /= allArtists.Length; percent *= 5; progress.Report(10 + percent); } var innerProgress = new ActionableProgress <double>(); innerProgress.RegisterAction(pct => progress.Report(15 + pct * .85)); await _libraryManager.ValidateArtists(cancellationToken, innerProgress).ConfigureAwait(false); }
/// <summary> /// Runs the specified progress. /// </summary> /// <param name="progress">The progress.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns>Task.</returns> public async Task Run(IProgress<double> progress, CancellationToken cancellationToken) { var allItems = _libraryManager.RootFolder.RecursiveChildren.ToList(); var allArtists = await GetAllArtists(allItems).ConfigureAwait(false); progress.Report(10); var allMusicArtists = allItems.OfType<MusicArtist>().ToList(); var allSongs = allItems.OfType<Audio>().ToList(); var numComplete = 0; foreach (var artist in allArtists) { var musicArtist = FindMusicArtist(artist, allMusicArtists); if (musicArtist != null) { artist.Images = new Dictionary<ImageType, string>(musicArtist.Images); artist.BackdropImagePaths = musicArtist.BackdropImagePaths.ToList(); artist.ScreenshotImagePaths = musicArtist.ScreenshotImagePaths.ToList(); artist.SetProviderId(MetadataProviders.Musicbrainz, musicArtist.GetProviderId(MetadataProviders.Musicbrainz)); artist.Genres = musicArtist.Genres.ToList(); } else { // Avoid implicitly captured closure var artist1 = artist; artist.Genres = allSongs.Where(i => i.HasArtist(artist1.Name)) .SelectMany(i => i.Genres) .Distinct(StringComparer.OrdinalIgnoreCase) .ToList(); } numComplete++; double percent = numComplete; percent /= allArtists.Length; percent *= 5; progress.Report(10 + percent); } var innerProgress = new ActionableProgress<double>(); innerProgress.RegisterAction(pct => progress.Report(15 + pct * .85)); await _libraryManager.ValidateArtists(cancellationToken, innerProgress).ConfigureAwait(false); }
private async Task DownloadContent(string user, CancellationToken cancellationToken, IProgress <double> progress) { var channels = await _channelManager.GetChannelsInternal(new ChannelQuery { UserId = user }, cancellationToken); var numComplete = 0; var numItems = channels.Items.Length; foreach (var channel in channels.Items) { var channelId = channel.Id.ToString("N"); var features = _channelManager.GetChannelFeatures(channelId); const int currentRefreshLevel = 1; var maxRefreshLevel = features.AutoRefreshLevels ?? 0; maxRefreshLevel = Math.Max(maxRefreshLevel, 2); if (maxRefreshLevel > 0) { var innerProgress = new ActionableProgress <double>(); var startingNumberComplete = numComplete; innerProgress.RegisterAction(p => { double innerPercent = startingNumberComplete; innerPercent += (p / 100); innerPercent /= numItems; progress.Report(innerPercent * 100); }); try { await GetAllItems(user, channelId, null, currentRefreshLevel, maxRefreshLevel, innerProgress, cancellationToken).ConfigureAwait(false); } catch (Exception ex) { _logger.ErrorException("Error getting channel content", ex); } } numComplete++; double percent = numComplete; percent /= numItems; progress.Report(percent * 100); } progress.Report(100); }
private async Task DownloadContent(string user, CancellationToken cancellationToken, IProgress<double> progress) { var channels = await _channelManager.GetChannelsInternal(new ChannelQuery { UserId = user }, cancellationToken); var numComplete = 0; var numItems = channels.Items.Length; foreach (var channel in channels.Items) { var channelId = channel.Id.ToString("N"); var features = _channelManager.GetChannelFeatures(channelId); const int currentRefreshLevel = 1; var maxRefreshLevel = features.AutoRefreshLevels ?? 0; if (maxRefreshLevel > 0) { var innerProgress = new ActionableProgress<double>(); var startingNumberComplete = numComplete; innerProgress.RegisterAction(p => { double innerPercent = startingNumberComplete; innerPercent += (p / 100); innerPercent /= numItems; progress.Report(innerPercent * 100); }); try { await GetAllItems(user, channelId, null, currentRefreshLevel, maxRefreshLevel, innerProgress, cancellationToken).ConfigureAwait(false); } catch (Exception ex) { _logger.ErrorException("Error getting channel content", ex); } } numComplete++; double percent = numComplete; percent /= numItems; progress.Report(percent * 100); } progress.Report(100); }
public async Task Execute(CancellationToken cancellationToken, IProgress<double> progress) { var innerProgress = new ActionableProgress<double>(); innerProgress.RegisterAction(p => progress.Report(.95 * p)); await UpdateToLatestSchema(cancellationToken, innerProgress).ConfigureAwait(false); innerProgress = new ActionableProgress<double>(); innerProgress.RegisterAction(p => progress.Report(95 + (.05 * p))); //await CleanDeadItems(cancellationToken, innerProgress).ConfigureAwait(false); progress.Report(100); }
/// <summary> /// Inits this instance. /// </summary> /// <returns>Task.</returns> public virtual async Task Init(IProgress <double> progress) { try { // https://github.com/ServiceStack/ServiceStack/blob/master/tests/ServiceStack.WebHost.IntegrationTests/Web.config#L4 Licensing.RegisterLicense("1001-e1JlZjoxMDAxLE5hbWU6VGVzdCBCdXNpbmVzcyxUeXBlOkJ1c2luZXNzLEhhc2g6UHVNTVRPclhvT2ZIbjQ5MG5LZE1mUTd5RUMzQnBucTFEbTE3TDczVEF4QUNMT1FhNXJMOWkzVjFGL2ZkVTE3Q2pDNENqTkQyUktRWmhvUVBhYTBiekJGUUZ3ZE5aZHFDYm9hL3lydGlwUHI5K1JsaTBYbzNsUC85cjVJNHE5QVhldDN6QkE4aTlvdldrdTgyTk1relY2eis2dFFqTThYN2lmc0JveHgycFdjPSxFeHBpcnk6MjAxMy0wMS0wMX0="); } catch { // Failing under mono } progress.Report(1); JsonSerializer = CreateJsonSerializer(); Logger = LogManager.GetLogger("App"); IsFirstRun = !ConfigurationManager.CommonConfiguration.IsStartupWizardCompleted; progress.Report(2); LogManager.LogSeverity = ConfigurationManager.CommonConfiguration.EnableDebugLevelLogging ? LogSeverity.Debug : LogSeverity.Info; // Put the app config in the log for troubleshooting purposes Logger.LogMultiline("Application Configuration:", LogSeverity.Info, new StringBuilder(JsonSerializer.SerializeToString(ConfigurationManager.CommonConfiguration))); progress.Report(3); DiscoverTypes(); progress.Report(14); Logger.Info("Version {0} initializing", ApplicationVersion); SetHttpLimit(); progress.Report(15); var innerProgress = new ActionableProgress <double>(); innerProgress.RegisterAction(p => progress.Report((.8 * p) + 15)); await RegisterResources(innerProgress).ConfigureAwait(false); FindParts(); progress.Report(95); await InstallIsoMounters(CancellationToken.None).ConfigureAwait(false); progress.Report(100); }
private async Task RefreshMetadataRecursive(MetadataRefreshOptions refreshOptions, bool recursive, IProgress <double> progress, CancellationToken cancellationToken) { var children = ActualChildren.ToList(); var percentages = new Dictionary <Guid, double>(children.Count); var numComplete = 0; var count = children.Count; foreach (var child in children) { cancellationToken.ThrowIfCancellationRequested(); if (child.IsFolder) { var innerProgress = new ActionableProgress <double>(); // Avoid implicitly captured closure var currentChild = child; innerProgress.RegisterAction(p => { lock (percentages) { percentages[currentChild.Id] = p / 100; var innerPercent = percentages.Values.Sum(); innerPercent /= count; innerPercent *= 100; progress.Report(innerPercent); } }); await RefreshChildMetadata(child, refreshOptions, recursive, innerProgress, cancellationToken) .ConfigureAwait(false); } else { await RefreshChildMetadata(child, refreshOptions, false, new Progress <double>(), cancellationToken) .ConfigureAwait(false); } numComplete++; double percent = numComplete; percent /= count; percent *= 100; progress.Report(percent); } progress.Report(100); }
/// <summary> /// Validates the people. /// </summary> /// <param name="cancellationToken">The cancellation token.</param> /// <param name="progress">The progress.</param> /// <returns>Task.</returns> public async Task ValidatePeople(CancellationToken cancellationToken, IProgress<double> progress) { var innerProgress = new ActionableProgress<double>(); innerProgress.RegisterAction(pct => progress.Report(pct * .15)); // Run prescan tasks await RunPrescanTasks(innerProgress, cancellationToken).ConfigureAwait(false); progress.Report(15); var people = _libraryManager.RootFolder.GetRecursiveChildren() .SelectMany(c => c.People) .DistinctBy(p => p.Name, StringComparer.OrdinalIgnoreCase) .ToList(); var numComplete = 0; foreach (var person in people) { cancellationToken.ThrowIfCancellationRequested(); try { var item = _libraryManager.GetPerson(person.Name); await item.RefreshMetadata(cancellationToken).ConfigureAwait(false); } catch (Exception ex) { _logger.ErrorException("Error validating IBN entry {0}", ex, person.Name); } // Update progress numComplete++; double percent = numComplete; percent /= people.Count; progress.Report(15 + 85 * percent); } progress.Report(100); _logger.Info("People validation complete"); // Bad practice, i know. But we keep a lot in memory, unfortunately. GC.Collect(2, GCCollectionMode.Forced, true); GC.Collect(2, GCCollectionMode.Forced, true); }
/// <summary> /// Validates the people. /// </summary> /// <param name="cancellationToken">The cancellation token.</param> /// <param name="progress">The progress.</param> /// <returns>Task.</returns> public async Task ValidatePeople(CancellationToken cancellationToken, IProgress <double> progress) { var innerProgress = new ActionableProgress <double>(); innerProgress.RegisterAction(pct => progress.Report(pct * .15)); // Run prescan tasks await RunPrescanTasks(innerProgress, cancellationToken).ConfigureAwait(false); progress.Report(15); var people = _libraryManager.RootFolder.GetRecursiveChildren() .SelectMany(c => c.People) .DistinctBy(p => p.Name, StringComparer.OrdinalIgnoreCase) .ToList(); var numComplete = 0; foreach (var person in people) { cancellationToken.ThrowIfCancellationRequested(); try { var item = _libraryManager.GetPerson(person.Name); await item.RefreshMetadata(cancellationToken).ConfigureAwait(false); } catch (Exception ex) { _logger.ErrorException("Error validating IBN entry {0}", ex, person.Name); } // Update progress numComplete++; double percent = numComplete; percent /= people.Count; progress.Report(15 + 85 * percent); } progress.Report(100); _logger.Info("People validation complete"); // Bad practice, i know. But we keep a lot in memory, unfortunately. GC.Collect(2, GCCollectionMode.Forced, true); GC.Collect(2, GCCollectionMode.Forced, true); }
public async Task Execute(CancellationToken cancellationToken, IProgress <double> progress) { var innerProgress = new ActionableProgress <double>(); innerProgress.RegisterAction(p => progress.Report(.95 * p)); await UpdateToLatestSchema(cancellationToken, innerProgress).ConfigureAwait(false); innerProgress = new ActionableProgress <double>(); innerProgress.RegisterAction(p => progress.Report(95 + (.05 * p))); //await CleanDeadItems(cancellationToken, innerProgress).ConfigureAwait(false); progress.Report(100); }
private async Task GetNewMedia(IServerSyncProvider provider, ISyncDataProvider dataProvider, SyncTarget target, string serverId, string serverName, IProgress <double> progress, CancellationToken cancellationToken) { var jobItems = await _syncManager.GetReadySyncItems(target.Id).ConfigureAwait(false); var numComplete = 0; double startingPercent = 0; double percentPerItem = 1; if (jobItems.Count > 0) { percentPerItem /= jobItems.Count; } foreach (var jobItem in jobItems) { cancellationToken.ThrowIfCancellationRequested(); var currentPercent = startingPercent; var innerProgress = new ActionableProgress <double>(); innerProgress.RegisterAction(pct => { var totalProgress = pct * percentPerItem; totalProgress += currentPercent; progress.Report(totalProgress); }); try { await GetItem(provider, dataProvider, target, serverId, serverName, jobItem, innerProgress, cancellationToken).ConfigureAwait(false); } catch (Exception ex) { _logger.ErrorException("Error syncing item", ex); } numComplete++; startingPercent = numComplete; startingPercent /= jobItems.Count; startingPercent *= 100; progress.Report(startingPercent); } }
private async Task GetItem(IServerSyncProvider provider, SyncTarget target, string serverId, SyncedItem jobItem, IProgress <double> progress, CancellationToken cancellationToken) { var libraryItem = jobItem.Item; var internalSyncJobItem = _syncManager.GetJobItem(jobItem.SyncJobItemId); var fileTransferProgress = new ActionableProgress <double>(); fileTransferProgress.RegisterAction(pct => progress.Report(pct * .92)); await _syncManager.ReportSyncJobItemTransferBeginning(internalSyncJobItem.Id); var transferSuccess = false; Exception transferException = null; try { //await provider.TransferItemFile(serverId, libraryItem.Id, internalSyncJobItem.OutputPath, target, cancellationToken) // .ConfigureAwait(false); progress.Report(92); transferSuccess = true; progress.Report(99); } catch (Exception ex) { _logger.ErrorException("Error transferring sync job file", ex); transferException = ex; } if (transferSuccess) { await _syncManager.ReportSyncJobItemTransferred(jobItem.SyncJobItemId).ConfigureAwait(false); } else { await _syncManager.ReportSyncJobItemTransferFailed(jobItem.SyncJobItemId).ConfigureAwait(false); throw transferException; } }
private async Task DownloadContent(string user, CancellationToken cancellationToken, IProgress <double> progress) { var innerProgress = new ActionableProgress <double>(); innerProgress.RegisterAction(p => progress.Report(0 + (.8 * p))); await DownloadAllChannelContent(user, cancellationToken, innerProgress).ConfigureAwait(false); progress.Report(80); innerProgress = new ActionableProgress <double>(); innerProgress.RegisterAction(p => progress.Report(80 + (.2 * p))); await DownloadLatestChannelContent(user, cancellationToken, progress).ConfigureAwait(false); progress.Report(100); }
public async Task SyncJobItems(SyncJobItem[] items, bool enableConversion, IProgress <double> progress, CancellationToken cancellationToken) { if (items.Length > 0) { if (!SyncRegistrationInfo.Instance.IsRegistered) { _logger.Debug("Cancelling sync job processing. Please obtain a supporter membership."); return; } } var numComplete = 0; foreach (var item in items) { cancellationToken.ThrowIfCancellationRequested(); double percentPerItem = 1; percentPerItem /= items.Length; var startingPercent = numComplete * percentPerItem * 100; var innerProgress = new ActionableProgress <double>(); innerProgress.RegisterAction(p => progress.Report(startingPercent + (percentPerItem * p))); // Pull it fresh from the db just to make sure it wasn't deleted or cancelled while another item was converting var jobItem = enableConversion ? _syncRepo.GetJobItem(item.Id) : item; if (jobItem != null) { var job = _syncRepo.GetJob(jobItem.JobId); if (jobItem.Status != SyncJobItemStatus.Cancelled) { await ProcessJobItem(job, jobItem, enableConversion, innerProgress, cancellationToken).ConfigureAwait(false); } job = _syncRepo.GetJob(jobItem.JobId); await UpdateJobStatus(job).ConfigureAwait(false); } numComplete++; double percent = numComplete; percent /= items.Length; progress.Report(100 * percent); } }
/// <summary> /// Runs the specified progress. /// </summary> /// <param name="progress">The progress.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns>Task.</returns> public async Task Run(IProgress<double> progress, CancellationToken cancellationToken) { var allItems = _libraryManager.RootFolder.GetRecursiveChildren(); var allSongs = allItems.OfType<Audio>().ToList(); var innerProgress = new ActionableProgress<double>(); innerProgress.RegisterAction(pct => progress.Report(pct * .8)); var allArtists = await GetAllArtists(allSongs, cancellationToken, innerProgress).ConfigureAwait(false); progress.Report(80); var numComplete = 0; var numArtists = allArtists.Count; foreach (var artist in allArtists) { cancellationToken.ThrowIfCancellationRequested(); // Only do this for artists accessed by name. Folder-based artists get it from the normal refresh if (artist.IsAccessedByName && !artist.LockedFields.Contains(MetadataFields.Genres)) { // Avoid implicitly captured closure var artist1 = artist; artist.Genres = allSongs.Where(i => i.HasArtist(artist1.Name)) .SelectMany(i => i.Genres) .Distinct(StringComparer.OrdinalIgnoreCase) .ToList(); } numComplete++; double percent = numComplete; percent /= numArtists; percent *= 20; progress.Report(80 + percent); } progress.Report(100); }
/// <summary> /// Runs the prescan tasks. /// </summary> /// <param name="progress">The progress.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns>Task.</returns> private async Task RunPrescanTasks(IProgress <double> progress, CancellationToken cancellationToken) { var tasks = _prescanTasks.ToList(); var numComplete = 0; var numTasks = tasks.Count; foreach (var task in tasks) { var innerProgress = new ActionableProgress <double>(); // Prevent access to modified closure var currentNumComplete = numComplete; innerProgress.RegisterAction(pct => { double innerPercent = (currentNumComplete * 100) + pct; innerPercent /= numTasks; progress.Report(innerPercent); }); try { await task.Run(innerProgress, cancellationToken); } catch (OperationCanceledException) { _logger.Info("Pre-scan task cancelled: {0}", task.GetType().Name); break; } catch (Exception ex) { _logger.ErrorException("Error running pre-scan task", ex); } numComplete++; double percent = numComplete; percent /= numTasks; progress.Report(percent * 100); } progress.Report(100); }
private async Task DownloadAllChannelContent(string userId, CancellationToken cancellationToken, IProgress <double> progress) { var result = await _manager.GetAllMedia(new AllChannelMediaQuery { UserId = userId }, cancellationToken).ConfigureAwait(false); progress.Report(5); var innerProgress = new ActionableProgress <double>(); innerProgress.RegisterAction(p => progress.Report(5 + (.95 * p))); var path = _manager.ChannelDownloadPath; await DownloadChannelContent(result, path, cancellationToken, innerProgress).ConfigureAwait(false); }
/// <summary> /// Runs the specified progress. /// </summary> /// <param name="progress">The progress.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns>Task.</returns> public async Task Run(IProgress<double> progress, CancellationToken cancellationToken) { if (!_config.Configuration.EnableInternetProviders && !_config.Configuration.EnableTmdbUpdates) { progress.Report(100); return; } var innerProgress = new ActionableProgress<double>(); innerProgress.RegisterAction(pct => progress.Report(pct * .8)); await Run(innerProgress, false, cancellationToken).ConfigureAwait(false); progress.Report(80); //innerProgress = new ActionableProgress<double>(); //innerProgress.RegisterAction(pct => progress.Report(80 + pct * .2)); //await Run(innerProgress, true, cancellationToken).ConfigureAwait(false); progress.Report(100); }
public async Task Sync(IEnumerable <IServerSyncProvider> providers, IProgress <double> progress, CancellationToken cancellationToken) { var targets = providers .SelectMany(i => i.GetAllSyncTargets().Select(t => new Tuple <IServerSyncProvider, SyncTarget>(i, t))) .ToList(); var numComplete = 0; double startingPercent = 0; double percentPerItem = 1; if (targets.Count > 0) { percentPerItem /= targets.Count; } foreach (var target in targets) { cancellationToken.ThrowIfCancellationRequested(); var currentPercent = startingPercent; var innerProgress = new ActionableProgress <double>(); innerProgress.RegisterAction(pct => { var totalProgress = pct * percentPerItem; totalProgress += currentPercent; progress.Report(totalProgress); }); var dataProvider = _syncManager.GetDataProvider(target.Item1, target.Item2); await new MediaSync(_logger, _syncManager, _appHost, _fileSystem) .Sync(target.Item1, dataProvider, target.Item2, innerProgress, cancellationToken) .ConfigureAwait(false); numComplete++; startingPercent = numComplete; startingPercent /= targets.Count; startingPercent *= 100; progress.Report(startingPercent); } }
/// <summary> /// Runs the specified progress. /// </summary> /// <param name="progress">The progress.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns>Task.</returns> public async Task Run(IProgress <double> progress, CancellationToken cancellationToken) { if (!_config.Configuration.EnableInternetProviders) { progress.Report(100); return; } var innerProgress = new ActionableProgress <double>(); innerProgress.RegisterAction(pct => progress.Report(pct * .8)); await Run(innerProgress, false, cancellationToken).ConfigureAwait(false); progress.Report(80); //innerProgress = new ActionableProgress<double>(); //innerProgress.RegisterAction(pct => progress.Report(80 + pct * .2)); //await Run(innerProgress, true, cancellationToken).ConfigureAwait(false); progress.Report(100); }
public async Task Sync(IEnumerable<IServerSyncProvider> providers, IProgress<double> progress, CancellationToken cancellationToken) { var targets = providers .SelectMany(i => i.GetAllSyncTargets().Select(t => new Tuple<IServerSyncProvider, SyncTarget>(i, t))) .ToList(); var numComplete = 0; double startingPercent = 0; double percentPerItem = 1; if (targets.Count > 0) { percentPerItem /= targets.Count; } foreach (var target in targets) { cancellationToken.ThrowIfCancellationRequested(); var currentPercent = startingPercent; var innerProgress = new ActionableProgress<double>(); innerProgress.RegisterAction(pct => { var totalProgress = pct * percentPerItem; totalProgress += currentPercent; progress.Report(totalProgress); }); var dataProvider = _syncManager.GetDataProvider(target.Item1, target.Item2); await new MediaSync(_logger, _syncManager, _appHost, _fileSystem, _config) .Sync(target.Item1, dataProvider, target.Item2, innerProgress, cancellationToken) .ConfigureAwait(false); numComplete++; startingPercent = numComplete; startingPercent /= targets.Count; startingPercent *= 100; progress.Report(startingPercent); } }
/// <summary> /// Runs the specified progress. /// </summary> /// <param name="progress">The progress.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns>Task.</returns> public async Task Run(IProgress<double> progress, CancellationToken cancellationToken) { var allItems = _libraryManager.RootFolder.RecursiveChildren.ToList(); var allArtists = await GetAllArtists(allItems).ConfigureAwait(false); progress.Report(10); var allMusicArtists = allItems.OfType<MusicArtist>().ToList(); var numComplete = 0; foreach (var artist in allArtists) { var musicArtist = FindMusicArtist(artist, allMusicArtists); if (musicArtist != null) { artist.Images = new Dictionary<ImageType, string>(musicArtist.Images); artist.BackdropImagePaths = musicArtist.BackdropImagePaths.ToList(); artist.ScreenshotImagePaths = musicArtist.ScreenshotImagePaths.ToList(); artist.SetProviderId(MetadataProviders.Musicbrainz, musicArtist.GetProviderId(MetadataProviders.Musicbrainz)); } numComplete++; double percent = numComplete; percent /= allArtists.Length; percent *= 5; progress.Report(10 + percent); } var innerProgress = new ActionableProgress<double>(); innerProgress.RegisterAction(pct => progress.Report(15 + pct * .85)); await _libraryManager.ValidateArtists(cancellationToken, innerProgress).ConfigureAwait(false); }
private async Task GetItem(IServerSyncProvider provider, ISyncDataProvider dataProvider, SyncTarget target, string serverId, string serverName, SyncedItem jobItem, IProgress<double> progress, CancellationToken cancellationToken) { var libraryItem = jobItem.Item; var internalSyncJobItem = _syncManager.GetJobItem(jobItem.SyncJobItemId); var internalSyncJob = _syncManager.GetJob(jobItem.SyncJobId); var localItem = CreateLocalItem(provider, jobItem, internalSyncJob, target, libraryItem, serverId, serverName, jobItem.OriginalFileName); await _syncManager.ReportSyncJobItemTransferBeginning(internalSyncJobItem.Id); var transferSuccess = false; Exception transferException = null; var options = _config.GetSyncOptions(); try { var fileTransferProgress = new ActionableProgress<double>(); fileTransferProgress.RegisterAction(pct => progress.Report(pct * .92)); var sendFileResult = await SendFile(provider, internalSyncJobItem.OutputPath, localItem.LocalPath.Split(PathSeparatorChar), target, options, fileTransferProgress, cancellationToken).ConfigureAwait(false); if (localItem.Item.MediaSources != null) { var mediaSource = localItem.Item.MediaSources.FirstOrDefault(); if (mediaSource != null) { mediaSource.Path = sendFileResult.Path; mediaSource.Protocol = sendFileResult.Protocol; mediaSource.RequiredHttpHeaders = sendFileResult.RequiredHttpHeaders; mediaSource.SupportsTranscoding = false; } } localItem.FileId = sendFileResult.Id; // Create db record await dataProvider.AddOrUpdate(target, localItem).ConfigureAwait(false); if (localItem.Item.MediaSources != null) { var mediaSource = localItem.Item.MediaSources.FirstOrDefault(); if (mediaSource != null) { await SendSubtitles(localItem, mediaSource, provider, dataProvider, target, options, cancellationToken).ConfigureAwait(false); } } progress.Report(92); transferSuccess = true; progress.Report(99); } catch (Exception ex) { _logger.ErrorException("Error transferring sync job file", ex); transferException = ex; } if (transferSuccess) { await _syncManager.ReportSyncJobItemTransferred(jobItem.SyncJobItemId).ConfigureAwait(false); } else { await _syncManager.ReportSyncJobItemTransferFailed(jobItem.SyncJobItemId).ConfigureAwait(false); throw transferException; } }
/// <summary> /// Validates the people. /// </summary> /// <param name="cancellationToken">The cancellation token.</param> /// <param name="progress">The progress.</param> /// <returns>Task.</returns> public async Task ValidatePeople(CancellationToken cancellationToken, IProgress<double> progress) { var innerProgress = new ActionableProgress<double>(); innerProgress.RegisterAction(pct => progress.Report(pct * .15)); var peopleOptions = _config.Configuration.PeopleMetadataOptions; var people = _libraryManager.RootFolder.GetRecursiveChildren() .SelectMany(i => i.People) .Where(i => !string.IsNullOrWhiteSpace(i.Name)) .ToList(); var dict = new Dictionary<string, bool>(StringComparer.OrdinalIgnoreCase); foreach (var person in people) { bool current; if (!dict.TryGetValue(person.Name, out current) || !current) { dict[person.Name] = DownloadMetadata(person, peopleOptions); } } var numComplete = 0; foreach (var person in dict) { cancellationToken.ThrowIfCancellationRequested(); try { var item = _libraryManager.GetPerson(person.Key); var options = new MetadataRefreshOptions { MetadataRefreshMode = person.Value ? MetadataRefreshMode.Default : MetadataRefreshMode.ValidationOnly, ImageRefreshMode = person.Value ? ImageRefreshMode.Default : ImageRefreshMode.ValidationOnly }; await item.RefreshMetadata(options, cancellationToken).ConfigureAwait(false); } catch (Exception ex) { _logger.ErrorException("Error validating IBN entry {0}", ex, person); } // Update progress numComplete++; double percent = numComplete; percent /= people.Count; progress.Report(100 * percent); } progress.Report(100); _logger.Info("People validation complete"); // Bad practice, i know. But we keep a lot in memory, unfortunately. GC.Collect(2, GCCollectionMode.Forced, true); GC.Collect(2, GCCollectionMode.Forced, true); }
/// <summary> /// Refreshes the children. /// </summary> /// <param name="children">The children.</param> /// <param name="progress">The progress.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <param name="recursive">if set to <c>true</c> [recursive].</param> /// <param name="forceRefreshMetadata">if set to <c>true</c> [force refresh metadata].</param> /// <returns>Task.</returns> private async Task RefreshChildren(IList<Tuple<BaseItem, bool>> children, IProgress<double> progress, CancellationToken cancellationToken, bool? recursive, bool forceRefreshMetadata = false) { var list = children; var percentages = new Dictionary<Guid, double>(list.Count); var tasks = new List<Task>(); foreach (var tuple in list) { if (tasks.Count > 7) { await Task.WhenAll(tasks).ConfigureAwait(false); } Tuple<BaseItem, bool> currentTuple = tuple; tasks.Add(Task.Run(async () => { cancellationToken.ThrowIfCancellationRequested(); var child = currentTuple.Item1; try { //refresh it await child.RefreshMetadata(cancellationToken, forceSave: currentTuple.Item2, forceRefresh: forceRefreshMetadata, resetResolveArgs: false).ConfigureAwait(false); } catch (IOException ex) { Logger.ErrorException("Error refreshing {0}", ex, child.Path ?? child.Name); } // Refresh children if a folder and the item changed or recursive is set to true var refreshChildren = child.IsFolder && (currentTuple.Item2 || (recursive.HasValue && recursive.Value)); if (refreshChildren) { // Don't refresh children if explicitly set to false if (recursive.HasValue && recursive.Value == false) { refreshChildren = false; } } if (refreshChildren) { cancellationToken.ThrowIfCancellationRequested(); var innerProgress = new ActionableProgress<double>(); innerProgress.RegisterAction(p => { lock (percentages) { percentages[child.Id] = p / 100; var percent = percentages.Values.Sum(); percent /= list.Count; progress.Report((90 * percent) + 10); } }); await ((Folder)child).ValidateChildren(innerProgress, cancellationToken, recursive, forceRefreshMetadata).ConfigureAwait(false); try { // Some folder providers are unable to refresh until children have been refreshed. await child.RefreshMetadata(cancellationToken, resetResolveArgs: false).ConfigureAwait(false); } catch (IOException ex) { Logger.ErrorException("Error refreshing {0}", ex, child.Path ?? child.Name); } } else { lock (percentages) { percentages[child.Id] = 1; var percent = percentages.Values.Sum(); percent /= list.Count; progress.Report((90 * percent) + 10); } } })); } cancellationToken.ThrowIfCancellationRequested(); await Task.WhenAll(tasks).ConfigureAwait(false); }
/// <summary> /// Installs the package. /// </summary> /// <param name="package">The package.</param> /// <param name="progress">The progress.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns>Task.</returns> /// <exception cref="System.ArgumentNullException">package</exception> public async Task InstallPackage(PackageVersionInfo package, IProgress<double> progress, CancellationToken cancellationToken) { if (package == null) { throw new ArgumentNullException("package"); } if (progress == null) { throw new ArgumentNullException("progress"); } if (cancellationToken == null) { throw new ArgumentNullException("cancellationToken"); } var installationInfo = new InstallationInfo { Id = Guid.NewGuid(), Name = package.name, UpdateClass = package.classification, Version = package.versionStr }; var innerCancellationTokenSource = new CancellationTokenSource(); var tuple = new Tuple<InstallationInfo, CancellationTokenSource>(installationInfo, innerCancellationTokenSource); // Add it to the in-progress list lock (CurrentInstallations) { CurrentInstallations.Add(tuple); } var innerProgress = new ActionableProgress<double>(); // Whenever the progress updates, update the outer progress object and InstallationInfo innerProgress.RegisterAction(percent => { progress.Report(percent); installationInfo.PercentComplete = percent; }); var linkedToken = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, innerCancellationTokenSource.Token).Token; var installationEventArgs = new InstallationEventArgs { InstallationInfo = installationInfo, PackageVersionInfo = package }; EventHelper.QueueEventIfNotNull(PackageInstalling, this, installationEventArgs, _logger); try { await InstallPackageInternal(package, innerProgress, linkedToken).ConfigureAwait(false); lock (CurrentInstallations) { CurrentInstallations.Remove(tuple); } CompletedInstallations.Add(installationInfo); EventHelper.QueueEventIfNotNull(PackageInstallationCompleted, this, installationEventArgs, _logger); } catch (OperationCanceledException) { lock (CurrentInstallations) { CurrentInstallations.Remove(tuple); } _logger.Info("Package installation cancelled: {0} {1}", package.name, package.versionStr); EventHelper.QueueEventIfNotNull(PackageInstallationCancelled, this, installationEventArgs, _logger); throw; } catch (Exception ex) { _logger.ErrorException("Package installation failed", ex); lock (CurrentInstallations) { CurrentInstallations.Remove(tuple); } EventHelper.QueueEventIfNotNull(PackageInstallationFailed, this, new InstallationFailedEventArgs { InstallationInfo = installationInfo, Exception = ex }, _logger); throw; } finally { // Dispose the progress object and remove the installation from the in-progress list innerProgress.Dispose(); tuple.Item2.Dispose(); } }
private async Task Sync(SyncJobItem jobItem, SyncJob job, Audio item, User user, bool enableConversion, SyncOptions syncOptions, IProgress<double> progress, CancellationToken cancellationToken) { var jobOptions = _syncManager.GetAudioOptions(jobItem, job); var conversionOptions = new AudioOptions { Profile = jobOptions.DeviceProfile }; conversionOptions.DeviceId = jobItem.TargetId; conversionOptions.Context = EncodingContext.Static; conversionOptions.ItemId = item.Id.ToString("N"); conversionOptions.MediaSources = _mediaSourceManager.GetStaticMediaSources(item, false, user).ToList(); var streamInfo = new StreamBuilder(_logger).BuildAudioItem(conversionOptions); var mediaSource = streamInfo.MediaSource; jobItem.MediaSourceId = streamInfo.MediaSourceId; jobItem.TemporaryPath = GetTemporaryPath(jobItem); if (streamInfo.PlayMethod == PlayMethod.Transcode && jobOptions.IsConverting) { if (!enableConversion) { return; } jobItem.Status = SyncJobItemStatus.Converting; await _syncManager.UpdateSyncJobItemInternal(jobItem).ConfigureAwait(false); await UpdateJobStatus(job).ConfigureAwait(false); try { var lastJobUpdate = DateTime.MinValue; var innerProgress = new ActionableProgress<double>(); innerProgress.RegisterAction(async pct => { progress.Report(pct); if ((DateTime.UtcNow - lastJobUpdate).TotalSeconds >= DatabaseProgressUpdateIntervalSeconds) { jobItem.Progress = pct / 2; await _syncManager.UpdateSyncJobItemInternal(jobItem).ConfigureAwait(false); await UpdateJobStatus(job).ConfigureAwait(false); } }); jobItem.OutputPath = await _mediaEncoder.EncodeAudio(new EncodingJobOptions(streamInfo, conversionOptions.Profile) { OutputDirectory = jobItem.TemporaryPath, CpuCoreLimit = syncOptions.TranscodingCpuCoreLimit }, innerProgress, cancellationToken); } catch (OperationCanceledException) { jobItem.Status = SyncJobItemStatus.Queued; jobItem.Progress = 0; } catch (Exception ex) { jobItem.Status = SyncJobItemStatus.Failed; _logger.ErrorException("Error during sync transcoding", ex); } if (jobItem.Status == SyncJobItemStatus.Failed || jobItem.Status == SyncJobItemStatus.Queued) { await _syncManager.UpdateSyncJobItemInternal(jobItem).ConfigureAwait(false); return; } jobItem.MediaSource = await GetEncodedMediaSource(jobItem.OutputPath, user, false).ConfigureAwait(false); } else { if (mediaSource.Protocol == MediaProtocol.File) { jobItem.OutputPath = mediaSource.Path; } else if (mediaSource.Protocol == MediaProtocol.Http) { jobItem.OutputPath = await DownloadFile(jobItem, mediaSource, cancellationToken).ConfigureAwait(false); } else { throw new InvalidOperationException(string.Format("Cannot direct stream {0} protocol", mediaSource.Protocol)); } jobItem.MediaSource = mediaSource; } jobItem.MediaSource.SupportsTranscoding = false; jobItem.Progress = 50; jobItem.Status = SyncJobItemStatus.ReadyToTransfer; await _syncManager.UpdateSyncJobItemInternal(jobItem).ConfigureAwait(false); }
/// <summary> /// Refreshes the children. /// </summary> /// <param name="children">The children.</param> /// <param name="directoryService">The directory service.</param> /// <param name="progress">The progress.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <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); foreach (var item in list) { cancellationToken.ThrowIfCancellationRequested(); var child = item; var innerProgress = new ActionableProgress<double>(); innerProgress.RegisterAction(p => { lock (percentages) { percentages[child.Id] = p / 100; var percent = percentages.Values.Sum(); percent /= childCount; progress.Report((10 * percent) + 10); } }); await child.ValidateChildrenWithCancellationSupport(innerProgress, cancellationToken, true, false, null, directoryService) .ConfigureAwait(false); } }
/// <summary> /// Validates the children internal. /// </summary> /// <param name="progress">The progress.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <param name="recursive">if set to <c>true</c> [recursive].</param> /// <param name="refreshChildMetadata">if set to <c>true</c> [refresh child metadata].</param> /// <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) { var locationType = LocationType; cancellationToken.ThrowIfCancellationRequested(); var validChildren = new List<BaseItem>(); if (locationType != LocationType.Remote && locationType != LocationType.Virtual) { IEnumerable<BaseItem> nonCachedChildren; try { nonCachedChildren = GetNonCachedChildren(directoryService); } catch (IOException ex) { nonCachedChildren = new BaseItem[] { }; Logger.ErrorException("Error getting file system entries for {0}", ex, Path); } if (nonCachedChildren == null) return; //nothing to validate progress.Report(5); //build a dictionary of the current children we have now by Id so we can compare quickly and easily var currentChildren = GetActualChildrenDictionary(); //create a list for our validated children var newItems = new List<BaseItem>(); cancellationToken.ThrowIfCancellationRequested(); foreach (var child in nonCachedChildren) { BaseItem currentChild; if (currentChildren.TryGetValue(child.Id, out currentChild)) { if (IsValidFromResolver(currentChild, child)) { var currentChildLocationType = currentChild.LocationType; if (currentChildLocationType != LocationType.Remote && currentChildLocationType != LocationType.Virtual) { currentChild.DateModified = child.DateModified; } currentChild.IsOffline = false; validChildren.Add(currentChild); } else { newItems.Add(child); validChildren.Add(child); } } else { // Brand new item - needs to be added newItems.Add(child); validChildren.Add(child); } } // If any items were added or removed.... if (newItems.Count > 0 || currentChildren.Count != validChildren.Count) { // That's all the new and changed ones - now see if there are any that are missing var itemsRemoved = currentChildren.Values.Except(validChildren).ToList(); var actualRemovals = new List<BaseItem>(); foreach (var item in itemsRemoved) { if (item.LocationType == LocationType.Virtual || item.LocationType == LocationType.Remote) { // Don't remove these because there's no way to accurately validate them. validChildren.Add(item); } else if (!string.IsNullOrEmpty(item.Path) && IsPathOffline(item.Path)) { item.IsOffline = true; validChildren.Add(item); } else { item.IsOffline = false; actualRemovals.Add(item); } } if (actualRemovals.Count > 0) { RemoveChildrenInternal(actualRemovals); foreach (var item in actualRemovals) { LibraryManager.ReportItemRemoved(item); } } await LibraryManager.CreateItems(newItems, cancellationToken).ConfigureAwait(false); AddChildrenInternal(newItems); await ItemRepository.SaveChildren(Id, ActualChildren.Select(i => i.Id).ToList(), cancellationToken).ConfigureAwait(false); } } progress.Report(10); cancellationToken.ThrowIfCancellationRequested(); if (recursive) { await ValidateSubFolders(ActualChildren.OfType<Folder>().ToList(), directoryService, progress, cancellationToken).ConfigureAwait(false); } progress.Report(20); if (refreshChildMetadata) { var container = this as IMetadataContainer; var innerProgress = new ActionableProgress<double>(); innerProgress.RegisterAction(p => progress.Report((.80 * p) + 20)); if (container != null) { await container.RefreshAllMetadata(refreshOptions, innerProgress, cancellationToken).ConfigureAwait(false); } else { await RefreshMetadataRecursive(refreshOptions, recursive, innerProgress, cancellationToken); } } progress.Report(100); }
private async Task RefreshMetadataRecursive(MetadataRefreshOptions refreshOptions, bool recursive, IProgress<double> progress, CancellationToken cancellationToken) { var children = ActualChildren.ToList(); var percentages = new Dictionary<Guid, double>(children.Count); var tasks = new List<Task>(); foreach (var child in children) { if (tasks.Count >= 2) { await Task.WhenAll(tasks).ConfigureAwait(false); tasks.Clear(); } cancellationToken.ThrowIfCancellationRequested(); var innerProgress = new ActionableProgress<double>(); // Avoid implicitly captured closure var currentChild = child; innerProgress.RegisterAction(p => { lock (percentages) { percentages[currentChild.Id] = p / 100; var percent = percentages.Values.Sum(); percent /= children.Count; percent *= 100; progress.Report(percent); } }); if (child.IsFolder) { await RefreshChildMetadata(child, refreshOptions, recursive, innerProgress, cancellationToken) .ConfigureAwait(false); } else { // Avoid implicitly captured closure var taskChild = child; tasks.Add(Task.Run(async () => await RefreshChildMetadata(taskChild, refreshOptions, false, innerProgress, cancellationToken).ConfigureAwait(false), cancellationToken)); } } await Task.WhenAll(tasks).ConfigureAwait(false); progress.Report(100); }
private async Task RefreshMetadataRecursive(MetadataRefreshOptions refreshOptions, bool recursive, IProgress<double> progress, CancellationToken cancellationToken) { var children = ActualChildren.ToList(); var percentages = new Dictionary<Guid, double>(children.Count); var numComplete = 0; var count = children.Count; foreach (var child in children) { cancellationToken.ThrowIfCancellationRequested(); if (child.IsFolder) { var innerProgress = new ActionableProgress<double>(); // Avoid implicitly captured closure var currentChild = child; innerProgress.RegisterAction(p => { lock (percentages) { percentages[currentChild.Id] = p / 100; var innerPercent = percentages.Values.Sum(); innerPercent /= count; innerPercent *= 100; progress.Report(innerPercent); } }); await RefreshChildMetadata(child, refreshOptions, recursive, innerProgress, cancellationToken) .ConfigureAwait(false); } else { await RefreshChildMetadata(child, refreshOptions, false, new Progress<double>(), cancellationToken) .ConfigureAwait(false); } numComplete++; double percent = numComplete; percent /= count; percent *= 100; progress.Report(percent); } progress.Report(100); }
private async Task GetNewMedia(IServerSyncProvider provider, ISyncDataProvider dataProvider, SyncTarget target, string serverId, string serverName, IProgress<double> progress, CancellationToken cancellationToken) { var jobItems = await _syncManager.GetReadySyncItems(target.Id).ConfigureAwait(false); var numComplete = 0; double startingPercent = 0; double percentPerItem = 1; if (jobItems.Count > 0) { percentPerItem /= jobItems.Count; } foreach (var jobItem in jobItems) { cancellationToken.ThrowIfCancellationRequested(); var currentPercent = startingPercent; var innerProgress = new ActionableProgress<double>(); innerProgress.RegisterAction(pct => { var totalProgress = pct * percentPerItem; totalProgress += currentPercent; progress.Report(totalProgress); }); try { await GetItem(provider, dataProvider, target, serverId, serverName, jobItem, innerProgress, cancellationToken).ConfigureAwait(false); } catch (Exception ex) { _logger.ErrorException("Error syncing item", ex); } numComplete++; startingPercent = numComplete; startingPercent /= jobItems.Count; startingPercent *= 100; progress.Report(startingPercent); } }
private async Task DownloadAllChannelContent(string userId, CancellationToken cancellationToken, IProgress<double> progress) { var result = await _manager.GetAllMediaInternal(new AllChannelMediaQuery { UserId = userId }, cancellationToken).ConfigureAwait(false); progress.Report(5); var innerProgress = new ActionableProgress<double>(); innerProgress.RegisterAction(p => progress.Report(5 + (.95 * p))); var path = _manager.ChannelDownloadPath; await DownloadChannelContent(result, path, cancellationToken, innerProgress).ConfigureAwait(false); }
private async Task Sync(SyncJobItem jobItem, SyncJob job, Video item, User user, bool enableConversion, SyncOptions syncOptions, IProgress<double> progress, CancellationToken cancellationToken) { var jobOptions = _syncManager.GetVideoOptions(jobItem, job); var conversionOptions = new VideoOptions { Profile = jobOptions.DeviceProfile }; conversionOptions.DeviceId = jobItem.TargetId; conversionOptions.Context = EncodingContext.Static; conversionOptions.ItemId = item.Id.ToString("N"); conversionOptions.MediaSources = _mediaSourceManager.GetStaticMediaSources(item, false, user).ToList(); var streamInfo = new StreamBuilder(_logger).BuildVideoItem(conversionOptions); var mediaSource = streamInfo.MediaSource; // No sense creating external subs if we're already burning one into the video var externalSubs = streamInfo.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode ? new List<SubtitleStreamInfo>() : streamInfo.GetExternalSubtitles(false, true, null, null); // Mark as requiring conversion if transcoding the video, or if any subtitles need to be extracted var requiresVideoTranscoding = streamInfo.PlayMethod == PlayMethod.Transcode && jobOptions.IsConverting; var requiresConversion = requiresVideoTranscoding || externalSubs.Any(i => RequiresExtraction(i, mediaSource)); if (requiresConversion && !enableConversion) { return; } jobItem.MediaSourceId = streamInfo.MediaSourceId; jobItem.TemporaryPath = GetTemporaryPath(jobItem); if (requiresConversion) { jobItem.Status = SyncJobItemStatus.Converting; } if (requiresVideoTranscoding) { // Save the job item now since conversion could take a while await _syncManager.UpdateSyncJobItemInternal(jobItem).ConfigureAwait(false); await UpdateJobStatus(job).ConfigureAwait(false); try { var lastJobUpdate = DateTime.MinValue; var innerProgress = new ActionableProgress<double>(); innerProgress.RegisterAction(async pct => { progress.Report(pct); if ((DateTime.UtcNow - lastJobUpdate).TotalSeconds >= DatabaseProgressUpdateIntervalSeconds) { jobItem.Progress = pct / 2; await _syncManager.UpdateSyncJobItemInternal(jobItem).ConfigureAwait(false); await UpdateJobStatus(job).ConfigureAwait(false); } }); jobItem.OutputPath = await _mediaEncoder.EncodeVideo(new EncodingJobOptions(streamInfo, conversionOptions.Profile) { OutputDirectory = jobItem.TemporaryPath, CpuCoreLimit = syncOptions.TranscodingCpuCoreLimit, ReadInputAtNativeFramerate = !syncOptions.EnableFullSpeedTranscoding }, innerProgress, cancellationToken); } catch (OperationCanceledException) { jobItem.Status = SyncJobItemStatus.Queued; jobItem.Progress = 0; } catch (Exception ex) { jobItem.Status = SyncJobItemStatus.Failed; _logger.ErrorException("Error during sync transcoding", ex); } if (jobItem.Status == SyncJobItemStatus.Failed || jobItem.Status == SyncJobItemStatus.Queued) { await _syncManager.UpdateSyncJobItemInternal(jobItem).ConfigureAwait(false); return; } jobItem.MediaSource = await GetEncodedMediaSource(jobItem.OutputPath, user, true).ConfigureAwait(false); } else { if (mediaSource.Protocol == MediaProtocol.File) { jobItem.OutputPath = mediaSource.Path; } else if (mediaSource.Protocol == MediaProtocol.Http) { jobItem.OutputPath = await DownloadFile(jobItem, mediaSource, cancellationToken).ConfigureAwait(false); } else { throw new InvalidOperationException(string.Format("Cannot direct stream {0} protocol", mediaSource.Protocol)); } jobItem.MediaSource = mediaSource; } jobItem.MediaSource.SupportsTranscoding = false; if (externalSubs.Count > 0) { // Save the job item now since conversion could take a while await _syncManager.UpdateSyncJobItemInternal(jobItem).ConfigureAwait(false); await ConvertSubtitles(jobItem, externalSubs, streamInfo, cancellationToken).ConfigureAwait(false); } jobItem.Progress = 50; jobItem.Status = SyncJobItemStatus.ReadyToTransfer; await _syncManager.UpdateSyncJobItemInternal(jobItem).ConfigureAwait(false); }
/// <summary> /// Validates the people. /// </summary> /// <param name="cancellationToken">The cancellation token.</param> /// <param name="progress">The progress.</param> /// <returns>Task.</returns> public async Task ValidatePeople(CancellationToken cancellationToken, IProgress<double> progress) { var innerProgress = new ActionableProgress<double>(); innerProgress.RegisterAction(pct => progress.Report(pct * .15)); var peopleOptions = _config.Configuration.PeopleMetadataOptions; var people = _libraryManager.GetAllPeople(); var dict = new Dictionary<string, bool>(StringComparer.OrdinalIgnoreCase); foreach (var person in people) { var isMetadataEnabled = DownloadMetadata(person, peopleOptions); bool currentValue; if (dict.TryGetValue(person.Name, out currentValue)) { if (!currentValue && isMetadataEnabled) { dict[person.Name] = true; } } else { dict[person.Name] = isMetadataEnabled; } } var numComplete = 0; var validIds = new List<Guid>(); foreach (var person in dict) { cancellationToken.ThrowIfCancellationRequested(); try { var item = _libraryManager.GetPerson(person.Key); validIds.Add(item.Id); var hasMetdata = !string.IsNullOrWhiteSpace(item.Overview); var performFullRefresh = !hasMetdata && (DateTime.UtcNow - item.DateLastRefreshed).TotalDays >= 30; var defaultMetadataRefreshMode = performFullRefresh ? MetadataRefreshMode.FullRefresh : MetadataRefreshMode.Default; var imageRefreshMode = performFullRefresh ? ImageRefreshMode.FullRefresh : ImageRefreshMode.Default; var options = new MetadataRefreshOptions(_fileSystem) { MetadataRefreshMode = person.Value ? defaultMetadataRefreshMode : MetadataRefreshMode.ValidationOnly, ImageRefreshMode = person.Value ? imageRefreshMode : ImageRefreshMode.ValidationOnly }; await item.RefreshMetadata(options, cancellationToken).ConfigureAwait(false); } catch (OperationCanceledException) { throw; } catch (Exception ex) { _logger.ErrorException("Error validating IBN entry {0}", ex, person); } // Update progress numComplete++; double percent = numComplete; percent /= people.Count; progress.Report(100 * percent); } var allIds = _libraryManager.GetItemIds(new InternalItemsQuery { IncludeItemTypes = new[] { typeof(Person).Name } }); var invalidIds = allIds .Except(validIds) .ToList(); foreach (var id in invalidIds) { cancellationToken.ThrowIfCancellationRequested(); var item = _libraryManager.GetItemById(id); if (item != null) { await _libraryManager.DeleteItem(item, new DeleteOptions { DeleteFileLocation = false }).ConfigureAwait(false); } } progress.Report(100); _logger.Info("People validation complete"); // Bad practice, i know. But we keep a lot in memory, unfortunately. GC.Collect(2, GCCollectionMode.Forced, true); GC.Collect(2, GCCollectionMode.Forced, true); }
private async Task GetAllItems(string user, string channelId, string folderId, int currentRefreshLevel, int maxRefreshLevel, IProgress<double> progress, CancellationToken cancellationToken) { var folderItems = new List<string>(); var innerProgress = new ActionableProgress<double>(); innerProgress.RegisterAction(p => progress.Report(p / 2)); var result = await _channelManager.GetChannelItemsInternal(new ChannelItemQuery { ChannelId = channelId, UserId = user, FolderId = folderId }, innerProgress, cancellationToken); folderItems.AddRange(result.Items.Where(i => i.IsFolder).Select(i => i.Id.ToString("N"))); var totalRetrieved = result.Items.Length; var totalCount = result.TotalRecordCount; while (totalRetrieved < totalCount) { result = await _channelManager.GetChannelItemsInternal(new ChannelItemQuery { ChannelId = channelId, UserId = user, StartIndex = totalRetrieved, FolderId = folderId }, new Progress<double>(), cancellationToken); folderItems.AddRange(result.Items.Where(i => i.IsFolder).Select(i => i.Id.ToString("N"))); totalRetrieved += result.Items.Length; totalCount = result.TotalRecordCount; } progress.Report(50); if (currentRefreshLevel < maxRefreshLevel) { var numComplete = 0; var numItems = folderItems.Count; foreach (var folder in folderItems) { try { innerProgress = new ActionableProgress<double>(); var startingNumberComplete = numComplete; innerProgress.RegisterAction(p => { double innerPercent = startingNumberComplete; innerPercent += (p / 100); innerPercent /= numItems; progress.Report((innerPercent * 50) + 50); }); await GetAllItems(user, channelId, folder, currentRefreshLevel + 1, maxRefreshLevel, innerProgress, cancellationToken).ConfigureAwait(false); } catch (Exception ex) { _logger.ErrorException("Error getting channel content", ex); } numComplete++; double percent = numComplete; percent /= numItems; progress.Report((percent * 50) + 50); } } progress.Report(100); }
public async Task SyncJobItems(SyncJobItem[] items, bool enableConversion, IProgress<double> progress, CancellationToken cancellationToken) { if (items.Length > 0) { if (!SyncRegistrationInfo.Instance.IsRegistered) { _logger.Debug("Cancelling sync job processing. Please obtain a supporter membership."); return; } } var numComplete = 0; foreach (var item in items) { cancellationToken.ThrowIfCancellationRequested(); double percentPerItem = 1; percentPerItem /= items.Length; var startingPercent = numComplete * percentPerItem * 100; var innerProgress = new ActionableProgress<double>(); innerProgress.RegisterAction(p => progress.Report(startingPercent + (percentPerItem * p))); // Pull it fresh from the db just to make sure it wasn't deleted or cancelled while another item was converting var jobItem = enableConversion ? _syncRepo.GetJobItem(item.Id) : item; if (jobItem != null) { var job = _syncRepo.GetJob(jobItem.JobId); if (jobItem.Status != SyncJobItemStatus.Cancelled) { await ProcessJobItem(job, jobItem, enableConversion, innerProgress, cancellationToken).ConfigureAwait(false); } job = _syncRepo.GetJob(jobItem.JobId); await UpdateJobStatus(job).ConfigureAwait(false); } numComplete++; double percent = numComplete; percent /= items.Length; progress.Report(100 * percent); } }
private async Task DownloadContent(string user, CancellationToken cancellationToken, IProgress<double> progress) { var innerProgress = new ActionableProgress<double>(); innerProgress.RegisterAction(p => progress.Report(0 + (.8 * p))); await DownloadAllChannelContent(user, cancellationToken, innerProgress).ConfigureAwait(false); progress.Report(80); innerProgress = new ActionableProgress<double>(); innerProgress.RegisterAction(p => progress.Report(80 + (.2 * p))); await DownloadLatestChannelContent(user, cancellationToken, progress).ConfigureAwait(false); progress.Report(100); }
private async Task RefreshChannelsInternal(IProgress<double> progress, CancellationToken cancellationToken) { var numComplete = 0; double progressPerService = _services.Count == 0 ? 0 : 1 / _services.Count; var newChannelIdList = new List<Guid>(); var newProgramIdList = new List<Guid>(); foreach (var service in _services) { cancellationToken.ThrowIfCancellationRequested(); _logger.Debug("Refreshing guide from {0}", service.Name); try { var innerProgress = new ActionableProgress<double>(); innerProgress.RegisterAction(p => progress.Report(p * progressPerService)); var idList = await RefreshChannelsInternal(service, innerProgress, cancellationToken).ConfigureAwait(false); newChannelIdList.AddRange(idList.Item1); newProgramIdList.AddRange(idList.Item2); } catch (OperationCanceledException) { throw; } catch (Exception ex) { _logger.ErrorException("Error refreshing channels for service", ex); } numComplete++; double percent = numComplete; percent /= _services.Count; progress.Report(100 * percent); } await CleanDatabaseInternal(newChannelIdList, new[] { typeof(LiveTvChannel).Name }, progress, cancellationToken).ConfigureAwait(false); await CleanDatabaseInternal(newProgramIdList, new[] { typeof(LiveTvProgram).Name }, progress, cancellationToken).ConfigureAwait(false); var coreService = _services.OfType<EmbyTV.EmbyTV>().FirstOrDefault(); if (coreService != null) { await coreService.RefreshSeriesTimers(cancellationToken, new Progress<double>()).ConfigureAwait(false); } // Load these now which will prefetch metadata var dtoOptions = new DtoOptions(); dtoOptions.Fields.Remove(ItemFields.SyncInfo); await GetRecordings(new RecordingQuery(), dtoOptions, cancellationToken).ConfigureAwait(false); progress.Report(100); }