|
@@ -1,3 +1,5 @@
|
|
|
|
+#pragma warning disable CS1591
|
|
|
|
+
|
|
using System;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Collections.Generic;
|
|
using System.Globalization;
|
|
using System.Globalization;
|
|
@@ -25,7 +27,6 @@ using MediaBrowser.Model.Globalization;
|
|
using MediaBrowser.Model.IO;
|
|
using MediaBrowser.Model.IO;
|
|
using MediaBrowser.Model.MediaInfo;
|
|
using MediaBrowser.Model.MediaInfo;
|
|
using MediaBrowser.Model.Providers;
|
|
using MediaBrowser.Model.Providers;
|
|
-using MediaBrowser.Model.Serialization;
|
|
|
|
using Microsoft.Extensions.Logging;
|
|
using Microsoft.Extensions.Logging;
|
|
|
|
|
|
namespace MediaBrowser.Providers.MediaInfo
|
|
namespace MediaBrowser.Providers.MediaInfo
|
|
@@ -33,13 +34,10 @@ namespace MediaBrowser.Providers.MediaInfo
|
|
public class FFProbeVideoInfo
|
|
public class FFProbeVideoInfo
|
|
{
|
|
{
|
|
private readonly ILogger _logger;
|
|
private readonly ILogger _logger;
|
|
- private readonly IIsoManager _isoManager;
|
|
|
|
private readonly IMediaEncoder _mediaEncoder;
|
|
private readonly IMediaEncoder _mediaEncoder;
|
|
private readonly IItemRepository _itemRepo;
|
|
private readonly IItemRepository _itemRepo;
|
|
private readonly IBlurayExaminer _blurayExaminer;
|
|
private readonly IBlurayExaminer _blurayExaminer;
|
|
private readonly ILocalizationManager _localization;
|
|
private readonly ILocalizationManager _localization;
|
|
- private readonly IApplicationPaths _appPaths;
|
|
|
|
- private readonly IJsonSerializer _json;
|
|
|
|
private readonly IEncodingManager _encodingManager;
|
|
private readonly IEncodingManager _encodingManager;
|
|
private readonly IFileSystem _fileSystem;
|
|
private readonly IFileSystem _fileSystem;
|
|
private readonly IServerConfigurationManager _config;
|
|
private readonly IServerConfigurationManager _config;
|
|
@@ -48,16 +46,27 @@ namespace MediaBrowser.Providers.MediaInfo
|
|
private readonly ILibraryManager _libraryManager;
|
|
private readonly ILibraryManager _libraryManager;
|
|
private readonly IMediaSourceManager _mediaSourceManager;
|
|
private readonly IMediaSourceManager _mediaSourceManager;
|
|
|
|
|
|
- public FFProbeVideoInfo(ILogger logger, IMediaSourceManager mediaSourceManager, IIsoManager isoManager, IMediaEncoder mediaEncoder, IItemRepository itemRepo, IBlurayExaminer blurayExaminer, ILocalizationManager localization, IApplicationPaths appPaths, IJsonSerializer json, IEncodingManager encodingManager, IFileSystem fileSystem, IServerConfigurationManager config, ISubtitleManager subtitleManager, IChapterManager chapterManager, ILibraryManager libraryManager)
|
|
|
|
|
|
+ private readonly long _dummyChapterDuration = TimeSpan.FromMinutes(5).Ticks;
|
|
|
|
+
|
|
|
|
+ public FFProbeVideoInfo(
|
|
|
|
+ ILogger logger,
|
|
|
|
+ IMediaSourceManager mediaSourceManager,
|
|
|
|
+ IMediaEncoder mediaEncoder,
|
|
|
|
+ IItemRepository itemRepo,
|
|
|
|
+ IBlurayExaminer blurayExaminer,
|
|
|
|
+ ILocalizationManager localization,
|
|
|
|
+ IEncodingManager encodingManager,
|
|
|
|
+ IFileSystem fileSystem,
|
|
|
|
+ IServerConfigurationManager config,
|
|
|
|
+ ISubtitleManager subtitleManager,
|
|
|
|
+ IChapterManager chapterManager,
|
|
|
|
+ ILibraryManager libraryManager)
|
|
{
|
|
{
|
|
_logger = logger;
|
|
_logger = logger;
|
|
- _isoManager = isoManager;
|
|
|
|
_mediaEncoder = mediaEncoder;
|
|
_mediaEncoder = mediaEncoder;
|
|
_itemRepo = itemRepo;
|
|
_itemRepo = itemRepo;
|
|
_blurayExaminer = blurayExaminer;
|
|
_blurayExaminer = blurayExaminer;
|
|
_localization = localization;
|
|
_localization = localization;
|
|
- _appPaths = appPaths;
|
|
|
|
- _json = json;
|
|
|
|
_encodingManager = encodingManager;
|
|
_encodingManager = encodingManager;
|
|
_fileSystem = fileSystem;
|
|
_fileSystem = fileSystem;
|
|
_config = config;
|
|
_config = config;
|
|
@@ -159,7 +168,7 @@ namespace MediaBrowser.Providers.MediaInfo
|
|
{
|
|
{
|
|
List<MediaStream> mediaStreams;
|
|
List<MediaStream> mediaStreams;
|
|
IReadOnlyList<MediaAttachment> mediaAttachments;
|
|
IReadOnlyList<MediaAttachment> mediaAttachments;
|
|
- List<ChapterInfo> chapters;
|
|
|
|
|
|
+ ChapterInfo[] chapters;
|
|
|
|
|
|
if (mediaInfo != null)
|
|
if (mediaInfo != null)
|
|
{
|
|
{
|
|
@@ -177,6 +186,7 @@ namespace MediaBrowser.Providers.MediaInfo
|
|
{
|
|
{
|
|
video.RunTimeTicks = mediaInfo.RunTimeTicks;
|
|
video.RunTimeTicks = mediaInfo.RunTimeTicks;
|
|
}
|
|
}
|
|
|
|
+
|
|
video.Size = mediaInfo.Size;
|
|
video.Size = mediaInfo.Size;
|
|
|
|
|
|
if (video.VideoType == VideoType.VideoFile)
|
|
if (video.VideoType == VideoType.VideoFile)
|
|
@@ -189,19 +199,20 @@ namespace MediaBrowser.Providers.MediaInfo
|
|
{
|
|
{
|
|
video.Container = null;
|
|
video.Container = null;
|
|
}
|
|
}
|
|
|
|
+
|
|
video.Container = mediaInfo.Container;
|
|
video.Container = mediaInfo.Container;
|
|
|
|
|
|
- chapters = mediaInfo.Chapters == null ? new List<ChapterInfo>() : mediaInfo.Chapters.ToList();
|
|
|
|
|
|
+ chapters = mediaInfo.Chapters == null ? Array.Empty<ChapterInfo>() : mediaInfo.Chapters;
|
|
if (blurayInfo != null)
|
|
if (blurayInfo != null)
|
|
{
|
|
{
|
|
- FetchBdInfo(video, chapters, mediaStreams, blurayInfo);
|
|
|
|
|
|
+ FetchBdInfo(video, ref chapters, mediaStreams, blurayInfo);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
else
|
|
{
|
|
{
|
|
mediaStreams = new List<MediaStream>();
|
|
mediaStreams = new List<MediaStream>();
|
|
mediaAttachments = Array.Empty<MediaAttachment>();
|
|
mediaAttachments = Array.Empty<MediaAttachment>();
|
|
- chapters = new List<ChapterInfo>();
|
|
|
|
|
|
+ chapters = Array.Empty<ChapterInfo>();
|
|
}
|
|
}
|
|
|
|
|
|
await AddExternalSubtitles(video, mediaStreams, options, cancellationToken).ConfigureAwait(false);
|
|
await AddExternalSubtitles(video, mediaStreams, options, cancellationToken).ConfigureAwait(false);
|
|
@@ -231,9 +242,9 @@ namespace MediaBrowser.Providers.MediaInfo
|
|
if (options.MetadataRefreshMode == MetadataRefreshMode.FullRefresh ||
|
|
if (options.MetadataRefreshMode == MetadataRefreshMode.FullRefresh ||
|
|
options.MetadataRefreshMode == MetadataRefreshMode.Default)
|
|
options.MetadataRefreshMode == MetadataRefreshMode.Default)
|
|
{
|
|
{
|
|
- if (chapters.Count == 0 && mediaStreams.Any(i => i.Type == MediaStreamType.Video))
|
|
|
|
|
|
+ if (chapters.Length == 0 && mediaStreams.Any(i => i.Type == MediaStreamType.Video))
|
|
{
|
|
{
|
|
- AddDummyChapters(video, chapters);
|
|
|
|
|
|
+ chapters = CreateDummyChapters(video);
|
|
}
|
|
}
|
|
|
|
|
|
NormalizeChapterNames(chapters);
|
|
NormalizeChapterNames(chapters);
|
|
@@ -246,28 +257,29 @@ namespace MediaBrowser.Providers.MediaInfo
|
|
|
|
|
|
await _encodingManager.RefreshChapterImages(video, options.DirectoryService, chapters, extractDuringScan, false, cancellationToken).ConfigureAwait(false);
|
|
await _encodingManager.RefreshChapterImages(video, options.DirectoryService, chapters, extractDuringScan, false, cancellationToken).ConfigureAwait(false);
|
|
|
|
|
|
- _chapterManager.SaveChapters(video.Id.ToString(), chapters);
|
|
|
|
|
|
+ _chapterManager.SaveChapters(video.Id, chapters);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
- private void NormalizeChapterNames(List<ChapterInfo> chapters)
|
|
|
|
|
|
+ private void NormalizeChapterNames(ChapterInfo[] chapters)
|
|
{
|
|
{
|
|
- var index = 1;
|
|
|
|
-
|
|
|
|
- foreach (var chapter in chapters)
|
|
|
|
|
|
+ for (int i = 0; i < chapters.Length; i++)
|
|
{
|
|
{
|
|
|
|
+ string name = chapters[i].Name;
|
|
// Check if the name is empty and/or if the name is a time
|
|
// Check if the name is empty and/or if the name is a time
|
|
// Some ripping programs do that.
|
|
// Some ripping programs do that.
|
|
- if (string.IsNullOrWhiteSpace(chapter.Name) ||
|
|
|
|
- TimeSpan.TryParse(chapter.Name, out var time))
|
|
|
|
|
|
+ if (string.IsNullOrWhiteSpace(name) ||
|
|
|
|
+ TimeSpan.TryParse(name, out _))
|
|
{
|
|
{
|
|
- chapter.Name = string.Format(_localization.GetLocalizedString("ChapterNameValue"), index.ToString(CultureInfo.InvariantCulture));
|
|
|
|
|
|
+ chapters[i].Name = string.Format(
|
|
|
|
+ CultureInfo.InvariantCulture,
|
|
|
|
+ _localization.GetLocalizedString("ChapterNameValue"),
|
|
|
|
+ (i + 1).ToString(CultureInfo.InvariantCulture));
|
|
}
|
|
}
|
|
- index++;
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
- private void FetchBdInfo(BaseItem item, List<ChapterInfo> chapters, List<MediaStream> mediaStreams, BlurayDiscInfo blurayInfo)
|
|
|
|
|
|
+ private void FetchBdInfo(BaseItem item, ref ChapterInfo[] chapters, List<MediaStream> mediaStreams, BlurayDiscInfo blurayInfo)
|
|
{
|
|
{
|
|
var video = (Video)item;
|
|
var video = (Video)item;
|
|
|
|
|
|
@@ -301,13 +313,15 @@ namespace MediaBrowser.Providers.MediaInfo
|
|
|
|
|
|
if (blurayInfo.Chapters != null)
|
|
if (blurayInfo.Chapters != null)
|
|
{
|
|
{
|
|
- chapters.Clear();
|
|
|
|
-
|
|
|
|
- chapters.AddRange(blurayInfo.Chapters.Select(c => new ChapterInfo
|
|
|
|
|
|
+ double[] brChapter = blurayInfo.Chapters;
|
|
|
|
+ chapters = new ChapterInfo[brChapter.Length];
|
|
|
|
+ for (int i = 0; i < brChapter.Length; i++)
|
|
{
|
|
{
|
|
- StartPositionTicks = TimeSpan.FromSeconds(c).Ticks
|
|
|
|
-
|
|
|
|
- }));
|
|
|
|
|
|
+ chapters[i] = new ChapterInfo
|
|
|
|
+ {
|
|
|
|
+ StartPositionTicks = TimeSpan.FromSeconds(brChapter[i]).Ticks
|
|
|
|
+ };
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
videoStream = mediaStreams.FirstOrDefault(s => s.Type == MediaStreamType.Video);
|
|
videoStream = mediaStreams.FirstOrDefault(s => s.Type == MediaStreamType.Video);
|
|
@@ -495,17 +509,17 @@ namespace MediaBrowser.Providers.MediaInfo
|
|
var libraryOptions = _libraryManager.GetLibraryOptions(video);
|
|
var libraryOptions = _libraryManager.GetLibraryOptions(video);
|
|
|
|
|
|
string[] subtitleDownloadLanguages;
|
|
string[] subtitleDownloadLanguages;
|
|
- bool SkipIfEmbeddedSubtitlesPresent;
|
|
|
|
- bool SkipIfAudioTrackMatches;
|
|
|
|
- bool RequirePerfectMatch;
|
|
|
|
|
|
+ bool skipIfEmbeddedSubtitlesPresent;
|
|
|
|
+ bool skipIfAudioTrackMatches;
|
|
|
|
+ bool requirePerfectMatch;
|
|
bool enabled;
|
|
bool enabled;
|
|
|
|
|
|
if (libraryOptions.SubtitleDownloadLanguages == null)
|
|
if (libraryOptions.SubtitleDownloadLanguages == null)
|
|
{
|
|
{
|
|
subtitleDownloadLanguages = subtitleOptions.DownloadLanguages;
|
|
subtitleDownloadLanguages = subtitleOptions.DownloadLanguages;
|
|
- SkipIfEmbeddedSubtitlesPresent = subtitleOptions.SkipIfEmbeddedSubtitlesPresent;
|
|
|
|
- SkipIfAudioTrackMatches = subtitleOptions.SkipIfAudioTrackMatches;
|
|
|
|
- RequirePerfectMatch = subtitleOptions.RequirePerfectMatch;
|
|
|
|
|
|
+ skipIfEmbeddedSubtitlesPresent = subtitleOptions.SkipIfEmbeddedSubtitlesPresent;
|
|
|
|
+ skipIfAudioTrackMatches = subtitleOptions.SkipIfAudioTrackMatches;
|
|
|
|
+ requirePerfectMatch = subtitleOptions.RequirePerfectMatch;
|
|
enabled = (subtitleOptions.DownloadEpisodeSubtitles &&
|
|
enabled = (subtitleOptions.DownloadEpisodeSubtitles &&
|
|
video is Episode) ||
|
|
video is Episode) ||
|
|
(subtitleOptions.DownloadMovieSubtitles &&
|
|
(subtitleOptions.DownloadMovieSubtitles &&
|
|
@@ -514,9 +528,9 @@ namespace MediaBrowser.Providers.MediaInfo
|
|
else
|
|
else
|
|
{
|
|
{
|
|
subtitleDownloadLanguages = libraryOptions.SubtitleDownloadLanguages;
|
|
subtitleDownloadLanguages = libraryOptions.SubtitleDownloadLanguages;
|
|
- SkipIfEmbeddedSubtitlesPresent = libraryOptions.SkipSubtitlesIfEmbeddedSubtitlesPresent;
|
|
|
|
- SkipIfAudioTrackMatches = libraryOptions.SkipSubtitlesIfAudioTrackMatches;
|
|
|
|
- RequirePerfectMatch = libraryOptions.RequirePerfectSubtitleMatch;
|
|
|
|
|
|
+ skipIfEmbeddedSubtitlesPresent = libraryOptions.SkipSubtitlesIfEmbeddedSubtitlesPresent;
|
|
|
|
+ skipIfAudioTrackMatches = libraryOptions.SkipSubtitlesIfAudioTrackMatches;
|
|
|
|
+ requirePerfectMatch = libraryOptions.RequirePerfectSubtitleMatch;
|
|
enabled = true;
|
|
enabled = true;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -526,9 +540,9 @@ namespace MediaBrowser.Providers.MediaInfo
|
|
_subtitleManager)
|
|
_subtitleManager)
|
|
.DownloadSubtitles(video,
|
|
.DownloadSubtitles(video,
|
|
currentStreams.Concat(externalSubtitleStreams).ToList(),
|
|
currentStreams.Concat(externalSubtitleStreams).ToList(),
|
|
- SkipIfEmbeddedSubtitlesPresent,
|
|
|
|
- SkipIfAudioTrackMatches,
|
|
|
|
- RequirePerfectMatch,
|
|
|
|
|
|
+ skipIfEmbeddedSubtitlesPresent,
|
|
|
|
+ skipIfAudioTrackMatches,
|
|
|
|
+ requirePerfectMatch,
|
|
subtitleDownloadLanguages,
|
|
subtitleDownloadLanguages,
|
|
libraryOptions.DisabledSubtitleFetchers,
|
|
libraryOptions.DisabledSubtitleFetchers,
|
|
libraryOptions.SubtitleFetcherOrder,
|
|
libraryOptions.SubtitleFetcherOrder,
|
|
@@ -547,43 +561,45 @@ namespace MediaBrowser.Providers.MediaInfo
|
|
}
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// <summary>
|
|
- /// The dummy chapter duration
|
|
|
|
- /// </summary>
|
|
|
|
- private readonly long _dummyChapterDuration = TimeSpan.FromMinutes(5).Ticks;
|
|
|
|
-
|
|
|
|
- /// <summary>
|
|
|
|
- /// Adds the dummy chapters.
|
|
|
|
|
|
+ /// Creates dummy chapters.
|
|
/// </summary>
|
|
/// </summary>
|
|
/// <param name="video">The video.</param>
|
|
/// <param name="video">The video.</param>
|
|
- /// <param name="chapters">The chapters.</param>
|
|
|
|
- private void AddDummyChapters(Video video, List<ChapterInfo> chapters)
|
|
|
|
|
|
+ /// <return>An array of dummy chapters.</returns>
|
|
|
|
+ private ChapterInfo[] CreateDummyChapters(Video video)
|
|
{
|
|
{
|
|
var runtime = video.RunTimeTicks ?? 0;
|
|
var runtime = video.RunTimeTicks ?? 0;
|
|
|
|
|
|
if (runtime < 0)
|
|
if (runtime < 0)
|
|
{
|
|
{
|
|
- throw new ArgumentException(string.Format("{0} has invalid runtime of {1}", video.Name, runtime));
|
|
|
|
|
|
+ throw new ArgumentException(
|
|
|
|
+ string.Format(
|
|
|
|
+ CultureInfo.InvariantCulture,
|
|
|
|
+ "{0} has invalid runtime of {1}",
|
|
|
|
+ video.Name,
|
|
|
|
+ runtime));
|
|
}
|
|
}
|
|
|
|
|
|
if (runtime < _dummyChapterDuration)
|
|
if (runtime < _dummyChapterDuration)
|
|
{
|
|
{
|
|
- return;
|
|
|
|
|
|
+ return Array.Empty<ChapterInfo>();
|
|
}
|
|
}
|
|
|
|
|
|
- long currentChapterTicks = 0;
|
|
|
|
- var index = 1;
|
|
|
|
-
|
|
|
|
// Limit to 100 chapters just in case there's some incorrect metadata here
|
|
// Limit to 100 chapters just in case there's some incorrect metadata here
|
|
- while (currentChapterTicks < runtime && index < 100)
|
|
|
|
|
|
+ int chapterCount = (int)Math.Min(runtime / _dummyChapterDuration, 100);
|
|
|
|
+ var chapters = new ChapterInfo[chapterCount];
|
|
|
|
+
|
|
|
|
+ long currentChapterTicks = 0;
|
|
|
|
+ for (int i = 0; i < chapterCount; i++)
|
|
{
|
|
{
|
|
- chapters.Add(new ChapterInfo
|
|
|
|
|
|
+ chapters[i] = new ChapterInfo
|
|
{
|
|
{
|
|
StartPositionTicks = currentChapterTicks
|
|
StartPositionTicks = currentChapterTicks
|
|
- });
|
|
|
|
|
|
+ };
|
|
|
|
|
|
- index++;
|
|
|
|
currentChapterTicks += _dummyChapterDuration;
|
|
currentChapterTicks += _dummyChapterDuration;
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ return chapters;
|
|
}
|
|
}
|
|
|
|
|
|
private string[] FetchFromDvdLib(Video item)
|
|
private string[] FetchFromDvdLib(Video item)
|