Browse Source

fix ogg song metadata (#1030)

pull/1032/head
Jason Dove 3 years ago committed by GitHub
parent
commit
6a640d3708
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      CHANGELOG.md
  2. 2
      ErsatzTV.Core/Interfaces/Metadata/ILocalStatisticsProvider.cs
  3. 16
      ErsatzTV.Core/Metadata/LocalMetadataProvider.cs
  4. 160
      ErsatzTV.Core/Metadata/LocalStatisticsProvider.cs
  5. 2
      ErsatzTV.Core/Metadata/MetadataSongTag.cs

1
CHANGELOG.md

@ -8,6 +8,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). @@ -8,6 +8,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- Fix removing Jellyfin and Emby libraries that have been deleted from the source media server
- Fix `Work-Ahead HLS Segmenter Limit` setting to properly limit number of channels that can work-ahead at once
- Include base path value in generated channel playlist (M3U) and channel guide (XMLTV) links
- Fix parsing song metadata from OGG audio files
### Added
- Add audio stream selector scripts for episodes and movies

2
ErsatzTV.Core/Interfaces/Metadata/ILocalStatisticsProvider.cs

@ -12,5 +12,5 @@ public interface ILocalStatisticsProvider @@ -12,5 +12,5 @@ public interface ILocalStatisticsProvider
MediaItem mediaItem,
string mediaItemPath);
Task<Either<BaseError, Dictionary<string, string>>> GetFormatTags(string ffprobePath, MediaItem mediaItem);
Task<Either<BaseError, Dictionary<string, string>>> GetSongTags(string ffprobePath, MediaItem mediaItem);
}

16
ErsatzTV.Core/Metadata/LocalMetadataProvider.cs

