IDScanner.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698
  1. #include "IDScanner.h"
  2. #include "main.h"
  3. #include "../winamp/wa_ipc.h"
  4. #include "api__ml_plg.h"
  5. #include "playlist.h"
  6. #include <assert.h>
  7. #include <atlbase.h>
  8. #include <strsafe.h> // include this last
  9. //#define DEBUG_CALLBACKS
  10. IDScanner::IDScanner() : systemCallbacks(0)
  11. {
  12. musicID=0;
  13. killswitch=0;
  14. filesComplete=0;
  15. filesTotal=0;
  16. state=STATE_IDLE;
  17. m_dwCookie=0;
  18. syscb_registered=false;
  19. // Create the stack that will hold our batched up files for step 4 processing
  20. //process_items;
  21. }
  22. IDScanner::~IDScanner()
  23. {
  24. // ToDo: Make sure we clean up the processing stack here if we need to do that
  25. //Shutdown();
  26. }
  27. void IDScanner::Shutdown()
  28. {
  29. if (musicID)
  30. {
  31. IConnectionPoint *icp = GetConnectionPoint(musicID, DIID__ICDDBMusicIDManagerEvents);
  32. if (icp)
  33. {
  34. icp->Unadvise(m_dwCookie);
  35. icp->Release();
  36. }
  37. musicID->Shutdown();
  38. musicID->Release();
  39. }
  40. musicID=0;
  41. // Deregister the system callbacks
  42. WASABI_API_SYSCB->syscb_deregisterCallback(this);
  43. }
  44. static HRESULT FillTag(ICddbFileInfo *info, BSTR filename)
  45. {
  46. ICddbID3TagPtr infotag = NULL;
  47. infotag.CreateInstance(CLSID_CddbID3Tag);
  48. ICddbFileTag2_5Ptr tag2_5 = NULL;
  49. infotag->QueryInterface(&tag2_5);
  50. itemRecordW *record = AGAVE_API_MLDB->GetFile(filename);
  51. if (record && infotag && tag2_5)
  52. {
  53. wchar_t itemp[64] = {0};
  54. if (record->artist)
  55. infotag->put_LeadArtist(record->artist);
  56. if (record->album)
  57. infotag->put_Album(record->album);
  58. if (record->title)
  59. infotag->put_Title(record->title);
  60. if (record->genre)
  61. infotag->put_Genre(record->genre);
  62. if (record->track > 0)
  63. infotag->put_TrackPosition(_itow(record->track, itemp, 10));
  64. // TODO: if (record->tracks > 0)
  65. if (record->year > 0)
  66. infotag->put_Year(_itow(record->year, itemp, 10));
  67. if (record->publisher)
  68. infotag->put_Label(record->publisher);
  69. /*
  70. if (GetFileInfo(filename, L"ISRC", meta, 512) && meta[0])
  71. infotag->put_ISRC(meta);
  72. */
  73. if (record->disc > 0)
  74. infotag->put_PartOfSet(_itow(record->disc, itemp, 10));
  75. if (record->albumartist)
  76. tag2_5->put_DiscArtist(record->albumartist);
  77. if (record->composer)
  78. tag2_5->put_Composer(record->composer);
  79. if (record->length > 0)
  80. tag2_5->put_LengthMS(_itow(record->length*1000, itemp, 10));
  81. if (record->bpm > 0)
  82. infotag->put_BeatsPerMinute(_itow(record->bpm, itemp, 10));
  83. /*
  84. if (GetFileInfo(filename, L"conductor", meta, 512) && meta[0])
  85. tag2_5->put_Conductor(meta);
  86. */
  87. AGAVE_API_MLDB->FreeRecord(record);
  88. }
  89. if (info) info->put_Tag(infotag);
  90. return S_OK;
  91. }
  92. void IDScanner::CommitFileInfo(ICddbFileInfo *match)
  93. {
  94. ICddbFileTagPtr tag;
  95. match->get_Tag(&tag);
  96. ICddbDisc2Ptr disc1, disc;
  97. match->get_Disc(&disc1);
  98. ICddbDisc2_5Ptr disc2_5;
  99. ICddbTrackPtr track;
  100. ICddbTrack2_5Ptr track2;
  101. if (disc1)
  102. {
  103. musicID->GetFullDisc(disc1, &disc);
  104. if (disc == 0)
  105. disc=disc1;
  106. disc->QueryInterface(&disc2_5);
  107. disc->GetTrack(1, &track);
  108. if (track)
  109. track->QueryInterface(&track2);
  110. }
  111. CComBSTR file, tagID, extData;
  112. match->get_Filename(&file);
  113. tag->get_FileId(&tagID);
  114. playlistMgr->FileSetTagID(file, tagID, CDDB_UPDATE_NONE);
  115. ICddbFileTag2_5Ptr tag2;
  116. tag->QueryInterface(&tag2);
  117. playlistMgr->FileSetFieldVal(file, gnpl_crit_field_xdev1, L"0"); // mark as done!
  118. if (tag2) // try tag first
  119. tag2->get_ExtDataSerialized(&extData);
  120. if (!extData && track2 != 0) // WMA files don't get their tag object's extended data set correctly, so fallback to track extended data
  121. track2->get_ExtDataSerialized(&extData);
  122. if (!extData && disc2_5 != 0) // finally, fall back to disc extended data
  123. disc2_5->get_ExtDataSerialized(&extData);
  124. playlistMgr->FileSetExtDataSerialized(file, extData, CDDB_UPDATE_NONE);
  125. if (tagID)
  126. AGAVE_API_MLDB->SetField(file, "GracenoteFileID", tagID);
  127. if (extData)
  128. AGAVE_API_MLDB->SetField(file, "GracenoteExtData", extData);
  129. // TODO: if we don't have an artist & album, we might as well grab this out of the tag now
  130. // TODO: make thread-safe and optional
  131. /*
  132. updateFileInfo(file, L"GracenoteFileID", tagID);
  133. updateFileInfo(file, L"GracenoteExtData", extData);
  134. WriteFileInfo(file);
  135. */
  136. }
  137. STDMETHODIMP STDMETHODCALLTYPE IDScanner::QueryInterface(REFIID riid, PVOID *ppvObject)
  138. {
  139. if (!ppvObject)
  140. return E_POINTER;
  141. else if (IsEqualIID(riid, __uuidof(_ICDDBMusicIDManagerEvents)))
  142. *ppvObject = (_ICDDBMusicIDManagerEvents *)this;
  143. else if (IsEqualIID(riid, IID_IDispatch))
  144. *ppvObject = (IDispatch *)this;
  145. else if (IsEqualIID(riid, IID_IUnknown))
  146. *ppvObject = this;
  147. else
  148. {
  149. *ppvObject = NULL;
  150. return E_NOINTERFACE;
  151. }
  152. AddRef();
  153. return S_OK;
  154. }
  155. ULONG STDMETHODCALLTYPE IDScanner::AddRef(void)
  156. {
  157. return 1;
  158. }
  159. ULONG STDMETHODCALLTYPE IDScanner::Release(void)
  160. {
  161. return 0;
  162. }
  163. HRESULT STDMETHODCALLTYPE IDScanner::Invoke(DISPID dispid, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, EXCEPINFO FAR * pexecinfo, unsigned int FAR *puArgErr)
  164. {
  165. switch (dispid)
  166. {
  167. case 1: // OnTrackIDStatusUpdate, params: CddbMusicIDStatus Status, BSTR filename, long* Abort
  168. {
  169. //long *abort = pdispparams->rgvarg[0].plVal;
  170. // TODO: is this safe to put here? Or does this make us get partial results
  171. }
  172. break;
  173. case 2: // OnAlbumIDStatusUpdate, params: CddbMusicIDStatus Status, BSTR filename, long current_file, long total_files, long* Abort
  174. {
  175. long *abort = pdispparams->rgvarg[0].plVal;
  176. /*long total_files = pdispparams->rgvarg[1].lVal;
  177. long current_file= pdispparams->rgvarg[2].lVal;*/
  178. CddbMusicIDStatus status = (CddbMusicIDStatus)pdispparams->rgvarg[4].lVal;
  179. BSTR filename = pdispparams->rgvarg[3].bstrVal;
  180. // TODO: is this safe to put here? Or does this make us get partial results
  181. if (killswitch)
  182. *abort = 1;
  183. }
  184. break;
  185. case 3: // OnTrackIDComplete, params: LONG match_code, ICddbFileInfo* pInfoIn, ICddbFileInfoList* pListOut
  186. break;
  187. case 4:
  188. break;// OnAlbumIDComplete, params: LONG match_code, ICddbFileInfoList* pListIn, ICddbFileInfoLists* pListsOut
  189. case 5:
  190. break; // OnGetFingerprint
  191. case 6:
  192. break;
  193. case 7://OnLibraryIDListStarted
  194. break;
  195. case 8: // OnLibraryIDListComplete
  196. {
  197. long *abort = pdispparams->rgvarg[0].plVal;
  198. if (killswitch)
  199. *abort = 1;
  200. /*long FilesError =pdispparams->rgvarg[1].lVal;
  201. long FilesNoMatch=pdispparams->rgvarg[2].lVal;
  202. long FilesFuzzy=pdispparams->rgvarg[3].lVal;
  203. long FilesExact=pdispparams->rgvarg[4].lVal;*/
  204. filesTotal=pdispparams->rgvarg[5].lVal;
  205. filesComplete=pdispparams->rgvarg[6].lVal;
  206. IDispatch *disp = pdispparams->rgvarg[7].pdispVal;
  207. if (disp)
  208. {
  209. ICddbFileInfoList* matchList=0;
  210. disp->QueryInterface(&matchList);
  211. if (matchList)
  212. {
  213. long matchcount;
  214. matchList->get_Count(&matchcount);
  215. for (int j = 1;j <= matchcount;j++)
  216. {
  217. ICddbFileInfoPtr match;
  218. matchList->GetFileInfo(j, &match);
  219. CommitFileInfo(match);
  220. }
  221. matchList->Release();
  222. }
  223. return S_OK;
  224. }
  225. else
  226. return E_FAIL;
  227. }
  228. break;
  229. case 9: //OnLibraryIDComplete
  230. break;
  231. case 10: // OnGetFingerprintInfo
  232. {
  233. long *abort = pdispparams->rgvarg[0].plVal;
  234. IDispatch *disp = pdispparams->rgvarg[1].pdispVal;
  235. BSTR filename = pdispparams->rgvarg[2].bstrVal;
  236. ICddbFileInfoPtr info;
  237. disp->QueryInterface(&info);
  238. return AGAVE_API_GRACENOTE->CreateFingerprint(musicID, AGAVE_API_DECODE, info, filename, abort);
  239. }
  240. break;
  241. case 11: // OnGetTagInfo
  242. {
  243. pdispparams->rgvarg[0].plVal;
  244. IDispatch *disp = pdispparams->rgvarg[1].pdispVal;
  245. BSTR filename = pdispparams->rgvarg[2].bstrVal;
  246. ICddbFileInfoPtr info;
  247. disp->QueryInterface(&info);
  248. return FillTag(info, filename);
  249. }
  250. break;
  251. }
  252. return DISP_E_MEMBERNOTFOUND;
  253. }
  254. HRESULT STDMETHODCALLTYPE IDScanner::GetIDsOfNames(REFIID riid, OLECHAR FAR* FAR* rgszNames, unsigned int cNames, LCID lcid, DISPID FAR* rgdispid)
  255. {
  256. *rgdispid = DISPID_UNKNOWN;
  257. return DISP_E_UNKNOWNNAME;
  258. }
  259. HRESULT STDMETHODCALLTYPE IDScanner::GetTypeInfo(unsigned int itinfo, LCID lcid, ITypeInfo FAR* FAR* pptinfo)
  260. {
  261. return E_NOTIMPL;
  262. }
  263. HRESULT STDMETHODCALLTYPE IDScanner::GetTypeInfoCount(unsigned int FAR * pctinfo)
  264. {
  265. return E_NOTIMPL;
  266. }
  267. void IDScanner::SetGracenoteData(BSTR filename, BSTR tagID, BSTR extData)
  268. {
  269. bool foundExt=false;
  270. if (extData && extData[0])
  271. {
  272. playlistMgr->FileSetExtDataSerialized(filename, extData, CDDB_UPDATE_NONE);
  273. CComBSTR test;
  274. playlistMgr->FileGetExtDataSerialized(filename, &test, 0); // benski> 24 Jul 2007 - there is a currently a bug that makes this always E_FAIL
  275. if (test)
  276. foundExt=true;
  277. }
  278. if (!foundExt) // no Extended Data (or invalid), but we have a Tag ID, we'll ask the playlist SDK to do a quick lookup
  279. {
  280. playlistMgr->FileSetTagID(filename, tagID, CDDB_UPDATE_EXTENDED);
  281. // write back to Media Library database
  282. CComBSTR extData;
  283. playlistMgr->FileGetExtDataSerialized(filename, &extData, 0); // benski> 24 Jul 2007 - there is a currently a bug that makes this always E_FAIL
  284. if (extData)
  285. AGAVE_API_MLDB->SetField(filename, "GracenoteExtData", extData);
  286. }
  287. else
  288. playlistMgr->FileSetTagID(filename, tagID, CDDB_UPDATE_NONE);
  289. }
  290. /*
  291. //void IDScanner::ProcessDatabaseDifferences(Device * dev, C_ItemList * ml0,C_ItemList * itemRecordsOnDevice, C_ItemList * itemRecordsNotOnDevice, C_ItemList * songsInML, C_ItemList * songsNotInML)
  292. void IDScanner::ProcessDatabaseDifferences(Device * dev, C_ItemList * ml0,C_ItemList * itemRecordsOnDevice, C_ItemList * itemRecordsNotOnDevice, C_ItemList * songsInML, C_ItemList * songsNotInML)
  293. {
  294. C_ItemList device2;
  295. C_ItemList *device0=&device2;
  296. int l = dev->getPlaylistLength(0);
  297. for(int i=0; i<l; i++) device0->Add((void*)dev->getPlaylistTrack(0,i));
  298. qsort(ml0->GetAll(),ml0->GetSize(),sizeof(void*),sortfunc_ItemRecords);
  299. nu::qsort(device0->GetAll(), device0->GetSize(), sizeof(void*), dev, compareSongs);
  300. C_ItemList *ml = new C_ItemList;
  301. C_ItemList *device = new C_ItemList;
  302. int i,j;
  303. {
  304. itemRecordW * lastice = NULL;
  305. songid_t lastsong = NULL;
  306. for(i=0; i<ml0->GetSize(); i++) {
  307. itemRecordW * it = (itemRecordW*)ml0->Get(i);
  308. if(lastice) if(compareItemRecords(lastice,it)==0) continue;
  309. ml->Add(it);
  310. lastice = it;
  311. }
  312. for(i=0; i<device0->GetSize(); i++) {
  313. songid_t song = (songid_t)device0->Get(i);
  314. if(lastsong) if(compareSongs((void*)&song,(void*)&lastsong, dev)==0) continue;
  315. device->Add((void*)song);
  316. lastsong = song;
  317. }
  318. }
  319. i=0,j=0;
  320. int li = device->GetSize();
  321. int lj = ml->GetSize();
  322. while(i<li && j<lj) {
  323. itemRecordW * it = (itemRecordW*)ml->Get(j);
  324. songid_t song = (songid_t)device->Get(i);
  325. int cmp = compareItemRecordAndSongId(it,song, dev);
  326. if(cmp == 0) { // song on both
  327. if(itemRecordsOnDevice) itemRecordsOnDevice->Add(it);
  328. if(songsInML) songsInML->Add((void*)song);
  329. i++;
  330. j++;
  331. }
  332. else if(cmp > 0) { //song in ml and not on device
  333. if(itemRecordsNotOnDevice) itemRecordsNotOnDevice->Add(it);
  334. j++;
  335. }
  336. else { // song on device but not in ML
  337. if(songsNotInML) songsNotInML->Add((void*)song);
  338. i++;
  339. }
  340. }
  341. // any leftovers?
  342. if(songsNotInML) while(i<li) {
  343. songid_t song = (songid_t)device->Get(i++);
  344. songsNotInML->Add((void*)song);
  345. }
  346. if(itemRecordsNotOnDevice) while(j<lj) {
  347. itemRecordW * it = (itemRecordW *)ml->Get(j++);
  348. itemRecordsNotOnDevice->Add(it);
  349. }
  350. delete ml; delete device;
  351. }
  352. */
  353. /*
  354. 2-pass strategy
  355. Pass 1: Find all tracks with Gracenote Extended Data
  356. Pass 2: Find File ID & extended data by fingerprint
  357. */
  358. void IDScanner::ScanDatabase()
  359. {
  360. filesComplete=0;
  361. filesTotal=0;
  362. state=STATE_INITIALIZING;
  363. killswitch=0; // reset just in case
  364. if (SetupPlaylistSDK())
  365. {
  366. // If this is our first time running then lets register the wasabi system callbacks for adding and removing tracks
  367. if (!syscb_registered)
  368. {
  369. WASABI_API_SYSCB->syscb_registerCallback(this);
  370. syscb_registered = true;
  371. }
  372. // Set up the MLDB manager
  373. InitializeMLDBManager();
  374. state=STATE_SYNC;
  375. /* Get a list of files in the media library database */
  376. itemRecordListW *results = AGAVE_API_MLDB->Query(L"type=0");
  377. if (results)
  378. {
  379. filesTotal=results->Size;
  380. for (int i=0;i<results->Size;i++)
  381. {
  382. if (killswitch)
  383. break;
  384. wchar_t * filename = results->Items[i].filename;
  385. HRESULT hr=playlistMgr->AddEntry(filename); // Add entry to gracenote DB
  386. assert(SUCCEEDED(S_OK));
  387. if (hr == S_OK)
  388. {
  389. // Fill in Artist & Album info since we have it in the itemRecordList anyway
  390. // TODO: probably want to use SKIP_THE_AND_WHITESPACE here
  391. if (results->Items[i].album && results->Items[i].album[0])
  392. hr=playlistMgr->FileSetFieldVal(filename, gnpl_crit_field_album_name, results->Items[i].album);
  393. if (results->Items[i].artist && results->Items[i].artist[0])
  394. hr=playlistMgr->FileSetFieldVal(filename, gnpl_crit_field_track_artist_name, results->Items[i].artist);
  395. // Populate title information so that we have more complete data.
  396. if (results->Items[i].title && results->Items[i].title[0])
  397. hr=playlistMgr->FileSetFieldVal(filename, gnpl_crit_field_track_name, results->Items[i].title);
  398. wchar_t storage[64] = {0};
  399. // Populate the file length in milliseconds
  400. if (results->Items[i].length > 0)
  401. {
  402. _itow(results->Items[i].length,storage, 10);
  403. hr=playlistMgr->FileSetFieldVal(filename, gnpl_crit_field_file_length, storage);
  404. }
  405. // Populate the file size in kilobytes
  406. if (results->Items[i].filesize > 0)
  407. {
  408. _itow(results->Items[i].filesize,storage, 10);
  409. hr=playlistMgr->FileSetFieldVal(filename, gnpl_crit_field_file_size, storage);
  410. }
  411. wchar_t *tagID = getRecordExtendedItem(&results->Items[i], L"GracenoteFileID");
  412. if (tagID && tagID[0])
  413. {
  414. SetGracenoteData(filename, tagID, getRecordExtendedItem(&results->Items[i], L"GracenoteExtData"));
  415. hr=playlistMgr->FileSetFieldVal(filename, gnpl_crit_field_xdev1, L"0"); // done with this file!
  416. }
  417. else
  418. hr=playlistMgr->FileSetFieldVal(filename, gnpl_crit_field_xdev1, L"1"); // move to phase 1
  419. }
  420. filesComplete=i+1;
  421. }
  422. AGAVE_API_MLDB->FreeRecordList(results);
  423. state=STATE_METADATA;
  424. filesComplete=0;
  425. if (!killswitch)
  426. Pass1();
  427. filesComplete=0;
  428. state=STATE_MUSICID;
  429. if (!killswitch)
  430. Pass2();
  431. state=STATE_DONE;
  432. if (!killswitch)
  433. AGAVE_API_MLDB->Sync();
  434. }
  435. // Set the pass 2 flag back so that on next generation we dont try to run it
  436. run_pass2_flag = false;
  437. }
  438. else
  439. state=STATE_ERROR;
  440. }
  441. bool IDScanner::GetStatus(long *pass, long *track, long *tracks)
  442. {
  443. *pass = state;
  444. *track = filesComplete;
  445. *tracks = filesTotal;
  446. return true;
  447. }
  448. // System callback handlers from WASABI
  449. FOURCC IDScanner::GetEventType()
  450. {
  451. return api_mldb::SYSCALLBACK;
  452. }
  453. int IDScanner::notify(int msg, intptr_t param1, intptr_t param2)
  454. {
  455. wchar_t *filename = (wchar_t *)param1;
  456. switch (msg)
  457. {
  458. case api_mldb::MLDB_FILE_ADDED:
  459. {
  460. DebugCallbackMessage(param1, L"File Added: '%s'");
  461. // Call the add/update function that needs to run on our lonesome playlist generator thread
  462. WASABI_API_THREADPOOL->RunFunction(plg_thread, IDScanner::MLDBFileAddedOnThread, _wcsdup(filename), (intptr_t)this, api_threadpool::FLAG_REQUIRE_COM_STA);
  463. }
  464. break;
  465. case api_mldb::MLDB_FILE_REMOVED_PRE:
  466. {
  467. // We are not concerned with the PRE scenario
  468. //DebugCallbackMessage(param1, L"File Removed PRE: '%s'");
  469. }
  470. break;
  471. case api_mldb::MLDB_FILE_REMOVED_POST:
  472. {
  473. WASABI_API_THREADPOOL->RunFunction(plg_thread, IDScanner::MLDBFileRemovedOnThread, _wcsdup(filename), (intptr_t)this, api_threadpool::FLAG_REQUIRE_COM_STA);
  474. // We will only care about the post scenario since we just need to remove the file entry from gracenote.
  475. //DebugCallbackMessage(param1, L"File Removed POST: '%s'");
  476. }
  477. break;
  478. case api_mldb::MLDB_FILE_UPDATED:
  479. {
  480. // For now we call the add method even on an update
  481. WASABI_API_THREADPOOL->RunFunction(plg_thread, IDScanner::MLDBFileAddedOnThread, _wcsdup(filename), (intptr_t)this, api_threadpool::FLAG_REQUIRE_COM_STA);
  482. //DebugCallbackMessage(param1, L"File Updated: '%s'");
  483. }
  484. break;
  485. case api_mldb::MLDB_CLEARED:
  486. {
  487. WASABI_API_THREADPOOL->RunFunction(plg_thread, IDScanner::MLDBClearedOnThread, 0, (intptr_t)this, api_threadpool::FLAG_REQUIRE_COM_STA);
  488. //DebugCallbackMessage(param1, L"MLDB Cleared");
  489. }
  490. break;
  491. default: return 0;
  492. }
  493. return 1;
  494. }
  495. // Outputs a messagebox with a filename to know when callbacks are being triggered
  496. inline void IDScanner::DebugCallbackMessage(const intptr_t text, const wchar_t *message)
  497. {
  498. //#ifdef DEBUG_CALLBACKS
  499. #if defined(DEBUG) && defined(DEBUG_CALLBACKS)
  500. const int size = MAX_PATH + 256;
  501. wchar_t *filename = (wchar_t *)text;
  502. wchar_t buff[size] = {0};
  503. //wsprintf(buff, size, message, filename);
  504. StringCchPrintf(buff, size, message, filename);
  505. MessageBox(0, buff, L"Wasabi Callback Debug", 0);
  506. #endif
  507. }
  508. int IDScanner::MLDBFileAddedOnThread(HANDLE handle, void *user_data, intptr_t id)
  509. {
  510. if (!playlistMgr) return 0;
  511. // Variables to hold information about the file query
  512. wchar_t *filename = (wchar_t *)user_data;
  513. IDScanner *scanner = (IDScanner *)id;
  514. wchar_t buff[1024] = {0};
  515. _ltow(scanner->state, buff, 10);
  516. itemRecordW *result = AGAVE_API_MLDB->GetFile(filename);
  517. HRESULT hr=playlistMgr->AddEntry(filename); // Add the file entry to the gracenote DB
  518. assert(SUCCEEDED(S_OK));
  519. if (hr == S_OK /*&& results->Size == 1*/)
  520. {
  521. // Fill in Artist & Album info since we have it in the itemRecordList anyway
  522. // TODO: probably want to use SKIP_THE_AND_WHITESPACE here
  523. if (result->album && result->album[0])
  524. playlistMgr->FileSetFieldVal(filename, gnpl_crit_field_album_name, result->album);
  525. if (result->artist && result->artist[0])
  526. playlistMgr->FileSetFieldVal(filename, gnpl_crit_field_track_artist_name, result->artist);
  527. // Populate title, file size, and length information so that we have more complete data.
  528. if (result->title && result->title[0])
  529. playlistMgr->FileSetFieldVal(filename, gnpl_crit_field_track_name, result->title);
  530. wchar_t storage[64] = {0};
  531. // Populate the file length in milliseconds
  532. if (result->length > 0)
  533. {
  534. _itow(result->length,storage, 10);
  535. playlistMgr->FileSetFieldVal(filename, gnpl_crit_field_file_length, storage);
  536. }
  537. // Populate the file size in kilobytes
  538. if (result->filesize > 0)
  539. {
  540. _itow(result->filesize,storage, 10);
  541. playlistMgr->FileSetFieldVal(filename, gnpl_crit_field_file_size, storage);
  542. }
  543. wchar_t *tagID = getRecordExtendedItem(result, L"GracenoteFileID");
  544. if (tagID && tagID[0])
  545. {
  546. scanner->SetGracenoteData(filename, tagID, getRecordExtendedItem(result, L"GracenoteExtData"));
  547. // We have everything we need at this point in the gracenote DB
  548. playlistMgr->FileSetFieldVal(filename, gnpl_crit_field_xdev1, L"0"); // done with this file!
  549. }
  550. else // Set it to the final scan
  551. {
  552. playlistMgr->FileSetFieldVal(filename, gnpl_crit_field_xdev1, L"2"); // move to phase 2, we can skip phase 1
  553. // Add the current file to the step 4 processing stack
  554. // TODOD is there a mem leak here??
  555. ProcessItem *itemz = new ProcessItem();
  556. itemz->filename = filename;
  557. //scanner->process_items.push(*itemz); // Add the current item coming in to the queue
  558. // Set the flag so that we know we will need to rerun step 4 (pass 2) on a playlist regeneration, this only needs to happen if there is an actual change.
  559. run_pass2_flag = true;
  560. }
  561. }
  562. if (result)
  563. AGAVE_API_MLDB->FreeRecord(result);
  564. // ToDo: We need to do this free when we pop it off of the processing stack later
  565. free(filename); // Clean up the user data
  566. return 0;
  567. }
  568. int IDScanner::MLDBFileRemovedOnThread(HANDLE handle, void *user_data, intptr_t id)
  569. {
  570. wchar_t *filename = (wchar_t *)user_data;
  571. HRESULT hr = playlistMgr->DeleteFile(filename);
  572. if (hr == S_OK)
  573. return 0;
  574. else
  575. return 1;
  576. free(filename); // Clean up the user data
  577. }
  578. int IDScanner::MLDBClearedOnThread(HANDLE handle, void *user_data, intptr_t id)
  579. {
  580. return ResetDB(false);
  581. }
  582. int IDScanner::ProcessStackItems(void)
  583. {
  584. // ToDo: Run through the stack items and process stage 4 on them
  585. //this->
  586. return 1;
  587. }
  588. #define CBCLASS IDScanner
  589. START_DISPATCH;
  590. CB(SYSCALLBACK_GETEVENTTYPE, GetEventType);
  591. CB(SYSCALLBACK_NOTIFY, notify);
  592. END_DISPATCH;
  593. #undef CBCLASS