mirror of
https://github.com/jellyfin/jellyfin.git
synced 2024-09-06 03:26:07 +02:00
don't try to keep extracting images that fail
This commit is contained in:
parent
3b5f0a3058
commit
6611b53606
4 changed files with 109 additions and 47 deletions
|
@ -1,4 +1,5 @@
|
||||||
using MediaBrowser.Common.IO;
|
using System.Collections.Generic;
|
||||||
|
using MediaBrowser.Common.IO;
|
||||||
using MediaBrowser.Common.MediaInfo;
|
using MediaBrowser.Common.MediaInfo;
|
||||||
using MediaBrowser.Controller.Entities;
|
using MediaBrowser.Controller.Entities;
|
||||||
using MediaBrowser.Controller.Library;
|
using MediaBrowser.Controller.Library;
|
||||||
|
@ -145,9 +146,10 @@ namespace MediaBrowser.Controller.MediaInfo
|
||||||
/// <param name="cancellationToken">The cancellation token.</param>
|
/// <param name="cancellationToken">The cancellation token.</param>
|
||||||
/// <param name="extractImages">if set to <c>true</c> [extract images].</param>
|
/// <param name="extractImages">if set to <c>true</c> [extract images].</param>
|
||||||
/// <param name="saveItem">if set to <c>true</c> [save item].</param>
|
/// <param name="saveItem">if set to <c>true</c> [save item].</param>
|
||||||
|
/// <param name="previouslyFailedExtractions">The previously failed extractions.</param>
|
||||||
/// <returns>Task.</returns>
|
/// <returns>Task.</returns>
|
||||||
/// <exception cref="System.ArgumentNullException"></exception>
|
/// <exception cref="System.ArgumentNullException"></exception>
|
||||||
public async Task PopulateChapterImages(Video video, CancellationToken cancellationToken, bool extractImages, bool saveItem)
|
public async Task<bool> PopulateChapterImages(Video video, CancellationToken cancellationToken, bool extractImages, bool saveItem)
|
||||||
{
|
{
|
||||||
if (video.Chapters == null)
|
if (video.Chapters == null)
|
||||||
{
|
{
|
||||||
|
@ -157,9 +159,10 @@ namespace MediaBrowser.Controller.MediaInfo
|
||||||
// Can't extract images if there are no video streams
|
// Can't extract images if there are no video streams
|
||||||
if (video.MediaStreams == null || video.MediaStreams.All(m => m.Type != MediaStreamType.Video))
|
if (video.MediaStreams == null || video.MediaStreams.All(m => m.Type != MediaStreamType.Video))
|
||||||
{
|
{
|
||||||
return;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var success = true;
|
||||||
var changesMade = false;
|
var changesMade = false;
|
||||||
|
|
||||||
foreach (var chapter in video.Chapters)
|
foreach (var chapter in video.Chapters)
|
||||||
|
@ -201,6 +204,7 @@ namespace MediaBrowser.Controller.MediaInfo
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
|
success = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -216,6 +220,8 @@ namespace MediaBrowser.Controller.MediaInfo
|
||||||
{
|
{
|
||||||
await _libraryManager.UpdateItem(video, CancellationToken.None).ConfigureAwait(false);
|
await _libraryManager.UpdateItem(video, CancellationToken.None).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
@ -72,9 +72,7 @@ namespace MediaBrowser.Controller.Providers.MediaInfo
|
||||||
|
|
||||||
if (video != null)
|
if (video != null)
|
||||||
{
|
{
|
||||||
await
|
await Kernel.Instance.FFMpegManager.PopulateChapterImages(video, cancellationToken, false, false).ConfigureAwait(false);
|
||||||
Kernel.Instance.FFMpegManager.PopulateChapterImages(video, cancellationToken, false, false)
|
|
||||||
.ConfigureAwait(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SetLastRefreshed(item, DateTime.UtcNow);
|
SetLastRefreshed(item, DateTime.UtcNow);
|
||||||
|
|
|
@ -83,7 +83,7 @@ namespace MediaBrowser.Controller.Providers.Music
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
return "16";
|
return "17";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -106,8 +106,20 @@ namespace MediaBrowser.Controller.Providers.Music
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var comparisonData = Guid.Empty;
|
||||||
|
|
||||||
|
var artistMusicBrainzId = item.Parent.GetProviderId(MetadataProviders.Musicbrainz);
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(artistMusicBrainzId))
|
||||||
|
{
|
||||||
|
var artistXmlPath = FanArtArtistProvider.GetArtistDataPath(ConfigurationManager.CommonApplicationPaths, artistMusicBrainzId);
|
||||||
|
artistXmlPath = Path.Combine(artistXmlPath, "fanart.xml");
|
||||||
|
|
||||||
|
comparisonData = GetComparisonData(new FileInfo(artistXmlPath));
|
||||||
|
}
|
||||||
|
|
||||||
// Refresh anytime the parent mbz id changes
|
// Refresh anytime the parent mbz id changes
|
||||||
if (providerInfo.Data != GetComparisonData(item.Parent.GetProviderId(MetadataProviders.Musicbrainz)))
|
if (providerInfo.Data != comparisonData)
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -119,9 +131,9 @@ namespace MediaBrowser.Controller.Providers.Music
|
||||||
/// Gets the comparison data.
|
/// Gets the comparison data.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>Guid.</returns>
|
/// <returns>Guid.</returns>
|
||||||
private Guid GetComparisonData(string id)
|
private Guid GetComparisonData(FileInfo artistXmlFileInfo)
|
||||||
{
|
{
|
||||||
return string.IsNullOrEmpty(id) ? Guid.Empty : id.GetMD5();
|
return artistXmlFileInfo.Exists ? (artistXmlFileInfo.FullName + artistXmlFileInfo.LastWriteTimeUtc.Ticks).GetMD5() : Guid.Empty;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -145,25 +157,29 @@ namespace MediaBrowser.Controller.Providers.Music
|
||||||
item.ProviderData[Id] = data;
|
item.ProviderData[Id] = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var comparisonData = Guid.Empty;
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(artistMusicBrainzId))
|
if (!string.IsNullOrEmpty(artistMusicBrainzId))
|
||||||
{
|
|
||||||
var album = (MusicAlbum)item;
|
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(album.MusicBrainzReleaseGroupId))
|
|
||||||
{
|
|
||||||
album.MusicBrainzReleaseGroupId = await GetReleaseGroupId(item.GetProviderId(MetadataProviders.Musicbrainz), cancellationToken).ConfigureAwait(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
// If still empty there's nothing more we can do
|
|
||||||
if (!string.IsNullOrEmpty(album.MusicBrainzReleaseGroupId))
|
|
||||||
{
|
{
|
||||||
var artistXmlPath = FanArtArtistProvider.GetArtistDataPath(ConfigurationManager.CommonApplicationPaths, artistMusicBrainzId);
|
var artistXmlPath = FanArtArtistProvider.GetArtistDataPath(ConfigurationManager.CommonApplicationPaths, artistMusicBrainzId);
|
||||||
artistXmlPath = Path.Combine(artistXmlPath, "fanart.xml");
|
artistXmlPath = Path.Combine(artistXmlPath, "fanart.xml");
|
||||||
|
|
||||||
var artistXmlFileInfo = new FileInfo(artistXmlPath);
|
var artistXmlFileInfo = new FileInfo(artistXmlPath);
|
||||||
|
|
||||||
|
comparisonData = GetComparisonData(artistXmlFileInfo);
|
||||||
|
|
||||||
if (artistXmlFileInfo.Exists)
|
if (artistXmlFileInfo.Exists)
|
||||||
{
|
{
|
||||||
|
var album = (MusicAlbum)item;
|
||||||
|
|
||||||
|
var releaseEntryId = item.GetProviderId(MetadataProviders.Musicbrainz);
|
||||||
|
|
||||||
|
// Fanart uses the release group id so we'll have to get that now using the release entry id
|
||||||
|
if (string.IsNullOrEmpty(album.MusicBrainzReleaseGroupId))
|
||||||
|
{
|
||||||
|
album.MusicBrainzReleaseGroupId = await GetReleaseGroupId(releaseEntryId, cancellationToken).ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
|
||||||
var doc = new XmlDocument();
|
var doc = new XmlDocument();
|
||||||
|
|
||||||
doc.Load(artistXmlPath);
|
doc.Load(artistXmlPath);
|
||||||
|
@ -172,7 +188,13 @@ namespace MediaBrowser.Controller.Providers.Music
|
||||||
|
|
||||||
if (ConfigurationManager.Configuration.DownloadMusicAlbumImages.Disc && !item.HasImage(ImageType.Disc))
|
if (ConfigurationManager.Configuration.DownloadMusicAlbumImages.Disc && !item.HasImage(ImageType.Disc))
|
||||||
{
|
{
|
||||||
var node = doc.SelectSingleNode("//fanart/music/albums/album[@id=\"" + album.MusicBrainzReleaseGroupId + "\"]/cdart/@url");
|
// Try try with the release entry Id, if that doesn't produce anything try the release group id
|
||||||
|
var node = doc.SelectSingleNode("//fanart/music/albums/album[@id=\"" + releaseEntryId + "\"]/cdart/@url");
|
||||||
|
|
||||||
|
if (node == null && !string.IsNullOrEmpty(album.MusicBrainzReleaseGroupId))
|
||||||
|
{
|
||||||
|
node = doc.SelectSingleNode("//fanart/music/albums/album[@id=\"" + album.MusicBrainzReleaseGroupId + "\"]/cdart/@url");
|
||||||
|
}
|
||||||
|
|
||||||
var path = node != null ? node.Value : null;
|
var path = node != null ? node.Value : null;
|
||||||
|
|
||||||
|
@ -184,7 +206,13 @@ namespace MediaBrowser.Controller.Providers.Music
|
||||||
|
|
||||||
if (ConfigurationManager.Configuration.DownloadMusicAlbumImages.Primary && !item.HasImage(ImageType.Primary))
|
if (ConfigurationManager.Configuration.DownloadMusicAlbumImages.Primary && !item.HasImage(ImageType.Primary))
|
||||||
{
|
{
|
||||||
var node = doc.SelectSingleNode("//fanart/music/albums/album[@id=\"" + album.MusicBrainzReleaseGroupId + "\"]/albumcover/@url");
|
// Try try with the release entry Id, if that doesn't produce anything try the release group id
|
||||||
|
var node = doc.SelectSingleNode("//fanart/music/albums/album[@id=\"" + releaseEntryId + "\"]/albumcover/@url");
|
||||||
|
|
||||||
|
if (node == null && !string.IsNullOrEmpty(album.MusicBrainzReleaseGroupId))
|
||||||
|
{
|
||||||
|
node = doc.SelectSingleNode("//fanart/music/albums/album[@id=\"" + album.MusicBrainzReleaseGroupId + "\"]/albumcover/@url");
|
||||||
|
}
|
||||||
|
|
||||||
var path = node != null ? node.Value : null;
|
var path = node != null ? node.Value : null;
|
||||||
|
|
||||||
|
@ -194,10 +222,10 @@ namespace MediaBrowser.Controller.Providers.Music
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
data.Data = GetComparisonData(artistMusicBrainzId);
|
data.Data = comparisonData;
|
||||||
SetLastRefreshed(item, DateTime.UtcNow);
|
SetLastRefreshed(item, DateTime.UtcNow);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -4,12 +4,14 @@ using MediaBrowser.Controller.Entities;
|
||||||
using MediaBrowser.Controller.Library;
|
using MediaBrowser.Controller.Library;
|
||||||
using MediaBrowser.Model.Entities;
|
using MediaBrowser.Model.Entities;
|
||||||
using MediaBrowser.Model.Logging;
|
using MediaBrowser.Model.Logging;
|
||||||
|
using MediaBrowser.Model.Serialization;
|
||||||
|
using MoreLinq;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using MoreLinq;
|
|
||||||
|
|
||||||
namespace MediaBrowser.Server.Implementations.ScheduledTasks
|
namespace MediaBrowser.Server.Implementations.ScheduledTasks
|
||||||
{
|
{
|
||||||
|
@ -18,6 +20,8 @@ namespace MediaBrowser.Server.Implementations.ScheduledTasks
|
||||||
/// </summary>
|
/// </summary>
|
||||||
class ChapterImagesTask : IScheduledTask
|
class ChapterImagesTask : IScheduledTask
|
||||||
{
|
{
|
||||||
|
private readonly IJsonSerializer _jsonSerializer;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The _kernel
|
/// The _kernel
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -47,11 +51,13 @@ namespace MediaBrowser.Server.Implementations.ScheduledTasks
|
||||||
/// <param name="kernel">The kernel.</param>
|
/// <param name="kernel">The kernel.</param>
|
||||||
/// <param name="logManager">The log manager.</param>
|
/// <param name="logManager">The log manager.</param>
|
||||||
/// <param name="libraryManager">The library manager.</param>
|
/// <param name="libraryManager">The library manager.</param>
|
||||||
public ChapterImagesTask(Kernel kernel, ILogManager logManager, ILibraryManager libraryManager)
|
/// <param name="jsonSerializer">The json serializer.</param>
|
||||||
|
public ChapterImagesTask(Kernel kernel, ILogManager logManager, ILibraryManager libraryManager, IJsonSerializer jsonSerializer)
|
||||||
{
|
{
|
||||||
_kernel = kernel;
|
_kernel = kernel;
|
||||||
_logger = logManager.GetLogger(GetType().Name);
|
_logger = logManager.GetLogger(GetType().Name);
|
||||||
_libraryManager = libraryManager;
|
_libraryManager = libraryManager;
|
||||||
|
_jsonSerializer = jsonSerializer;
|
||||||
|
|
||||||
libraryManager.ItemAdded += libraryManager_ItemAdded;
|
libraryManager.ItemAdded += libraryManager_ItemAdded;
|
||||||
libraryManager.ItemUpdated += libraryManager_ItemAdded;
|
libraryManager.ItemUpdated += libraryManager_ItemAdded;
|
||||||
|
@ -93,8 +99,9 @@ namespace MediaBrowser.Server.Implementations.ScheduledTasks
|
||||||
NewItemTimer = null;
|
NewItemTimer = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Limit to video files to reduce changes of ffmpeg crash dialog
|
||||||
foreach (var item in newItems
|
foreach (var item in newItems
|
||||||
.Where(i => i.LocationType == LocationType.FileSystem && string.IsNullOrEmpty(i.PrimaryImagePath) && i.MediaStreams.Any(m => m.Type == MediaStreamType.Video))
|
.Where(i => i.LocationType == LocationType.FileSystem && i.VideoType == VideoType.VideoFile && string.IsNullOrEmpty(i.PrimaryImagePath) && i.MediaStreams.Any(m => m.Type == MediaStreamType.Video))
|
||||||
.Take(1))
|
.Take(1))
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
|
@ -135,11 +142,34 @@ namespace MediaBrowser.Server.Implementations.ScheduledTasks
|
||||||
|
|
||||||
var numComplete = 0;
|
var numComplete = 0;
|
||||||
|
|
||||||
|
var failHistoryPath = Path.Combine(_kernel.FFMpegManager.VideoImagesDataPath, "failures.json");
|
||||||
|
|
||||||
|
List<string> previouslyFailedImages;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
previouslyFailedImages = _jsonSerializer.DeserializeFromFile<List<string>>(failHistoryPath);
|
||||||
|
}
|
||||||
|
catch (FileNotFoundException)
|
||||||
|
{
|
||||||
|
previouslyFailedImages = new List<string>();
|
||||||
|
}
|
||||||
|
|
||||||
foreach (var video in videos)
|
foreach (var video in videos)
|
||||||
{
|
{
|
||||||
cancellationToken.ThrowIfCancellationRequested();
|
cancellationToken.ThrowIfCancellationRequested();
|
||||||
|
|
||||||
await _kernel.FFMpegManager.PopulateChapterImages(video, cancellationToken, true, true);
|
var key = video.Path + video.DateModified.Ticks;
|
||||||
|
|
||||||
|
var extract = !previouslyFailedImages.Contains(key, StringComparer.OrdinalIgnoreCase);
|
||||||
|
|
||||||
|
var success = await _kernel.FFMpegManager.PopulateChapterImages(video, cancellationToken, extract, true);
|
||||||
|
|
||||||
|
if (!success)
|
||||||
|
{
|
||||||
|
previouslyFailedImages.Add(key);
|
||||||
|
_jsonSerializer.SerializeToFile(previouslyFailedImages, failHistoryPath);
|
||||||
|
}
|
||||||
|
|
||||||
numComplete++;
|
numComplete++;
|
||||||
double percent = numComplete;
|
double percent = numComplete;
|
||||||
|
|
Loading…
Reference in a new issue