@ -277,7 +277,7 @@ public class LocalMetadataProvider : ILocalMetadataProvider @@ -277,7 +277,7 @@ public class LocalMetadataProvider : ILocalMetadataProvider
try
{
Either<BaseError, Dictionary<string, string>> maybeTags =
await _localStatisticsProvider.GetFormatTags(ffprobePath, song);
await _localStatisticsProvider.GetSongTags(ffprobePath, song);
foreach (Dictionary<string, string> tags in maybeTags.RightToSeq())
{
@ -297,37 +297,37 @@ public class LocalMetadataProvider : ILocalMetadataProvider @@ -297,37 +297,37 @@ public class LocalMetadataProvider : ILocalMetadataProvider
Tags = new List<Tag>()
};
if (tags.TryGetValue(MetadataFormatTag.Album, out string album))
if (tags.TryGetValue(MetadataSongTag.Album, out string album))
{
result.Album = album;
}
if (tags.TryGetValue(MetadataFormatTag.Artist, out string artist))
if (tags.TryGetValue(MetadataSongTag.Artist, out string artist))
{
result.Artist = artist;
}
if (tags.TryGetValue(MetadataFormatTag.AlbumArtist, out string albumArtist))
if (tags.TryGetValue(MetadataSongTag.AlbumArtist, out string albumArtist))
{
result.AlbumArtist = albumArtist;
}
if (tags.TryGetValue(MetadataFormatTag.Date, out string date))
if (tags.TryGetValue(MetadataSongTag.Date, out string date))
{
result.Date = date;
}
if (tags.TryGetValue(MetadataFormatTag.Genre, out string genre))
if (tags.TryGetValue(MetadataSongTag.Genre, out string genre))
{
result.Genres.AddRange(SplitGenres(genre).Map(n => new Genre { Name = n }));
}
if (tags.TryGetValue(MetadataFormatTag.Title, out string title))
if (tags.TryGetValue(MetadataSongTag.Title, out string title))
{
result.Title = title;
}
if (tags.TryGetValue(MetadataFormatTag.Track, out string track))
if (tags.TryGetValue(MetadataSongTag.Track, out string track))
{
result.Track = track;
}

160
ErsatzTV.Core/Metadata/LocalStatisticsProvider.cs

@ -82,7 +82,7 @@ public class LocalStatisticsProvider : ILocalStatisticsProvider @@ -82,7 +82,7 @@ public class LocalStatisticsProvider : ILocalStatisticsProvider
}
}
public async Task<Either<BaseError, Dictionary<string, string>>> GetFormatTags(
public async Task<Either<BaseError, Dictionary<string, string>>> GetSongTags(
string ffprobePath,
MediaItem mediaItem)
{
@ -90,55 +90,109 @@ public class LocalStatisticsProvider : ILocalStatisticsProvider @@ -90,55 +90,109 @@ public class LocalStatisticsProvider : ILocalStatisticsProvider
{
string mediaItemPath = mediaItem.GetHeadVersion().MediaFiles.Head().Path;
Either<BaseError, FFprobe> maybeProbe = await GetProbeOutput(ffprobePath, mediaItemPath);
return maybeProbe.Match(
ffprobe =>
{
var result = new Dictionary<string, string>();
foreach (BaseError error in maybeProbe.LeftToSeq())
{
return error;
}
if (!string.IsNullOrWhiteSpace(ffprobe?.format?.tags?.album))
{
result.Add(MetadataFormatTag.Album, ffprobe.format.tags.album);
}
Option<FFprobeTags> maybeFormatTags = maybeProbe.RightToSeq()
.Map(p => p?.format?.tags ?? FFprobeTags.Empty)
.HeadOrNone();
if (!string.IsNullOrWhiteSpace(ffprobe?.format?.tags?.albumArtist))
{
result.Add(MetadataFormatTag.AlbumArtist, ffprobe.format.tags.albumArtist);
}
Option<FFprobeTags> maybeAudioTags = maybeProbe.RightToSeq()
.Bind(p => p.streams.Filter(s => s.codec_type == "audio").HeadOrNone())
.Map(s => s.tags ?? FFprobeTags.Empty)
.HeadOrNone();
if (!string.IsNullOrWhiteSpace(ffprobe?.format?.tags?.artist))
{
result.Add(MetadataFormatTag.Artist, ffprobe.format.tags.artist);
foreach (FFprobeTags formatTags in maybeFormatTags)
foreach (FFprobeTags audioTags in maybeAudioTags)
{
var result = new Dictionary<string, string>();
// if no album artist is present, use the track artist
if (!result.ContainsKey(MetadataFormatTag.AlbumArtist))
{
result.Add(MetadataFormatTag.AlbumArtist, ffprobe.format.tags.artist);
}
}
// album
if (!string.IsNullOrWhiteSpace(formatTags.album))
{
result.Add(MetadataSongTag.Album, formatTags.album);
}
else if (!string.IsNullOrWhiteSpace(audioTags.album))
{
result.Add(MetadataSongTag.Album, audioTags.album);
}
if (!string.IsNullOrWhiteSpace(ffprobe?.format?.tags?.date))
{
result.Add(MetadataFormatTag.Date, ffprobe.format.tags.date);
}
// album artist
if (!string.IsNullOrWhiteSpace(formatTags.albumArtist))
{
result.Add(MetadataSongTag.AlbumArtist, formatTags.albumArtist);
}
else if (!string.IsNullOrWhiteSpace(audioTags.albumArtist))
{
result.Add(MetadataSongTag.AlbumArtist, audioTags.albumArtist);
}
if (!string.IsNullOrWhiteSpace(ffprobe?.format?.tags?.genre))
{
result.Add(MetadataFormatTag.Genre, ffprobe.format.tags.genre);
}
// artist
if (!string.IsNullOrWhiteSpace(formatTags.artist))
{
result.Add(MetadataSongTag.Artist, formatTags.artist);
if (!string.IsNullOrWhiteSpace(ffprobe?.format?.tags?.title))
// if no album artist is present, use the track artist
if (!result.ContainsKey(MetadataSongTag.AlbumArtist))
{
result.Add(MetadataFormatTag.Title, ffprobe.format.tags.title);
result.Add(MetadataSongTag.AlbumArtist, formatTags.artist);
}
}
else if (!string.IsNullOrWhiteSpace(audioTags.artist))
{
result.Add(MetadataSongTag.Artist, audioTags.artist);
if (!string.IsNullOrWhiteSpace(ffprobe?.format?.tags?.track))
// if no album artist is present, use the track artist
if (!result.ContainsKey(MetadataSongTag.AlbumArtist))
{
result.Add(MetadataFormatTag.Track, ffprobe.format.tags.track);
result.Add(MetadataSongTag.AlbumArtist, audioTags.artist);
}
}
return Right<BaseError, Dictionary<string, string>>(result);
},
Left<BaseError, Dictionary<string, string>>);
// date
if (!string.IsNullOrWhiteSpace(formatTags.date))
{
result.Add(MetadataSongTag.Date, formatTags.date);
}
else if (!string.IsNullOrWhiteSpace(audioTags.date))
{
result.Add(MetadataSongTag.Date, audioTags.date);
}
// genre
if (!string.IsNullOrWhiteSpace(formatTags.genre))
{
result.Add(MetadataSongTag.Genre, formatTags.genre);
}
else if (!string.IsNullOrWhiteSpace(audioTags.genre))
{
result.Add(MetadataSongTag.Genre, audioTags.genre);
}
// title
if (!string.IsNullOrWhiteSpace(formatTags.title))
{
result.Add(MetadataSongTag.Title, formatTags.title);
}
else if (!string.IsNullOrWhiteSpace(audioTags.title))
{
result.Add(MetadataSongTag.Title, audioTags.title);
}
// track
if (!string.IsNullOrWhiteSpace(formatTags.track))
{
result.Add(MetadataSongTag.Track, formatTags.track);
}
else if (!string.IsNullOrWhiteSpace(audioTags.track))
{
result.Add(MetadataSongTag.Track, audioTags.track);
}
return result;
}
}
catch (Exception ex)
{
@ -146,6 +200,8 @@ public class LocalStatisticsProvider : ILocalStatisticsProvider @@ -146,6 +200,8 @@ public class LocalStatisticsProvider : ILocalStatisticsProvider
_client.Notify(ex);
return BaseError.New(ex.Message);
}
return BaseError.New("BUG - this should never happen");
}
private async Task<bool> ApplyVersionUpdate(MediaItem mediaItem, MediaVersion version, string filePath)
@ -467,22 +523,10 @@ public class LocalStatisticsProvider : ILocalStatisticsProvider @@ -467,22 +523,10 @@ public class LocalStatisticsProvider : ILocalStatisticsProvider
// ReSharper disable InconsistentNaming
public record FFprobe(FFprobeFormat format, List<FFprobeStream> streams, List<FFprobeChapter> chapters);
public record FFprobeFormat(string duration, FFprobeFormatTags tags);
public record FFprobeFormat(string duration, FFprobeTags tags);
public record FFprobeDisposition(int @default, int forced, int attached_pic);
public record FFprobeTags(string language, string title, string filename, string mimetype);
public record FFprobeFormatTags(
string title,
string artist,
[property: JsonProperty(PropertyName = "album_artist")]
string albumArtist,
string album,
string track,
string genre,
string date);
public record FFprobeStream(
int index,
string codec_name,
@ -505,5 +549,21 @@ public class LocalStatisticsProvider : ILocalStatisticsProvider @@ -505,5 +549,21 @@ public class LocalStatisticsProvider : ILocalStatisticsProvider
string start_time,
string end_time,
FFprobeTags tags);
public record FFprobeTags(
string language,
string title,
string filename,
string mimetype,
string artist,
[property: JsonProperty(PropertyName = "album_artist")]
string albumArtist,
string album,
string track,
string genre,
string date)
{
public static readonly FFprobeTags Empty = new(null, null, null, null, null, null, null, null, null, null);
}
// ReSharper restore InconsistentNaming
}

2
ErsatzTV.Core/Metadata/MetadataFormatTag.cs → ErsatzTV.Core/Metadata/MetadataSongTag.cs

@ -1,6 +1,6 @@ @@ -1,6 +1,6 @@
namespace ErsatzTV.Core.Metadata;
public static class MetadataFormatTag
public static class MetadataSongTag
{
public static readonly string Album = "album";
public static readonly string Artist = "artist";
Loading…
Cancel
Save