aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs21
-rw-r--r--MediaBrowser.Providers/MediaInfo/AudioResolver.cs271
-rw-r--r--MediaBrowser.Providers/MediaInfo/FFProbeProvider.cs16
-rw-r--r--MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs16
4 files changed, 114 insertions, 210 deletions
diff --git a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs
index 5326ecd20..5695ee2db 100644
--- a/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs
+++ b/MediaBrowser.Controller/MediaEncoding/EncodingHelper.cs
@@ -678,12 +678,6 @@ namespace MediaBrowser.Controller.MediaEncoding
arg.Append("-i ")
.Append(GetInputPathArgument(state));
- if (state.AudioStream.IsExternal)
- {
- arg.Append(" -i ")
- .Append(string.Format(CultureInfo.InvariantCulture, "file:\"{0}\"", state.AudioStream.Path));
- }
-
if (state.SubtitleStream != null
&& state.SubtitleDeliveryMethod == SubtitleDeliveryMethod.Encode
&& state.SubtitleStream.IsExternal && !state.SubtitleStream.IsTextSubtitleStream)
@@ -702,6 +696,12 @@ namespace MediaBrowser.Controller.MediaEncoding
arg.Append(" -i \"").Append(subtitlePath).Append('\"');
}
+ if (state.AudioStream != null && state.AudioStream.IsExternal)
+ {
+ arg.Append(" -i ")
+ .Append(string.Format(CultureInfo.InvariantCulture, "file:\"{0}\"", state.AudioStream.Path));
+ }
+
return arg.ToString();
}
@@ -2007,7 +2007,14 @@ namespace MediaBrowser.Controller.MediaEncoding
{
if (state.AudioStream.IsExternal)
{
- args += " -map 1:a";
+ int externalAudioMapIndex = state.SubtitleStream != null && state.SubtitleStream.IsExternal ? 2 : 1;
+ int externalAudioStream = state.MediaSource.MediaStreams.Where(i => i.Path == state.AudioStream.Path).ToList().IndexOf(state.AudioStream);
+
+ args += string.Format(
+ CultureInfo.InvariantCulture,
+ " -map {0}:{1}",
+ externalAudioMapIndex,
+ externalAudioStream);
}
else
{
diff --git a/MediaBrowser.Providers/MediaInfo/AudioResolver.cs b/MediaBrowser.Providers/MediaInfo/AudioResolver.cs
index fce2fa551..8d5f8d86e 100644
--- a/MediaBrowser.Providers/MediaInfo/AudioResolver.cs
+++ b/MediaBrowser.Providers/MediaInfo/AudioResolver.cs
@@ -1,13 +1,13 @@
-#nullable disable
-
#pragma warning disable CA1002, CS1591
using System;
using System.Collections.Generic;
using System.IO;
-using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using Emby.Naming.Audio;
+using Emby.Naming.Common;
+using Jellyfin.Extensions;
using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.MediaEncoding;
using MediaBrowser.Controller.Providers;
@@ -21,24 +21,15 @@ namespace MediaBrowser.Providers.MediaInfo
{
public class AudioResolver
{
- private readonly ILocalizationManager _localization;
-
- private readonly IMediaEncoder _mediaEncoder;
-
- private readonly CancellationToken _cancellationToken;
-
- public AudioResolver(ILocalizationManager localization, IMediaEncoder mediaEncoder, CancellationToken cancellationToken = default)
- {
- _localization = localization;
- _mediaEncoder = mediaEncoder;
- _cancellationToken = cancellationToken;
- }
-
- public List<MediaStream> GetExternalAudioStreams(
+ public async Task<List<MediaStream>> GetExternalAudioStreams(
Video video,
int startIndex,
IDirectoryService directoryService,
- bool clearCache)
+ NamingOptions namingOptions,
+ bool clearCache,
+ ILocalizationManager localizationManager,
+ IMediaEncoder mediaEncoder,
+ CancellationToken cancellationToken)
{
var streams = new List<MediaStream>();
@@ -47,198 +38,117 @@ namespace MediaBrowser.Providers.MediaInfo
return streams;
}
- AddExternalAudioStreams(streams, video.ContainingFolderPath, video.Path, startIndex, directoryService, clearCache);
-
- startIndex += streams.Count;
+ List<string> paths = GetExternalAudioFiles(video, directoryService, namingOptions, clearCache);
- string folder = video.GetInternalMetadataPath();
-
- if (!Directory.Exists(folder))
- {
- return streams;
- }
-
- try
- {
- AddExternalAudioStreams(streams, folder, video.Path, startIndex, directoryService, clearCache);
- }
- catch (IOException)
- {
- }
+ await AddExternalAudioStreams(streams, paths, startIndex, localizationManager, mediaEncoder, cancellationToken);
return streams;
}
- public IEnumerable<string> GetExternalAudioFiles(
+ public List<string> GetExternalAudioFiles(
Video video,
IDirectoryService directoryService,
+ NamingOptions namingOptions,
bool clearCache)
{
+ List<string> paths = new List<string>();
+
if (!video.IsFileProtocol)
{
- yield break;
+ return paths;
}
- var streams = GetExternalAudioStreams(video, 0, directoryService, clearCache);
+ paths.AddRange(GetAudioFilesFromFolder(video.ContainingFolderPath, video.Path, directoryService, namingOptions, clearCache));
+ paths.AddRange(GetAudioFilesFromFolder(video.GetInternalMetadataPath(), video.Path, directoryService, namingOptions, clearCache));
- foreach (var stream in streams)
- {
- yield return stream.Path;
- }
+ return paths;
}
- public void AddExternalAudioStreams(
- List<MediaStream> streams,
- string videoPath,
- int startIndex,
- IReadOnlyList<string> files)
+ private List<string> GetAudioFilesFromFolder(
+ string folder,
+ string videoFileName,
+ IDirectoryService directoryService,
+ NamingOptions namingOptions,
+ bool clearCache)
{
- var videoFileNameWithoutExtension = NormalizeFilenameForAudioComparison(videoPath);
+ List<string> paths = new List<string>();
+ string videoFileNameWithoutExtension = Path.GetFileNameWithoutExtension(videoFileName);
- for (var i = 0; i < files.Count; i++)
+ if (!Directory.Exists(folder))
+ {
+ return paths;
+ }
+
+ var files = directoryService.GetFilePaths(folder, clearCache, true);
+ for (int i = 0; i < files.Count; i++)
{
+ string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(files[i]);
- var fullName = files[i];
- var extension = Path.GetExtension(fullName.AsSpan());
- if (!IsAudioExtension(extension))
+ if (!AudioFileParser.IsAudioFile(files[i], namingOptions))
{
continue;
}
- Model.MediaInfo.MediaInfo mediaInfo = GetMediaInfo(fullName).Result;
- MediaStream mediaStream = mediaInfo.MediaStreams.First();
- mediaStream.Index = startIndex++;
- mediaStream.Type = MediaStreamType.Audio;
- mediaStream.IsExternal = true;
- mediaStream.Path = fullName;
- mediaStream.IsDefault = false;
- mediaStream.Title = null;
-
- var fileNameWithoutExtension = NormalizeFilenameForAudioComparison(fullName);
-
// The audio filename must either be equal to the video filename or start with the video filename followed by a dot
- if (videoFileNameWithoutExtension.Equals(fileNameWithoutExtension, StringComparison.OrdinalIgnoreCase))
- {
- mediaStream.Path = fullName;
- }
- else if (fileNameWithoutExtension.Length > videoFileNameWithoutExtension.Length
+ if (videoFileNameWithoutExtension.Equals(fileNameWithoutExtension, StringComparison.OrdinalIgnoreCase) ||
+ (fileNameWithoutExtension.Length > videoFileNameWithoutExtension.Length
&& fileNameWithoutExtension[videoFileNameWithoutExtension.Length] == '.'
- && fileNameWithoutExtension.StartsWith(videoFileNameWithoutExtension, StringComparison.OrdinalIgnoreCase))
+ && fileNameWithoutExtension.StartsWith(videoFileNameWithoutExtension, StringComparison.OrdinalIgnoreCase)))
{
-
- // Support xbmc naming conventions - 300.spanish.m4a
- var languageSpan = fileNameWithoutExtension;
- while (languageSpan.Length > 0)
- {
- var lastDot = languageSpan.LastIndexOf('.');
- var currentSlice = languageSpan[lastDot..];
- languageSpan = languageSpan[(lastDot + 1)..];
- break;
- }
-
- // Try to translate to three character code
- // Be flexible and check against both the full and three character versions
- var language = languageSpan.ToString();
- var culture = _localization.FindLanguageInfo(language);
-
- language = culture == null ? language : culture.ThreeLetterISOLanguageName;
- mediaStream.Language = language;
- }
- else
- {
- continue;
+ paths.Add(files[i]);
}
-
- mediaStream.Codec = extension.TrimStart('.').ToString().ToLowerInvariant();
-
- streams.Add(mediaStream);
}
+
+ return paths;
}
- private static bool IsAudioExtension(ReadOnlySpan<char> extension)
+ public async Task AddExternalAudioStreams(
+ List<MediaStream> streams,
+ List<string> paths,
+ int startIndex,
+ ILocalizationManager localizationManager,
+ IMediaEncoder mediaEncoder,
+ CancellationToken cancellationToken)
{
- String[] audioExtensions = new[]
+ foreach (string path in paths)
{
- ".nsv",
- ".m4a",
- ".flac",
- ".aac",
- ".strm",
- ".pls",
- ".rm",
- ".mpa",
- ".wav",
- ".wma",
- ".ogg",
- ".opus",
- ".mp3",
- ".mp2",
- ".mod",
- ".amf",
- ".669",
- ".dmf",
- ".dsm",
- ".far",
- ".gdm",
- ".imf",
- ".it",
- ".m15",
- ".med",
- ".okt",
- ".s3m",
- ".stm",
- ".sfx",
- ".ult",
- ".uni",
- ".xm",
- ".sid",
- ".ac3",
- ".dts",
- ".cue",
- ".aif",
- ".aiff",
- ".ape",
- ".mac",
- ".mpc",
- ".mp+",
- ".mpp",
- ".shn",
- ".wv",
- ".nsf",
- ".spc",
- ".gym",
- ".adplug",
- ".adx",
- ".dsp",
- ".adp",
- ".ymf",
- ".ast",
- ".afc",
- ".hps",
- ".xsp",
- ".acc",
- ".m4b",
- ".oga",
- ".dsf",
- ".mka"
- };
+ string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(path);
+ Model.MediaInfo.MediaInfo mediaInfo = await GetMediaInfo(path, mediaEncoder, cancellationToken);
- foreach (String audioExtension in audioExtensions)
- {
- if (extension.Equals(audioExtension, StringComparison.OrdinalIgnoreCase))
+ foreach (MediaStream mediaStream in mediaInfo.MediaStreams)
{
- return true;
+ mediaStream.Index = startIndex++;
+ mediaStream.Type = MediaStreamType.Audio;
+ mediaStream.IsExternal = true;
+ mediaStream.Path = path;
+ mediaStream.IsDefault = false;
+ mediaStream.Title = null;
+
+ if (mediaStream.Language == null)
+ {
+ // Try to translate to three character code
+ // Be flexible and check against both the full and three character versions
+ var language = StringExtensions.RightPart(fileNameWithoutExtension, '.').ToString();
+
+ if (language != fileNameWithoutExtension)
+ {
+ var culture = localizationManager.FindLanguageInfo(language);
+
+ language = culture == null ? language : culture.ThreeLetterISOLanguageName;
+ mediaStream.Language = language;
+ }
+ }
+
+ streams.Add(mediaStream);
}
}
-
- return false;
}
- private Task<Model.MediaInfo.MediaInfo> GetMediaInfo(string path)
+ private Task<Model.MediaInfo.MediaInfo> GetMediaInfo(string path, IMediaEncoder mediaEncoder, CancellationToken cancellationToken)
{
- _cancellationToken.ThrowIfCancellationRequested();
+ cancellationToken.ThrowIfCancellationRequested();
- return _mediaEncoder.GetMediaInfo(
+ return mediaEncoder.GetMediaInfo(
new MediaInfoRequest
{
MediaType = DlnaProfileType.Audio,
@@ -248,28 +158,7 @@ namespace MediaBrowser.Providers.MediaInfo
Protocol = MediaProtocol.File
}
},
- _cancellationToken);
- }
-
- private static ReadOnlySpan<char> NormalizeFilenameForAudioComparison(string filename)
- {
- // Try to account for sloppy file naming
- filename = filename.Replace("_", string.Empty, StringComparison.Ordinal);
- filename = filename.Replace(" ", string.Empty, StringComparison.Ordinal);
- return Path.GetFileNameWithoutExtension(filename.AsSpan());
- }
-
- private void AddExternalAudioStreams(
- List<MediaStream> streams,
- string folder,
- string videoPath,
- int startIndex,
- IDirectoryService directoryService,
- bool clearCache)
- {
- var files = directoryService.GetFilePaths(folder, clearCache, true);
-
- AddExternalAudioStreams(streams, videoPath, startIndex, files);
+ cancellationToken);
}
}
}
diff --git a/MediaBrowser.Providers/MediaInfo/FFProbeProvider.cs b/MediaBrowser.Providers/MediaInfo/FFProbeProvider.cs
index 1e7fcf2d2..98909c94e 100644
--- a/MediaBrowser.Providers/MediaInfo/FFProbeProvider.cs
+++ b/MediaBrowser.Providers/MediaInfo/FFProbeProvider.cs
@@ -7,6 +7,7 @@ using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using Emby.Naming.Common;
using MediaBrowser.Controller.Chapters;
using MediaBrowser.Controller.Configuration;
using MediaBrowser.Controller.Entities;
@@ -50,10 +51,10 @@ namespace MediaBrowser.Providers.MediaInfo
private readonly IMediaSourceManager _mediaSourceManager;
private readonly SubtitleResolver _subtitleResolver;
- private readonly AudioResolver _audioResolver;
-
private readonly Task<ItemUpdateType> _cachedTask = Task.FromResult(ItemUpdateType.None);
+ private readonly NamingOptions _namingOptions;
+
public FFProbeProvider(
ILogger<FFProbeProvider> logger,
IMediaSourceManager mediaSourceManager,
@@ -65,7 +66,8 @@ namespace MediaBrowser.Providers.MediaInfo
IServerConfigurationManager config,
ISubtitleManager subtitleManager,
IChapterManager chapterManager,
- ILibraryManager libraryManager)
+ ILibraryManager libraryManager,
+ NamingOptions namingOptions)
{
_logger = logger;
_mediaEncoder = mediaEncoder;
@@ -78,9 +80,9 @@ namespace MediaBrowser.Providers.MediaInfo
_chapterManager = chapterManager;
_libraryManager = libraryManager;
_mediaSourceManager = mediaSourceManager;
+ _namingOptions = namingOptions;
_subtitleResolver = new SubtitleResolver(BaseItem.LocalizationManager);
- _audioResolver = new AudioResolver(BaseItem.LocalizationManager, mediaEncoder);
}
public string Name => "ffprobe";
@@ -114,9 +116,10 @@ namespace MediaBrowser.Providers.MediaInfo
return true;
}
+ AudioResolver audioResolver = new AudioResolver();
if (item.SupportsLocalMetadata && video != null && !video.IsPlaceHolder
&& !video.AudioFiles.SequenceEqual(
- _audioResolver.GetExternalAudioFiles(video, directoryService, false), StringComparer.Ordinal))
+ audioResolver.GetExternalAudioFiles(video, directoryService, _namingOptions, false), StringComparer.Ordinal))
{
_logger.LogDebug("Refreshing {0} due to external audio change.", item.Path);
return true;
@@ -199,7 +202,8 @@ namespace MediaBrowser.Providers.MediaInfo
_config,
_subtitleManager,
_chapterManager,
- _libraryManager);
+ _libraryManager,
+ _namingOptions);
return prober.ProbeVideo(item, options, cancellationToken);
}
diff --git a/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs b/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs
index 2d49e43ca..39950db70 100644
--- a/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs
+++ b/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs
@@ -10,6 +10,7 @@ using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using DvdLib.Ifo;
+using Emby.Naming.Common;
using MediaBrowser.Common.Configuration;
using MediaBrowser.Controller.Chapters;
using MediaBrowser.Controller.Configuration;
@@ -44,6 +45,7 @@ namespace MediaBrowser.Providers.MediaInfo
private readonly ISubtitleManager _subtitleManager;
private readonly IChapterManager _chapterManager;
private readonly ILibraryManager _libraryManager;
+ private readonly NamingOptions _namingOptions;
private readonly IMediaSourceManager _mediaSourceManager;
private readonly long _dummyChapterDuration = TimeSpan.FromMinutes(5).Ticks;
@@ -59,7 +61,8 @@ namespace MediaBrowser.Providers.MediaInfo
IServerConfigurationManager config,
ISubtitleManager subtitleManager,
IChapterManager chapterManager,
- ILibraryManager libraryManager)
+ ILibraryManager libraryManager,
+ NamingOptions namingOptions)
{
_logger = logger;
_mediaEncoder = mediaEncoder;
@@ -71,6 +74,7 @@ namespace MediaBrowser.Providers.MediaInfo
_subtitleManager = subtitleManager;
_chapterManager = chapterManager;
_libraryManager = libraryManager;
+ _namingOptions = namingOptions;
_mediaSourceManager = mediaSourceManager;
}
@@ -214,7 +218,7 @@ namespace MediaBrowser.Providers.MediaInfo
await AddExternalSubtitles(video, mediaStreams, options, cancellationToken).ConfigureAwait(false);
- AddExternalAudio(video, mediaStreams, options, cancellationToken);
+ await AddExternalAudio(video, mediaStreams, options, cancellationToken);
var libraryOptions = _libraryManager.GetLibraryOptions(video);
@@ -583,18 +587,18 @@ namespace MediaBrowser.Providers.MediaInfo
/// <param name="currentStreams">The current streams.</param>
/// <param name="options">The refreshOptions.</param>
/// <param name="cancellationToken">The cancellation token.</param>
- private void AddExternalAudio(
+ private async Task AddExternalAudio(
Video video,
List<MediaStream> currentStreams,
MetadataRefreshOptions options,
CancellationToken cancellationToken)
{
- var audioResolver = new AudioResolver(_localization, _mediaEncoder, cancellationToken);
+ var audioResolver = new AudioResolver();
var startIndex = currentStreams.Count == 0 ? 0 : currentStreams.Max(i => i.Index) + 1;
- var externalAudioStreams = audioResolver.GetExternalAudioStreams(video, startIndex, options.DirectoryService, false);
+ var externalAudioStreams = await audioResolver.GetExternalAudioStreams(video, startIndex, options.DirectoryService, _namingOptions, false, _localization, _mediaEncoder, cancellationToken);
- video.AudioFiles = externalAudioStreams.Select(i => i.Path).ToArray();
+ video.AudioFiles = externalAudioStreams.Select(i => i.Path).Distinct().ToArray();
currentStreams.AddRange(externalAudioStreams);
}