Пример #1
1
        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);
        }
Пример #3
0
        /// <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);
            }
        }
Пример #4
0
        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);
        }
Пример #5
0
        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);
        }
Пример #6
0
        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++;
            }
        }
Пример #7
0
        /// <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));
        }
Пример #8
0
        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);
        }
Пример #9
0
        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);
        }
Пример #11
0
        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);
        }
Пример #12
0
        /// <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);
        }
Пример #13
0
        /// <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");
        }
Пример #14
0
        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);
        }
Пример #15
0
        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;
        }
Пример #16
0
        /// <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);
        }
Пример #19
0
        /// <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);
        }
Пример #20
0
        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);
        }
Пример #21
0
        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);
        }
Пример #22
0
        /// <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);
        }
Пример #23
0
        /// <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);
        }
Пример #24
0
        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);
        }
Пример #25
0
        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);
        }
Пример #26
0
        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);
        }
Пример #27
0
        /// <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);
        }
Пример #28
0
        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);
        }
Пример #29
0
        /// <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);
        }
Пример #30
0
        /// <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);
        }
Пример #31
0
        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);
        }
Пример #32
0
        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);
            }
        }
Пример #33
0
        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;
            }
        }
Пример #34
0
        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);
        }
Пример #35
0
        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);
            }
        }
Пример #36
0
        /// <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);
        }
Пример #37
0
        /// <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);
        }
Пример #38
0
        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);
        }
Пример #40
0
        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);
            }
        }
Пример #41
0
        /// <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);
        }
Пример #42
0
        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);
            }
        }
Пример #43
0
        /// <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);
        }
Пример #44
0
        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;
            }
        }
Пример #45
0
        /// <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);
        }
Пример #46
0
        /// <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);
        }
Пример #47
0
        /// <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();
            }
        }
Пример #48
0
        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);
        }
Пример #49
0
        /// <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);
            }
        }
Пример #50
0
        /// <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);
        }
Пример #51
0
        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);
        }
Пример #52
0
        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);
        }
Пример #53
0
        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);
        }
Пример #55
0
        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);
        }
Пример #56
0
        /// <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);
        }
Пример #57
0
        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);
        }
Пример #58
0
        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);
        }
Пример #60
0
        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);
        }