Found the solution here https://hydrogenaud.io/index.php/topic,63308.0.html
If I ever make another component, I will base it on foo_sample. Luckily I only wanted some really simple context menu entry which adds songs to a playlist and makes an entry in the playback queue to transition to that playlist. It's kinda amazing I was able to pull this off just by power of educated guesses alone (especially the bit_array part - I just guess(ed) it's a mask for what items from data to add). Anyone fancy a read?
#include "stdafx.h"
namespace {
// Identifier of our context menu group. Substitute with your own when reusing code.
static const GUID guid_smart_queue_item_group = { 0x239af9eb, 0x826a, 0x4b6d, { 0xb6, 0x2e, 0x81, 0x83, 0x97, 0x5a, 0xdf, 0x3c } };
static contextmenu_group_factory g_mygroup(guid_smart_queue_item_group, contextmenu_groups::root, 0);
static void SmartQueue(metadb_handle_list_cref data);
static bool GetPlaylistHasQueuedItems(size_t playlist);
class SmartQueueMenuItem : public contextmenu_item_simple {
public:
enum {
cmd_smart_queue = 0,
cmd_total
};
GUID get_parent() { return guid_smart_queue_item_group; }
unsigned get_num_items() { return cmd_total; }
void get_item_name(unsigned p_index, pfc::string_base & p_out) {
switch (p_index) {
case cmd_smart_queue: p_out = "Smart-queue selection"; break;
default: uBugCheck(); // should never happen unless somebody called us with invalid parameters - bail
}
}
void context_command(unsigned p_index, metadb_handle_list_cref p_data, const GUID& p_caller) {
switch (p_index) {
case cmd_smart_queue:
SmartQueue(p_data);
break;
default:
uBugCheck();
}
}
GUID get_item_guid(unsigned p_index) {
// These GUIDs identify our context menu items. Substitute with your own GUIDs when reusing code.
static const GUID guid_item1 = { 0xd1456e09, 0x6a99, 0x45e5,{ 0xb8, 0x03, 0xff, 0x82, 0x8b, 0xd3, 0x4b, 0x59 } };
switch (p_index) {
case cmd_smart_queue: return guid_item1;
default: uBugCheck(); // should never happen unless somebody called us with invalid parameters - bail
}
}
bool get_item_description(unsigned p_index, pfc::string_base & p_out) {
switch (p_index) {
case cmd_smart_queue:
p_out = "Add selection to playlist \"Queue\" and queue the first track.";
return true;
default:
uBugCheck(); // should never happen unless somebody called us with invalid parameters - bail
}
}
};
static contextmenu_item_factory_t<SmartQueueMenuItem> g_smart_queue_menu_item_factory;
/// Adds all songs in data to a playlist called "Queue". The first item of data will be
/// queued if no item in playlist "Queue" is queued yet and no playback is currently
/// happening on the "Queue" playlist. If playback is active and the currentl playing
/// song matches the first song in data, the second song in data will be queued instead,
/// if possible.
static void SmartQueue(metadb_handle_list_cref data) {
t_size numItems = data.get_count();
if (numItems == 0)
return;
static_api_ptr_t<playlist_manager_v4> pm;
// Make sure that playlist "Queue" exists and get it
t_size queuePlaylist = pm->find_or_create_playlist("Queue");
pfc::bit_array_var_impl ba;
ba.set(numItems, true);
t_size newFirst = pm->playlist_get_item_count(queuePlaylist);
// Add data to the playlist "Queue"
pm->playlist_add_items(queuePlaylist, data, ba);
t_size newEnd = pm->playlist_get_item_count(queuePlaylist);
static_api_ptr_t<playback_control_v3> pc;
if ((!pc->is_playing() || (pm->get_playing_playlist() != queuePlaylist)) && !GetPlaylistHasQueuedItems(queuePlaylist)) {
// We queue the first item in data if "Queue" playlist contains no queued items
// and playback is either inactive or playing from another playlist.
t_size queueIndex = newFirst;
t_size playingPlaylist;
t_size playingItem;
if (pc->is_playing() && pm->get_playing_item_location(&playingPlaylist, &playingItem)) {
metadb_handle_ptr playingTrack = pm->playlist_get_item_handle(playingPlaylist, playingItem);
metadb_handle_ptr addedTrack = pm->playlist_get_item_handle(queuePlaylist, newFirst);
if (playingTrack == addedTrack) {
// We just added the track which is currently playing to "Queue" playlist,
// so instead of queueing it, queue the next one so it doesn't play twice.
queueIndex++;
}
}
// If queueIndex is out of bounds, let's hope the user queues some more songs
// before the playing one ends.
if (queueIndex < newEnd)
pm->queue_add_item_playlist(queuePlaylist, queueIndex);
}
}
/// Returns true if the given playlist contains at least one queued item, false otherwise.
static bool GetPlaylistHasQueuedItems(size_t playlist) {
static_api_ptr_t<playlist_manager_v4> pm;
pfc::list_t<t_playback_queue_item> queueItems;
pm->queue_get_contents(queueItems);
size_t queueCount = queueItems.get_count();
// O(n) but appears to be the fastest way to do it atm.
for (size_t i = 0; i < queueCount; i++) {
if (playlist == queueItems.get_item(i).m_playlist) {
return true;
}
}
return false;
}
}
And thanks for the help!