aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBond-009 <bond.009@outlook.com>2021-09-03 17:15:58 +0200
committerGitHub <noreply@github.com>2021-09-03 17:15:58 +0200
commit3ec7ecf3995bb41e2ddd7e937f593b8fa4dfd552 (patch)
tree1a20fb4b3b4f09be63cd3e8e69fb4d5eb944c3ee
parent79e51b7fa20dbcb013ddd335fa829f83802dae71 (diff)
parent7f52cda03c9731fcbd57fd8c9ed8806c6965d054 (diff)
Merge pull request #6358 from MrTimscampi/audio-people
-rw-r--r--MediaBrowser.Controller/Entities/Audio/Audio.cs2
-rw-r--r--MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs58
-rw-r--r--MediaBrowser.Model/Entities/PersonType.cs40
-rw-r--r--tests/Jellyfin.MediaEncoding.Tests/Probing/ProbeResultNormalizerTests.cs34
-rw-r--r--tests/Jellyfin.MediaEncoding.Tests/Test Data/Probing/music_metadata.json144
5 files changed, 265 insertions, 13 deletions
diff --git a/MediaBrowser.Controller/Entities/Audio/Audio.cs b/MediaBrowser.Controller/Entities/Audio/Audio.cs
index 7bf1219ec..536668e50 100644
--- a/MediaBrowser.Controller/Entities/Audio/Audio.cs
+++ b/MediaBrowser.Controller/Entities/Audio/Audio.cs
@@ -43,7 +43,7 @@ namespace MediaBrowser.Controller.Entities.Audio
public override bool SupportsPlayedStatus => true;
[JsonIgnore]
- public override bool SupportsPeople => false;
+ public override bool SupportsPeople => true;
[JsonIgnore]
public override bool SupportsAddingToPlaylist => true;
diff --git a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs
index 93093bb18..04f0be307 100644
--- a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs
+++ b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs
@@ -7,6 +7,7 @@ using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
+using System.Text.RegularExpressions;
using System.Xml;
using Jellyfin.Extensions;
using MediaBrowser.Controller.Library;
@@ -27,7 +28,9 @@ namespace MediaBrowser.MediaEncoding.Probing
private readonly char[] _nameDelimiters = { '/', '|', ';', '\\' };
- private readonly CultureInfo _usCulture = new CultureInfo("en-US");
+ private static readonly Regex _performerPattern = new (@"(?<name>.*) \((?<instrument>.*)\)");
+
+ private readonly CultureInfo _usCulture = new ("en-US");
private readonly ILogger _logger;
private readonly ILocalizationManager _localization;
@@ -1128,7 +1131,26 @@ namespace MediaBrowser.MediaEncoding.Probing
}
}
- // Check for writer some music is tagged that way as alternative to composer/lyricist
+ if (tags.TryGetValue("performer", out var performer) && !string.IsNullOrWhiteSpace(performer))
+ {
+ foreach (var person in Split(performer, false))
+ {
+ Match match = _performerPattern.Match(person);
+
+ // If the performer doesn't have any instrument/role associated, it won't match. In that case, chances are it's simply a band name, so we skip it.
+ if (match.Success)
+ {
+ people.Add(new BaseItemPerson
+ {
+ Name = match.Groups["name"].Value,
+ Type = PersonType.Actor,
+ Role = CultureInfo.CurrentCulture.TextInfo.ToTitleCase(match.Groups["instrument"].Value)
+ });
+ }
+ }
+ }
+
+ // In cases where there isn't sufficient information as to which role a writer performed on a recording, tagging software uses the "writer" tag.
if (tags.TryGetValue("writer", out var writer) && !string.IsNullOrWhiteSpace(writer))
{
foreach (var person in Split(writer, false))
@@ -1137,6 +1159,38 @@ namespace MediaBrowser.MediaEncoding.Probing
}
}
+ if (tags.TryGetValue("arranger", out var arranger) && !string.IsNullOrWhiteSpace(arranger))
+ {
+ foreach (var person in Split(arranger, false))
+ {
+ people.Add(new BaseItemPerson { Name = person, Type = PersonType.Arranger });
+ }
+ }
+
+ if (tags.TryGetValue("engineer", out var engineer) && !string.IsNullOrWhiteSpace(engineer))
+ {
+ foreach (var person in Split(engineer, false))
+ {
+ people.Add(new BaseItemPerson { Name = person, Type = PersonType.Engineer });
+ }
+ }
+
+ if (tags.TryGetValue("mixer", out var mixer) && !string.IsNullOrWhiteSpace(mixer))
+ {
+ foreach (var person in Split(mixer, false))
+ {
+ people.Add(new BaseItemPerson { Name = person, Type = PersonType.Mixer });
+ }
+ }
+
+ if (tags.TryGetValue("remixer", out var remixer) && !string.IsNullOrWhiteSpace(remixer))
+ {
+ foreach (var person in Split(remixer, false))
+ {
+ people.Add(new BaseItemPerson { Name = person, Type = PersonType.Remixer });
+ }
+ }
+
audio.People = people.ToArray();
// Set album artist
diff --git a/MediaBrowser.Model/Entities/PersonType.cs b/MediaBrowser.Model/Entities/PersonType.cs
index 81db9c613..b985507f0 100644
--- a/MediaBrowser.Model/Entities/PersonType.cs
+++ b/MediaBrowser.Model/Entities/PersonType.cs
@@ -1,48 +1,68 @@
namespace MediaBrowser.Model.Entities
{
/// <summary>
- /// Struct PersonType.
+ /// Types of persons.
/// </summary>
- public class PersonType
+ public static class PersonType
{
/// <summary>
- /// The actor.
+ /// A person whose profession is acting on the stage, in films, or on television.
/// </summary>
public const string Actor = "Actor";
/// <summary>
- /// The director.
+ /// A person who supervises the actors and other staff in a film, play, or similar production.
/// </summary>
public const string Director = "Director";
/// <summary>
- /// The composer.
+ /// A person who writes music, especially as a professional occupation.
/// </summary>
public const string Composer = "Composer";
/// <summary>
- /// The writer.
+ /// A writer of a book, article, or document. Can also be used as a generic term for music writer if there is a lack of specificity.
/// </summary>
public const string Writer = "Writer";
/// <summary>
- /// The guest star.
+ /// A well-known actor or other performer who appears in a work in which they do not have a regular role.
/// </summary>
public const string GuestStar = "GuestStar";
/// <summary>
- /// The producer.
+ /// A person responsible for the financial and managerial aspects of the making of a film or broadcast or for staging a play, opera, etc.
/// </summary>
public const string Producer = "Producer";
/// <summary>
- /// The conductor.
+ /// A person who directs the performance of an orchestra or choir.
/// </summary>
public const string Conductor = "Conductor";
/// <summary>
- /// The lyricist.
+ /// A person who writes the words to a song or musical.
/// </summary>
public const string Lyricist = "Lyricist";
+
+ /// <summary>
+ /// A person who adapts a musical composition for performance.
+ /// </summary>
+ public const string Arranger = "Arranger";
+
+ /// <summary>
+ /// An audio engineer who performed a general engineering role.
+ /// </summary>
+ public const string Engineer = "Engineer";
+
+ /// <summary>
+ /// An engineer responsible for using a mixing console to mix a recorded track into a single piece of music suitable for release.
+ /// </summary>
+ public const string Mixer = "Mixer";
+
+ /// <summary>
+ /// A person who remixed a recording by taking one or more other tracks, substantially altering them and mixing them together with other material.
+ /// </summary>
+ public const string Remixer = "Remixer";
}
}
diff --git a/tests/Jellyfin.MediaEncoding.Tests/Probing/ProbeResultNormalizerTests.cs b/tests/Jellyfin.MediaEncoding.Tests/Probing/ProbeResultNormalizerTests.cs
index 59037c263..fcb85a3ac 100644
--- a/tests/Jellyfin.MediaEncoding.Tests/Probing/ProbeResultNormalizerTests.cs
+++ b/tests/Jellyfin.MediaEncoding.Tests/Probing/ProbeResultNormalizerTests.cs
@@ -4,6 +4,7 @@ using System.IO;
using System.Text.Json;
using Jellyfin.Extensions.Json;
using MediaBrowser.MediaEncoding.Probing;
+using MediaBrowser.Model.Dto;
using MediaBrowser.Model.Entities;
using MediaBrowser.Model.MediaInfo;
using Microsoft.Extensions.Logging.Abstractions;
@@ -91,5 +92,38 @@ namespace Jellyfin.MediaEncoding.Tests.Probing
Assert.Contains("Pop", res.Genres);
Assert.Contains("Jazz", res.Genres);
}
+
+ [Fact]
+ public void GetMediaInfo_Music_Success()
+ {
+ var bytes = File.ReadAllBytes("Test Data/Probing/music_metadata.json");
+ var internalMediaInfoResult = JsonSerializer.Deserialize<InternalMediaInfoResult>(bytes, _jsonOptions);
+ MediaInfo res = _probeResultNormalizer.GetMediaInfo(internalMediaInfoResult, null, true, "Test Data/Probing/music.flac", MediaProtocol.File);
+
+ Assert.Equal("UP NO MORE", res.Name);
+ Assert.Single(res.Artists);
+ Assert.Equal("TWICE", res.Artists[0]);
+ Assert.Equal("Eyes wide open", res.Album);
+ Assert.Equal(2020, res.ProductionYear);
+ Assert.True(res.PremiereDate.HasValue);
+ Assert.Equal(DateTime.Parse("2020-10-26T00:00Z", DateTimeFormatInfo.CurrentInfo).ToUniversalTime(), res.PremiereDate);
+ Assert.Equal(22, res.People.Length);
+ Assert.Equal("Krysta Youngs", res.People[0].Name);
+ Assert.Equal(PersonType.Composer, res.People[0].Type);
+ Assert.Equal("Julia Ross", res.People[1].Name);
+ Assert.Equal(PersonType.Composer, res.People[1].Type);
+ Assert.Equal("Yiwoomin", res.People[2].Name);
+ Assert.Equal(PersonType.Composer, res.People[2].Type);
+ Assert.Equal("Ji-hyo Park", res.People[3].Name);
+ Assert.Equal(PersonType.Lyricist, res.People[3].Type);
+ Assert.Equal("Yiwoomin", res.People[4].Name);
+ Assert.Equal(PersonType.Actor, res.People[4].Type);
+ Assert.Equal("Electric Piano", res.People[4].Role);
+ Assert.Equal(4, res.Genres.Length);
+ Assert.Contains("Electronic", res.Genres);
+ Assert.Contains("Trance", res.Genres);
+ Assert.Contains("Dance", res.Genres);
+ Assert.Contains("Jazz", res.Genres);
+ }
}
}
diff --git a/tests/Jellyfin.MediaEncoding.Tests/Test Data/Probing/music_metadata.json b/tests/Jellyfin.MediaEncoding.Tests/Test Data/Probing/music_metadata.json
new file mode 100644
index 000000000..6530629fe
--- /dev/null
+++ b/tests/Jellyfin.MediaEncoding.Tests/Test Data/Probing/music_metadata.json
@@ -0,0 +1,144 @@
+{
+ "streams": [
+ {
+ "index": 0,
+ "codec_name": "flac",
+ "codec_long_name": "FLAC (Free Lossless Audio Codec)",
+ "codec_type": "audio",
+ "codec_tag_string": "[0][0][0][0]",
+ "codec_tag": "0x0000",
+ "sample_fmt": "s16",
+ "sample_rate": "44100",
+ "channels": 2,
+ "channel_layout": "stereo",
+ "bits_per_sample": 0,
+ "r_frame_rate": "0/0",
+ "avg_frame_rate": "0/0",
+ "time_base": "1/44100",
+ "start_pts": 0,
+ "start_time": "0.000000",
+ "duration_ts": 9447984,
+ "duration": "214.240000",
+ "bits_per_raw_sample": "16",
+ "disposition": {
+ "default": 0,
+ "dub": 0,
+ "original": 0,
+ "comment": 0,
+ "lyrics": 0,
+ "karaoke": 0,
+ "forced": 0,
+ "hearing_impaired": 0,
+ "visual_impaired": 0,
+ "clean_effects": 0,
+ "attached_pic": 0,
+ "timed_thumbnails": 0
+ }
+ },
+ {
+ "index": 1,
+ "codec_name": "mjpeg",
+ "codec_long_name": "Motion JPEG",
+ "profile": "Baseline",
+ "codec_type": "video",
+ "codec_tag_string": "[0][0][0][0]",
+ "codec_tag": "0x0000",
+ "width": 500,
+ "height": 500,
+ "coded_width": 500,
+ "coded_height": 500,
+ "closed_captions": 0,
+ "has_b_frames": 0,
+ "sample_aspect_ratio": "1:1",
+ "display_aspect_ratio": "1:1",
+ "pix_fmt": "yuvj420p",
+ "level": -99,
+ "color_range": "pc",
+ "color_space": "bt470bg",
+ "chroma_location": "center",
+ "refs": 1,
+ "r_frame_rate": "90000/1",
+ "avg_frame_rate": "0/0",
+ "time_base": "1/90000",
+ "start_pts": 0,
+ "start_time": "0.000000",
+ "duration_ts": 19281600,
+ "duration": "214.240000",
+ "bits_per_raw_sample": "8",
+ "disposition": {
+ "default": 0,
+ "dub": 0,
+ "original": 0,
+ "comment": 0,
+ "lyrics": 0,
+ "karaoke": 0,
+ "forced": 0,
+ "hearing_impaired": 0,
+ "visual_impaired": 0,
+ "clean_effects": 0,
+ "attached_pic": 1,
+ "timed_thumbnails": 0
+ },
+ "tags": {
+ "comment": "Cover (front)"
+ }
+ }
+ ],
+ "format": {
+ "filename": "03 UP NO MORE.flac",
+ "nb_streams": 2,
+ "nb_programs": 0,
+ "format_name": "flac",
+ "format_long_name": "raw FLAC",
+ "start_time": "0.000000",
+ "duration": "214.240000",
+ "size": "28714641",
+ "bit_rate": "1072242",
+ "probe_score": 100,
+ "tags": {
+ "MUSICBRAINZ_RELEASEGROUPID": "aa05ff10-8589-4c9c-a0d4-6b024f4e4556",
+ "ORIGINALDATE": "2020-10-26",
+ "ORIGINALYEAR": "2020",
+ "RELEASETYPE": "album",
+ "MUSICBRAINZ_ALBUMID": "222e6610-75c9-400e-8dc3-bb61f9fc5ca7",
+ "SCRIPT": "Latn",
+ "ALBUM": "Eyes wide open",
+ "RELEASECOUNTRY": "JP",
+ "BARCODE": "190295105280",
+ "LABEL": "JYP Entertainment",
+ "RELEASESTATUS": "official",
+ "DATE": "2020-10-26",
+ "MUSICBRAINZ_ALBUMARTISTID": "8da127cc-c432-418f-b356-ef36210d82ac",
+ "album_artist": "TWICE",
+ "ALBUMARTISTSORT": "TWICE",
+ "TOTALDISCS": "1",
+ "TOTALTRACKS": "13",
+ "MEDIA": "Digital Media",
+ "disc": "1",
+ "MUSICBRAINZ_TRACKID": "7d1a1044-b564-480d-9df3-22f9656fdb97",
+ "TITLE": "UP NO MORE",
+ "ISRC": "US5TA2000136",
+ "PERFORMER": "Yiwoomin (electric piano);Yiwoomin (synthesizer);Yiwoomin (bass);Yiwoomin (guitar);TWICE;Tzu-yu Chou (vocals);Momo Hirai (vocals);Na-yeon Im (vocals);Da-hyun Kim (vocals);Sana Minatozaki (vocals);Mina Myoui (vocals);Ji-hyo Park (vocals);Chae-young Son (vocals);Jeong-yeon Yoo (vocals);Perrie (background vocals)",
+ "MIXER": "Bong Won Shin",
+ "ARRANGER": "Krysta Youngs;Julia Ross;Yiwoomin",
+ "MUSICBRAINZ_WORKID": "02b37083-0337-4721-9f17-bf31971043e8",
+ "LANGUAGE": "kor;eng",
+ "WORK": "Up No More",
+ "COMPOSER": "Krysta Youngs;Julia Ross;Yiwoomin",
+ "COMPOSERSORT": "Krysta Youngs;Ross, Julia;Yiwoomin",
+ "LYRICIST": "Ji-hyo Park",
+ "MUSICBRAINZ_ARTISTID": "8da127cc-c432-418f-b356-ef36210d82ac",
+ "ARTIST": "TWICE",
+ "ARTISTSORT": "TWICE",
+ "ARTISTS": "TWICE",
+ "MUSICBRAINZ_RELEASETRACKID": "ad49b840-da9e-4e7c-924b-29fdee187052",
+ "track": "3",
+ "GENRE": "Electronic;Trance;Dance;Jazz",
+ "WEBSITE": "http://twice.jype.com/;http://www.twicejapan.com/",
+ "ACOUSTID_ID": "aae2e972-108c-4d0c-8e31-9d078283e3dc",
+ "MOOD": "Not acoustic;Not aggressive;Electronic;Happy;Party;Not relaxed;Not sad",
+ "TRACKTOTAL": "13",
+ "DISCTOTAL": "1"
+ }
+ }
+}