From 9ec2870b1034e0b64ebde3e29a3779c7f6bb2ac4 Mon Sep 17 00:00:00 2001 From: luz paz Date: Mon, 15 Aug 2022 06:48:34 -0400 Subject: Fix various typos Found via `codespell -q 3 -S ./Emby.Server.Implementations/Localization -L allready,doesnt,inh,receivedfrom,whoknows` --- MediaBrowser.Model/Dto/BaseItemDto.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'MediaBrowser.Model/Dto') diff --git a/MediaBrowser.Model/Dto/BaseItemDto.cs b/MediaBrowser.Model/Dto/BaseItemDto.cs index 094dc73b2..fdb84fa32 100644 --- a/MediaBrowser.Model/Dto/BaseItemDto.cs +++ b/MediaBrowser.Model/Dto/BaseItemDto.cs @@ -294,13 +294,13 @@ namespace MediaBrowser.Model.Dto public NameGuidPair[] GenreItems { get; set; } /// - /// Gets or sets wether the item has a logo, this will hold the Id of the Parent that has one. + /// Gets or sets whether the item has a logo, this will hold the Id of the Parent that has one. /// /// The parent logo item id. public Guid? ParentLogoItemId { get; set; } /// - /// Gets or sets wether the item has any backdrops, this will hold the Id of the Parent that has one. + /// Gets or sets whether the item has any backdrops, this will hold the Id of the Parent that has one. /// /// The parent backdrop item id. public Guid? ParentBackdropItemId { get; set; } @@ -506,7 +506,7 @@ namespace MediaBrowser.Model.Dto public string ParentLogoImageTag { get; set; } /// - /// Gets or sets wether the item has fan art, this will hold the Id of the Parent that has one. + /// Gets or sets whether the item has fan art, this will hold the Id of the Parent that has one. /// /// The parent art item id. public Guid? ParentArtItemId { get; set; } -- cgit v1.2.3 From 9d5cf67dfe2d5871d42a55a5e114c5ead1036ff0 Mon Sep 17 00:00:00 2001 From: 1hitsong <3330318+1hitsong@users.noreply.github.com> Date: Sat, 10 Sep 2022 14:58:03 -0400 Subject: Create ILyricsProvider --- Emby.Server.Implementations/Dto/DtoService.cs | 5 + Jellyfin.Api/Helpers/ItemHelper.cs | 117 +++++++++++++--------- Jellyfin.Api/Models/UserDtos/ILyricsProvider.cs | 34 +++++++ Jellyfin.Api/Models/UserDtos/LrcLyricsProvider.cs | 117 ++++++++++++++++++++++ Jellyfin.Api/Models/UserDtos/Lyric.cs | 18 ++++ Jellyfin.Api/Models/UserDtos/Lyrics.cs | 23 ----- Jellyfin.Api/Models/UserDtos/TxtLyricsProvider.cs | 81 +++++++++++++++ MediaBrowser.Model/Dto/BaseItemDto.cs | 2 + 8 files changed, 325 insertions(+), 72 deletions(-) create mode 100644 Jellyfin.Api/Models/UserDtos/ILyricsProvider.cs create mode 100644 Jellyfin.Api/Models/UserDtos/LrcLyricsProvider.cs create mode 100644 Jellyfin.Api/Models/UserDtos/Lyric.cs delete mode 100644 Jellyfin.Api/Models/UserDtos/Lyrics.cs create mode 100644 Jellyfin.Api/Models/UserDtos/TxtLyricsProvider.cs (limited to 'MediaBrowser.Model/Dto') diff --git a/Emby.Server.Implementations/Dto/DtoService.cs b/Emby.Server.Implementations/Dto/DtoService.cs index 09ba36851..96717cff5 100644 --- a/Emby.Server.Implementations/Dto/DtoService.cs +++ b/Emby.Server.Implementations/Dto/DtoService.cs @@ -7,6 +7,7 @@ using System.Collections.Generic; using System.Globalization; using System.IO; using System.Linq; +using Jellyfin.Api.Helpers; using Jellyfin.Data.Entities; using Jellyfin.Data.Enums; using Jellyfin.Extensions; @@ -139,6 +140,10 @@ namespace Emby.Server.Implementations.Dto { LivetvManager.AddInfoToProgramDto(new[] { (item, dto) }, options.Fields, user).GetAwaiter().GetResult(); } + else if (item is Audio) + { + dto.HasLocalLyricsFile = ItemHelper.HasLyricFile(item.Path); + } if (item is IItemByName itemByName && options.ContainsField(ItemFields.ItemCounts)) diff --git a/Jellyfin.Api/Helpers/ItemHelper.cs b/Jellyfin.Api/Helpers/ItemHelper.cs index c1b5ea6cc..622eb0b9f 100644 --- a/Jellyfin.Api/Helpers/ItemHelper.cs +++ b/Jellyfin.Api/Helpers/ItemHelper.cs @@ -23,79 +23,98 @@ namespace Jellyfin.Api.Helpers /// Collection of Lyrics. internal static object? GetLyricData(BaseItem item) { - List lyricsList = new List(); + List providerList = new List(); - string lrcFilePath = @Path.ChangeExtension(item.Path, "lrc"); + // Find all classes that implement ILyricsProvider Interface + var foundLyricProviders = System.Reflection.Assembly.GetExecutingAssembly() + .GetTypes() + .Where(type => typeof(ILyricsProvider).IsAssignableFrom(type) && !type.IsInterface); - // LRC File not found, fallback to TXT file - if (!System.IO.File.Exists(lrcFilePath)) + if (!foundLyricProviders.Any()) { - string txtFilePath = @Path.ChangeExtension(item.Path, "txt"); - if (!System.IO.File.Exists(txtFilePath)) - { - return null; - } + return null; + } - var lyricTextData = System.IO.File.ReadAllText(txtFilePath); - string[] lyricTextLines = lyricTextData.Split(Environment.NewLine, StringSplitOptions.RemoveEmptyEntries); + foreach (var provider in foundLyricProviders) + { + providerList.Add((ILyricsProvider)Activator.CreateInstance(provider)); + } - foreach (var lyricLine in lyricTextLines) + foreach (ILyricsProvider provider in providerList) + { + provider.Process(item); + if (provider.HasData) { - lyricsList.Add(new Lyrics { Text = lyricLine }); + return provider.Data; } - - return new { lyrics = lyricsList }; } - // Process LRC File - Song lyricData; - List sortedLyricData = new List(); - var metaData = new ExpandoObject() as IDictionary; - string lrcFileContent = System.IO.File.ReadAllText(lrcFilePath); - - try - { - LyricParser lrcLyricParser = new LrcParser.Parser.Lrc.LrcParser(); - lyricData = lrcLyricParser.Decode(lrcFileContent); - var _metaData = lyricData.Lyrics - .Where(x => x.TimeTags.Count == 0) - .Where(x => x.Text.StartsWith("[", StringComparison.Ordinal) && x.Text.EndsWith("]", StringComparison.Ordinal)) - .Select(x => x.Text) - .ToList(); - - foreach (string dataRow in _metaData) - { - var data = dataRow.Split(":"); + return null; + } - string newPropertyName = data[0].Replace("[", string.Empty, StringComparison.Ordinal); - string newPropertyValue = data[1].Replace("]", string.Empty, StringComparison.Ordinal); + /// + /// Checks if requested item has a matching lyric file. + /// + /// Path of requested item. + /// True if item has a matching lyrics file. + public static string? GetLyricFilePath(string itemPath) + { + List supportedLyricFileExtensions = new List(); - metaData.Add(newPropertyName, newPropertyValue); - } + // Find all classes that implement ILyricsProvider Interface + var foundLyricProviders = System.Reflection.Assembly.GetExecutingAssembly() + .GetTypes() + .Where(type => typeof(ILyricsProvider).IsAssignableFrom(type) && !type.IsInterface); - sortedLyricData = lyricData.Lyrics.Where(x => x.TimeTags.Count > 0).OrderBy(x => x.TimeTags.ToArray()[0].Value).ToList(); - } - catch + if (!foundLyricProviders.Any()) { return null; } - if (lyricData == null) + // Iterate over all found lyric providers + foreach (var provider in foundLyricProviders) { - return null; + var foundProvider = (ILyricsProvider)Activator.CreateInstance(provider); + if (foundProvider?.FileExtensions is null) + { + continue; + } + + if (foundProvider.FileExtensions.Any()) + { + // Gather distinct list of handled file extentions + foreach (string lyricFileExtension in foundProvider.FileExtensions) + { + if (!supportedLyricFileExtensions.Contains(lyricFileExtension)) + { + supportedLyricFileExtensions.Add(lyricFileExtension); + } + } + } } - for (int i = 0; i < sortedLyricData.Count; i++) + foreach (string lyricFileExtension in supportedLyricFileExtensions) { - if (sortedLyricData[i].TimeTags.Count > 0) + string lyricFilePath = @Path.ChangeExtension(itemPath, lyricFileExtension); + if (System.IO.File.Exists(lyricFilePath)) { - var timeData = sortedLyricData[i].TimeTags.ToArray()[0].Value; - double ticks = Convert.ToDouble(timeData, new NumberFormatInfo()) * 10000; - lyricsList.Add(new Lyrics { Start = Math.Ceiling(ticks), Text = sortedLyricData[i].Text }); + return lyricFilePath; } } - return new { MetaData = metaData, lyrics = lyricsList }; + return null; + } + + + /// + /// Checks if requested item has a matching local lyric file. + /// + /// Path of requested item. + /// True if item has a matching lyrics file; otherwise false. + public static bool HasLyricFile(string itemPath) + { + string? lyricFilePath = GetLyricFilePath(itemPath); + return !string.IsNullOrEmpty(lyricFilePath); } } } diff --git a/Jellyfin.Api/Models/UserDtos/ILyricsProvider.cs b/Jellyfin.Api/Models/UserDtos/ILyricsProvider.cs new file mode 100644 index 000000000..37f1f5bbe --- /dev/null +++ b/Jellyfin.Api/Models/UserDtos/ILyricsProvider.cs @@ -0,0 +1,34 @@ +using System.Collections.ObjectModel; +using MediaBrowser.Controller.Entities; + +namespace Jellyfin.Api.Models.UserDtos +{ + /// + /// Interface ILyricsProvider. + /// + public interface ILyricsProvider + { + /// + /// Gets a value indicating the File Extenstions this provider works with. + /// + public Collection? FileExtensions { get; } + + /// + /// Gets a value indicating whether Process() generated data. + /// + /// true if data generated; otherwise, false. + bool HasData { get; } + + /// + /// Gets Data object generated by Process() method. + /// + /// Object with data if no error occured; otherwise, null. + object? Data { get; } + + /// + /// Opens lyric file for [the specified item], and processes it for API return. + /// + /// The item to to process. + void Process(BaseItem item); + } +} diff --git a/Jellyfin.Api/Models/UserDtos/LrcLyricsProvider.cs b/Jellyfin.Api/Models/UserDtos/LrcLyricsProvider.cs new file mode 100644 index 000000000..029acd6ca --- /dev/null +++ b/Jellyfin.Api/Models/UserDtos/LrcLyricsProvider.cs @@ -0,0 +1,117 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Dynamic; +using System.Globalization; +using System.Linq; +using LrcParser.Model; +using LrcParser.Parser; +using MediaBrowser.Controller.Entities; + +namespace Jellyfin.Api.Models.UserDtos +{ + /// + /// LRC File Lyric Provider. + /// + public class LrcLyricsProvider : ILyricsProvider + { + /// + /// Initializes a new instance of the class. + /// + public LrcLyricsProvider() + { + FileExtensions = new Collection + { + "lrc" + }; + } + + /// + /// Gets a value indicating the File Extenstions this provider works with. + /// + public Collection? FileExtensions { get; } + + /// + /// Gets or Sets a value indicating whether Process() generated data. + /// + /// true if data generated; otherwise, false. + public bool HasData { get; set; } + + /// + /// Gets or Sets Data object generated by Process() method. + /// + /// Object with data if no error occured; otherwise, null. + public object? Data { get; set; } + + /// + /// Opens lyric file for [the specified item], and processes it for API return. + /// + /// The item to to process. + public void Process(BaseItem item) + { + string? lyricFilePath = Helpers.ItemHelper.GetLyricFilePath(item.Path); + + if (string.IsNullOrEmpty(lyricFilePath)) + { + return; + } + + List lyricsList = new List(); + + List sortedLyricData = new List(); + var metaData = new ExpandoObject() as IDictionary; + string lrcFileContent = System.IO.File.ReadAllText(lyricFilePath); + + try + { + // Parse and sort lyric rows + LyricParser lrcLyricParser = new LrcParser.Parser.Lrc.LrcParser(); + Song lyricData = lrcLyricParser.Decode(lrcFileContent); + sortedLyricData = lyricData.Lyrics.Where(x => x.TimeTags.Count > 0).OrderBy(x => x.TimeTags.ToArray()[0].Value).ToList(); + + // Parse metadata rows + var metaDataRows = lyricData.Lyrics + .Where(x => x.TimeTags.Count == 0) + .Where(x => x.Text.StartsWith("[", StringComparison.Ordinal) && x.Text.EndsWith("]", StringComparison.Ordinal)) + .Select(x => x.Text) + .ToList(); + + foreach (string metaDataRow in metaDataRows) + { + var metaDataField = metaDataRow.Split(":"); + + string metaDataFieldName = metaDataField[0].Replace("[", string.Empty, StringComparison.Ordinal); + string metaDataFieldValue = metaDataField[1].Replace("]", string.Empty, StringComparison.Ordinal); + + metaData.Add(metaDataFieldName, metaDataFieldValue); + } + } + catch + { + return; + } + + if (!sortedLyricData.Any()) + { + return; + } + + for (int i = 0; i < sortedLyricData.Count; i++) + { + var timeData = sortedLyricData[i].TimeTags.ToArray()[0].Value; + double ticks = Convert.ToDouble(timeData, new NumberFormatInfo()) * 10000; + lyricsList.Add(new Lyric { Start = Math.Ceiling(ticks), Text = sortedLyricData[i].Text }); + } + + this.HasData = true; + if (metaData.Any()) + { + this.Data = new { MetaData = metaData, lyrics = lyricsList }; + } + else + { + this.Data = new { lyrics = lyricsList }; + } + } + } +} diff --git a/Jellyfin.Api/Models/UserDtos/Lyric.cs b/Jellyfin.Api/Models/UserDtos/Lyric.cs new file mode 100644 index 000000000..2794cd78a --- /dev/null +++ b/Jellyfin.Api/Models/UserDtos/Lyric.cs @@ -0,0 +1,18 @@ +namespace Jellyfin.Api.Models.UserDtos +{ + /// + /// Lyric dto. + /// + public class Lyric + { + /// + /// Gets or sets the start time (ticks). + /// + public double Start { get; set; } + + /// + /// Gets or sets the text. + /// + public string Text { get; set; } = string.Empty; + } +} diff --git a/Jellyfin.Api/Models/UserDtos/Lyrics.cs b/Jellyfin.Api/Models/UserDtos/Lyrics.cs deleted file mode 100644 index cd548eb03..000000000 --- a/Jellyfin.Api/Models/UserDtos/Lyrics.cs +++ /dev/null @@ -1,23 +0,0 @@ -namespace Jellyfin.Api.Models.UserDtos -{ - /// - /// Lyric dto. - /// - public class Lyrics - { - /// - /// Gets or sets the start. - /// - public double? Start { get; set; } - - /// - /// Gets or sets the text. - /// - public string? Text { get; set; } - - /// - /// Gets or sets the error. - /// - public string? Error { get; set; } - } -} diff --git a/Jellyfin.Api/Models/UserDtos/TxtLyricsProvider.cs b/Jellyfin.Api/Models/UserDtos/TxtLyricsProvider.cs new file mode 100644 index 000000000..03cce1ffb --- /dev/null +++ b/Jellyfin.Api/Models/UserDtos/TxtLyricsProvider.cs @@ -0,0 +1,81 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Dynamic; +using System.Globalization; +using System.Linq; +using LrcParser.Model; +using LrcParser.Parser; +using MediaBrowser.Controller.Entities; + +namespace Jellyfin.Api.Models.UserDtos +{ + /// + /// TXT File Lyric Provider. + /// + public class TxtLyricsProvider : ILyricsProvider + { + /// + /// Initializes a new instance of the class. + /// + public TxtLyricsProvider() + { + FileExtensions = new Collection + { + "lrc", "txt" + }; + } + + /// + /// Gets a value indicating the File Extenstions this provider works with. + /// + public Collection? FileExtensions { get; } + + /// + /// Gets or Sets a value indicating whether Process() generated data. + /// + /// true if data generated; otherwise, false. + public bool HasData { get; set; } + + /// + /// Gets or Sets Data object generated by Process() method. + /// + /// Object with data if no error occured; otherwise, null. + public object? Data { get; set; } + + /// + /// Opens lyric file for [the specified item], and processes it for API return. + /// + /// The item to to process. + public void Process(BaseItem item) + { + string? lyricFilePath = Helpers.ItemHelper.GetLyricFilePath(item.Path); + + if (string.IsNullOrEmpty(lyricFilePath)) + { + return; + } + + List lyricsList = new List(); + + string lyricData = System.IO.File.ReadAllText(lyricFilePath); + + // Splitting on Environment.NewLine caused some new lines to be missed in Windows. + char[] newLinedelims = new[] { '\r', '\n' }; + string[] lyricTextLines = lyricData.Split(newLinedelims, StringSplitOptions.RemoveEmptyEntries); + + if (!lyricTextLines.Any()) + { + return; + } + + foreach (string lyricLine in lyricTextLines) + { + lyricsList.Add(new Lyric { Text = lyricLine }); + } + + this.HasData = true; + this.Data = new { lyrics = lyricsList }; + } + } +} diff --git a/MediaBrowser.Model/Dto/BaseItemDto.cs b/MediaBrowser.Model/Dto/BaseItemDto.cs index fdb84fa32..b40a0210a 100644 --- a/MediaBrowser.Model/Dto/BaseItemDto.cs +++ b/MediaBrowser.Model/Dto/BaseItemDto.cs @@ -76,6 +76,8 @@ namespace MediaBrowser.Model.Dto public bool? CanDownload { get; set; } + public bool? HasLocalLyricsFile { get; set; } + public bool? HasSubtitles { get; set; } public string PreferredMetadataLanguage { get; set; } -- cgit v1.2.3 From d9be3874ba3842d5888c5cbbe583614ed990849e Mon Sep 17 00:00:00 2001 From: 1hitsong <3330318+1hitsong@users.noreply.github.com> Date: Thu, 15 Sep 2022 19:45:26 -0400 Subject: Auto stash before merge of "lyric-lrc-file-support" and "origin/lyric-lrc-file-support" --- Emby.Server.Implementations/ApplicationHost.cs | 2 + Emby.Server.Implementations/Dto/DtoService.cs | 9 +- Jellyfin.Api/Controllers/UserLibraryController.cs | 5 +- Jellyfin.Api/Helpers/ItemHelper.cs | 106 ------------------- Jellyfin.Api/Jellyfin.Api.csproj | 1 - Jellyfin.Api/Models/UserDtos/ILyricsProvider.cs | 34 ------ Jellyfin.Api/Models/UserDtos/LrcLyricsProvider.cs | 117 --------------------- Jellyfin.Api/Models/UserDtos/Lyric.cs | 18 ---- Jellyfin.Api/Models/UserDtos/TxtLyricsProvider.cs | 81 -------------- MediaBrowser.Controller/Lyrics/ILyricsProvider.cs | 24 +++++ MediaBrowser.Controller/Lyrics/Lyric.cs | 18 ++++ MediaBrowser.Controller/Lyrics/LyricInfo.cs | 87 +++++++++++++++ MediaBrowser.Controller/Lyrics/LyricResponse.cs | 15 +++ MediaBrowser.Model/Dto/BaseItemDto.cs | 2 +- MediaBrowser.Providers/Lyric/LrcLyricsProvider.cs | 112 ++++++++++++++++++++ MediaBrowser.Providers/Lyric/TxtLyricsProvider.cs | 74 +++++++++++++ .../MediaBrowser.Providers.csproj | 2 + 17 files changed, 345 insertions(+), 362 deletions(-) delete mode 100644 Jellyfin.Api/Helpers/ItemHelper.cs delete mode 100644 Jellyfin.Api/Models/UserDtos/ILyricsProvider.cs delete mode 100644 Jellyfin.Api/Models/UserDtos/LrcLyricsProvider.cs delete mode 100644 Jellyfin.Api/Models/UserDtos/Lyric.cs delete mode 100644 Jellyfin.Api/Models/UserDtos/TxtLyricsProvider.cs create mode 100644 MediaBrowser.Controller/Lyrics/ILyricsProvider.cs create mode 100644 MediaBrowser.Controller/Lyrics/Lyric.cs create mode 100644 MediaBrowser.Controller/Lyrics/LyricInfo.cs create mode 100644 MediaBrowser.Controller/Lyrics/LyricResponse.cs create mode 100644 MediaBrowser.Providers/Lyric/LrcLyricsProvider.cs create mode 100644 MediaBrowser.Providers/Lyric/TxtLyricsProvider.cs (limited to 'MediaBrowser.Model/Dto') diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs index 3e9c540e7..5487e5e02 100644 --- a/Emby.Server.Implementations/ApplicationHost.cs +++ b/Emby.Server.Implementations/ApplicationHost.cs @@ -68,6 +68,7 @@ using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.LiveTv; +using MediaBrowser.Controller.Lyrics; using MediaBrowser.Controller.MediaEncoding; using MediaBrowser.Controller.Net; using MediaBrowser.Controller.Notifications; @@ -95,6 +96,7 @@ using MediaBrowser.Model.Serialization; using MediaBrowser.Model.System; using MediaBrowser.Model.Tasks; using MediaBrowser.Providers.Chapters; +using MediaBrowser.Providers.Lyric; using MediaBrowser.Providers.Manager; using MediaBrowser.Providers.Plugins.Tmdb; using MediaBrowser.Providers.Subtitles; diff --git a/Emby.Server.Implementations/Dto/DtoService.cs b/Emby.Server.Implementations/Dto/DtoService.cs index 96717cff5..bed82a4bb 100644 --- a/Emby.Server.Implementations/Dto/DtoService.cs +++ b/Emby.Server.Implementations/Dto/DtoService.cs @@ -19,6 +19,7 @@ using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.LiveTv; +using MediaBrowser.Controller.Lyrics; using MediaBrowser.Controller.Persistence; using MediaBrowser.Controller.Playlists; using MediaBrowser.Controller.Providers; @@ -51,6 +52,8 @@ namespace Emby.Server.Implementations.Dto private readonly IMediaSourceManager _mediaSourceManager; private readonly Lazy _livetvManagerFactory; + private readonly IEnumerable _lyricProviders; + public DtoService( ILogger logger, ILibraryManager libraryManager, @@ -60,7 +63,8 @@ namespace Emby.Server.Implementations.Dto IProviderManager providerManager, IApplicationHost appHost, IMediaSourceManager mediaSourceManager, - Lazy livetvManagerFactory) + Lazy livetvManagerFactory, + IEnumerable lyricProviders) { _logger = logger; _libraryManager = libraryManager; @@ -71,6 +75,7 @@ namespace Emby.Server.Implementations.Dto _appHost = appHost; _mediaSourceManager = mediaSourceManager; _livetvManagerFactory = livetvManagerFactory; + _lyricProviders = lyricProviders; } private ILiveTvManager LivetvManager => _livetvManagerFactory.Value; @@ -142,7 +147,7 @@ namespace Emby.Server.Implementations.Dto } else if (item is Audio) { - dto.HasLocalLyricsFile = ItemHelper.HasLyricFile(item.Path); + dto.HasLyrics = MediaBrowser.Controller.Lyrics.LyricInfo.HasLyricFile(_lyricProviders, item.Path); } if (item is IItemByName itemByName diff --git a/Jellyfin.Api/Controllers/UserLibraryController.cs b/Jellyfin.Api/Controllers/UserLibraryController.cs index 123c5e079..3da78c116 100644 --- a/Jellyfin.Api/Controllers/UserLibraryController.cs +++ b/Jellyfin.Api/Controllers/UserLibraryController.cs @@ -13,6 +13,7 @@ using MediaBrowser.Controller.Dto; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Entities.Audio; using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.Lyrics; using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Dto; using MediaBrowser.Model.Entities; @@ -414,8 +415,8 @@ namespace Jellyfin.Api.Controllers return NotFound(); } - // Super nieve implementation. I would suggest building a lyric service of some sort and doing this there. - foreach (var provider in _lyricProviders) + var result = MediaBrowser.Controller.Lyrics.LyricInfo.GetLyricData(_lyricProviders, item); + if (result is not null) { provider.Process(item); if (provider.HasData) diff --git a/Jellyfin.Api/Helpers/ItemHelper.cs b/Jellyfin.Api/Helpers/ItemHelper.cs deleted file mode 100644 index 49bb8af8e..000000000 --- a/Jellyfin.Api/Helpers/ItemHelper.cs +++ /dev/null @@ -1,106 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Dynamic; -using System.Globalization; -using System.IO; -using System.Linq; -using Jellyfin.Api.Models.UserDtos; -using LrcParser.Model; -using LrcParser.Parser; -using MediaBrowser.Controller.Entities; - -namespace Jellyfin.Api.Helpers -{ - /// - /// Item helper. - /// - public static class ItemHelper - { - /// - /// Opens lyrics file, converts to a List of Lyrics, and returns it. - /// - /// Requested Item. - /// Collection of Lyrics. - internal static object? GetLyricData(BaseItem item) - { - // Find all classes that implement ILyricsProvider Interface - var foundLyricProviders = System.Reflection.Assembly.GetExecutingAssembly() - .GetTypes() - .Where(type => typeof(ILyricsProvider).IsAssignableFrom(type) && !type.IsInterface); - - if (!foundLyricProviders.Any()) - { - return null; - } - - foreach (var provider in foundLyricProviders) - { - ILyricsProvider? newProvider = Activator.CreateInstance(provider) as ILyricsProvider; - if (newProvider is not null) - { - newProvider.Process(item); - if (newProvider.HasData) - { - return newProvider.Data; - } - } - } - - return null; - } - - /// - /// Checks if requested item has a matching lyric file. - /// - /// Path of requested item. - /// True if item has a matching lyrics file. - public static string? GetLyricFilePath(string itemPath) - { - // Find all classes that implement ILyricsProvider Interface - var foundLyricProviders = System.Reflection.Assembly.GetExecutingAssembly() - .GetTypes() - .Where(type => typeof(ILyricsProvider).IsAssignableFrom(type) && !type.IsInterface); - - if (!foundLyricProviders.Any()) - { - return null; - } - - // Iterate over all found lyric providers - foreach (var provider in foundLyricProviders) - { - ILyricsProvider? foundProvider = Activator.CreateInstance(provider) as ILyricsProvider; - if (foundProvider?.FileExtensions is null) - { - continue; - } - - if (foundProvider.FileExtensions.Any()) - { - foreach (string lyricFileExtension in foundProvider.FileExtensions) - { - string lyricFilePath = @Path.ChangeExtension(itemPath, lyricFileExtension); - if (System.IO.File.Exists(lyricFilePath)) - { - return lyricFilePath; - } - } - } - } - - return null; - } - - - /// - /// Checks if requested item has a matching local lyric file. - /// - /// Path of requested item. - /// True if item has a matching lyrics file; otherwise false. - public static bool HasLyricFile(string itemPath) - { - string? lyricFilePath = GetLyricFilePath(itemPath); - return !string.IsNullOrEmpty(lyricFilePath); - } - } -} diff --git a/Jellyfin.Api/Jellyfin.Api.csproj b/Jellyfin.Api/Jellyfin.Api.csproj index 972387e02..894d87138 100644 --- a/Jellyfin.Api/Jellyfin.Api.csproj +++ b/Jellyfin.Api/Jellyfin.Api.csproj @@ -17,7 +17,6 @@ - diff --git a/Jellyfin.Api/Models/UserDtos/ILyricsProvider.cs b/Jellyfin.Api/Models/UserDtos/ILyricsProvider.cs deleted file mode 100644 index 37f1f5bbe..000000000 --- a/Jellyfin.Api/Models/UserDtos/ILyricsProvider.cs +++ /dev/null @@ -1,34 +0,0 @@ -using System.Collections.ObjectModel; -using MediaBrowser.Controller.Entities; - -namespace Jellyfin.Api.Models.UserDtos -{ - /// - /// Interface ILyricsProvider. - /// - public interface ILyricsProvider - { - /// - /// Gets a value indicating the File Extenstions this provider works with. - /// - public Collection? FileExtensions { get; } - - /// - /// Gets a value indicating whether Process() generated data. - /// - /// true if data generated; otherwise, false. - bool HasData { get; } - - /// - /// Gets Data object generated by Process() method. - /// - /// Object with data if no error occured; otherwise, null. - object? Data { get; } - - /// - /// Opens lyric file for [the specified item], and processes it for API return. - /// - /// The item to to process. - void Process(BaseItem item); - } -} diff --git a/Jellyfin.Api/Models/UserDtos/LrcLyricsProvider.cs b/Jellyfin.Api/Models/UserDtos/LrcLyricsProvider.cs deleted file mode 100644 index 029acd6ca..000000000 --- a/Jellyfin.Api/Models/UserDtos/LrcLyricsProvider.cs +++ /dev/null @@ -1,117 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.Dynamic; -using System.Globalization; -using System.Linq; -using LrcParser.Model; -using LrcParser.Parser; -using MediaBrowser.Controller.Entities; - -namespace Jellyfin.Api.Models.UserDtos -{ - /// - /// LRC File Lyric Provider. - /// - public class LrcLyricsProvider : ILyricsProvider - { - /// - /// Initializes a new instance of the class. - /// - public LrcLyricsProvider() - { - FileExtensions = new Collection - { - "lrc" - }; - } - - /// - /// Gets a value indicating the File Extenstions this provider works with. - /// - public Collection? FileExtensions { get; } - - /// - /// Gets or Sets a value indicating whether Process() generated data. - /// - /// true if data generated; otherwise, false. - public bool HasData { get; set; } - - /// - /// Gets or Sets Data object generated by Process() method. - /// - /// Object with data if no error occured; otherwise, null. - public object? Data { get; set; } - - /// - /// Opens lyric file for [the specified item], and processes it for API return. - /// - /// The item to to process. - public void Process(BaseItem item) - { - string? lyricFilePath = Helpers.ItemHelper.GetLyricFilePath(item.Path); - - if (string.IsNullOrEmpty(lyricFilePath)) - { - return; - } - - List lyricsList = new List(); - - List sortedLyricData = new List(); - var metaData = new ExpandoObject() as IDictionary; - string lrcFileContent = System.IO.File.ReadAllText(lyricFilePath); - - try - { - // Parse and sort lyric rows - LyricParser lrcLyricParser = new LrcParser.Parser.Lrc.LrcParser(); - Song lyricData = lrcLyricParser.Decode(lrcFileContent); - sortedLyricData = lyricData.Lyrics.Where(x => x.TimeTags.Count > 0).OrderBy(x => x.TimeTags.ToArray()[0].Value).ToList(); - - // Parse metadata rows - var metaDataRows = lyricData.Lyrics - .Where(x => x.TimeTags.Count == 0) - .Where(x => x.Text.StartsWith("[", StringComparison.Ordinal) && x.Text.EndsWith("]", StringComparison.Ordinal)) - .Select(x => x.Text) - .ToList(); - - foreach (string metaDataRow in metaDataRows) - { - var metaDataField = metaDataRow.Split(":"); - - string metaDataFieldName = metaDataField[0].Replace("[", string.Empty, StringComparison.Ordinal); - string metaDataFieldValue = metaDataField[1].Replace("]", string.Empty, StringComparison.Ordinal); - - metaData.Add(metaDataFieldName, metaDataFieldValue); - } - } - catch - { - return; - } - - if (!sortedLyricData.Any()) - { - return; - } - - for (int i = 0; i < sortedLyricData.Count; i++) - { - var timeData = sortedLyricData[i].TimeTags.ToArray()[0].Value; - double ticks = Convert.ToDouble(timeData, new NumberFormatInfo()) * 10000; - lyricsList.Add(new Lyric { Start = Math.Ceiling(ticks), Text = sortedLyricData[i].Text }); - } - - this.HasData = true; - if (metaData.Any()) - { - this.Data = new { MetaData = metaData, lyrics = lyricsList }; - } - else - { - this.Data = new { lyrics = lyricsList }; - } - } - } -} diff --git a/Jellyfin.Api/Models/UserDtos/Lyric.cs b/Jellyfin.Api/Models/UserDtos/Lyric.cs deleted file mode 100644 index f83fc9839..000000000 --- a/Jellyfin.Api/Models/UserDtos/Lyric.cs +++ /dev/null @@ -1,18 +0,0 @@ -namespace Jellyfin.Api.Models.UserDtos -{ - /// - /// Lyric dto. - /// - public class Lyric - { - /// - /// Gets or sets the start time (ticks). - /// - public double? Start { get; set; } - - /// - /// Gets or sets the text. - /// - public string Text { get; set; } = string.Empty; - } -} diff --git a/Jellyfin.Api/Models/UserDtos/TxtLyricsProvider.cs b/Jellyfin.Api/Models/UserDtos/TxtLyricsProvider.cs deleted file mode 100644 index 03cce1ffb..000000000 --- a/Jellyfin.Api/Models/UserDtos/TxtLyricsProvider.cs +++ /dev/null @@ -1,81 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.Dynamic; -using System.Globalization; -using System.Linq; -using LrcParser.Model; -using LrcParser.Parser; -using MediaBrowser.Controller.Entities; - -namespace Jellyfin.Api.Models.UserDtos -{ - /// - /// TXT File Lyric Provider. - /// - public class TxtLyricsProvider : ILyricsProvider - { - /// - /// Initializes a new instance of the class. - /// - public TxtLyricsProvider() - { - FileExtensions = new Collection - { - "lrc", "txt" - }; - } - - /// - /// Gets a value indicating the File Extenstions this provider works with. - /// - public Collection? FileExtensions { get; } - - /// - /// Gets or Sets a value indicating whether Process() generated data. - /// - /// true if data generated; otherwise, false. - public bool HasData { get; set; } - - /// - /// Gets or Sets Data object generated by Process() method. - /// - /// Object with data if no error occured; otherwise, null. - public object? Data { get; set; } - - /// - /// Opens lyric file for [the specified item], and processes it for API return. - /// - /// The item to to process. - public void Process(BaseItem item) - { - string? lyricFilePath = Helpers.ItemHelper.GetLyricFilePath(item.Path); - - if (string.IsNullOrEmpty(lyricFilePath)) - { - return; - } - - List lyricsList = new List(); - - string lyricData = System.IO.File.ReadAllText(lyricFilePath); - - // Splitting on Environment.NewLine caused some new lines to be missed in Windows. - char[] newLinedelims = new[] { '\r', '\n' }; - string[] lyricTextLines = lyricData.Split(newLinedelims, StringSplitOptions.RemoveEmptyEntries); - - if (!lyricTextLines.Any()) - { - return; - } - - foreach (string lyricLine in lyricTextLines) - { - lyricsList.Add(new Lyric { Text = lyricLine }); - } - - this.HasData = true; - this.Data = new { lyrics = lyricsList }; - } - } -} diff --git a/MediaBrowser.Controller/Lyrics/ILyricsProvider.cs b/MediaBrowser.Controller/Lyrics/ILyricsProvider.cs new file mode 100644 index 000000000..bac32a398 --- /dev/null +++ b/MediaBrowser.Controller/Lyrics/ILyricsProvider.cs @@ -0,0 +1,24 @@ +using System.Collections.Generic; +using MediaBrowser.Controller.Entities; + +namespace MediaBrowser.Controller.Lyrics +{ + /// + /// Interface ILyricsProvider. + /// + public interface ILyricsProvider + { + /// + /// Gets the supported media types for this provider. + /// + /// The supported media types. + IEnumerable SupportedMediaTypes { get; } + + /// + /// Gets the lyrics. + /// + /// The item to to process. + /// Task{LyricResponse}. + LyricResponse? GetLyrics(BaseItem item); + } +} diff --git a/MediaBrowser.Controller/Lyrics/Lyric.cs b/MediaBrowser.Controller/Lyrics/Lyric.cs new file mode 100644 index 000000000..d44546dd3 --- /dev/null +++ b/MediaBrowser.Controller/Lyrics/Lyric.cs @@ -0,0 +1,18 @@ +namespace MediaBrowser.Controller.Lyrics +{ + /// + /// Lyric dto. + /// + public class Lyric + { + /// + /// Gets or sets the start time (ticks). + /// + public double? Start { get; set; } + + /// + /// Gets or sets the text. + /// + public string Text { get; set; } = string.Empty; + } +} diff --git a/MediaBrowser.Controller/Lyrics/LyricInfo.cs b/MediaBrowser.Controller/Lyrics/LyricInfo.cs new file mode 100644 index 000000000..83a10701a --- /dev/null +++ b/MediaBrowser.Controller/Lyrics/LyricInfo.cs @@ -0,0 +1,87 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Threading.Tasks; +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Lyrics; +using MediaBrowser.Controller.Net; +using Microsoft.AspNetCore.Mvc; + +namespace MediaBrowser.Controller.Lyrics +{ + /// + /// Item helper. + /// + public class LyricInfo + { + /// + /// Opens lyrics file, converts to a List of Lyrics, and returns it. + /// + /// Collection of all registered interfaces. + /// Requested Item. + /// Collection of Lyrics. + public static LyricResponse? GetLyricData(IEnumerable lyricProviders, BaseItem item) + { + + foreach (var provider in lyricProviders) + { + var result = provider.GetLyrics(item); + if (result is not null) + { + return result; + } + } + + return new LyricResponse + { + Lyrics = new List + { + new Lyric { Start = 0, Text = "Test" } + } + }; + } + + /// + /// Checks if requested item has a matching lyric file. + /// + /// The current lyricProvider interface. + /// Path of requested item. + /// True if item has a matching lyrics file. + public static string? GetLyricFilePath(ILyricsProvider lyricProvider, string itemPath) + { + if (lyricProvider.SupportedMediaTypes.Any()) + { + foreach (string lyricFileExtension in lyricProvider.SupportedMediaTypes) + { + string lyricFilePath = @Path.ChangeExtension(itemPath, lyricFileExtension); + if (System.IO.File.Exists(lyricFilePath)) + { + return lyricFilePath; + } + } + } + + return null; + } + + /// + /// Checks if requested item has a matching local lyric file. + /// + /// Collection of all registered interfaces. + /// Path of requested item. + /// True if item has a matching lyrics file; otherwise false. + public static bool HasLyricFile(IEnumerable lyricProviders, string itemPath) + { + foreach (var provider in lyricProviders) + { + if (GetLyricFilePath(provider, itemPath) is not null) + { + return true; + } + } + + return false; + } + } +} diff --git a/MediaBrowser.Controller/Lyrics/LyricResponse.cs b/MediaBrowser.Controller/Lyrics/LyricResponse.cs new file mode 100644 index 000000000..e312638ec --- /dev/null +++ b/MediaBrowser.Controller/Lyrics/LyricResponse.cs @@ -0,0 +1,15 @@ +#nullable disable + +#pragma warning disable CS1591 + +using System.Collections.Generic; + +namespace MediaBrowser.Controller.Lyrics +{ + public class LyricResponse + { + public IDictionary MetaData { get; set; } + + public IEnumerable Lyrics { get; set; } + } +} diff --git a/MediaBrowser.Model/Dto/BaseItemDto.cs b/MediaBrowser.Model/Dto/BaseItemDto.cs index b40a0210a..2a86fded2 100644 --- a/MediaBrowser.Model/Dto/BaseItemDto.cs +++ b/MediaBrowser.Model/Dto/BaseItemDto.cs @@ -76,7 +76,7 @@ namespace MediaBrowser.Model.Dto public bool? CanDownload { get; set; } - public bool? HasLocalLyricsFile { get; set; } + public bool? HasLyrics { get; set; } public bool? HasSubtitles { get; set; } diff --git a/MediaBrowser.Providers/Lyric/LrcLyricsProvider.cs b/MediaBrowser.Providers/Lyric/LrcLyricsProvider.cs new file mode 100644 index 000000000..e30d56308 --- /dev/null +++ b/MediaBrowser.Providers/Lyric/LrcLyricsProvider.cs @@ -0,0 +1,112 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Dynamic; +using System.Globalization; +using System.Linq; +using System.Threading.Tasks; +using Jellyfin.Api.Helpers; +using LrcParser.Model; +using LrcParser.Parser; +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Lyrics; + +namespace MediaBrowser.Providers.Lyric +{ + /// + /// LRC File Lyric Provider. + /// + public class LrcLyricsProvider : ILyricsProvider + { + /// + /// Initializes a new instance of the class. + /// + public LrcLyricsProvider() + { + SupportedMediaTypes = new Collection + { + "lrc" + }; + } + + /// + /// Gets a value indicating the File Extenstions this provider works with. + /// + public IEnumerable SupportedMediaTypes { get; } + + /// + /// Gets or Sets Data object generated by Process() method. + /// + /// Object with data if no error occured; otherwise, null. + public object? Data { get; set; } + + /// + /// Opens lyric file for [the specified item], and processes it for API return. + /// + /// The item to to process. + /// A representing the asynchronous operation. + public LyricResponse? GetLyrics(BaseItem item) + { + string? lyricFilePath = LyricInfo.GetLyricFilePath(this, item.Path); + + if (string.IsNullOrEmpty(lyricFilePath)) + { + return null; + } + + List lyricsList = new List(); + + List sortedLyricData = new List(); + var metaData = new ExpandoObject() as IDictionary; + string lrcFileContent = System.IO.File.ReadAllText(lyricFilePath); + + try + { + // Parse and sort lyric rows + LyricParser lrcLyricParser = new LrcParser.Parser.Lrc.LrcParser(); + Song lyricData = lrcLyricParser.Decode(lrcFileContent); + sortedLyricData = lyricData.Lyrics.Where(x => x.TimeTags.Count > 0).OrderBy(x => x.TimeTags.ToArray()[0].Value).ToList(); + + // Parse metadata rows + var metaDataRows = lyricData.Lyrics + .Where(x => x.TimeTags.Count == 0) + .Where(x => x.Text.StartsWith("[", StringComparison.Ordinal) && x.Text.EndsWith("]", StringComparison.Ordinal)) + .Select(x => x.Text) + .ToList(); + + foreach (string metaDataRow in metaDataRows) + { + var metaDataField = metaDataRow.Split(":"); + + string metaDataFieldName = metaDataField[0].Replace("[", string.Empty, StringComparison.Ordinal); + string metaDataFieldValue = metaDataField[1].Replace("]", string.Empty, StringComparison.Ordinal); + + metaData.Add(metaDataFieldName, metaDataFieldValue); + } + } + catch + { + return null; + } + + if (!sortedLyricData.Any()) + { + return null; + } + + for (int i = 0; i < sortedLyricData.Count; i++) + { + var timeData = sortedLyricData[i].TimeTags.ToArray()[0].Value; + double ticks = Convert.ToDouble(timeData, new NumberFormatInfo()) * 10000; + lyricsList.Add(new MediaBrowser.Controller.Lyrics.Lyric { Start = Math.Ceiling(ticks), Text = sortedLyricData[i].Text }); + } + + if (metaData.Any()) + { + return new LyricResponse { MetaData = metaData, Lyrics = lyricsList }; + } + + return new LyricResponse { Lyrics = lyricsList }; + } + } +} diff --git a/MediaBrowser.Providers/Lyric/TxtLyricsProvider.cs b/MediaBrowser.Providers/Lyric/TxtLyricsProvider.cs new file mode 100644 index 000000000..2a5da4e4d --- /dev/null +++ b/MediaBrowser.Providers/Lyric/TxtLyricsProvider.cs @@ -0,0 +1,74 @@ +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using System.Threading.Tasks; +using Jellyfin.Api.Helpers; +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Lyrics; + +namespace MediaBrowser.Providers.Lyric +{ + /// + /// TXT File Lyric Provider. + /// + public class TxtLyricsProvider : ILyricsProvider + { + /// + /// Initializes a new instance of the class. + /// + public TxtLyricsProvider() + { + SupportedMediaTypes = new Collection + { + "lrc", "txt" + }; + } + + /// + /// Gets a value indicating the File Extenstions this provider works with. + /// + public IEnumerable SupportedMediaTypes { get; } + + /// + /// Gets or Sets Data object generated by Process() method. + /// + /// Object with data if no error occured; otherwise, null. + public object? Data { get; set; } + + /// + /// Opens lyric file for [the specified item], and processes it for API return. + /// + /// The item to to process. + /// A representing the asynchronous operation. + public LyricResponse? GetLyrics(BaseItem item) + { + string? lyricFilePath = LyricInfo.GetLyricFilePath(this, item.Path); + + if (string.IsNullOrEmpty(lyricFilePath)) + { + return null; + } + + List lyricsList = new List(); + + string lyricData = System.IO.File.ReadAllText(lyricFilePath); + + // Splitting on Environment.NewLine caused some new lines to be missed in Windows. + char[] newLinedelims = new[] { '\r', '\n' }; + string[] lyricTextLines = lyricData.Split(newLinedelims, StringSplitOptions.RemoveEmptyEntries); + + if (!lyricTextLines.Any()) + { + return null; + } + + foreach (string lyricLine in lyricTextLines) + { + lyricsList.Add(new MediaBrowser.Controller.Lyrics.Lyric { Text = lyricLine }); + } + + return new LyricResponse { Lyrics = lyricsList }; + } + } +} diff --git a/MediaBrowser.Providers/MediaBrowser.Providers.csproj b/MediaBrowser.Providers/MediaBrowser.Providers.csproj index 9864db9ac..8514489f8 100644 --- a/MediaBrowser.Providers/MediaBrowser.Providers.csproj +++ b/MediaBrowser.Providers/MediaBrowser.Providers.csproj @@ -6,6 +6,7 @@ + @@ -16,6 +17,7 @@ + -- cgit v1.2.3 From 2eb00bf3c06b1a73c530f192a2622579f09851ff Mon Sep 17 00:00:00 2001 From: Dmitry Lyzo Date: Mon, 31 Oct 2022 12:50:53 +0300 Subject: fix secondary audio Browsers (Chrome, Firefox) can only play the first track, even if the second track is the default. Ignore default flag when testing on secondary audio. External audio tracks are not secondary. --- MediaBrowser.Model/Dlna/StreamBuilder.cs | 9 +++------ MediaBrowser.Model/Dto/MediaSourceInfo.cs | 10 +++------- 2 files changed, 6 insertions(+), 13 deletions(-) (limited to 'MediaBrowser.Model/Dto') diff --git a/MediaBrowser.Model/Dlna/StreamBuilder.cs b/MediaBrowser.Model/Dlna/StreamBuilder.cs index da1e6c3d3..6e9b943f7 100644 --- a/MediaBrowser.Model/Dlna/StreamBuilder.cs +++ b/MediaBrowser.Model/Dlna/StreamBuilder.cs @@ -1085,9 +1085,6 @@ namespace MediaBrowser.Model.Dlna bool? isInterlaced = videoStream?.IsInterlaced; string videoCodecTag = videoStream?.CodecTag; bool? isAvc = videoStream?.IsAVC; - // Audio - var defaultLanguage = audioStream?.Language ?? string.Empty; - var defaultMarked = audioStream?.IsDefault ?? false; TransportStreamTimestamp? timestamp = videoStream == null ? TransportStreamTimestamp.None : mediaSource.Timestamp; int? packetLength = videoStream?.PacketLength; @@ -1119,7 +1116,7 @@ namespace MediaBrowser.Model.Dlna .SelectMany(codecProfile => checkVideoConditions(codecProfile.Conditions))); // Check audiocandidates profile conditions - var audioStreamMatches = candidateAudioStreams.ToDictionary(s => s, audioStream => CheckVideoAudioStreamDirectPlay(options, mediaSource, container, audioStream, defaultLanguage, defaultMarked)); + var audioStreamMatches = candidateAudioStreams.ToDictionary(s => s, audioStream => CheckVideoAudioStreamDirectPlay(options, mediaSource, container, audioStream)); TranscodeReason subtitleProfileReasons = 0; if (subtitleStream != null) @@ -1240,10 +1237,10 @@ namespace MediaBrowser.Model.Dlna return (Profile: null, PlayMethod: null, AudioStreamIndex: null, TranscodeReasons: failureReasons); } - private TranscodeReason CheckVideoAudioStreamDirectPlay(VideoOptions options, MediaSourceInfo mediaSource, string container, MediaStream audioStream, string language, bool isDefault) + private TranscodeReason CheckVideoAudioStreamDirectPlay(VideoOptions options, MediaSourceInfo mediaSource, string container, MediaStream audioStream) { var profile = options.Profile; - var audioFailureConditions = GetProfileConditionsForVideoAudio(profile.CodecProfiles, container, audioStream.Codec, audioStream.Channels, audioStream.BitRate, audioStream.SampleRate, audioStream.BitDepth, audioStream.Profile, !audioStream.IsDefault); + var audioFailureConditions = GetProfileConditionsForVideoAudio(profile.CodecProfiles, container, audioStream.Codec, audioStream.Channels, audioStream.BitRate, audioStream.SampleRate, audioStream.BitDepth, audioStream.Profile, mediaSource.IsSecondaryAudio(audioStream)); var audioStreamFailureReasons = AggregateFailureConditions(mediaSource, profile, "VideoAudioCodecProfile", audioFailureConditions); if (audioStream?.IsExternal == true) diff --git a/MediaBrowser.Model/Dto/MediaSourceInfo.cs b/MediaBrowser.Model/Dto/MediaSourceInfo.cs index bb9848848..c348e83ae 100644 --- a/MediaBrowser.Model/Dto/MediaSourceInfo.cs +++ b/MediaBrowser.Model/Dto/MediaSourceInfo.cs @@ -230,19 +230,15 @@ namespace MediaBrowser.Model.Dto public bool? IsSecondaryAudio(MediaStream stream) { - // Look for the first audio track marked as default - foreach (var currentStream in MediaStreams) + if (stream.IsExternal) { - if (currentStream.Type == MediaStreamType.Audio && currentStream.IsDefault) - { - return currentStream.Index != stream.Index; - } + return false; } // Look for the first audio track foreach (var currentStream in MediaStreams) { - if (currentStream.Type == MediaStreamType.Audio) + if (currentStream.Type == MediaStreamType.Audio && !currentStream.IsExternal) { return currentStream.Index != stream.Index; } -- cgit v1.2.3