aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--MediaBrowser.Controller/Library/ILibraryManager.cs5
-rw-r--r--MediaBrowser.Controller/MediaInfo/FFMpegManager.cs110
-rw-r--r--MediaBrowser.Providers/MediaInfo/AudioImageProvider.cs53
-rw-r--r--MediaBrowser.Providers/MediaInfo/VideoImageProvider.cs44
-rw-r--r--MediaBrowser.Server.Implementations/Library/LibraryManager.cs9
-rw-r--r--MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs10
-rw-r--r--MediaBrowser.Server.Implementations/ScheduledTasks/ChapterImagesTask.cs2
7 files changed, 159 insertions, 74 deletions
diff --git a/MediaBrowser.Controller/Library/ILibraryManager.cs b/MediaBrowser.Controller/Library/ILibraryManager.cs
index 338edd568..ae34621cb 100644
--- a/MediaBrowser.Controller/Library/ILibraryManager.cs
+++ b/MediaBrowser.Controller/Library/ILibraryManager.cs
@@ -116,6 +116,11 @@ namespace MediaBrowser.Controller.Library
Task ValidateMediaLibrary(IProgress<double> progress, CancellationToken cancellationToken);
/// <summary>
+ /// Queues the library scan.
+ /// </summary>
+ void QueueLibraryScan();
+
+ /// <summary>
/// Gets the default view.
/// </summary>
/// <returns>IEnumerable{VirtualFolderInfo}.</returns>
diff --git a/MediaBrowser.Controller/MediaInfo/FFMpegManager.cs b/MediaBrowser.Controller/MediaInfo/FFMpegManager.cs
index e53acfc02..fad204c69 100644
--- a/MediaBrowser.Controller/MediaInfo/FFMpegManager.cs
+++ b/MediaBrowser.Controller/MediaInfo/FFMpegManager.cs
@@ -1,7 +1,8 @@
-using MediaBrowser.Common.IO;
+using System.Globalization;
+using MediaBrowser.Common.Extensions;
+using MediaBrowser.Common.IO;
using MediaBrowser.Common.MediaInfo;
using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.IO;
using MediaBrowser.Controller.Persistence;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.Logging;
@@ -19,18 +20,6 @@ namespace MediaBrowser.Controller.MediaInfo
/// </summary>
public class FFMpegManager
{
- /// <summary>
- /// Gets or sets the video image cache.
- /// </summary>
- /// <value>The video image cache.</value>
- internal FileSystemRepository VideoImageCache { get; set; }
-
- /// <summary>
- /// Gets or sets the subtitle cache.
- /// </summary>
- /// <value>The subtitle cache.</value>
- internal FileSystemRepository SubtitleCache { get; set; }
-
private readonly IServerApplicationPaths _appPaths;
private readonly IMediaEncoder _encoder;
private readonly ILogger _logger;
@@ -53,32 +42,17 @@ namespace MediaBrowser.Controller.MediaInfo
_logger = logger;
_itemRepo = itemRepo;
_fileSystem = fileSystem;
-
- VideoImageCache = new FileSystemRepository(VideoImagesDataPath);
- SubtitleCache = new FileSystemRepository(SubtitleCachePath);
}
/// <summary>
- /// Gets the video images data path.
+ /// Gets the chapter images data path.
/// </summary>
- /// <value>The video images data path.</value>
- public string VideoImagesDataPath
+ /// <value>The chapter images data path.</value>
+ public string ChapterImagesPath
{
get
{
- return Path.Combine(_appPaths.DataPath, "extracted-video-images");
- }
- }
-
- /// <summary>
- /// Gets the audio images data path.
- /// </summary>
- /// <value>The audio images data path.</value>
- public string AudioImagesDataPath
- {
- get
- {
- return Path.Combine(_appPaths.DataPath, "extracted-audio-images");
+ return Path.Combine(_appPaths.DataPath, "chapter-images");
}
}
@@ -86,7 +60,7 @@ namespace MediaBrowser.Controller.MediaInfo
/// Gets the subtitle cache path.
/// </summary>
/// <value>The subtitle cache path.</value>
- public string SubtitleCachePath
+ private string SubtitleCachePath
{
get
{
@@ -122,6 +96,8 @@ namespace MediaBrowser.Controller.MediaInfo
var runtimeTicks = video.RunTimeTicks ?? 0;
+ var currentImages = GetSavedChapterImages(video);
+
foreach (var chapter in chapters)
{
if (chapter.StartPositionTicks >= runtimeTicks)
@@ -130,11 +106,9 @@ namespace MediaBrowser.Controller.MediaInfo
break;
}
- var filename = video.Path + "_" + video.DateModified.Ticks + "_" + chapter.StartPositionTicks;
-
- var path = VideoImageCache.GetResourcePath(filename, ".jpg");
+ var path = GetChapterImagePath(video, chapter.StartPositionTicks);
- if (!File.Exists(path))
+ if (!currentImages.Contains(path, StringComparer.OrdinalIgnoreCase))
{
if (extractImages)
{
@@ -188,9 +162,35 @@ namespace MediaBrowser.Controller.MediaInfo
await _itemRepo.SaveChapters(video.Id, chapters, cancellationToken).ConfigureAwait(false);
}
+ DeleteDeadImages(currentImages, chapters);
+
return success;
}
+ private void DeleteDeadImages(IEnumerable<string> images, IEnumerable<ChapterInfo> chapters)
+ {
+ var deadImages = images
+ .Except(chapters.Select(i => i.ImagePath), StringComparer.OrdinalIgnoreCase)
+ .Where(i => BaseItem.SupportedImageExtensions.Contains(Path.GetExtension(i), StringComparer.OrdinalIgnoreCase))
+ .ToList();
+
+ foreach (var image in deadImages)
+ {
+ _logger.Debug("Deleting dead chapter image {0}", image);
+
+ try
+ {
+ File.Delete(image);
+ }
+ catch (IOException ex)
+ {
+ _logger.ErrorException("Error deleting {0}.", ex, image);
+ }
+ }
+ }
+
+ private readonly CultureInfo UsCulture = new CultureInfo("en-US");
+
/// <summary>
/// Gets the subtitle cache path.
/// </summary>
@@ -220,7 +220,39 @@ namespace MediaBrowser.Controller.MediaInfo
ticksParam += _fileSystem.GetLastWriteTimeUtc(stream.Path).Ticks;
}
- return SubtitleCache.GetResourcePath(input.Id + "_" + subtitleStreamIndex + "_" + input.DateModified.Ticks + ticksParam, outputExtension);
+ var filename = (input.Id + "_" + subtitleStreamIndex.ToString(UsCulture) + "_" + input.DateModified.Ticks.ToString(UsCulture) + ticksParam).GetMD5() + outputExtension;
+
+ var prefix = filename.Substring(0, 1);
+
+ return Path.Combine(SubtitleCachePath, prefix, filename);
+ }
+
+ public string GetChapterImagePath(Video video, long chapterPositionTicks)
+ {
+ var filename = video.DateModified.Ticks.ToString(UsCulture) + "_" + chapterPositionTicks.ToString(UsCulture) + ".jpg";
+
+ var videoId = video.Id.ToString();
+ var prefix = videoId.Substring(0, 1);
+
+ return Path.Combine(ChapterImagesPath, prefix, videoId, filename);
+ }
+
+ public List<string> GetSavedChapterImages(Video video)
+ {
+ var videoId = video.Id.ToString();
+ var prefix = videoId.Substring(0, 1);
+
+ var path = Path.Combine(ChapterImagesPath, prefix, videoId);
+
+ try
+ {
+ return Directory.EnumerateFiles(path)
+ .ToList();
+ }
+ catch (DirectoryNotFoundException)
+ {
+ return new List<string>();
+ }
}
}
}
diff --git a/MediaBrowser.Providers/MediaInfo/AudioImageProvider.cs b/MediaBrowser.Providers/MediaInfo/AudioImageProvider.cs
index 264b24b87..5782e3e63 100644
--- a/MediaBrowser.Providers/MediaInfo/AudioImageProvider.cs
+++ b/MediaBrowser.Providers/MediaInfo/AudioImageProvider.cs
@@ -1,6 +1,5 @@
-using MediaBrowser.Common.IO;
+using MediaBrowser.Common.Extensions;
using MediaBrowser.Common.MediaInfo;
-using MediaBrowser.Controller;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Entities.Audio;
@@ -23,12 +22,6 @@ namespace MediaBrowser.Providers.MediaInfo
public class AudioImageProvider : BaseMetadataProvider
{
/// <summary>
- /// Gets or sets the image cache.
- /// </summary>
- /// <value>The image cache.</value>
- public FileSystemRepository ImageCache { get; set; }
-
- /// <summary>
/// The _locks
/// </summary>
private readonly ConcurrentDictionary<string, SemaphoreSlim> _locks = new ConcurrentDictionary<string, SemaphoreSlim>();
@@ -48,8 +41,6 @@ namespace MediaBrowser.Providers.MediaInfo
: base(logManager, configurationManager)
{
_mediaEncoder = mediaEncoder;
-
- ImageCache = new FileSystemRepository(Kernel.Instance.FFMpegManager.AudioImagesDataPath);
}
/// <summary>
@@ -113,7 +104,7 @@ namespace MediaBrowser.Providers.MediaInfo
return ItemUpdateType.ImageUpdate;
}
}
-
+
/// <summary>
/// Fetches metadata and returns true or false indicating if any work that requires persistence was done
/// </summary>
@@ -154,13 +145,7 @@ namespace MediaBrowser.Providers.MediaInfo
{
cancellationToken.ThrowIfCancellationRequested();
- var album = item.Parent as MusicAlbum;
-
- var filename = item.Album ?? string.Empty;
- filename += item.Artists.FirstOrDefault() ?? string.Empty;
- filename += album == null ? item.Id.ToString("N") + item.DateModified.Ticks : album.Id.ToString("N") + album.DateModified.Ticks;
-
- var path = ImageCache.GetResourcePath(filename + "_primary", ".jpg");
+ var path = GetAudioImagePath(item);
if (!File.Exists(path))
{
@@ -196,6 +181,38 @@ namespace MediaBrowser.Providers.MediaInfo
}
/// <summary>
+ /// Gets the audio image path.
+ /// </summary>
+ /// <param name="item">The item.</param>
+ /// <returns>System.String.</returns>
+ private string GetAudioImagePath(Audio item)
+ {
+ var album = item.Parent as MusicAlbum;
+
+ var filename = item.Album ?? string.Empty;
+ filename += item.Artists.FirstOrDefault() ?? string.Empty;
+ filename += album == null ? item.Id.ToString("N") + item.DateModified.Ticks : album.Id.ToString("N") + album.DateModified.Ticks + "_primary";
+
+ filename = filename.GetMD5() + ".jpg";
+
+ var prefix = filename.Substring(0, 1);
+
+ return Path.Combine(AudioImagesPath, prefix, filename);
+ }
+
+ /// <summary>
+ /// Gets the audio images data path.
+ /// </summary>
+ /// <value>The audio images data path.</value>
+ public string AudioImagesPath
+ {
+ get
+ {
+ return Path.Combine(ConfigurationManager.ApplicationPaths.DataPath, "extracted-audio-images");
+ }
+ }
+
+ /// <summary>
/// Gets the lock.
/// </summary>
/// <param name="filename">The filename.</param>
diff --git a/MediaBrowser.Providers/MediaInfo/VideoImageProvider.cs b/MediaBrowser.Providers/MediaInfo/VideoImageProvider.cs
index 2864983ce..b35d5e07e 100644
--- a/MediaBrowser.Providers/MediaInfo/VideoImageProvider.cs
+++ b/MediaBrowser.Providers/MediaInfo/VideoImageProvider.cs
@@ -1,6 +1,5 @@
-using MediaBrowser.Common.IO;
+using MediaBrowser.Common.Extensions;
using MediaBrowser.Common.MediaInfo;
-using MediaBrowser.Controller;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
@@ -12,7 +11,6 @@ using MediaBrowser.Model.Logging;
using System;
using System.Collections.Concurrent;
using System.IO;
-using System.Linq;
using System.Threading;
using System.Threading.Tasks;
@@ -21,12 +19,6 @@ namespace MediaBrowser.Providers.MediaInfo
class VideoImageProvider : BaseMetadataProvider
{
/// <summary>
- /// Gets or sets the image cache.
- /// </summary>
- /// <value>The image cache.</value>
- public FileSystemRepository ImageCache { get; set; }
-
- /// <summary>
/// The _locks
/// </summary>
private readonly ConcurrentDictionary<string, SemaphoreSlim> _locks = new ConcurrentDictionary<string, SemaphoreSlim>();
@@ -42,8 +34,6 @@ namespace MediaBrowser.Providers.MediaInfo
{
_mediaEncoder = mediaEncoder;
_isoManager = isoManager;
-
- ImageCache = new FileSystemRepository(Kernel.Instance.FFMpegManager.VideoImagesDataPath);
}
/// <summary>
@@ -206,9 +196,7 @@ namespace MediaBrowser.Providers.MediaInfo
{
cancellationToken.ThrowIfCancellationRequested();
- var filename = item.Path + "_" + item.DateModified.Ticks + "_primary";
-
- var path = ImageCache.GetResourcePath(filename, ".jpg");
+ var path = GetVideoImagePath(item);
if (!File.Exists(path))
{
@@ -310,5 +298,33 @@ namespace MediaBrowser.Providers.MediaInfo
{
return _locks.GetOrAdd(filename, key => new SemaphoreSlim(1, 1));
}
+
+ /// <summary>
+ /// Gets the video images data path.
+ /// </summary>
+ /// <value>The video images data path.</value>
+ public string VideoImagesPath
+ {
+ get
+ {
+ return Path.Combine(ConfigurationManager.ApplicationPaths.DataPath, "extracted-video-images");
+ }
+ }
+
+ /// <summary>
+ /// Gets the audio image path.
+ /// </summary>
+ /// <param name="item">The item.</param>
+ /// <returns>System.String.</returns>
+ private string GetVideoImagePath(Video item)
+ {
+ var filename = item.Path + "_" + item.DateModified.Ticks + "_primary";
+
+ filename = filename.GetMD5() + ".jpg";
+
+ var prefix = filename.Substring(0, 1);
+
+ return Path.Combine(VideoImagesPath, prefix, filename);
+ }
}
}
diff --git a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs
index 791beb941..11c99a32c 100644
--- a/MediaBrowser.Server.Implementations/Library/LibraryManager.cs
+++ b/MediaBrowser.Server.Implementations/Library/LibraryManager.cs
@@ -899,6 +899,15 @@ namespace MediaBrowser.Server.Implementations.Library
}
/// <summary>
+ /// Queues the library scan.
+ /// </summary>
+ public void QueueLibraryScan()
+ {
+ // Just run the scheduled task so that the user can see it
+ _taskManager.QueueScheduledTask<RefreshMediaLibraryTask>();
+ }
+
+ /// <summary>
/// Validates the media library internal.
/// </summary>
/// <param name="progress">The progress.</param>
diff --git a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs
index 37794cb3d..e06b99999 100644
--- a/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs
+++ b/MediaBrowser.Server.Implementations/LiveTv/LiveTvManager.cs
@@ -420,14 +420,20 @@ namespace MediaBrowser.Server.Implementations.LiveTv
{
var info = _tvDtoService.GetTimerInfo(timer);
- return ActiveService.UpdateTimerAsync(info, cancellationToken);
+ var service = GetServices(timer.ServiceName, null)
+ .First();
+
+ return service.UpdateTimerAsync(info, cancellationToken);
}
public Task UpdateSeriesTimer(SeriesTimerInfoDto timer, CancellationToken cancellationToken)
{
var info = _tvDtoService.GetSeriesTimerInfo(timer);
- return ActiveService.UpdateSeriesTimerAsync(info, cancellationToken);
+ var service = GetServices(timer.ServiceName, null)
+ .First();
+
+ return service.UpdateSeriesTimerAsync(info, cancellationToken);
}
public async Task<QueryResult<SeriesTimerInfoDto>> GetSeriesTimers(SeriesTimerQuery query, CancellationToken cancellationToken)
diff --git a/MediaBrowser.Server.Implementations/ScheduledTasks/ChapterImagesTask.cs b/MediaBrowser.Server.Implementations/ScheduledTasks/ChapterImagesTask.cs
index 9270b879a..7af077785 100644
--- a/MediaBrowser.Server.Implementations/ScheduledTasks/ChapterImagesTask.cs
+++ b/MediaBrowser.Server.Implementations/ScheduledTasks/ChapterImagesTask.cs
@@ -145,7 +145,7 @@ namespace MediaBrowser.Server.Implementations.ScheduledTasks
var numComplete = 0;
- var failHistoryPath = Path.Combine(_kernel.FFMpegManager.VideoImagesDataPath, "failures.txt");
+ var failHistoryPath = Path.Combine(_kernel.FFMpegManager.ChapterImagesPath, "failures.txt");
List<string> previouslyFailedImages;