Refactor LbzRpcService and add HandleNewListenData method

Refactored the LbzRpcService class to improve code structure and
efficiency. Moved `lastRecording` and `albumArtUrl` fields to class
scope and removed their initialization from the loop.

Enhanced album art URL handling with `TrySetAlbumArtUrl` and
`SetAlbumArtUrl` methods. Prioritized MusicBrainz data and added
fallback to YouTube thumbnails.
This commit is contained in:
Thord Johansson 2024-10-20 22:18:12 +02:00
parent 67a3549e7b
commit 832832c4d2

View File

@ -8,6 +8,8 @@ using Topshelf;
using System.Web;
using MetaBrainz.MusicBrainz.Interfaces.Entities;
using MetaBrainz.MusicBrainz.Interfaces.Searches;
using MetaBrainz.ListenBrainz.Interfaces;
using System.Net;
public class LbzRpcService
@ -17,6 +19,8 @@ public class LbzRpcService
readonly Thread t;
bool running = false;
private string? lastRecording;
private string albumArtUrl = "";
public LbzRpcService()
{
@ -71,10 +75,6 @@ public class LbzRpcService
InitializeDiscordRpc();
string? lastRecording = null;
List<Button> buttons = new List<Button>();
string albumArtUrl = "";
while (running)
{
if (!connected)
@ -88,7 +88,7 @@ public class LbzRpcService
var ignoredPlayers = config_data["general"]["ignored_sources"].Split(",", StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
MetaBrainz.ListenBrainz.Interfaces.IPlayingNow? listen = null;
IPlayingNow? listen = null;
try
{
@ -114,115 +114,11 @@ public class LbzRpcService
var listenData = listen.Track?.Info;
if (listenData != null)
{
if (listenData.AdditionalInfo.OriginUrl != null
&& (listenData.AdditionalInfo.OriginUrl?.Host == "music.youtube.com" || listenData.AdditionalInfo.OriginUrl?.Host == "www.youtube.com")
&& GetYoutubeId(listenData.AdditionalInfo.OriginUrl) != null
&& lastRecording != GetYoutubeId(listenData.AdditionalInfo.OriginUrl))
{
lastRecording = GetYoutubeId(listenData.AdditionalInfo.OriginUrl);
Console.WriteLine("Searching for release {0} on MusicBrainz", listenData.Release);
Query q = new("LBZ-DRPC", new Version(1, 0, 0));
ISearchResult<IRelease>? release = null;
if (listenData.Release != null || listenData.Artist != null)
{
release = q.FindReleases(listenData.Release ?? listenData.Artist, 1).Results?.FirstOrDefault();
if (release?.Item.CoverArtArchive == null || !release.Item.CoverArtArchive.Front)
{
if (release?.Item.Aliases != null)
foreach (IAlias alias in release.Item.Aliases)
{
if (alias.Primary == true)
{
var r = q.FindReleases(alias.Name, 1).Results?.FirstOrDefault();
if (release != null && release.Item.CoverArtArchive?.Front == true)
{
release = r;
}
}
};
}
}
lastRecording = GetYoutubeId(listenData.AdditionalInfo.OriginUrl);
if (release != null)
{
albumArtUrl = "https://coverartarchive.org/release/" + release.Item.Id + "/front-250.jpg";
//albumArtUrl = "https://coverartarchive.org/release/" + release?.Item.Id + "/front-250.jpg";
}
else
{
var youtubeId = GetYoutubeId(listenData.AdditionalInfo.OriginUrl);
albumArtUrl = "https://img.youtube.com/vi/" + youtubeId + "/mqdefault.jpg";
}
}
else if (lastRecording != listenData.AdditionalInfo?.RecordingId.ToString() && listenData.AdditionalInfo?.RecordingId != null) // MusicBrainz ID available
{
Console.WriteLine("Listening to {0} by {1}", listenData.Name, listenData.Artist);
lastRecording = listenData.AdditionalInfo?.RecordingId.ToString();
buttons = [];
if (listenData.AdditionalInfo?.RecordingId != null)
{
buttons.Add(new Button() { Label = "Listen on MusicBrainz", Url = $"https://listenbrainz.org/player/?recording_mbids={listenData.AdditionalInfo?.RecordingId}" });
}
buttons.Add(new Button() { Label = $"{username} on ListenBrainz", Url = $"https://listenbrainz.org/user/{username}" });
string? newAlbumArt = null;
if (config_data["general"]["prioritise_musicbrainz"] == "true" && listenData.AdditionalInfo?.ReleaseId != null)
{
newAlbumArt = "https://coverartarchive.org/release/" + listenData.AdditionalInfo?.ReleaseId + "/front-250.jpg";
}
else if (config_data["general"]["prioritise_musicbrainz"] == "true" && listenData.Release != null)
{
var release = FindMusicBrainzRelease(listenData.Release);
newAlbumArt = "https://coverartarchive.org/release/" + release?.Item.Id + "/front-250.jpg";
}
if (newAlbumArt == null)
{
if ((listenData.AdditionalInfo?.OriginUrl?.ToString().Contains("youtube") == true
|| listenData.AdditionalInfo?.OriginUrl?.ToString().Contains("youtu.be") == true)
&& GetYoutubeId(listenData.AdditionalInfo.OriginUrl) != null)
{
newAlbumArt = "https://img.youtube.com/vi/" + GetYoutubeId(listenData.AdditionalInfo.OriginUrl) + "/0.jpg";
}
else if (listenData.AdditionalInfo?.ReleaseId != null)
{
newAlbumArt = "https://coverartarchive.org/release/" + listenData.AdditionalInfo?.ReleaseId + "/front-250.jpg";
}
else if (listenData.Release != null)
{
var release = FindMusicBrainzRelease(listenData.Release);
newAlbumArt = "https://coverartarchive.org/release/" + release?.Item.Id + "/front-250.jpg";
}
}
Console.WriteLine("Album art URL: " + (newAlbumArt ?? "(none)"));
albumArtUrl = newAlbumArt ?? "";
}
else
{
albumArtUrl = "";
}
client.SetPresence(new RichPresence()
{
Details = $"{listenData.Name}",
State = listenData.Artist,
Buttons = buttons.ToArray(),
Assets = new Assets()
{
SmallImageKey = "play",
LargeImageKey = albumArtUrl?.Length > 0 ? albumArtUrl : null,
LargeImageText = $"Listening to {listenData.Name} by {listenData.Artist}{(listenData.AdditionalInfo?.MediaPlayer != null ? " (via " + listenData.AdditionalInfo.MediaPlayer + ")" : "")}"
}
});
RichPresence? presence = null;
HandleNewListenData(listenData, out presence, config_data);
if (presence != null)
client.SetPresence(presence);
}
else if (listenData == null)
{
@ -250,6 +146,188 @@ public class LbzRpcService
}
}
private void HandleNewListenData(ITrackInfo listenData, out RichPresence? presence, IniData config_data)
{
if (listenData == null || config_data == null)
{
presence = null;
return;
}
var buttons = new List<Button>();
var username = config_data["general"]["listenbrainz_username"];
var ignoredPlayers = config_data["general"]["ignored_sources"].Split(",", StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
var prioritizeMusicBrainz = config_data["general"]["prioritise_musicbrainz"];
if (listenData.AdditionalInfo.OriginUrl != null
&& (listenData.AdditionalInfo.OriginUrl?.Host == "music.youtube.com" || listenData.AdditionalInfo.OriginUrl?.Host == "www.youtube.com")
&& GetYoutubeId(listenData.AdditionalInfo.OriginUrl) != null
&& lastRecording != GetYoutubeId(listenData.AdditionalInfo.OriginUrl))
{
lastRecording = GetYoutubeId(listenData.AdditionalInfo.OriginUrl);
Console.WriteLine("Searching for release {0} on MusicBrainz", listenData.Release);
Query q = new("LBZ-DRPC", new Version(1, 0, 0));
ISearchResult<IRelease>? release = null;
if (listenData.Release != null || listenData.Artist != null)
{
release = q.FindReleases(listenData.Release ?? listenData.Artist, 1).Results?.FirstOrDefault();
if (release?.Item.CoverArtArchive == null || !release.Item.CoverArtArchive.Front)
{
if (release?.Item.Aliases != null)
foreach (IAlias alias in release.Item.Aliases)
{
if (alias.Primary == true)
{
var r = q.FindReleases(alias.Name, 1).Results?.FirstOrDefault();
if (release != null && release.Item.CoverArtArchive?.Front == true)
{
release = r;
}
}
};
}
}
lastRecording = GetYoutubeId(listenData.AdditionalInfo.OriginUrl);
if (release != null && TrySetAlbumArtUrl("https://coverartarchive.org/release/" + release.Item.Id + "/front-250.jpg"))
{
// all is well, carry on at the end of the if block
}
else if (GetYoutubeId(listenData.AdditionalInfo.OriginUrl) != null)
{
var youtubeId = GetYoutubeId(listenData.AdditionalInfo.OriginUrl);
SetAlbumArtUrl("https://img.youtube.com/vi/" + youtubeId + "/mqdefault.jpg");
}
else
{
SetAlbumArtUrl(null);
}
}
else if (lastRecording != listenData.AdditionalInfo?.RecordingId.ToString() && listenData.AdditionalInfo?.RecordingId != null) // MusicBrainz ID available
{
Console.WriteLine("Listening to {0} by {1}", listenData.Name, listenData.Artist);
lastRecording = listenData.AdditionalInfo?.RecordingId.ToString();
buttons = [];
if (listenData.AdditionalInfo?.RecordingId != null)
{
buttons.Add(new Button() { Label = "Listen on MusicBrainz", Url = $"https://listenbrainz.org/player/?recording_mbids={listenData.AdditionalInfo?.RecordingId}" });
}
buttons.Add(new Button() { Label = $"{username} on ListenBrainz", Url = $"https://listenbrainz.org/user/{username}" });
string? newAlbumArt = null;
if (prioritizeMusicBrainz == "true" && listenData.AdditionalInfo?.ReleaseId != null)
{
newAlbumArt = "https://coverartarchive.org/release/" + listenData.AdditionalInfo?.ReleaseId + "/front-250.jpg";
}
else if (config_data["general"]["prioritise_musicbrainz"] == "true" && listenData.Release != null)
{
var release = FindMusicBrainzRelease(listenData.Release);
newAlbumArt = "https://coverartarchive.org/release/" + release?.Item.Id + "/front-250.jpg";
}
if (newAlbumArt == null)
{
if ((listenData.AdditionalInfo?.OriginUrl?.ToString().Contains("youtube") == true
|| listenData.AdditionalInfo?.OriginUrl?.ToString().Contains("youtu.be") == true)
&& GetYoutubeId(listenData.AdditionalInfo.OriginUrl) != null)
{
Console.WriteLine("Using YouTube thumbnail as album art");
newAlbumArt = "https://img.youtube.com/vi/" + GetYoutubeId(listenData.AdditionalInfo.OriginUrl) + "/0.jpg";
}
else if (listenData.AdditionalInfo?.ReleaseId != null)
{
Console.WriteLine("Using ListenBrainz release ID as album art");
newAlbumArt = "https://coverartarchive.org/release/" + listenData.AdditionalInfo?.ReleaseId + "/front-250.jpg";
}
else if (listenData.Release != null)
{
var release = FindMusicBrainzRelease(listenData.Release);
newAlbumArt = "https://coverartarchive.org/release/" + release?.Item.Id + "/front-250.jpg";
}
}
Console.WriteLine("Album art URL: " + (newAlbumArt ?? "(none)"));
SetAlbumArtUrl(newAlbumArt);
}
presence = new RichPresence()
{
Details = $"{listenData.Name}",
State = listenData.Artist,
Buttons = buttons.ToArray(),
Assets = new Assets()
{
SmallImageKey = "play",
LargeImageKey = albumArtUrl?.Length > 0 ? albumArtUrl : null,
LargeImageText = $"Listening to {listenData.Name} by {listenData.Artist}{(listenData.AdditionalInfo?.MediaPlayer != null ? " (via " + listenData.AdditionalInfo.MediaPlayer + ")" : "")}"
}
};
}
/// <summary>
/// Attempts to download the album art from the given URL and sets it as the album art URL if successful.
/// This ensures that the URL points to a valid image file (fails when e.g. Internet Archive returns a 404 page).
/// </summary>
/// <param name="url"></param>
/// <returns></returns>
private bool TrySetAlbumArtUrl(string url)
{
if (url == null)
{
SetAlbumArtUrl(null);
return true;
}
Console.WriteLine("Validating album art URL {0}", url ?? "(none)");
// check if the URL is valid
try
{
var request = new HttpClient();
request.Timeout = TimeSpan.FromSeconds(5);
Task<HttpResponseMessage> response = request.GetAsync(url);
try
{
response.Wait();
}
catch (AggregateException) // TaskCanceledException
{
// Request timed out
return false;
}
if (response.Result.StatusCode == HttpStatusCode.OK)
{
SetAlbumArtUrl(url);
return true;
}
}
catch (WebException)
{
// URL is invalid
return false;
}
return false;
}
private void SetAlbumArtUrl(string? url)
{
if (url != albumArtUrl)
{
Console.WriteLine("Setting album art URL to {0}", url ?? "(none)");
albumArtUrl = url ?? "";
}
}
private ISearchResult<IRelease>? FindMusicBrainzRelease(string release)
{
Console.WriteLine("Searching for release {0} on MusicBrainz", release);