This shouldn't be too complicated but I'm busy with other things. But I will supply some code that will probably come in handy for anyone that wants to take it on.
Use it at your own risk. It works for me but I'm not going to pretend I know what I'm doing.... there could be a better way.
This code iterates through all the songs in the musicbee library and creates a list (albums_) of all the albums. it then sorts the list based on the sortmask.
namespace MusicBeePlugin
{
//album structure
public struct Album
{
public string artist;
public string name;
public string cover;
public string sortMask;
public string albumId;
public bool isLoaded;
public Album(string artist, string name, string cover, string sortMask, string albumId, bool isLoaded)
{
this.artist = artist;
this.name = name;
this.cover = cover;
this.sortMask = sortMask;
this.albumId = albumId;
this.isLoaded = isLoaded;
}
}
//-------------------
// Class to handle loading albums
//-------------------
public class AlbumsLoader
{
// album list
public static List<Album> albums_ = new();
public static int GetAlbumsCount()
{
return albums_.Count;
}
public static string GetAlbumCover(int index)
{
return albums_[index].cover;
}
public static string GetAlbumName(int index)
{
return albums_[index].name;
}
public static string GetAlbumArtist(int index)
{
return albums_[index].artist;
}
public static string GetAlbumId(int index)
{
return albums_[index].albumId;
}
// ------------------------------------
// Query Musicbee for all unique albums
// ------------------------------------
public static void LoadAlbums()
{
int index;
// get a list of songs from musicbee
Plugin.MbApiInterface.Library_QueryFilesEx("domain=Library", out string[]? files);
//only load what is in the files element.
//Plugin.MbApiInterface.Library_QueryFilesEx("domain=DisplayedFiles", out files);
//find unique albums and add them to the albums_ list.
if (files.Length != 0)
{
foreach (string file in files)
{
string currentAlbum = Plugin.MbApiInterface.Library_GetFileTag(file, Plugin.MetaDataType.Album);
string currentArtist = Plugin.MbApiInterface.Library_GetFileTag(file, Plugin.MetaDataType.AlbumArtist);
string uniqueAlbumId = Plugin.MbApiInterface.Library_GetFileTag(file, Plugin.MetaDataType.AlbumUniqueId);
string sortMask = Plugin.MbApiInterface.Library_GetFileTag(file, Plugin.MetaDataType.SortAlbumArtist);
string sortAlbum = Plugin.MbApiInterface.Library_GetFileTag(file, Plugin.MetaDataType.SortAlbum);
// if sortalbum exists, append the first 3 letters to the sort mask to make sorting better for
//artists with multiple albums.
if (!string.IsNullOrEmpty(sortAlbum) && sortAlbum.Length > 2)
{
sortMask += sortAlbum.Substring(0, 3);
}
//check if album already exists
index = albums_.FindIndex(x => x.albumId == uniqueAlbumId); //currentAlbum
if(index == -1) {
Album a = new Album(currentArtist,currentAlbum,file,sortMask,uniqueAlbumId, false);
albums_.Add(a);
}
}
}
albums_.Sort((x, y) => x.sortMask.CompareTo(y.sortMask));
files = null;
}
}
}
Once you have the albums_ list populated, you just need to iterate through it to get all the covers out and mash them together to make your snapshot.
Something like
foreach (Album a in albums_)
{
Plugin.MbApiInterface.Library_GetArtworkEx(a.cover, 0, true, out Plugin.PictureLocations pictureLocation, out string pictureUrl, out byte[]? imageData);
if (imageData != null)
{
using (var ms = new MemoryStream(imageData))
{
bmp = new Bitmap(ms);
}
// insert code here to format the bmp and append it to your snapshot image
// you can use a.artist and a.name to get the artist and album name
bmp = null;
} else {
// insert code here to handle albums that don't have artwork
}
imageData = null;
}
I don't know if it's necessary to set bmp and imageData to null afterwards but it seemed to work better for memory management.
You will need code to format the BMP to the right size, set number of albums per row etc and append them to a snapshot image then save it as a file.
The album name and artist will also need to be converted from a string to an image. Character encoding is a massive PITA.