| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635 | #include "playlist.h"#include <shlwapi.h>#include "main.h"#include "api__ml_plg.h"#include "../nu/MediaLibraryInterface.h"#include "impl_playlist.h"//#import	"../gracenote/CDDBControlWinamp.dll" no_namespace, named_guids, raw_interfaces_only#include "../gracenote/cddbcontrolwinamp.tlh"#include "../winamp/ipc_pe.h"#include "resource.h"#include <strsafe.h>//extern Playlist currentPlaylist;ICddbPlaylist25Mgr *playlistMgr;ICddbMLDBManager *mldbMgr;Playlist currentPlaylist;Playlist seedPlaylist;class PlaylistEventHandler : public DPlaylist2Events{	STDMETHODIMP STDMETHODCALLTYPE QueryInterface(REFIID riid, PVOID *ppvObject)	{		if (!ppvObject)			return E_POINTER;		else if (IsEqualIID(riid, __uuidof(DPlaylist2Events)))			*ppvObject = (DPlaylist2Events *)this;		else if (IsEqualIID(riid, IID_IDispatch))			*ppvObject = (IDispatch *)this;		else if (IsEqualIID(riid, IID_IUnknown))			*ppvObject = this;		else		{			*ppvObject = NULL;			return E_NOINTERFACE;		}		AddRef();		return S_OK;	}	ULONG STDMETHODCALLTYPE AddRef(void)	{		return 1;	}	ULONG STDMETHODCALLTYPE Release(void)	{		return 0;	}	HRESULT STDMETHODCALLTYPE Invoke(DISPID dispid, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, EXCEPINFO FAR * pexecinfo, unsigned int FAR *puArgErr)	{		switch (dispid)		{		case 1:			break;		case 2:			break;		case 3:			break;		case 4:			break;		case 5:			break;		}		return DISP_E_MEMBERNOTFOUND;	}	HRESULT STDMETHODCALLTYPE GetIDsOfNames(REFIID riid, OLECHAR FAR* FAR* rgszNames, unsigned int cNames, LCID lcid, DISPID FAR* rgdispid)	{		*rgdispid = DISPID_UNKNOWN;		return DISP_E_UNKNOWNNAME;	}	HRESULT STDMETHODCALLTYPE GetTypeInfo(unsigned int itinfo, LCID lcid, ITypeInfo FAR* FAR* pptinfo)	{		return E_NOTIMPL;	}	HRESULT STDMETHODCALLTYPE GetTypeInfoCount(unsigned int FAR * pctinfo)	{		return E_NOTIMPL;	}};static IConnectionPoint *GetConnectionPoint(IUnknown *punk, REFIID riid){	if (!punk)		return 0;	IConnectionPointContainer *pcpc;	IConnectionPoint *pcp = 0;	HRESULT hr = punk->QueryInterface(IID_IConnectionPointContainer, (void **) & pcpc);	if (SUCCEEDED(hr))	{		pcpc->FindConnectionPoint(riid, &pcp);		pcpc->Release();	}	return pcp;}static PlaylistEventHandler events;static DWORD m_dwCookie = 0;//static DWORD m_dwCookie_MldbMgr = 0;bool SetupPlaylistSDK(){	if (!playlistMgr)	{		//playlistMgr = AGAVE_API_GRACENOTE->GetPlaylistManager();		//AGAVE_API_GRACENOTE->GetPlaylistManagerWithMLDBManager(&playlistMgr, &mldbMgr);		AGAVE_API_GRACENOTE->GetPlaylistManager(&playlistMgr, &mldbMgr);		IConnectionPoint *icp = GetConnectionPoint(playlistMgr, DIID_DPlaylist2Events);		if (icp)		{			icp->Advise(static_cast<IDispatch *>(&events), &m_dwCookie);			icp->Release();		}	}	return !!playlistMgr;}void ShutdownPlaylistSDK(){	if (playlistMgr)	{		if (mldbMgr)		{			mldbMgr->Detach(playlistMgr);	// Detach the mldb manager from the playlist manager if it is not null		}		IConnectionPoint *icp = GetConnectionPoint(playlistMgr, DIID_DPlaylist2Events);		if (icp)		{			icp->Unadvise(m_dwCookie);			icp->Release();		}		if (mldbMgr)			mldbMgr->Release();		// Release the mldb manager if its not null		playlistMgr->Shutdown();		playlistMgr->Release();	}	mldbMgr=0;	playlistMgr=0;}// Caller must cleanup the BSTRBSTR SetAndCreatePath(/*wchar_t *path_to_create,*/ const wchar_t *node){	wchar_t path_to_create[MAX_PATH] = {0};		BSTR bPath = 0;		PathCombineW(path_to_create, WASABI_API_APP->path_getUserSettingsPath(), L"Plugins");	CreateDirectoryW(path_to_create, 0);	PathAppendW(path_to_create, node);	CreateDirectoryW(path_to_create, 0);	bPath = SysAllocString(path_to_create);	return bPath;	// modified path as return value}// IMPORTANT: Make sure to call this on the gracenote dedicated thread.int RestoreGracenoteMLDB(void){	long restoreFlags = PL_MLDB_RESTORE_BASE | PL_MLDB_RESTORE_INDEX;	//wchar_t backupPath[MAX_PATH] = {0};	BSTR bDataPath = SetAndCreatePath(GRACENOTE_DB_BASE_PATH);	BSTR bBackupPath = SetAndCreatePath(GRACENOTE_DB_BACKUP_PATH);	// Restore the db files.	mldbMgr->RestoreDBFiles(restoreFlags, bDataPath, bBackupPath);	SysFreeString(bDataPath);	SysFreeString(bBackupPath);	return NErr_Success;}// Backs up the gracenote MLDB so that it can be restored on corruption// IMPORTANT: Make sure to call this on the gracenote dedicated thread.int BackupGracenoteMLDB(void){	long backupFlags = PL_MLDB_BACKUP_BASE | PL_MLDB_BACKUP_INDEX;	//wchar_t backupPath[MAX_PATH] = {0};	BSTR bDataPath = SetAndCreatePath(GRACENOTE_DB_BASE_PATH);	BSTR bBackupPath = SetAndCreatePath(GRACENOTE_DB_BACKUP_PATH);	// Backup the db files.	mldbMgr->BackupDBFiles(backupFlags, bDataPath, bBackupPath);	SysFreeString(bDataPath);	SysFreeString(bBackupPath);	return NErr_Success;}/*BOOL DeleteGracenoteFile(char *filename){	BOOL result;	char path[MAX_PATH] = {0};	//PathCombineA(path,mediaLibrary.GetIniDirectory(),"Plugins\\Gracenote");	PathCombineA(path,"C:\\Users\\bigg\\AppData\\Roaming\\Winamp\\","Plugins\\Gracenote");	PathAppendA(path, filename);	result = DeleteFileA(path);	return result;}*/void CheckForResetError(HRESULT error){	if (error != S_OK)	{		MessageBoxW(0, WASABI_API_LNGSTRINGW(IDS_ERROR_RESET), (LPWSTR)plugin.description, MB_OK| MB_ICONERROR);	}}void CheckForShutdownError(HRESULT error){	if (error != S_OK)	{		MessageBoxW(plugin.hwndWinampParent, WASABI_API_LNGSTRINGW(IDS_CANNOT_SHUT_DOWN), (LPWSTR)plugin.description, MB_OK| MB_ICONERROR);	}}// Deprecated: Currently not used, remove at some point/*INT_PTR CALLBACK ResettingProcedure(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam){	switch (msg)	{		case WM_INITDIALOG:			//ShowWindow(hwndDlg,SW_HIDE);			ShowWindow(hwndDlg, SW_SHOW);			return 0;			break;		case WM_QUIT:			EndDialog(hwndDlg,0);			return 0;			break;	}	return 0;}*/// IMPORTANT: Make sure to call this on the gracenote dedicated thread.int DeleteGracenoteMLDB(bool silent){	long deleteFlags = PL_MLDB_DELETE_INDEX | PL_MLDB_DELETE_BASE | PL_MLDB_DELETE_OTHER | PL_MLDB_DELETE_BACKUPS;	//long deleteFlags = PL_MLDB_DELETE_INDEX | PL_MLDB_DELETE_BASE | PL_MLDB_DELETE_OTHER; // | PL_MLDB_DELETE_BACKUPS;	BSTR bDataPath = SetAndCreatePath(GRACENOTE_DB_BASE_PATH);			HRESULT error = 0;	if (playlistMgr)		error = playlistMgr->Shutdown();	if (!silent)		CheckForShutdownError(error);	// Spawn the working window	//HWND hwndResetWorking = WASABI_API_CREATEDIALOG(IDD_NAG, plugin.hwndWinampParent, ResettingProcedure);	if (mldbMgr)		error = mldbMgr->DeleteDBFiles(deleteFlags, bDataPath);	//SendMessage(hwndResetWorking, WM_QUIT, 0, 0);	if (!silent)		CheckForResetError(error);	SysFreeString(bDataPath);	return NErr_Success;		// NOT the HRESULT so that non zero values return as false}int InitializeMLDBManager(void){	// Other initializations for the MLDB manager can go here	///BackupGracenoteMLDB();	return NErr_Success;}static void ConfigureGeneratorPrefs(ICddbPLMoreLikeThisCfg *config){	// ToDo: (BigG) Consider using some of the different algorithms	// GNPL_MORELIKETHIS_ALG_20 (Playlist SDK 2.0) 	// GNPL_MORELIKETHIS_ALG_25 (Playlist SDK 2.5) 	// GNPL_MORELIKETHIS_ALG_DSP_1 (Playlist SDK 2.6) 	// GNPL_MORELIKETHIS_ALG_DSP_25 (Playlist SDK 2.6)	config->put_Algorithm(GNPL_MORELIKETHIS_ALG_DEFAULT);	if(!multipleAlbums) config->put_MaxPerAlbum(1);	if(!multipleArtists) config->put_MaxPerArtist(1);	//config->put_TrackLimit(plLength);	config->put_TrackLimit(0);		// Dont put a limit on gracenote (return all tracks)}//void playPlaylist(Playlist &pl, bool enqueue=false, int startplaybackat=0/*-1 for don't start playback*/, const wchar_t *seedfn=NULL, int useSeed=FALSE)void playPlaylist(Playlist &pl, bool enqueue=false, int startplaybackat=0/*-1 for don't start playback*/, int useSeed=FALSE){	extern winampMediaLibraryPlugin plugin;	const size_t number_of_seeds = seedPlaylist.GetNumItems();	wchar_t seedFilename[MAX_PATH] = {0};	seedFilename[0] = 0;	if(!enqueue)		mediaLibrary.ClearPlaylist();	// Enqueue the seed tracks first	if(useSeed)	{		for (size_t i = 0; i < number_of_seeds; i++)		{			seedPlaylist.GetItem(i, seedFilename, MAX_PATH);			// Get the playlist filename			enqueueFileWithMetaStructW s={seedFilename,NULL,PathFindExtensionW(seedFilename),-1};			SendMessage(plugin.hwndWinampParent, WM_WA_IPC, (WPARAM)&s, IPC_PLAYFILEW);		}	}	size_t listLength = pl.GetNumItems();	for(size_t i=0; i<listLength; i++)	{		wchar_t filename[MAX_PATH] = {0};		pl.GetItem(i,filename,MAX_PATH);		//if(seedfn && !_wcsicmp(seedfn,filename))			// Not really sure this is necessary... just making sure that the same file doesnt get added twice		//	continue;		enqueueFileWithMetaStructW s={filename,NULL,PathFindExtensionW(filename),-1};		SendMessage(plugin.hwndWinampParent, WM_WA_IPC, (WPARAM)&s, IPC_PLAYFILEW);	}	if(!enqueue && startplaybackat != -1)	{ //play item startplaybackat		SendMessage(plugin.hwndWinampParent,WM_WA_IPC,startplaybackat,IPC_SETPLAYLISTPOS);		SendMessage(plugin.hwndWinampParent,WM_COMMAND,40047,0); //stop		SendMessage(plugin.hwndWinampParent,WM_COMMAND,40045,0); //play	}}// Tests wether an item can be added to a playlist and still stay under the current targetbool PlaylistIsFull(Playlist *playlist, /*uint64_t*/ unsigned int currentItemLength, /*uint64_t*/ unsigned int currentItemSize){#define POWER_2_TO_20 1048576	// 1024 * 1024	uint64_t measurement = 0;		// See what type we care about items, size, or length	switch (plLengthType)	{	case PL_ITEMS:				// Check for number of items		{			measurement = currentPlaylist.GetNumItems() + ( (useSeed) ? seedPlaylist.GetNumItems() : 0 );		// Add the data from the seed track if we are using it				if ( (measurement + 1) > plItems )			// See if an extra item will put us over.			return true;		else			return false;		}		break;	case PL_MINUTES:			// Check for minutes used		{		measurement = currentPlaylist.GetPlaylistLengthMilliseconds() + ( (useSeed) ? seedPlaylist.GetPlaylistLengthMilliseconds() : 0 );		if ( (measurement + (currentItemLength) ) > (plMinutes * 60 * 1000) )			return true;		else			return false;		}		break;	case PL_MEGABYTES:			// Check for megabytes used		{		measurement = currentPlaylist.GetPlaylistSizeBytes() + ( (useSeed) ? seedPlaylist.GetPlaylistSizeBytes() : 0 );		if ( (measurement + (uint64_t)currentItemSize) > ((uint64_t)plMegabytes * POWER_2_TO_20) )			return true;		else			return false;		}		break;	}		return true;}bool MatchesQuery(const wchar_t *filename, const wchar_t *user_query){	// Get an item that mathces both the filename and the query	itemRecordW *result = AGAVE_API_MLDB->GetFileIf(filename, user_query);		if (result)	{		AGAVE_API_MLDB->FreeRecord(result);									// Clean up the records list since we are done using it				return true;	}	else	{		AGAVE_API_MLDB->FreeRecord(result);									// Clean up the records list since we are done using it				return false;	}}// Callback for getting a tag for gracenote library itemsstatic wchar_t * TitleTagFuncGracenote(const wchar_t * tag, void * p){ //return 0 if not found, -1 for empty tag	//tagItem * s = (tagItem *)p;	//wchar_t *filename = (wchar_t *)p;	ICddbPL2Result *gracenoteResult = (ICddbPL2Result *)p;	BSTR tag_data;		if (!_wcsicmp(tag, L"artist"))			gracenoteResult->GetArtist(&tag_data)/*wsprintf(buf,L"%s",L"artist")*/;	else if (!_wcsicmp(tag, L"album"))		gracenoteResult->GetAlbum(&tag_data);	else if (!_wcsicmp(tag, L"title"))		gracenoteResult->GetTitle(&tag_data);	else if (!_wcsicmp(tag, L"filename"))	gracenoteResult->GetFilename(&tag_data);	else		return 0;	//else if (!_wcsicmp(tag, L"genre"))			-;	//else if (!_wcsicmp(tag, L"year"))			-;	//else if (!_wcsicmp(tag, L"tracknumber"))	-;	//else if (!_wcsicmp(tag, L"discnumber"))		-;	//else if (!_wcsicmp(tag, L"bitrate"))		-;		//else if (!_wcsicmp(tag, L"albumartist"))	-;	//else if (!_wcsicmp(tag, L"composer"))		-;	//else if (!_wcsicmp(tag, L"publisher"))		-;	return tag_data;}// Callback for getting a tag for media library itemsstatic wchar_t * TitleTagFuncML(const wchar_t * tag, void * p){ //return 0 if not found, -1 for empty tag	itemRecordW *mlResult = (itemRecordW *)p;	if (!mlResult)		return 0;		// Return 0 because we dont have this ml object		wchar_t buf[128] = {0};	wchar_t *tag_data = 0;	if (!_wcsicmp(tag, L"artist"))				tag_data = mlResult->artist;	else if (!_wcsicmp(tag, L"album"))			tag_data = mlResult->album;	else if (!_wcsicmp(tag, L"title"))			tag_data = mlResult->title;	else if (!_wcsicmp(tag, L"filename"))		tag_data = mlResult->filename;	else if (!_wcsicmp(tag, L"genre"))			tag_data = mlResult->genre;	else if (!_wcsicmp(tag, L"year"))			if (mlResult->year > 0) { StringCchPrintfW(buf, 128, L"%04d", mlResult->year); tag_data = buf; }	else if (!_wcsicmp(tag, L"tracknumber") || !_wcsicmp(tag, L"track"))	if (mlResult->track > 0) { StringCchPrintfW(buf, 128, L"%04d", mlResult->track); tag_data = buf; }	else if (!_wcsicmp(tag, L"discnumber"))		if (mlResult->disc > 0) { StringCchPrintfW(buf, 128, L"%d", mlResult->disc); tag_data = buf; }	else if (!_wcsicmp(tag, L"bitrate"))		if (mlResult->bitrate > 0) { StringCchPrintfW(buf, 128, L"%d", mlResult->bitrate); tag_data = buf; }	else if (!_wcsicmp(tag, L"albumartist"))	tag_data = mlResult->albumartist;	else if (!_wcsicmp(tag, L"composer"))		tag_data = mlResult->composer;	else if (!_wcsicmp(tag, L"publisher"))		tag_data = mlResult->publisher;	else if (!_wcsicmp(tag, L"bpm"))			if (mlResult->bpm > 0) { StringCchPrintfW(buf, 128, L"%d", mlResult->bpm); tag_data = buf; }	else if (!_wcsicmp(tag, L"comment"))		tag_data = mlResult->comment;	else if (!_wcsicmp(tag, L"discs"))			if (mlResult->discs > 0) { StringCchPrintfW(buf, 128, L"%d", mlResult->discs); tag_data = buf; }	else if (!_wcsicmp(tag, L"filesize"))		if (mlResult->filesize > 0) { StringCchPrintfW(buf, 128, L"%d", mlResult->filesize); tag_data = buf; }	//else if (!_wcsicmp(tag, L"filetime"))		tag_data = mlResult->filetime;	else if (!_wcsicmp(tag, L"length"))			if (mlResult->length > 0) { StringCchPrintfW(buf, 128, L"%d", mlResult->length); tag_data = buf; }	else if (!_wcsicmp(tag, L"playcount"))		if (mlResult->playcount > 0) { StringCchPrintfW(buf, 128, L"%d", mlResult->playcount); tag_data = buf; }	else if (!_wcsicmp(tag, L"rating"))			if (mlResult->rating > 0) { StringCchPrintfW(buf, 128, L"%d", mlResult->rating); tag_data = buf; }	else		return 0;	return _wcsdup(tag_data);}// Callback to free a tag in gracenote librarystatic void TitleTagFreeFuncGracenote(wchar_t *tag_data, void *p){	if(tag_data)		SysFreeString(tag_data);}// Callback to free a tag in media librarystatic void TitleTagFreeFuncML(wchar_t *tag_data, void *p){	if(tag_data)		free(tag_data);}// Retreive the title formatting for gracenote libraryvoid GetTitleFormattingGracenote(const wchar_t *filename, ICddbPL2Result * gracenoteResult, wchar_t * buf, int len){	waFormatTitleExtended fmt={ filename, 1, NULL, (void *)gracenoteResult, buf, len, TitleTagFuncGracenote, TitleTagFreeFuncGracenote };	SendMessage(plugin.hwndWinampParent, WM_WA_IPC, (WPARAM)&fmt, IPC_FORMAT_TITLE_EXTENDED);}// Retreive the title formatting for media libraryvoid GetTitleFormattingML(const wchar_t *filename, itemRecordW *mlResult, wchar_t * buf, int len){	waFormatTitleExtended fmt={ filename, 1, NULL, (void *)mlResult, buf, len, TitleTagFuncML, TitleTagFreeFuncML };	SendMessage(plugin.hwndWinampParent, WM_WA_IPC, (WPARAM)&fmt, IPC_FORMAT_TITLE_EXTENDED);}static int MoreLikeTheseSongsFunc(HANDLE handle, void *user_data, intptr_t id){		Playlist *pl = (Playlist *)user_data;	const int number_of_files = (int)pl->GetNumItems();	isGenerating = true;	//Sleep(501);						// Wait for the update timer to finish its cycles, This is EVIL, keep it removed...	SetMarqueeProgress(true);			// Turn the marquee off because we are actually generating the tracks	SetDlgItemText(hwndDlgCurrent, IDC_STATIC_PROGRESS_STATE, WASABI_API_LNGSTRINGW(IDS_GENERATING));	//EnableWindow (GetDlgItem(hwndDlgCurrent, IDC_BUTTON_REGENERATE), FALSE );	SetButtonsEnabledState(false);		// Disable the buttons once we start generating here	if (SetupPlaylistSDK())	{		HRESULT hr;		ICddbPLMoreLikeThisCfgPtr cfg;		cfg.CreateInstance(CLSID_CddbPLMoreLikeThisCfg);		ConfigureGeneratorPrefs(cfg);		ICddbPL2ResultListPtr results;		wchar_t plFilename[MAX_PATH] = {0};		if (number_of_files == 1)			// Call the regular morelikethis function if there is only the standard seed track		{			pl->GetItem(0, plFilename, MAX_PATH);			BSTR i_dunno = SysAllocString(plFilename);			hr=playlistMgr->MoreLikeThisSong(i_dunno, cfg, &results);			SysFreeString(i_dunno);		}		else if (number_of_files > 1)			// We have more than 1 seed track		{			// Create the variant of an array of filenames for MoreLikeTheseSongs			VARIANT fileList;			VariantInit((VARIANTARG *)&fileList);			SAFEARRAY *psa = SafeArrayCreateVector (VT_BSTR, 0, number_of_files);			BSTR *data;			SafeArrayAccessData(psa, (void **)&data);			for (size_t i=0;i!=number_of_files;i++)			{				pl->GetItem(i, plFilename, MAX_PATH);				data[i] = SysAllocString(plFilename);			}			SafeArrayUnaccessData(psa);			V_VT(&fileList) = VT_ARRAY|VT_BSTR;			V_ARRAY(&fileList) = psa;									hr=playlistMgr->MoreLikeTheseSongs(fileList, cfg, &results);		}		else		// We dont have any seed tracks (this should not happen because we shouldnt get this far.		{			return 1;		// Failure		}		long count=-1;		if (results && SUCCEEDED(hr=results->get_Count(&count)) && count)		{			currentPlaylist.Clear();			for (long i=0;i<count;i++)			{				ICddbPL2Result *result;				if (SUCCEEDED(hr=results->GetResult(i+1, &result)))				{					BSTR filename = 0;					BSTR title = 0;										unsigned int length = -1;					unsigned int size = 0;					result->GetFilename(&filename);					result->GetTitle(&title);					result->GetTracklength(&length);	// Gracenote is returning seconds here					result->GetFilesize(&size);			// Gracenote took the size as kilobytes but it is returning it to us as bytes										length *= 1000;						// Multiply length by 1000 to turn it into milliseconds from seconds					// Get the winamp user formatted title.					wchar_t winamp_title[512] = {0};					GetTitleFormattingGracenote(filename, result, winamp_title, 512);										// Only check for the query if the user wants to apply one					if ( useMLQuery == TRUE && MatchesQuery(filename, mlQuery ) == false )					{						SysFreeString(filename);						SysFreeString(title);						result->Release();						continue;					}					// Lets check for the playlist limit to see if we should add this track					if ( !PlaylistIsFull(¤tPlaylist, length, size) )						currentPlaylist.AppendWithInfo(filename, winamp_title, length, size);					// DONT break here if we are full, keep going as we may find something that will fit into the playlist eventually					SysFreeString(filename);					SysFreeString(title);					result->Release();				}			}			/*char cfg[1024 + 32] = {0};			char *dir = (char*)SendMessage(plugin.hwndWinampParent, WM_WA_IPC, 0, IPC_GETINIDIRECTORY);			PathCombineA(cfg, dir, "Plugins\\gen_ml.ini");			int en = GetPrivateProfileIntA("gen_ml_config","enqueuedef",0,cfg);*/			PopulateResults(¤tPlaylist);		}		else /*if (count == 0)*/		{			PopulateResults(0);			// Call populate with an empty playlist			CantPopulateResults();		// Display warning about not being able to generate any tracks		}	}	isGenerating = false;	return 0;}void MoreLikeTheseSongs(Playlist *pl){	// Capture the stats, we dont care if its successful or not, we only care about the try	if (AGAVE_API_STATS)		AGAVE_API_STATS->IncrementStat(api_stats::PLG_COUNT);	// Call the the mor like this fuction on the gracenote reserved thread	WASABI_API_THREADPOOL->RunFunction(plg_thread, MoreLikeTheseSongsFunc, pl, 0, api_threadpool::FLAG_REQUIRE_COM_STA);}
 |