mirror of
https://github.com/jellyfin/jellyfin.git
synced 2026-05-04 07:46:32 +01:00
@@ -260,6 +260,8 @@ namespace MediaBrowser.Providers.Books.OpenPackagingFormat
|
||||
return PersonKind.Lyricist;
|
||||
case "mus":
|
||||
return PersonKind.AlbumArtist;
|
||||
case "nrt":
|
||||
return PersonKind.Narrator;
|
||||
case "oth":
|
||||
return PersonKind.Unknown;
|
||||
case "trl":
|
||||
|
||||
@@ -7,6 +7,7 @@ using System.Threading.Tasks;
|
||||
using ATL;
|
||||
using Jellyfin.Data.Enums;
|
||||
using Jellyfin.Extensions;
|
||||
using MediaBrowser.Controller.Chapters;
|
||||
using MediaBrowser.Controller.Entities;
|
||||
using MediaBrowser.Controller.Entities.Audio;
|
||||
using MediaBrowser.Controller.Library;
|
||||
@@ -38,6 +39,7 @@ namespace MediaBrowser.Providers.MediaInfo
|
||||
private readonly LyricResolver _lyricResolver;
|
||||
private readonly ILyricManager _lyricManager;
|
||||
private readonly IMediaStreamRepository _mediaStreamRepository;
|
||||
private readonly IChapterManager _chapterManager;
|
||||
|
||||
/// <summary>
|
||||
/// 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="lyricManager">Instance of the <see cref="ILyricManager"/> interface.</param>
|
||||
/// <param name="mediaStreamRepository">Instance of the <see cref="IMediaStreamRepository"/>.</param>
|
||||
/// <param name="chapterManager">Instance of the <see cref="IChapterManager"/> interface.</param>
|
||||
public AudioFileProber(
|
||||
ILogger<AudioFileProber> logger,
|
||||
IMediaSourceManager mediaSourceManager,
|
||||
@@ -56,7 +59,8 @@ namespace MediaBrowser.Providers.MediaInfo
|
||||
ILibraryManager libraryManager,
|
||||
LyricResolver lyricResolver,
|
||||
ILyricManager lyricManager,
|
||||
IMediaStreamRepository mediaStreamRepository)
|
||||
IMediaStreamRepository mediaStreamRepository,
|
||||
IChapterManager chapterManager)
|
||||
{
|
||||
_mediaEncoder = mediaEncoder;
|
||||
_libraryManager = libraryManager;
|
||||
@@ -65,6 +69,7 @@ namespace MediaBrowser.Providers.MediaInfo
|
||||
_lyricResolver = lyricResolver;
|
||||
_lyricManager = lyricManager;
|
||||
_mediaStreamRepository = mediaStreamRepository;
|
||||
_chapterManager = chapterManager;
|
||||
ATL.Settings.DisplayValueSeparator = InternalValueSeparator;
|
||||
ATL.Settings.UseFileNameWhenNoTitle = false;
|
||||
ATL.Settings.ID3v2_separatev2v3Values = false;
|
||||
@@ -99,6 +104,7 @@ namespace MediaBrowser.Providers.MediaInfo
|
||||
new MediaInfoRequest
|
||||
{
|
||||
MediaType = DlnaProfileType.Audio,
|
||||
ExtractChapters = item is AudioBook,
|
||||
MediaSource = new MediaSourceInfo
|
||||
{
|
||||
Path = path,
|
||||
@@ -151,6 +157,11 @@ namespace MediaBrowser.Providers.MediaInfo
|
||||
audio.HasLyrics = mediaStreams.Any(s => s.Type == MediaStreamType.Lyric);
|
||||
|
||||
_mediaStreamRepository.SaveMediaStreams(audio.Id, mediaStreams, cancellationToken);
|
||||
|
||||
if (audio is AudioBook && mediaInfo.Chapters is { Length: > 0 })
|
||||
{
|
||||
_chapterManager.SaveChapters(audio, mediaInfo.Chapters);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -212,18 +223,6 @@ namespace MediaBrowser.Providers.MediaInfo
|
||||
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;
|
||||
if (libraryOptions.PreferNonstandardArtistsTag)
|
||||
{
|
||||
@@ -244,32 +243,100 @@ namespace MediaBrowser.Providers.MediaInfo
|
||||
performers = performers.SelectMany(p => SplitWithCustomDelimiter(p, libraryOptions.GetCustomTagDelimiters(), libraryOptions.DelimiterWhitelist)).ToArray();
|
||||
}
|
||||
|
||||
foreach (var performer in performers)
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(performer))
|
||||
{
|
||||
PeopleHelper.AddPerson(people, new PersonInfo
|
||||
{
|
||||
Name = performer,
|
||||
Type = PersonKind.Artist
|
||||
});
|
||||
}
|
||||
}
|
||||
var isAudioBook = audio is AudioBook;
|
||||
|
||||
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
|
||||
{
|
||||
Name = composer,
|
||||
Type = PersonKind.Composer
|
||||
Name = performer.Trim(),
|
||||
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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
if (trackGainTag is not null)
|
||||
|
||||
@@ -110,7 +110,8 @@ namespace MediaBrowser.Providers.MediaInfo
|
||||
libraryManager,
|
||||
_lyricResolver,
|
||||
lyricManager,
|
||||
mediaStreamRepository);
|
||||
mediaStreamRepository,
|
||||
chapterManager);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
||||
Reference in New Issue
Block a user