playlist.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635
  1. #include "playlist.h"
  2. #include <shlwapi.h>
  3. #include "main.h"
  4. #include "api__ml_plg.h"
  5. #include "../nu/MediaLibraryInterface.h"
  6. #include "impl_playlist.h"
  7. //#import "../gracenote/CDDBControlWinamp.dll" no_namespace, named_guids, raw_interfaces_only
  8. #include "../gracenote/cddbcontrolwinamp.tlh"
  9. #include "../winamp/ipc_pe.h"
  10. #include "resource.h"
  11. #include <strsafe.h>
  12. //extern Playlist currentPlaylist;
  13. ICddbPlaylist25Mgr *playlistMgr;
  14. ICddbMLDBManager *mldbMgr;
  15. Playlist currentPlaylist;
  16. Playlist seedPlaylist;
  17. class PlaylistEventHandler : public DPlaylist2Events
  18. {
  19. STDMETHODIMP STDMETHODCALLTYPE QueryInterface(REFIID riid, PVOID *ppvObject)
  20. {
  21. if (!ppvObject)
  22. return E_POINTER;
  23. else if (IsEqualIID(riid, __uuidof(DPlaylist2Events)))
  24. *ppvObject = (DPlaylist2Events *)this;
  25. else if (IsEqualIID(riid, IID_IDispatch))
  26. *ppvObject = (IDispatch *)this;
  27. else if (IsEqualIID(riid, IID_IUnknown))
  28. *ppvObject = this;
  29. else
  30. {
  31. *ppvObject = NULL;
  32. return E_NOINTERFACE;
  33. }
  34. AddRef();
  35. return S_OK;
  36. }
  37. ULONG STDMETHODCALLTYPE AddRef(void)
  38. {
  39. return 1;
  40. }
  41. ULONG STDMETHODCALLTYPE Release(void)
  42. {
  43. return 0;
  44. }
  45. HRESULT STDMETHODCALLTYPE Invoke(DISPID dispid, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, EXCEPINFO FAR * pexecinfo, unsigned int FAR *puArgErr)
  46. {
  47. switch (dispid)
  48. {
  49. case 1:
  50. break;
  51. case 2:
  52. break;
  53. case 3:
  54. break;
  55. case 4:
  56. break;
  57. case 5:
  58. break;
  59. }
  60. return DISP_E_MEMBERNOTFOUND;
  61. }
  62. HRESULT STDMETHODCALLTYPE GetIDsOfNames(REFIID riid, OLECHAR FAR* FAR* rgszNames, unsigned int cNames, LCID lcid, DISPID FAR* rgdispid)
  63. {
  64. *rgdispid = DISPID_UNKNOWN;
  65. return DISP_E_UNKNOWNNAME;
  66. }
  67. HRESULT STDMETHODCALLTYPE GetTypeInfo(unsigned int itinfo, LCID lcid, ITypeInfo FAR* FAR* pptinfo)
  68. {
  69. return E_NOTIMPL;
  70. }
  71. HRESULT STDMETHODCALLTYPE GetTypeInfoCount(unsigned int FAR * pctinfo)
  72. {
  73. return E_NOTIMPL;
  74. }
  75. };
  76. static IConnectionPoint *GetConnectionPoint(IUnknown *punk, REFIID riid)
  77. {
  78. if (!punk)
  79. return 0;
  80. IConnectionPointContainer *pcpc;
  81. IConnectionPoint *pcp = 0;
  82. HRESULT hr = punk->QueryInterface(IID_IConnectionPointContainer, (void **) & pcpc);
  83. if (SUCCEEDED(hr))
  84. {
  85. pcpc->FindConnectionPoint(riid, &pcp);
  86. pcpc->Release();
  87. }
  88. return pcp;
  89. }
  90. static PlaylistEventHandler events;
  91. static DWORD m_dwCookie = 0;
  92. //static DWORD m_dwCookie_MldbMgr = 0;
  93. bool SetupPlaylistSDK()
  94. {
  95. if (!playlistMgr)
  96. {
  97. //playlistMgr = AGAVE_API_GRACENOTE->GetPlaylistManager();
  98. //AGAVE_API_GRACENOTE->GetPlaylistManagerWithMLDBManager(&playlistMgr, &mldbMgr);
  99. AGAVE_API_GRACENOTE->GetPlaylistManager(&playlistMgr, &mldbMgr);
  100. IConnectionPoint *icp = GetConnectionPoint(playlistMgr, DIID_DPlaylist2Events);
  101. if (icp)
  102. {
  103. icp->Advise(static_cast<IDispatch *>(&events), &m_dwCookie);
  104. icp->Release();
  105. }
  106. }
  107. return !!playlistMgr;
  108. }
  109. void ShutdownPlaylistSDK()
  110. {
  111. if (playlistMgr)
  112. {
  113. if (mldbMgr)
  114. {
  115. mldbMgr->Detach(playlistMgr); // Detach the mldb manager from the playlist manager if it is not null
  116. }
  117. IConnectionPoint *icp = GetConnectionPoint(playlistMgr, DIID_DPlaylist2Events);
  118. if (icp)
  119. {
  120. icp->Unadvise(m_dwCookie);
  121. icp->Release();
  122. }
  123. if (mldbMgr)
  124. mldbMgr->Release(); // Release the mldb manager if its not null
  125. playlistMgr->Shutdown();
  126. playlistMgr->Release();
  127. }
  128. mldbMgr=0;
  129. playlistMgr=0;
  130. }
  131. // Caller must cleanup the BSTR
  132. BSTR SetAndCreatePath(/*wchar_t *path_to_create,*/ const wchar_t *node)
  133. {
  134. wchar_t path_to_create[MAX_PATH] = {0};
  135. BSTR bPath = 0;
  136. PathCombineW(path_to_create, WASABI_API_APP->path_getUserSettingsPath(), L"Plugins");
  137. CreateDirectoryW(path_to_create, 0);
  138. PathAppendW(path_to_create, node);
  139. CreateDirectoryW(path_to_create, 0);
  140. bPath = SysAllocString(path_to_create);
  141. return bPath;
  142. // modified path as return value
  143. }
  144. // IMPORTANT: Make sure to call this on the gracenote dedicated thread.
  145. int RestoreGracenoteMLDB(void)
  146. {
  147. long restoreFlags = PL_MLDB_RESTORE_BASE | PL_MLDB_RESTORE_INDEX;
  148. //wchar_t backupPath[MAX_PATH] = {0};
  149. BSTR bDataPath = SetAndCreatePath(GRACENOTE_DB_BASE_PATH);
  150. BSTR bBackupPath = SetAndCreatePath(GRACENOTE_DB_BACKUP_PATH);
  151. // Restore the db files.
  152. mldbMgr->RestoreDBFiles(restoreFlags, bDataPath, bBackupPath);
  153. SysFreeString(bDataPath);
  154. SysFreeString(bBackupPath);
  155. return NErr_Success;
  156. }
  157. // Backs up the gracenote MLDB so that it can be restored on corruption
  158. // IMPORTANT: Make sure to call this on the gracenote dedicated thread.
  159. int BackupGracenoteMLDB(void)
  160. {
  161. long backupFlags = PL_MLDB_BACKUP_BASE | PL_MLDB_BACKUP_INDEX;
  162. //wchar_t backupPath[MAX_PATH] = {0};
  163. BSTR bDataPath = SetAndCreatePath(GRACENOTE_DB_BASE_PATH);
  164. BSTR bBackupPath = SetAndCreatePath(GRACENOTE_DB_BACKUP_PATH);
  165. // Backup the db files.
  166. mldbMgr->BackupDBFiles(backupFlags, bDataPath, bBackupPath);
  167. SysFreeString(bDataPath);
  168. SysFreeString(bBackupPath);
  169. return NErr_Success;
  170. }
  171. /*BOOL DeleteGracenoteFile(char *filename)
  172. {
  173. BOOL result;
  174. char path[MAX_PATH] = {0};
  175. //PathCombineA(path,mediaLibrary.GetIniDirectory(),"Plugins\\Gracenote");
  176. PathCombineA(path,"C:\\Users\\bigg\\AppData\\Roaming\\Winamp\\","Plugins\\Gracenote");
  177. PathAppendA(path, filename);
  178. result = DeleteFileA(path);
  179. return result;
  180. }*/
  181. void CheckForResetError(HRESULT error)
  182. {
  183. if (error != S_OK)
  184. {
  185. MessageBoxW(0, WASABI_API_LNGSTRINGW(IDS_ERROR_RESET), (LPWSTR)plugin.description, MB_OK| MB_ICONERROR);
  186. }
  187. }
  188. void CheckForShutdownError(HRESULT error)
  189. {
  190. if (error != S_OK)
  191. {
  192. MessageBoxW(plugin.hwndWinampParent, WASABI_API_LNGSTRINGW(IDS_CANNOT_SHUT_DOWN), (LPWSTR)plugin.description, MB_OK| MB_ICONERROR);
  193. }
  194. }
  195. // Deprecated: Currently not used, remove at some point
  196. /*
  197. INT_PTR CALLBACK ResettingProcedure(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
  198. {
  199. switch (msg)
  200. {
  201. case WM_INITDIALOG:
  202. //ShowWindow(hwndDlg,SW_HIDE);
  203. ShowWindow(hwndDlg, SW_SHOW);
  204. return 0;
  205. break;
  206. case WM_QUIT:
  207. EndDialog(hwndDlg,0);
  208. return 0;
  209. break;
  210. }
  211. return 0;
  212. }*/
  213. // IMPORTANT: Make sure to call this on the gracenote dedicated thread.
  214. int DeleteGracenoteMLDB(bool silent)
  215. {
  216. long deleteFlags = PL_MLDB_DELETE_INDEX | PL_MLDB_DELETE_BASE | PL_MLDB_DELETE_OTHER | PL_MLDB_DELETE_BACKUPS;
  217. //long deleteFlags = PL_MLDB_DELETE_INDEX | PL_MLDB_DELETE_BASE | PL_MLDB_DELETE_OTHER; // | PL_MLDB_DELETE_BACKUPS;
  218. BSTR bDataPath = SetAndCreatePath(GRACENOTE_DB_BASE_PATH);
  219. HRESULT error = 0;
  220. if (playlistMgr)
  221. error = playlistMgr->Shutdown();
  222. if (!silent)
  223. CheckForShutdownError(error);
  224. // Spawn the working window
  225. //HWND hwndResetWorking = WASABI_API_CREATEDIALOG(IDD_NAG, plugin.hwndWinampParent, ResettingProcedure);
  226. if (mldbMgr)
  227. error = mldbMgr->DeleteDBFiles(deleteFlags, bDataPath);
  228. //SendMessage(hwndResetWorking, WM_QUIT, 0, 0);
  229. if (!silent)
  230. CheckForResetError(error);
  231. SysFreeString(bDataPath);
  232. return NErr_Success; // NOT the HRESULT so that non zero values return as false
  233. }
  234. int InitializeMLDBManager(void)
  235. {
  236. // Other initializations for the MLDB manager can go here
  237. ///BackupGracenoteMLDB();
  238. return NErr_Success;
  239. }
  240. static void ConfigureGeneratorPrefs(ICddbPLMoreLikeThisCfg *config)
  241. {
  242. // ToDo: (BigG) Consider using some of the different algorithms
  243. // GNPL_MORELIKETHIS_ALG_20 (Playlist SDK 2.0)
  244. // GNPL_MORELIKETHIS_ALG_25 (Playlist SDK 2.5)
  245. // GNPL_MORELIKETHIS_ALG_DSP_1 (Playlist SDK 2.6)
  246. // GNPL_MORELIKETHIS_ALG_DSP_25 (Playlist SDK 2.6)
  247. config->put_Algorithm(GNPL_MORELIKETHIS_ALG_DEFAULT);
  248. if(!multipleAlbums) config->put_MaxPerAlbum(1);
  249. if(!multipleArtists) config->put_MaxPerArtist(1);
  250. //config->put_TrackLimit(plLength);
  251. config->put_TrackLimit(0); // Dont put a limit on gracenote (return all tracks)
  252. }
  253. //void playPlaylist(Playlist &pl, bool enqueue=false, int startplaybackat=0/*-1 for don't start playback*/, const wchar_t *seedfn=NULL, int useSeed=FALSE)
  254. void playPlaylist(Playlist &pl, bool enqueue=false, int startplaybackat=0/*-1 for don't start playback*/, int useSeed=FALSE)
  255. {
  256. extern winampMediaLibraryPlugin plugin;
  257. const size_t number_of_seeds = seedPlaylist.GetNumItems();
  258. wchar_t seedFilename[MAX_PATH] = {0};
  259. seedFilename[0] = 0;
  260. if(!enqueue)
  261. mediaLibrary.ClearPlaylist();
  262. // Enqueue the seed tracks first
  263. if(useSeed)
  264. {
  265. for (size_t i = 0; i < number_of_seeds; i++)
  266. {
  267. seedPlaylist.GetItem(i, seedFilename, MAX_PATH); // Get the playlist filename
  268. enqueueFileWithMetaStructW s={seedFilename,NULL,PathFindExtensionW(seedFilename),-1};
  269. SendMessage(plugin.hwndWinampParent, WM_WA_IPC, (WPARAM)&s, IPC_PLAYFILEW);
  270. }
  271. }
  272. size_t listLength = pl.GetNumItems();
  273. for(size_t i=0; i<listLength; i++)
  274. {
  275. wchar_t filename[MAX_PATH] = {0};
  276. pl.GetItem(i,filename,MAX_PATH);
  277. //if(seedfn && !_wcsicmp(seedfn,filename)) // Not really sure this is necessary... just making sure that the same file doesnt get added twice
  278. // continue;
  279. enqueueFileWithMetaStructW s={filename,NULL,PathFindExtensionW(filename),-1};
  280. SendMessage(plugin.hwndWinampParent, WM_WA_IPC, (WPARAM)&s, IPC_PLAYFILEW);
  281. }
  282. if(!enqueue && startplaybackat != -1)
  283. { //play item startplaybackat
  284. SendMessage(plugin.hwndWinampParent,WM_WA_IPC,startplaybackat,IPC_SETPLAYLISTPOS);
  285. SendMessage(plugin.hwndWinampParent,WM_COMMAND,40047,0); //stop
  286. SendMessage(plugin.hwndWinampParent,WM_COMMAND,40045,0); //play
  287. }
  288. }
  289. // Tests wether an item can be added to a playlist and still stay under the current target
  290. bool PlaylistIsFull(Playlist *playlist, /*uint64_t*/ unsigned int currentItemLength, /*uint64_t*/ unsigned int currentItemSize)
  291. {
  292. #define POWER_2_TO_20 1048576 // 1024 * 1024
  293. uint64_t measurement = 0;
  294. // See what type we care about items, size, or length
  295. switch (plLengthType)
  296. {
  297. case PL_ITEMS: // Check for number of items
  298. {
  299. measurement = currentPlaylist.GetNumItems() + ( (useSeed) ? seedPlaylist.GetNumItems() : 0 ); // Add the data from the seed track if we are using it
  300. if ( (measurement + 1) > plItems ) // See if an extra item will put us over.
  301. return true;
  302. else
  303. return false;
  304. }
  305. break;
  306. case PL_MINUTES: // Check for minutes used
  307. {
  308. measurement = currentPlaylist.GetPlaylistLengthMilliseconds() + ( (useSeed) ? seedPlaylist.GetPlaylistLengthMilliseconds() : 0 );
  309. if ( (measurement + (currentItemLength) ) > (plMinutes * 60 * 1000) )
  310. return true;
  311. else
  312. return false;
  313. }
  314. break;
  315. case PL_MEGABYTES: // Check for megabytes used
  316. {
  317. measurement = currentPlaylist.GetPlaylistSizeBytes() + ( (useSeed) ? seedPlaylist.GetPlaylistSizeBytes() : 0 );
  318. if ( (measurement + (uint64_t)currentItemSize) > ((uint64_t)plMegabytes * POWER_2_TO_20) )
  319. return true;
  320. else
  321. return false;
  322. }
  323. break;
  324. }
  325. return true;
  326. }
  327. bool MatchesQuery(const wchar_t *filename, const wchar_t *user_query)
  328. {
  329. // Get an item that mathces both the filename and the query
  330. itemRecordW *result = AGAVE_API_MLDB->GetFileIf(filename, user_query);
  331. if (result)
  332. {
  333. AGAVE_API_MLDB->FreeRecord(result); // Clean up the records list since we are done using it
  334. return true;
  335. }
  336. else
  337. {
  338. AGAVE_API_MLDB->FreeRecord(result); // Clean up the records list since we are done using it
  339. return false;
  340. }
  341. }
  342. // Callback for getting a tag for gracenote library items
  343. static wchar_t * TitleTagFuncGracenote(const wchar_t * tag, void * p)
  344. { //return 0 if not found, -1 for empty tag
  345. //tagItem * s = (tagItem *)p;
  346. //wchar_t *filename = (wchar_t *)p;
  347. ICddbPL2Result *gracenoteResult = (ICddbPL2Result *)p;
  348. BSTR tag_data;
  349. if (!_wcsicmp(tag, L"artist")) gracenoteResult->GetArtist(&tag_data)/*wsprintf(buf,L"%s",L"artist")*/;
  350. else if (!_wcsicmp(tag, L"album")) gracenoteResult->GetAlbum(&tag_data);
  351. else if (!_wcsicmp(tag, L"title")) gracenoteResult->GetTitle(&tag_data);
  352. else if (!_wcsicmp(tag, L"filename")) gracenoteResult->GetFilename(&tag_data);
  353. else
  354. return 0;
  355. //else if (!_wcsicmp(tag, L"genre")) -;
  356. //else if (!_wcsicmp(tag, L"year")) -;
  357. //else if (!_wcsicmp(tag, L"tracknumber")) -;
  358. //else if (!_wcsicmp(tag, L"discnumber")) -;
  359. //else if (!_wcsicmp(tag, L"bitrate")) -;
  360. //else if (!_wcsicmp(tag, L"albumartist")) -;
  361. //else if (!_wcsicmp(tag, L"composer")) -;
  362. //else if (!_wcsicmp(tag, L"publisher")) -;
  363. return tag_data;
  364. }
  365. // Callback for getting a tag for media library items
  366. static wchar_t * TitleTagFuncML(const wchar_t * tag, void * p)
  367. { //return 0 if not found, -1 for empty tag
  368. itemRecordW *mlResult = (itemRecordW *)p;
  369. if (!mlResult)
  370. return 0; // Return 0 because we dont have this ml object
  371. wchar_t buf[128] = {0};
  372. wchar_t *tag_data = 0;
  373. if (!_wcsicmp(tag, L"artist")) tag_data = mlResult->artist;
  374. else if (!_wcsicmp(tag, L"album")) tag_data = mlResult->album;
  375. else if (!_wcsicmp(tag, L"title")) tag_data = mlResult->title;
  376. else if (!_wcsicmp(tag, L"filename")) tag_data = mlResult->filename;
  377. else if (!_wcsicmp(tag, L"genre")) tag_data = mlResult->genre;
  378. else if (!_wcsicmp(tag, L"year")) if (mlResult->year > 0) { StringCchPrintfW(buf, 128, L"%04d", mlResult->year); tag_data = buf; }
  379. else if (!_wcsicmp(tag, L"tracknumber") || !_wcsicmp(tag, L"track")) if (mlResult->track > 0) { StringCchPrintfW(buf, 128, L"%04d", mlResult->track); tag_data = buf; }
  380. else if (!_wcsicmp(tag, L"discnumber")) if (mlResult->disc > 0) { StringCchPrintfW(buf, 128, L"%d", mlResult->disc); tag_data = buf; }
  381. else if (!_wcsicmp(tag, L"bitrate")) if (mlResult->bitrate > 0) { StringCchPrintfW(buf, 128, L"%d", mlResult->bitrate); tag_data = buf; }
  382. else if (!_wcsicmp(tag, L"albumartist")) tag_data = mlResult->albumartist;
  383. else if (!_wcsicmp(tag, L"composer")) tag_data = mlResult->composer;
  384. else if (!_wcsicmp(tag, L"publisher")) tag_data = mlResult->publisher;
  385. else if (!_wcsicmp(tag, L"bpm")) if (mlResult->bpm > 0) { StringCchPrintfW(buf, 128, L"%d", mlResult->bpm); tag_data = buf; }
  386. else if (!_wcsicmp(tag, L"comment")) tag_data = mlResult->comment;
  387. else if (!_wcsicmp(tag, L"discs")) if (mlResult->discs > 0) { StringCchPrintfW(buf, 128, L"%d", mlResult->discs); tag_data = buf; }
  388. else if (!_wcsicmp(tag, L"filesize")) if (mlResult->filesize > 0) { StringCchPrintfW(buf, 128, L"%d", mlResult->filesize); tag_data = buf; }
  389. //else if (!_wcsicmp(tag, L"filetime")) tag_data = mlResult->filetime;
  390. else if (!_wcsicmp(tag, L"length")) if (mlResult->length > 0) { StringCchPrintfW(buf, 128, L"%d", mlResult->length); tag_data = buf; }
  391. else if (!_wcsicmp(tag, L"playcount")) if (mlResult->playcount > 0) { StringCchPrintfW(buf, 128, L"%d", mlResult->playcount); tag_data = buf; }
  392. else if (!_wcsicmp(tag, L"rating")) if (mlResult->rating > 0) { StringCchPrintfW(buf, 128, L"%d", mlResult->rating); tag_data = buf; }
  393. else
  394. return 0;
  395. return _wcsdup(tag_data);
  396. }
  397. // Callback to free a tag in gracenote library
  398. static void TitleTagFreeFuncGracenote(wchar_t *tag_data, void *p)
  399. {
  400. if(tag_data)
  401. SysFreeString(tag_data);
  402. }
  403. // Callback to free a tag in media library
  404. static void TitleTagFreeFuncML(wchar_t *tag_data, void *p)
  405. {
  406. if(tag_data)
  407. free(tag_data);
  408. }
  409. // Retreive the title formatting for gracenote library
  410. void GetTitleFormattingGracenote(const wchar_t *filename, ICddbPL2Result * gracenoteResult, wchar_t * buf, int len)
  411. {
  412. waFormatTitleExtended fmt={ filename, 1, NULL, (void *)gracenoteResult, buf, len, TitleTagFuncGracenote, TitleTagFreeFuncGracenote };
  413. SendMessage(plugin.hwndWinampParent, WM_WA_IPC, (WPARAM)&fmt, IPC_FORMAT_TITLE_EXTENDED);
  414. }
  415. // Retreive the title formatting for media library
  416. void GetTitleFormattingML(const wchar_t *filename, itemRecordW *mlResult, wchar_t * buf, int len)
  417. {
  418. waFormatTitleExtended fmt={ filename, 1, NULL, (void *)mlResult, buf, len, TitleTagFuncML, TitleTagFreeFuncML };
  419. SendMessage(plugin.hwndWinampParent, WM_WA_IPC, (WPARAM)&fmt, IPC_FORMAT_TITLE_EXTENDED);
  420. }
  421. static int MoreLikeTheseSongsFunc(HANDLE handle, void *user_data, intptr_t id)
  422. {
  423. Playlist *pl = (Playlist *)user_data;
  424. const int number_of_files = (int)pl->GetNumItems();
  425. isGenerating = true;
  426. //Sleep(501); // Wait for the update timer to finish its cycles, This is EVIL, keep it removed...
  427. SetMarqueeProgress(true); // Turn the marquee off because we are actually generating the tracks
  428. SetDlgItemText(hwndDlgCurrent, IDC_STATIC_PROGRESS_STATE, WASABI_API_LNGSTRINGW(IDS_GENERATING));
  429. //EnableWindow (GetDlgItem(hwndDlgCurrent, IDC_BUTTON_REGENERATE), FALSE );
  430. SetButtonsEnabledState(false); // Disable the buttons once we start generating here
  431. if (SetupPlaylistSDK())
  432. {
  433. HRESULT hr;
  434. ICddbPLMoreLikeThisCfgPtr cfg;
  435. cfg.CreateInstance(CLSID_CddbPLMoreLikeThisCfg);
  436. ConfigureGeneratorPrefs(cfg);
  437. ICddbPL2ResultListPtr results;
  438. wchar_t plFilename[MAX_PATH] = {0};
  439. if (number_of_files == 1) // Call the regular morelikethis function if there is only the standard seed track
  440. {
  441. pl->GetItem(0, plFilename, MAX_PATH);
  442. BSTR i_dunno = SysAllocString(plFilename);
  443. hr=playlistMgr->MoreLikeThisSong(i_dunno, cfg, &results);
  444. SysFreeString(i_dunno);
  445. }
  446. else if (number_of_files > 1) // We have more than 1 seed track
  447. {
  448. // Create the variant of an array of filenames for MoreLikeTheseSongs
  449. VARIANT fileList;
  450. VariantInit((VARIANTARG *)&fileList);
  451. SAFEARRAY *psa = SafeArrayCreateVector (VT_BSTR, 0, number_of_files);
  452. BSTR *data;
  453. SafeArrayAccessData(psa, (void **)&data);
  454. for (size_t i=0;i!=number_of_files;i++)
  455. {
  456. pl->GetItem(i, plFilename, MAX_PATH);
  457. data[i] = SysAllocString(plFilename);
  458. }
  459. SafeArrayUnaccessData(psa);
  460. V_VT(&fileList) = VT_ARRAY|VT_BSTR;
  461. V_ARRAY(&fileList) = psa;
  462. hr=playlistMgr->MoreLikeTheseSongs(fileList, cfg, &results);
  463. }
  464. else // We dont have any seed tracks (this should not happen because we shouldnt get this far.
  465. {
  466. return 1; // Failure
  467. }
  468. long count=-1;
  469. if (results && SUCCEEDED(hr=results->get_Count(&count)) && count)
  470. {
  471. currentPlaylist.Clear();
  472. for (long i=0;i<count;i++)
  473. {
  474. ICddbPL2Result *result;
  475. if (SUCCEEDED(hr=results->GetResult(i+1, &result)))
  476. {
  477. BSTR filename = 0;
  478. BSTR title = 0;
  479. unsigned int length = -1;
  480. unsigned int size = 0;
  481. result->GetFilename(&filename);
  482. result->GetTitle(&title);
  483. result->GetTracklength(&length); // Gracenote is returning seconds here
  484. result->GetFilesize(&size); // Gracenote took the size as kilobytes but it is returning it to us as bytes
  485. length *= 1000; // Multiply length by 1000 to turn it into milliseconds from seconds
  486. // Get the winamp user formatted title.
  487. wchar_t winamp_title[512] = {0};
  488. GetTitleFormattingGracenote(filename, result, winamp_title, 512);
  489. // Only check for the query if the user wants to apply one
  490. if ( useMLQuery == TRUE && MatchesQuery(filename, mlQuery ) == false )
  491. {
  492. SysFreeString(filename);
  493. SysFreeString(title);
  494. result->Release();
  495. continue;
  496. }
  497. // Lets check for the playlist limit to see if we should add this track
  498. if ( !PlaylistIsFull(&currentPlaylist, length, size) )
  499. currentPlaylist.AppendWithInfo(filename, winamp_title, length, size);
  500. // DONT break here if we are full, keep going as we may find something that will fit into the playlist eventually
  501. SysFreeString(filename);
  502. SysFreeString(title);
  503. result->Release();
  504. }
  505. }
  506. /*char cfg[1024 + 32] = {0};
  507. char *dir = (char*)SendMessage(plugin.hwndWinampParent, WM_WA_IPC, 0, IPC_GETINIDIRECTORY);
  508. PathCombineA(cfg, dir, "Plugins\\gen_ml.ini");
  509. int en = GetPrivateProfileIntA("gen_ml_config","enqueuedef",0,cfg);*/
  510. PopulateResults(&currentPlaylist);
  511. }
  512. else /*if (count == 0)*/
  513. {
  514. PopulateResults(0); // Call populate with an empty playlist
  515. CantPopulateResults(); // Display warning about not being able to generate any tracks
  516. }
  517. }
  518. isGenerating = false;
  519. return 0;
  520. }
  521. void MoreLikeTheseSongs(Playlist *pl)
  522. {
  523. // Capture the stats, we dont care if its successful or not, we only care about the try
  524. if (AGAVE_API_STATS)
  525. AGAVE_API_STATS->IncrementStat(api_stats::PLG_COUNT);
  526. // Call the the mor like this fuction on the gracenote reserved thread
  527. WASABI_API_THREADPOOL->RunFunction(plg_thread, MoreLikeTheseSongsFunc, pl, 0, api_threadpool::FLAG_REQUIRE_COM_STA);
  528. }