GracenoteApi.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472
  1. #include "GracenoteApi.h"
  2. #include "api.h"
  3. #include "../winamp/api_decodefile.h"
  4. #include <bfc/error.h>
  5. #include <limits.h>
  6. #include <shlwapi.h>
  7. #include <strsafe.h>
  8. GracenoteApi::GracenoteApi()
  9. {
  10. cddbInitialized = false;
  11. playlistInitialized = false;
  12. pCDDBControl=0;
  13. }
  14. GracenoteApi::~GracenoteApi()
  15. {
  16. }
  17. void GracenoteApi::Close()
  18. {
  19. if (pCDDBControl)
  20. {
  21. pCDDBControl->Shutdown();
  22. pCDDBControl->Release();
  23. pCDDBControl=0;
  24. }
  25. }
  26. static void SetProxy(const wchar_t *proxy, ICddbOptions *options)
  27. {
  28. wchar_t user[1024]=L"";
  29. wchar_t pass[1024]=L"";
  30. wchar_t server[1024]=L"";
  31. int port=80;
  32. if (!_wcsnicmp(proxy,L"https:",6))
  33. port = 443;
  34. const wchar_t *skip = wcsstr(proxy, L"://");
  35. if (skip)
  36. proxy = skip+3;
  37. skip = wcsstr(proxy, L"@");
  38. if (skip)
  39. {
  40. const wchar_t *delimiter = wcsstr(proxy, L":");
  41. if (delimiter < skip) // make sure there's really a password (and we didn't end up finding the port number)
  42. {
  43. StringCchCopyNW(user, 1024, proxy, delimiter-proxy);
  44. StringCchCopyNW(pass, 1024, delimiter+1, skip-(delimiter+1));
  45. proxy=skip+1;
  46. }
  47. else
  48. {
  49. StringCchCopyNW(user, 1024, proxy, skip-proxy);
  50. proxy=skip+1;
  51. }
  52. }
  53. skip = wcsstr(proxy, L":"); // look for port
  54. if (skip)
  55. {
  56. StringCchCopyNW(server, 1024, proxy, skip-proxy);
  57. port = _wtoi(skip+1);
  58. }
  59. else
  60. StringCchCopyW(server, 1024, proxy);
  61. if (server[0])
  62. options->put_ProxyServer(server);
  63. if (port)
  64. options->put_ProxyServerPort(port);
  65. if (user[0])
  66. options->put_ProxyUserName(user);
  67. if (pass[0])
  68. options->put_ProxyPassword(pass);
  69. }
  70. // {C0A565DC-0CFE-405a-A27C-468B0C8A3A5C}
  71. static const GUID internetConfigGroupGUID =
  72. { 0xc0a565dc, 0xcfe, 0x405a, { 0xa2, 0x7c, 0x46, 0x8b, 0xc, 0x8a, 0x3a, 0x5c } };
  73. ICDDBControl2 *GracenoteApi::GetCDDB()
  74. {
  75. Nullsoft::Utility::AutoLock lock(cddbGuard);
  76. if (!cddbInitialized)
  77. {
  78. CoCreateInstance(__uuidof(CDDBNSWinampControl), 0, CLSCTX_INPROC_SERVER, IID_IUnknown, (void **)&pCDDBControl);
  79. if (pCDDBControl == NULL)
  80. return 0;
  81. #if 1 // TODO: benski> put back in once we can match winamp lang pack to a gracenote language ID
  82. // translate if necessary
  83. if (WASABI_API_LNG)
  84. {
  85. const wchar_t *langFolder = WASABI_API_LNG->GetLanguageFolder();
  86. if (langFolder)
  87. {
  88. WIN32_FIND_DATAW find;
  89. wchar_t mask[MAX_PATH] = {0}, maskLoc[16] = {0};
  90. // attempt to get the language code to help better guess the CDDB dll needed
  91. if(WASABI_API_LNG->GetLanguageIdentifier(LANG_IDENT_STR))
  92. StringCchPrintfW(maskLoc, 16, L"CddbLang%s.dll", WASABI_API_LNG->GetLanguageIdentifier(LANG_LANG_CODE));
  93. PathCombineW(mask, langFolder, maskLoc);
  94. HANDLE hFind = FindFirstFileW(mask, &find);
  95. // if the the guess provides nothing then scan for any valid dll (not ideal)
  96. if (hFind == INVALID_HANDLE_VALUE)
  97. {
  98. PathCombineW(mask, langFolder, L"CddbLang*.dll");
  99. hFind = FindFirstFileW(mask, &find);
  100. }
  101. if (hFind != INVALID_HANDLE_VALUE)
  102. {
  103. ICddbUIPtr ui;
  104. ui.CreateInstance(__uuidof(CddbNSWinampUI));
  105. if (ui)
  106. {
  107. long val = 0;
  108. wchar_t cddb_lang_fn[MAX_PATH] = {0};
  109. PathCombineW(cddb_lang_fn, langFolder, find.cFileName);
  110. // TODO: benski> gracenote wants a "language ID" but we don't have a good way of knowing it :(
  111. ui->SetUILanguage(0, cddb_lang_fn, &val);
  112. // TODO: benski> also need to set ICddbOptions language ID
  113. }
  114. }
  115. FindClose(hFind);
  116. }
  117. }
  118. #endif
  119. // winamp browser id
  120. //HRESULT hr = pCDDBControl->SetClientInfo(L"7944448", L"F8DE207FBA826F136FF2C7EFE0AAB181", L"1", L"regstring");
  121. //wa5's id
  122. const wchar_t *appVersion = WASABI_API_APP->main_getVersionNumString();
  123. /* development client ID */
  124. //HRESULT hr = pCDDBControl->SetClientInfo(L"3714048", L"B49286AE14F73CCD73C23B371A56DB00", const_cast<BSTR>(appVersion), L"regstring");
  125. /* Beta Client ID */
  126. //HRESULT hr = pCDDBControl->SetClientInfo(L"8337664", L"A222F2FA8B3E047291DFDBF465FD3C95", const_cast<BSTR>(appVersion), L"regstring");
  127. /* Production Client ID */
  128. BSTR appVersionBSTR = SysAllocString(appVersion);
  129. HRESULT hr = pCDDBControl->SetClientInfo(L"4896768", L"C1519CAE91489E405BCA93531837F2BE", appVersionBSTR, L"regstring");
  130. SysFreeString(appVersionBSTR);
  131. if (FAILED(hr))
  132. return 0;
  133. long flags = CACHE_UPDATE_FUZZY | CACHE_DONT_WRITE_ANY | CACHE_NO_LOOKUP_MEDIA; //CACHE_SUBMIT_ALL | CACHE_SUBMIT_OFFLINE | CACHE_SUBMIT_NEW | CACHE_NO_LOOKUP_MEDIA;
  134. // set cache path for cddb control
  135. ICddbOptionsPtr pOptions;
  136. hr = pCDDBControl->GetOptions(&pOptions);
  137. if (SUCCEEDED(hr))
  138. {
  139. wchar_t dataPath[MAX_PATH] = {0};
  140. PathCombineW(dataPath, WASABI_API_APP->path_getUserSettingsPath(), L"Plugins");
  141. CreateDirectoryW(dataPath, 0);
  142. PathAppendW(dataPath, L"Gracenote");
  143. CreateDirectoryW(dataPath, 0);
  144. hr = pOptions->put_LocalCachePath(dataPath);
  145. // initial cache flags
  146. //BOOL bOnline = SendMessage(line.hMainWindow, WM_USER, 0, 242);
  147. //if (!bOnline)
  148. //flags |= CACHE_DONT_CONNECT;
  149. // other needed settings
  150. hr = pOptions->put_ProgressEvents(FALSE);
  151. //hr = pOptions->put_LocalCacheFlags(CACHE_DONT_CREATE | CACHE_UPDATE_FUZZY | CACHE_SUBMIT_ALL);
  152. hr = pOptions->put_LocalCacheFlags(flags);
  153. hr = pOptions->put_LocalCacheSize(128 * 1024); // 128 megabyte limit on local cache size
  154. hr = pOptions->put_LocalCacheTimeout(5 * 365); // 5 years (e.g. when Gracenote contract runs out)
  155. hr = pOptions->put_TestSubmitMode(FALSE);
  156. //hr = pOptions->put_TestSubmitMode(TRUE); //CT> for BETA cycle...
  157. // this is supposed to turn off the spinning logo in the upper-left-hand corner
  158. hr = pOptions->put_ResourceModule(-1);
  159. // get n set proxy settings
  160. const wchar_t *proxy = AGAVE_API_CONFIG->GetString(internetConfigGroupGUID, L"proxy", L"");
  161. if (proxy && proxy[0])
  162. SetProxy(proxy, pOptions);
  163. // save settings
  164. hr = pCDDBControl->SetOptions(pOptions);
  165. }
  166. hr = pCDDBControl->Initialize(0/*(long)line.hMainWindow*/, (CDDBCacheFlags)flags);
  167. // checks for user registration
  168. long pVal=0;
  169. // this must be called when control is first initialized
  170. // this will load existing registration into control
  171. hr = pCDDBControl->IsRegistered(FALSE, &pVal);
  172. // if not reg'd, bring up reg UI (param1 = TRUE)
  173. if (!pVal)
  174. {
  175. // do headless registration
  176. ICddbUserInfoPtr pUser;
  177. hr = pCDDBControl->GetUserInfo(&pUser);
  178. if (pUser != NULL)
  179. {
  180. do
  181. {
  182. wchar_t strdata[129] = {0};
  183. size_t size = sizeof(strdata)/sizeof(*strdata);
  184. wchar_t *str = strdata;
  185. GUID uid = GUID_NULL;
  186. int x;
  187. unsigned char *p;
  188. CoCreateGuid(&uid);
  189. p = (unsigned char *) & uid;
  190. //lstrcpynW(str, L"WA2_", 129);
  191. StringCchCopyExW(str, size, L"WA5_", &str, &size, 0);
  192. for (x = 0; x < sizeof(uid); x ++)
  193. {
  194. StringCchPrintfExW(str, size, &str, &size, 0, L"%02X", p[x]);
  195. //wsprintfW(str + wcslen(str), L"%02X", p[x]);
  196. }
  197. // user name will have to be unique per install
  198. hr = pUser->put_UserHandle(strdata);
  199. hr = pUser->put_Password(strdata);
  200. hr = pCDDBControl->SetUserInfo(pUser);
  201. }
  202. while (hr == CDDBSVCHandleUsed);
  203. }
  204. // this is just to check again that the user is now registered
  205. hr = pCDDBControl->IsRegistered(FALSE, &pVal);
  206. }
  207. cddbInitialized = true;
  208. }
  209. if (pCDDBControl)
  210. pCDDBControl->AddRef();
  211. return pCDDBControl;
  212. }
  213. #if 0
  214. /// This is the deprecated version of GetPlaylistManager that is no longer used without the MLDB manager
  215. ICddbPlaylist25Mgr *GracenoteApi::GetPlaylistManager()
  216. {
  217. ICddbPlaylist25Mgr *playlistMgr;
  218. ICDDBControl2 *cddb = GetCDDB();
  219. if (!cddb)
  220. return 0;
  221. CoCreateInstance(__uuidof(CddbNSWinampPlaylist2Mgr), 0, CLSCTX_INPROC_SERVER, IID_IUnknown, (void **)&playlistMgr);
  222. if (playlistMgr)
  223. {
  224. playlistMgr->AddRef();
  225. wchar_t dataPath[MAX_PATH] = {0};
  226. PathCombineW(dataPath, WASABI_API_APP->path_getUserSettingsPath(), L"Plugins");
  227. CreateDirectoryW(dataPath, 0);
  228. PathAppendW(dataPath, L"Gracenote");
  229. CreateDirectoryW(dataPath, 0);
  230. if (SUCCEEDED(playlistMgr->Initialize(cddb, dataPath)))
  231. {
  232. playlistMgr->DownloadCorrelates(0);
  233. playlistInitialized = true;
  234. }
  235. else
  236. {
  237. playlistMgr->Release();
  238. playlistMgr=0;
  239. }
  240. }
  241. cddb->Release();
  242. return playlistMgr;
  243. }
  244. #endif
  245. /// Caller is responsible for freeing the returned BSTR !!!
  246. BSTR SetAndCreatePath(const wchar_t *node)
  247. {
  248. wchar_t path_to_create[MAX_PATH] = {0};
  249. BSTR bPath = 0;
  250. PathCombineW(path_to_create, WASABI_API_APP->path_getUserSettingsPath(), L"Plugins");
  251. CreateDirectoryW(path_to_create, 0);
  252. PathAppendW(path_to_create, node);
  253. CreateDirectoryW(path_to_create, 0);
  254. bPath = SysAllocString(path_to_create);
  255. // modified path as return value
  256. return bPath;
  257. }
  258. /// This has superceded the old GetPlaylistManager
  259. /// Returns both a playlist manager in 'playlistMgr' and an mldb manager in 'mldbMgr'
  260. //int GracenoteApi::GetPlaylistManagerWithMLDBManager(ICddbPlaylist25Mgr **playlistMgr, ICddbMLDBManager **mldbMgr)
  261. int GracenoteApi::GetPlaylistManager(ICddbPlaylist25Mgr **playlistMgr, ICddbMLDBManager **mldbMgr)
  262. {
  263. ICddbPlaylist25Mgr *playlistMgrCreated;
  264. ICddbMLDBManager *mldbMgrCreated;
  265. ICDDBControl2 *cddb = GetCDDB();
  266. if (!cddb)
  267. return 0;
  268. // Create the mldb manager
  269. CoCreateInstance(__uuidof(CddbMLDBManager), 0, CLSCTX_INPROC_SERVER, IID_IUnknown, (void **)&mldbMgrCreated);
  270. if (mldbMgrCreated)
  271. {
  272. //PL_MLDB_FLAGS_ZERO 0x00000000 Used for initialization.
  273. //PL_MLDB_CHECK_BASE 0x00000001 Causes CheckDB to verify the consistency of the MLDB data file.
  274. //PL_MLDB_CHECK_INDEX 0x00000002 Causes CheckDB to verify the consistency of the MLDB index file.
  275. //PL_MLDB_CHECK_DEEP 0x00000004 Causes CheckDB to perform a thorough check of the MLDB file(s).
  276. //PL_MLDB_CHECK_DEFAULT 0x00000007 Default operation of CheckDB.
  277. //PL_MLDB_CLEAR_INIT_FLAG 0x00000010 Causes ModifyInitFlag to remove the file indicating Playlist is initialized.
  278. //PL_MLDB_SET_INIT_FLAG 0x00000020 Causes ModifyInitFlag to create the file indicating Playlist is initialized.
  279. //PL_MLDB_BACKUP_BASE 0x00000100 Causes BackupDB to create a backup copy of the MLDB data file.
  280. //PL_MLDB_BACKUP_INDEX 0x00000200 Causes BackupDB to create a backup copy of the MLDB index file.
  281. //PL_MLDB_RESTORE_BASE 0x00000400 Causes RestoreDB to restore the MLDB data file from the backup copy.
  282. //PL_MLDB_RESTORE_INDEX 0x00000800 Causes RestoreDB to restore the MLDB index file from the backup copy.
  283. //PL_MLDB_DELETE_INDEX 0x00001000 Causes DeleteDBFiles to remove the MLDB index file.
  284. //PL_MLDB_DELETE_BASE 0x00002000 Causes DeleteDBFiles to remove the MLDB data file.
  285. //PL_MLDB_DELETE_BACKUPS 0x00004000 Causes DeleteDBFiles to remove the MLDBbackup files.
  286. //PL_MLDB_DELETE_OTHER 0x00008000 Causes DeleteDBFiles to remove the other (non-MLDB) files used by Playlist.
  287. //PL_MLDB_AUTO_REINDEX 0x00010000 When specified in SetOptions, will cause theindex file to be automatically rebuilt atinitialization if it is corrupt.
  288. //PL_MLDB_AUTO_BACKUP 0x00020000 When specified in SetOptions, will cause the MLDB files to be automatically backed up at shutdown (if they have been modified). PL_MLDB_AUTO_MANAGE_INIT_FLAG 0x00040000 When specified in SetOptions, will cause the “init file” to be managed automatically (created at initialization, deleted at shut down).
  289. //PL_MLDB_AUTO_CHECK_IF_INIT_SET 0x00080000 When specified in SetOptions, will cause the MLDB files to be check at initialization if the “init file” exists (meaning shut down wasn’t called).
  290. //PL_MLDB_AUTO_CHECK_AT_INIT 0x00100000 When specified in SetOptions, will cause the MLDB files to be checked always at initialization.
  291. //PL_MLDB_AUTO_DEFAULT 0x000C0000 The default automatic behavior if no flags are specified with SetOptions.
  292. //PL_MLDB_DEVICE_MLDB_42 0x01000000 Enable Gracenote Device SDK 4.2 compatibility for MLDB, list, and correlates files
  293. //long autoFlags = PL_MLDB_AUTO_DEFAULT;
  294. //long autoFlags = PL_MLDB_AUTO_REINDEX | PL_MLDB_AUTO_BACKUP | PL_MLDB_AUTO_MANAGE_INIT_FLAG | PL_MLDB_AUTO_CHECK_IF_INIT_SET | PL_MLDB_AUTO_CHECK_AT_INIT;
  295. long autoFlags = PL_MLDB_AUTO_REINDEX | PL_MLDB_AUTO_BACKUP | PL_MLDB_AUTO_MANAGE_INIT_FLAG | PL_MLDB_AUTO_CHECK_IF_INIT_SET;
  296. BSTR bDataPath = SetAndCreatePath(L"Gracenote");
  297. BSTR bBackupPath = SetAndCreatePath(L"Gracenote/Backup");
  298. mldbMgrCreated->AddRef();
  299. mldbMgrCreated->SetOptions(autoFlags, bBackupPath);
  300. CoCreateInstance(__uuidof(CddbNSWinampPlaylist2Mgr), 0, CLSCTX_INPROC_SERVER, IID_IUnknown, (void **)&playlistMgrCreated);
  301. if (playlistMgrCreated)
  302. {
  303. playlistMgrCreated->AddRef();
  304. mldbMgrCreated->Attach(playlistMgrCreated); // Attach the MLDB manager to the playlistMgr
  305. if (SUCCEEDED(playlistMgrCreated->Initialize(cddb, bDataPath)))
  306. {
  307. playlistMgrCreated->DownloadCorrelates(0);
  308. playlistInitialized = true;
  309. }
  310. else
  311. {
  312. playlistMgrCreated->Release();
  313. playlistMgrCreated=0;
  314. }
  315. }
  316. SysFreeString(bDataPath);
  317. SysFreeString(bBackupPath);
  318. }
  319. cddb->Release();
  320. *mldbMgr = mldbMgrCreated;
  321. *playlistMgr = playlistMgrCreated;
  322. if (mldbMgr && playlistMgr)
  323. return NErr_Success;
  324. else
  325. return NErr_FailedCreate;
  326. }
  327. /// Dont really have to use this, get the MLDB manager when creating the playlist manager
  328. ICddbMLDBManager *GracenoteApi::GetMLDBManager()
  329. {
  330. ICddbMLDBManager *mldbMgr;
  331. ICDDBControl2 *cddb = GetCDDB();
  332. if (!cddb)
  333. return 0;
  334. CoCreateInstance(__uuidof(CddbMLDBManager), 0, CLSCTX_INPROC_SERVER, IID_IUnknown, (void **)&mldbMgr);
  335. if (mldbMgr)
  336. {
  337. mldbMgr->AddRef();
  338. }
  339. cddb->Release();
  340. return mldbMgr;
  341. }
  342. HRESULT GracenoteApi::CreateFingerprint(ICDDBMusicIDManager *musicID, api_decodefile *decodeApi, ICddbFileInfo *info, const wchar_t *filename, long *killswitch)
  343. {
  344. if (!musicID || !decodeApi)
  345. return E_FAIL;
  346. ICddbMusicIDFingerprinterPtr fingerprinter;
  347. musicID->CreateFingerprinter(NULL, &fingerprinter);
  348. AudioParameters parameters;
  349. parameters.bitsPerSample = 16;
  350. parameters.channels = 2;
  351. parameters.sampleRate = 44100;
  352. ifc_audiostream *decoder = decodeApi->OpenAudioBackground(filename, &parameters);
  353. if (decoder)
  354. {
  355. HRESULT hr = fingerprinter->BeginAudioStream((long)parameters.sampleRate, (long)parameters.bitsPerSample, (long)parameters.channels);
  356. char data[65536] = {0};
  357. size_t decodeSize;
  358. int decode_killswitch=0, decode_error;
  359. while (decodeSize = decoder->ReadAudio((void *)data, sizeof(data), &decode_killswitch, &decode_error))
  360. {
  361. if (decodeSize > LONG_MAX) // I _really_ doubt this is going to happen, but just in case, since we cast down to a long
  362. break;
  363. if (*killswitch)
  364. break;
  365. hr = fingerprinter->WriteAudioData(data, (long)decodeSize);
  366. if (hr == CDDBMusicID_FPAcquired)
  367. break;
  368. }
  369. ICddbMusicIDFingerprintPtr fingerprint;
  370. fingerprinter->EndAudioStream(&fingerprint);
  371. decodeApi->CloseAudio(decoder);
  372. hr=info->put_Fingerprint(fingerprint);
  373. return S_OK;
  374. }
  375. return E_FAIL;
  376. }
  377. ICDDBMusicIDManager3 *GracenoteApi::GetMusicID()
  378. {
  379. ICDDBControl2 *cddb = GetCDDB();
  380. if (!cddb)
  381. return 0;
  382. ICDDBMusicIDManager3 *musicID;
  383. CoCreateInstance(__uuidof(CDDBNSWinampMusicIDManager), 0, CLSCTX_INPROC_SERVER, IID_IUnknown, (void **)&musicID);
  384. if (musicID)
  385. musicID->Initialize(cddb);
  386. cddb->Release();
  387. return musicID;
  388. }
  389. #define CBCLASS GracenoteApi
  390. START_DISPATCH;
  391. CB(API_GRACENOTE_GETCDDB, GetCDDB)
  392. CB(API_GRACENOTE_GETMUSICID, GetMusicID)
  393. CB(API_GRACENOTE_GETPLAYLISTMGR, GetPlaylistManager)
  394. //CB(API_GRACENOTE_GETPLAYLISTMGRWITHMLDBMGR, GetPlaylistManagerWithMLDBManager)
  395. CB(API_GRACENOTE_GETMLDBMGR, GetMLDBManager)
  396. CB(API_GRACENOTE_CREATEFINGERPRINT, CreateFingerprint)
  397. END_DISPATCH;
  398. #undef CBCLASS