| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213 | using MediaBrowser.Common.ScheduledTasks;using MediaBrowser.Controller;using MediaBrowser.Controller.Entities;using MediaBrowser.Controller.Entities.Movies;using MediaBrowser.Controller.Library;using MediaBrowser.Model.Logging;using System;using System.Collections.Generic;using System.IO;using System.Linq;using System.Threading;using System.Threading.Tasks;namespace MediaBrowser.Server.Implementations.ScheduledTasks{    /// <summary>    /// Class ImageCleanupTask    /// </summary>    public class ImageCleanupTask : IScheduledTask    {        /// <summary>        /// The _kernel        /// </summary>        private readonly Kernel _kernel;        /// <summary>        /// The _logger        /// </summary>        private readonly ILogger _logger;        private readonly ILibraryManager _libraryManager;        private readonly IServerApplicationPaths _appPaths;        /// <summary>        /// Initializes a new instance of the <see cref="ImageCleanupTask" /> class.        /// </summary>        /// <param name="kernel">The kernel.</param>        /// <param name="logger">The logger.</param>        /// <param name="libraryManager">The library manager.</param>        /// <param name="appPaths">The app paths.</param>        public ImageCleanupTask(Kernel kernel, ILogger logger, ILibraryManager libraryManager, IServerApplicationPaths appPaths)        {            _kernel = kernel;            _logger = logger;            _libraryManager = libraryManager;            _appPaths = appPaths;        }        /// <summary>        /// Creates the triggers that define when the task will run        /// </summary>        /// <returns>IEnumerable{BaseTaskTrigger}.</returns>        public IEnumerable<ITaskTrigger> GetDefaultTriggers()        {            return new ITaskTrigger[]                {                    new DailyTrigger { TimeOfDay = TimeSpan.FromHours(2) }                };        }        /// <summary>        /// Returns the task to be executed        /// </summary>        /// <param name="cancellationToken">The cancellation token.</param>        /// <param name="progress">The progress.</param>        /// <returns>Task.</returns>        public async Task Execute(CancellationToken cancellationToken, IProgress<double> progress)        {            var items = _libraryManager.RootFolder.RecursiveChildren.ToList();            foreach (var video in items.OfType<Video>().Where(v => v.Chapters != null))            {                await _kernel.FFMpegManager.PopulateChapterImages(video, cancellationToken, false, true).ConfigureAwait(false);            }            // First gather all image files            var files = GetFiles(_kernel.FFMpegManager.AudioImagesDataPath)                .Concat(GetFiles(_kernel.FFMpegManager.VideoImagesDataPath))                .Concat(GetFiles(_appPaths.DownloadedImagesDataPath))                .ToList();            // Now gather all items            items.Add(_libraryManager.RootFolder);            // Determine all possible image paths            var pathsInUse = items.SelectMany(GetPathsInUse)                .Distinct(StringComparer.OrdinalIgnoreCase)                .ToDictionary(p => p, StringComparer.OrdinalIgnoreCase);            var numComplete = 0;            foreach (var file in files)            {                cancellationToken.ThrowIfCancellationRequested();                if (!pathsInUse.ContainsKey(file))                {                    cancellationToken.ThrowIfCancellationRequested();                    try                    {                        File.Delete(file);                    }                    catch (IOException ex)                    {                        _logger.ErrorException("Error deleting {0}", ex, file);                    }                }                // Update progress                numComplete++;                double percent = numComplete;                percent /= files.Count;                progress.Report(100 * percent);            }        }        /// <summary>        /// Gets the paths in use.        /// </summary>        /// <param name="item">The item.</param>        /// <returns>IEnumerable{System.String}.</returns>        private IEnumerable<string> GetPathsInUse(BaseItem item)        {            IEnumerable<string> images = new List<string>();            if (item.Images != null)            {                images = images.Concat(item.Images.Values);            }            if (item.BackdropImagePaths != null)            {                images = images.Concat(item.BackdropImagePaths);            }            if (item.ScreenshotImagePaths != null)            {                images = images.Concat(item.ScreenshotImagePaths);            }            if (item.LocalTrailers != null)            {                images = item.LocalTrailers.Aggregate(images, (current, subItem) => current.Concat(GetPathsInUse(subItem)));            }            if (item.ThemeSongs != null)            {                images = item.ThemeSongs.Aggregate(images, (current, subItem) => current.Concat(GetPathsInUse(subItem)));            }            if (item.ThemeVideos != null)            {                images = item.ThemeVideos.Aggregate(images, (current, subItem) => current.Concat(GetPathsInUse(subItem)));            }            var video = item as Video;            if (video != null && video.Chapters != null)            {                images = images.Concat(video.Chapters.Where(i => !string.IsNullOrEmpty(i.ImagePath)).Select(i => i.ImagePath));            }            var movie = item as Movie;            if (movie != null && movie.SpecialFeatures != null)            {                images = movie.SpecialFeatures.Aggregate(images, (current, subItem) => current.Concat(GetPathsInUse(subItem)));            }                        return images;        }        /// <summary>        /// Gets the files.        /// </summary>        /// <param name="path">The path.</param>        /// <returns>IEnumerable{System.String}.</returns>        private IEnumerable<string> GetFiles(string path)        {            return Directory.EnumerateFiles(path, "*.jpg", SearchOption.AllDirectories).Concat(Directory.EnumerateFiles(path, "*.png", SearchOption.AllDirectories));        }        /// <summary>        /// Gets the name of the task        /// </summary>        /// <value>The name.</value>        public string Name        {            get { return "Images cleanup"; }        }        /// <summary>        /// Gets the description.        /// </summary>        /// <value>The description.</value>        public string Description        {            get { return "Deletes downloaded and extracted images that are no longer being used."; }        }        /// <summary>        /// Gets the category.        /// </summary>        /// <value>The category.</value>        public string Category        {            get            {                return "Maintenance";            }        }    }}
 |