mirror of
https://github.com/jellyfin/jellyfin.git
synced 2026-06-18 13:40:45 +01:00
@@ -7,6 +7,7 @@ using System.Threading.Tasks;
|
|||||||
using Jellyfin.Extensions;
|
using Jellyfin.Extensions;
|
||||||
using MediaBrowser.Controller.Chapters;
|
using MediaBrowser.Controller.Chapters;
|
||||||
using MediaBrowser.Controller.Entities;
|
using MediaBrowser.Controller.Entities;
|
||||||
|
using MediaBrowser.Controller.Entities.Audio;
|
||||||
using MediaBrowser.Controller.IO;
|
using MediaBrowser.Controller.IO;
|
||||||
using MediaBrowser.Controller.Library;
|
using MediaBrowser.Controller.Library;
|
||||||
using MediaBrowser.Controller.MediaEncoding;
|
using MediaBrowser.Controller.MediaEncoding;
|
||||||
@@ -232,12 +233,22 @@ public class ChapterManager : IChapterManager
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public void SaveChapters(Video video, IReadOnlyList<ChapterInfo> chapters)
|
public bool Supports(BaseItem item)
|
||||||
|
=> item is Video or Audio;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public void SaveChapters(BaseItem item, IReadOnlyList<ChapterInfo> chapters)
|
||||||
{
|
{
|
||||||
// Remove any chapters that are outside of the runtime of the video
|
if (!Supports(item))
|
||||||
var validChapters = chapters.Where(c => c.StartPositionTicks < video.RunTimeTicks).ToList();
|
{
|
||||||
_chapterRepository.SaveChapters(video.Id, validChapters);
|
_logger.LogWarning("Attempted to save chapters for unsupported item type {Type}: {Name} ({Id})", item.GetType().Name, item.Name, item.Id);
|
||||||
}
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove any chapters that are outside of the runtime of the item
|
||||||
|
var validChapters = chapters.Where(c => c.StartPositionTicks < item.RunTimeTicks).ToList();
|
||||||
|
_chapterRepository.SaveChapters(item.Id, validChapters);
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public ChapterInfo? GetChapter(Guid baseItemId, int index)
|
public ChapterInfo? GetChapter(Guid baseItemId, int index)
|
||||||
|
|||||||
@@ -1132,11 +1132,6 @@ namespace Emby.Server.Implementations.Dto
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options.ContainsField(ItemFields.Chapters))
|
|
||||||
{
|
|
||||||
dto.Chapters = _chapterManager.GetChapters(item.Id).ToList();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.ContainsField(ItemFields.Trickplay))
|
if (options.ContainsField(ItemFields.Trickplay))
|
||||||
{
|
{
|
||||||
var trickplay = _trickplayManager.GetTrickplayManifest(item).GetAwaiter().GetResult();
|
var trickplay = _trickplayManager.GetTrickplayManifest(item).GetAwaiter().GetResult();
|
||||||
@@ -1150,6 +1145,11 @@ namespace Emby.Server.Implementations.Dto
|
|||||||
dto.ExtraType = video.ExtraType;
|
dto.ExtraType = video.ExtraType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (options.ContainsField(ItemFields.Chapters))
|
||||||
|
{
|
||||||
|
dto.Chapters = _chapterManager.GetChapters(item.Id).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
if (options.ContainsField(ItemFields.MediaStreams))
|
if (options.ContainsField(ItemFields.MediaStreams))
|
||||||
{
|
{
|
||||||
// Add VideoInfo
|
// Add VideoInfo
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.Books
|
|||||||
{
|
{
|
||||||
public class BookResolver : ItemResolver<Book>
|
public class BookResolver : ItemResolver<Book>
|
||||||
{
|
{
|
||||||
private readonly string[] _validExtensions = { ".azw", ".azw3", ".cb7", ".cbr", ".cbt", ".cbz", ".epub", ".mobi", ".pdf", ".m4b", ".m4a", ".aac", ".flac", ".mp3", ".opus" };
|
private readonly string[] _validExtensions = { ".azw", ".azw3", ".cb7", ".cbr", ".cbt", ".cbz", ".epub", ".mobi", ".pdf" };
|
||||||
|
|
||||||
protected override Book Resolve(ItemResolveArgs args)
|
protected override Book Resolve(ItemResolveArgs args)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -976,7 +976,7 @@ public class LibraryController : BaseJellyfinApiController
|
|||||||
CollectionType.playlists => new[] { "Playlist" },
|
CollectionType.playlists => new[] { "Playlist" },
|
||||||
CollectionType.movies => new[] { "Movie" },
|
CollectionType.movies => new[] { "Movie" },
|
||||||
CollectionType.tvshows => new[] { "Series", "Season", "Episode" },
|
CollectionType.tvshows => new[] { "Series", "Season", "Episode" },
|
||||||
CollectionType.books => new[] { "Book" },
|
CollectionType.books => new[] { "Book", "AudioBook" },
|
||||||
CollectionType.music => new[] { "MusicArtist", "MusicAlbum", "Audio", "MusicVideo" },
|
CollectionType.music => new[] { "MusicArtist", "MusicAlbum", "Audio", "MusicVideo" },
|
||||||
CollectionType.homevideos => new[] { "Video", "Photo" },
|
CollectionType.homevideos => new[] { "Video", "Photo" },
|
||||||
CollectionType.photos => new[] { "Video", "Photo" },
|
CollectionType.photos => new[] { "Video", "Photo" },
|
||||||
|
|||||||
@@ -129,5 +129,10 @@ public enum PersonKind
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// A person who renders a text from one language into another.
|
/// A person who renders a text from one language into another.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Translator
|
Translator,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A person who narrates a book or other work.
|
||||||
|
/// </summary>
|
||||||
|
Narrator
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,12 +13,19 @@ namespace MediaBrowser.Controller.Chapters;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public interface IChapterManager
|
public interface IChapterManager
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a value indicating whether the specified item type is supported for chapter operations.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="item">The item to check.</param>
|
||||||
|
/// <returns><c>true</c> if the item type supports chapters; otherwise, <c>false</c>.</returns>
|
||||||
|
bool Supports(BaseItem item);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Saves the chapters.
|
/// Saves the chapters.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="video">The video.</param>
|
/// <param name="item">The item.</param>
|
||||||
/// <param name="chapters">The set of chapters.</param>
|
/// <param name="chapters">The set of chapters.</param>
|
||||||
void SaveChapters(Video video, IReadOnlyList<ChapterInfo> chapters);
|
void SaveChapters(BaseItem item, IReadOnlyList<ChapterInfo> chapters);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a single chapter of a BaseItem on a specific index.
|
/// Gets a single chapter of a BaseItem on a specific index.
|
||||||
|
|||||||
@@ -414,7 +414,7 @@ namespace MediaBrowser.MediaEncoding.Encoder
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public Task<MediaInfo> GetMediaInfo(MediaInfoRequest request, CancellationToken cancellationToken)
|
public Task<MediaInfo> GetMediaInfo(MediaInfoRequest request, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var extractChapters = request.MediaType == DlnaProfileType.Video && request.ExtractChapters;
|
var extractChapters = request.ExtractChapters;
|
||||||
var extraArgs = GetExtraArguments(request);
|
var extraArgs = GetExtraArguments(request);
|
||||||
|
|
||||||
return GetMediaInfoInternal(
|
return GetMediaInfoInternal(
|
||||||
|
|||||||
@@ -194,6 +194,11 @@ namespace MediaBrowser.MediaEncoding.Probing
|
|||||||
info.ProductionYear = info.PremiereDate.Value.Year;
|
info.ProductionYear = info.PremiereDate.Value.Year;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (data.Chapters is not null)
|
||||||
|
{
|
||||||
|
info.Chapters = data.Chapters.Select(GetChapterInfo).ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
// Set mediaType-specific metadata
|
// Set mediaType-specific metadata
|
||||||
if (isAudio)
|
if (isAudio)
|
||||||
{
|
{
|
||||||
@@ -238,11 +243,6 @@ namespace MediaBrowser.MediaEncoding.Probing
|
|||||||
|
|
||||||
FetchWtvInfo(info, data);
|
FetchWtvInfo(info, data);
|
||||||
|
|
||||||
if (data.Chapters is not null)
|
|
||||||
{
|
|
||||||
info.Chapters = data.Chapters.Select(GetChapterInfo).ToArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
ExtractTimestamp(info);
|
ExtractTimestamp(info);
|
||||||
|
|
||||||
if (tags.TryGetValue("stereo_mode", out var stereoMode) && string.Equals(stereoMode, "left_right", StringComparison.OrdinalIgnoreCase))
|
if (tags.TryGetValue("stereo_mode", out var stereoMode) && string.Equals(stereoMode, "left_right", StringComparison.OrdinalIgnoreCase))
|
||||||
|
|||||||
@@ -260,6 +260,8 @@ namespace MediaBrowser.Providers.Books.OpenPackagingFormat
|
|||||||
return PersonKind.Lyricist;
|
return PersonKind.Lyricist;
|
||||||
case "mus":
|
case "mus":
|
||||||
return PersonKind.AlbumArtist;
|
return PersonKind.AlbumArtist;
|
||||||
|
case "nrt":
|
||||||
|
return PersonKind.Narrator;
|
||||||
case "oth":
|
case "oth":
|
||||||
return PersonKind.Unknown;
|
return PersonKind.Unknown;
|
||||||
case "trl":
|
case "trl":
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ using System.Threading.Tasks;
|
|||||||
using ATL;
|
using ATL;
|
||||||
using Jellyfin.Data.Enums;
|
using Jellyfin.Data.Enums;
|
||||||
using Jellyfin.Extensions;
|
using Jellyfin.Extensions;
|
||||||
|
using MediaBrowser.Controller.Chapters;
|
||||||
using MediaBrowser.Controller.Entities;
|
using MediaBrowser.Controller.Entities;
|
||||||
using MediaBrowser.Controller.Entities.Audio;
|
using MediaBrowser.Controller.Entities.Audio;
|
||||||
using MediaBrowser.Controller.Library;
|
using MediaBrowser.Controller.Library;
|
||||||
@@ -38,6 +39,7 @@ namespace MediaBrowser.Providers.MediaInfo
|
|||||||
private readonly LyricResolver _lyricResolver;
|
private readonly LyricResolver _lyricResolver;
|
||||||
private readonly ILyricManager _lyricManager;
|
private readonly ILyricManager _lyricManager;
|
||||||
private readonly IMediaStreamRepository _mediaStreamRepository;
|
private readonly IMediaStreamRepository _mediaStreamRepository;
|
||||||
|
private readonly IChapterManager _chapterManager;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="AudioFileProber"/> class.
|
/// Initializes a new instance of the <see cref="AudioFileProber"/> class.
|
||||||
@@ -49,6 +51,7 @@ namespace MediaBrowser.Providers.MediaInfo
|
|||||||
/// <param name="lyricResolver">Instance of the <see cref="LyricResolver"/> interface.</param>
|
/// <param name="lyricResolver">Instance of the <see cref="LyricResolver"/> interface.</param>
|
||||||
/// <param name="lyricManager">Instance of the <see cref="ILyricManager"/> interface.</param>
|
/// <param name="lyricManager">Instance of the <see cref="ILyricManager"/> interface.</param>
|
||||||
/// <param name="mediaStreamRepository">Instance of the <see cref="IMediaStreamRepository"/>.</param>
|
/// <param name="mediaStreamRepository">Instance of the <see cref="IMediaStreamRepository"/>.</param>
|
||||||
|
/// <param name="chapterManager">Instance of the <see cref="IChapterManager"/> interface.</param>
|
||||||
public AudioFileProber(
|
public AudioFileProber(
|
||||||
ILogger<AudioFileProber> logger,
|
ILogger<AudioFileProber> logger,
|
||||||
IMediaSourceManager mediaSourceManager,
|
IMediaSourceManager mediaSourceManager,
|
||||||
@@ -56,7 +59,8 @@ namespace MediaBrowser.Providers.MediaInfo
|
|||||||
ILibraryManager libraryManager,
|
ILibraryManager libraryManager,
|
||||||
LyricResolver lyricResolver,
|
LyricResolver lyricResolver,
|
||||||
ILyricManager lyricManager,
|
ILyricManager lyricManager,
|
||||||
IMediaStreamRepository mediaStreamRepository)
|
IMediaStreamRepository mediaStreamRepository,
|
||||||
|
IChapterManager chapterManager)
|
||||||
{
|
{
|
||||||
_mediaEncoder = mediaEncoder;
|
_mediaEncoder = mediaEncoder;
|
||||||
_libraryManager = libraryManager;
|
_libraryManager = libraryManager;
|
||||||
@@ -65,6 +69,7 @@ namespace MediaBrowser.Providers.MediaInfo
|
|||||||
_lyricResolver = lyricResolver;
|
_lyricResolver = lyricResolver;
|
||||||
_lyricManager = lyricManager;
|
_lyricManager = lyricManager;
|
||||||
_mediaStreamRepository = mediaStreamRepository;
|
_mediaStreamRepository = mediaStreamRepository;
|
||||||
|
_chapterManager = chapterManager;
|
||||||
ATL.Settings.DisplayValueSeparator = InternalValueSeparator;
|
ATL.Settings.DisplayValueSeparator = InternalValueSeparator;
|
||||||
ATL.Settings.UseFileNameWhenNoTitle = false;
|
ATL.Settings.UseFileNameWhenNoTitle = false;
|
||||||
ATL.Settings.ID3v2_separatev2v3Values = false;
|
ATL.Settings.ID3v2_separatev2v3Values = false;
|
||||||
@@ -99,6 +104,7 @@ namespace MediaBrowser.Providers.MediaInfo
|
|||||||
new MediaInfoRequest
|
new MediaInfoRequest
|
||||||
{
|
{
|
||||||
MediaType = DlnaProfileType.Audio,
|
MediaType = DlnaProfileType.Audio,
|
||||||
|
ExtractChapters = item is AudioBook,
|
||||||
MediaSource = new MediaSourceInfo
|
MediaSource = new MediaSourceInfo
|
||||||
{
|
{
|
||||||
Path = path,
|
Path = path,
|
||||||
@@ -151,6 +157,11 @@ namespace MediaBrowser.Providers.MediaInfo
|
|||||||
audio.HasLyrics = mediaStreams.Any(s => s.Type == MediaStreamType.Lyric);
|
audio.HasLyrics = mediaStreams.Any(s => s.Type == MediaStreamType.Lyric);
|
||||||
|
|
||||||
_mediaStreamRepository.SaveMediaStreams(audio.Id, mediaStreams, cancellationToken);
|
_mediaStreamRepository.SaveMediaStreams(audio.Id, mediaStreams, cancellationToken);
|
||||||
|
|
||||||
|
if (audio is AudioBook && mediaInfo.Chapters is { Length: > 0 })
|
||||||
|
{
|
||||||
|
_chapterManager.SaveChapters(audio, mediaInfo.Chapters);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -212,18 +223,6 @@ namespace MediaBrowser.Providers.MediaInfo
|
|||||||
albumArtists = albumArtists.SelectMany(a => SplitWithCustomDelimiter(a, libraryOptions.GetCustomTagDelimiters(), libraryOptions.DelimiterWhitelist)).ToArray();
|
albumArtists = albumArtists.SelectMany(a => SplitWithCustomDelimiter(a, libraryOptions.GetCustomTagDelimiters(), libraryOptions.DelimiterWhitelist)).ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var albumArtist in albumArtists)
|
|
||||||
{
|
|
||||||
if (!string.IsNullOrWhiteSpace(albumArtist))
|
|
||||||
{
|
|
||||||
PeopleHelper.AddPerson(people, new PersonInfo
|
|
||||||
{
|
|
||||||
Name = albumArtist,
|
|
||||||
Type = PersonKind.AlbumArtist
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
string[]? performers = null;
|
string[]? performers = null;
|
||||||
if (libraryOptions.PreferNonstandardArtistsTag)
|
if (libraryOptions.PreferNonstandardArtistsTag)
|
||||||
{
|
{
|
||||||
@@ -244,32 +243,100 @@ namespace MediaBrowser.Providers.MediaInfo
|
|||||||
performers = performers.SelectMany(p => SplitWithCustomDelimiter(p, libraryOptions.GetCustomTagDelimiters(), libraryOptions.DelimiterWhitelist)).ToArray();
|
performers = performers.SelectMany(p => SplitWithCustomDelimiter(p, libraryOptions.GetCustomTagDelimiters(), libraryOptions.DelimiterWhitelist)).ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var performer in performers)
|
var isAudioBook = audio is AudioBook;
|
||||||
{
|
|
||||||
if (!string.IsNullOrWhiteSpace(performer))
|
|
||||||
{
|
|
||||||
PeopleHelper.AddPerson(people, new PersonInfo
|
|
||||||
{
|
|
||||||
Name = performer,
|
|
||||||
Type = PersonKind.Artist
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(trackComposer))
|
if (isAudioBook)
|
||||||
{
|
{
|
||||||
foreach (var composer in trackComposer.Split(InternalValueSeparator))
|
// For audiobooks: AlbumArtists/Performers = Author, NARRATOR tag = Narrator,
|
||||||
|
// ILLUSTRATOR tag = Illustrator, Composer = fallback Narrator, other performers = Cast.
|
||||||
|
// If album_artist is missing, fall back to artist/performers for the author role.
|
||||||
|
var authorSource = albumArtists.Length > 0 ? albumArtists : performers;
|
||||||
|
var authorNames = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
||||||
|
|
||||||
|
foreach (var author in authorSource)
|
||||||
{
|
{
|
||||||
if (!string.IsNullOrWhiteSpace(composer))
|
if (!string.IsNullOrWhiteSpace(author))
|
||||||
|
{
|
||||||
|
authorNames.Add(author.Trim());
|
||||||
|
PeopleHelper.AddPerson(people, new PersonInfo
|
||||||
|
{
|
||||||
|
Name = author.Trim(),
|
||||||
|
Type = PersonKind.Author
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Composer tag = Narrator (Audiobookshelf and other tools use Composer for narrator)
|
||||||
|
if (!string.IsNullOrWhiteSpace(trackComposer))
|
||||||
|
{
|
||||||
|
foreach (var composer in trackComposer.Split(InternalValueSeparator))
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrWhiteSpace(composer))
|
||||||
|
{
|
||||||
|
PeopleHelper.AddPerson(people, new PersonInfo
|
||||||
|
{
|
||||||
|
Name = composer.Trim(),
|
||||||
|
Type = PersonKind.Narrator
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Any performers not already listed as authors get added as cast
|
||||||
|
foreach (var performer in performers)
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrWhiteSpace(performer) && !authorNames.Contains(performer.Trim()))
|
||||||
{
|
{
|
||||||
PeopleHelper.AddPerson(people, new PersonInfo
|
PeopleHelper.AddPerson(people, new PersonInfo
|
||||||
{
|
{
|
||||||
Name = composer,
|
Name = performer.Trim(),
|
||||||
Type = PersonKind.Composer
|
Type = PersonKind.Actor
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Standard music track handling
|
||||||
|
foreach (var albumArtist in albumArtists)
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrWhiteSpace(albumArtist))
|
||||||
|
{
|
||||||
|
PeopleHelper.AddPerson(people, new PersonInfo
|
||||||
|
{
|
||||||
|
Name = albumArtist,
|
||||||
|
Type = PersonKind.AlbumArtist
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var performer in performers)
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrWhiteSpace(performer))
|
||||||
|
{
|
||||||
|
PeopleHelper.AddPerson(people, new PersonInfo
|
||||||
|
{
|
||||||
|
Name = performer,
|
||||||
|
Type = PersonKind.Artist
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(trackComposer))
|
||||||
|
{
|
||||||
|
foreach (var composer in trackComposer.Split(InternalValueSeparator))
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrWhiteSpace(composer))
|
||||||
|
{
|
||||||
|
PeopleHelper.AddPerson(people, new PersonInfo
|
||||||
|
{
|
||||||
|
Name = composer,
|
||||||
|
Type = PersonKind.Composer
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
_libraryManager.UpdatePeople(audio, people);
|
_libraryManager.UpdatePeople(audio, people);
|
||||||
|
|
||||||
@@ -359,6 +426,33 @@ namespace MediaBrowser.Providers.MediaInfo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Audiobook-specific metadata: Overview, Publisher, Series
|
||||||
|
if (audio is AudioBook audioBook)
|
||||||
|
{
|
||||||
|
if (!audio.LockedFields.Contains(MetadataField.Overview))
|
||||||
|
{
|
||||||
|
var trackDescription = GetSanitizedStringTag(track.Description, audio.Path);
|
||||||
|
var trackComment = GetSanitizedStringTag(track.Comment, audio.Path);
|
||||||
|
var overview = !string.IsNullOrWhiteSpace(trackDescription) ? trackDescription : trackComment;
|
||||||
|
|
||||||
|
if (!string.IsNullOrWhiteSpace(overview))
|
||||||
|
{
|
||||||
|
if (options.ReplaceAllMetadata || string.IsNullOrEmpty(audio.Overview))
|
||||||
|
{
|
||||||
|
audio.Overview = overview;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Publisher → Studio
|
||||||
|
var trackPublisher = GetSanitizedStringTag(track.Publisher, audio.Path);
|
||||||
|
if (!string.IsNullOrWhiteSpace(trackPublisher)
|
||||||
|
&& (options.ReplaceAllMetadata || audio.Studios is null || audio.Studios.Length == 0))
|
||||||
|
{
|
||||||
|
audio.SetStudios(new[] { trackPublisher! });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
TryGetSanitizedAdditionalFields(track, "REPLAYGAIN_TRACK_GAIN", out var trackGainTag);
|
TryGetSanitizedAdditionalFields(track, "REPLAYGAIN_TRACK_GAIN", out var trackGainTag);
|
||||||
|
|
||||||
if (trackGainTag is not null)
|
if (trackGainTag is not null)
|
||||||
|
|||||||
@@ -110,7 +110,8 @@ namespace MediaBrowser.Providers.MediaInfo
|
|||||||
libraryManager,
|
libraryManager,
|
||||||
_lyricResolver,
|
_lyricResolver,
|
||||||
lyricManager,
|
lyricManager,
|
||||||
mediaStreamRepository);
|
mediaStreamRepository,
|
||||||
|
chapterManager);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
|||||||
Reference in New Issue
Block a user