1
0

main.cpp 34 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100
  1. #define PLUGIN_VERSION L"2.79"
  2. #include <windows.h>
  3. #include <windowsx.h>
  4. #include <stdio.h>
  5. #include <shlwapi.h>
  6. #include <shlobj.h>
  7. #include "..\..\General\gen_ml/ml.h"
  8. #include "../winamp/wa_ipc.h"
  9. #include "../nu/AutoWide.h"
  10. #include "../nu/ns_wc.h"
  11. #include "../nu/AutoChar.h"
  12. #include "..\..\General\gen_ml/itemlist.h"
  13. #include "../playlist/ifc_playlistloadercallback.h"
  14. #include "LinkedQueue.h"
  15. #include "resource.h"
  16. #include <vector>
  17. #include <api/service/waServiceFactory.h>
  18. #include "api__ml_transcode.h"
  19. #include <strsafe.h>
  20. #define WM_TRANSCODE_START WM_APP+1
  21. #define WM_TRANSCODE_ADD WM_APP+10
  22. #define WM_TRANSCODE_UPDATEUI WM_APP+11
  23. #define WM_TRANSCODE_ABORT WM_APP+12
  24. static int init();
  25. static void quit();
  26. static HWND GetDialogBoxParent();
  27. static INT_PTR PluginMessageProc(int message_type, INT_PTR param1, INT_PTR param2, INT_PTR param3);
  28. extern "C" winampMediaLibraryPlugin plugin =
  29. {
  30. MLHDR_VER,
  31. "nullsoft(ml_transcode.dll)",
  32. init,
  33. quit,
  34. PluginMessageProc,
  35. 0,
  36. 0,
  37. 0,
  38. };
  39. typedef std::vector<const wchar_t*> PtrListWCharPtr;
  40. LinkedQueue transcodeQueue;
  41. int transcodeConfig(HWND parent); // returns fourcc
  42. void transcode(const itemRecordListW *ice, HWND parent);
  43. void transcode(PtrListWCharPtr &filenames, HWND parent);
  44. void addTrackToTranscodeQueue(itemRecordW *track, unsigned int format, const wchar_t* dest, const wchar_t* folder);
  45. void addTrackToTranscodeQueue(const wchar_t *track, unsigned int format, const wchar_t* dest, const wchar_t* folder);
  46. void filenameToItemRecord(const wchar_t *file, itemRecordW *ice);
  47. void copyTags(const itemRecordW *in, const wchar_t *out);
  48. extern void RecursiveCreateDirectory(wchar_t *buf1);
  49. extern wchar_t *FixReplacementVars(wchar_t *str, size_t str_size, itemRecordW *song);
  50. void FixFileLength(wchar_t *str);
  51. HWND transcoderWnd = NULL;
  52. wchar_t inifile[MAX_PATH] = {0};
  53. char inifileA[MAX_PATH] = {0};
  54. // wasabi based services for localisation support
  55. api_language *WASABI_API_LNG = 0;
  56. HINSTANCE WASABI_API_LNG_HINST = 0, WASABI_API_ORIG_HINST = 0;
  57. api_metadata *AGAVE_API_METADATA=0;
  58. api_application *WASABI_API_APP=0;
  59. api_playlistmanager *AGAVE_API_PLAYLISTMANAGER = 0;
  60. api_albumart *AGAVE_API_ALBUMART = 0;
  61. api_stats *AGAVE_API_STATS = 0;
  62. template <class api_T>
  63. void ServiceBuild(api_T *&api_t, GUID factoryGUID_t)
  64. {
  65. if (plugin.service)
  66. {
  67. waServiceFactory *factory = plugin.service->service_getServiceByGuid(factoryGUID_t);
  68. if (factory)
  69. api_t = reinterpret_cast<api_T *>( factory->getInterface() );
  70. }
  71. }
  72. template <class api_T>
  73. void ServiceRelease(api_T *api_t, GUID factoryGUID_t)
  74. {
  75. if (plugin.service && api_t)
  76. {
  77. waServiceFactory *factory = plugin.service->service_getServiceByGuid(factoryGUID_t);
  78. if (factory)
  79. factory->releaseInterface(api_t);
  80. }
  81. api_t = NULL;
  82. }
  83. int init()
  84. {
  85. ServiceBuild(WASABI_API_APP, applicationApiServiceGuid);
  86. ServiceBuild(WASABI_API_LNG, languageApiGUID);
  87. ServiceBuild(AGAVE_API_METADATA, api_metadataGUID);
  88. ServiceBuild(AGAVE_API_PLAYLISTMANAGER, api_playlistmanagerGUID);
  89. ServiceBuild(AGAVE_API_ALBUMART, albumArtGUID);
  90. ServiceBuild(AGAVE_API_STATS, AnonymousStatsGUID);
  91. const wchar_t *iniDirectory = WASABI_API_APP->path_getUserSettingsPath();
  92. PathCombine(inifile, iniDirectory, L"Plugins\\ml\\ml_transcode.ini");
  93. lstrcpynA(inifileA, AutoChar(inifile), MAX_PATH);
  94. // need to have this initialised before we try to do anything with localisation features
  95. WASABI_API_START_LANG(plugin.hDllInstance,MlTranscodeLangGUID);
  96. static wchar_t szDescription[256];
  97. StringCchPrintfW( szDescription, ARRAYSIZE( szDescription ), WASABI_API_LNGSTRINGW( IDS_NULLSOFT_FORMAT_CONVERTER ), PLUGIN_VERSION );
  98. plugin.description = (char*)szDescription;
  99. return ML_INIT_SUCCESS;
  100. }
  101. void quit()
  102. {
  103. if(IsWindow(transcoderWnd))
  104. SendMessage(transcoderWnd,WM_TRANSCODE_ABORT,0,0);
  105. ServiceRelease(WASABI_API_APP, applicationApiServiceGuid);
  106. ServiceRelease(WASABI_API_LNG, languageApiGUID);
  107. ServiceRelease(AGAVE_API_METADATA, api_metadataGUID);
  108. ServiceRelease(AGAVE_API_PLAYLISTMANAGER, api_playlistmanagerGUID);
  109. ServiceRelease(AGAVE_API_ALBUMART, albumArtGUID);
  110. ServiceRelease(AGAVE_API_STATS, AnonymousStatsGUID);
  111. }
  112. class TranscodePlaylistLoader : public ifc_playlistloadercallback
  113. {
  114. public:
  115. TranscodePlaylistLoader(PtrListWCharPtr*_fileList);
  116. void OnFile(const wchar_t *filename, const wchar_t *title, int lengthInMS, ifc_plentryinfo *info);
  117. protected:
  118. PtrListWCharPtr*fileList;
  119. RECVS_DISPATCH;
  120. };
  121. TranscodePlaylistLoader::TranscodePlaylistLoader(PtrListWCharPtr*_fileList)
  122. {
  123. fileList = _fileList;
  124. }
  125. void TranscodePlaylistLoader::OnFile(const wchar_t *filename, const wchar_t *title, int lengthInMS, ifc_plentryinfo *info)
  126. {
  127. fileList->push_back(_wcsdup(filename));
  128. }
  129. #define CBCLASS TranscodePlaylistLoader
  130. START_DISPATCH;
  131. VCB(IFC_PLAYLISTLOADERCALLBACK_ONFILE, OnFile)
  132. END_DISPATCH;
  133. #undef CBCLASS
  134. INT_PTR PluginMessageProc(int message_type, INT_PTR param1, INT_PTR param2, INT_PTR param3)
  135. {
  136. if (message_type == ML_MSG_ONSENDTOBUILD)
  137. {
  138. if (param1 == ML_TYPE_ITEMRECORDLIST || param1 == ML_TYPE_FILENAMES ||
  139. param1 == ML_TYPE_ITEMRECORDLISTW || param1 == ML_TYPE_FILENAMESW
  140. || (AGAVE_API_PLAYLISTMANAGER && (param1 == ML_TYPE_PLAYLIST || param1 == ML_TYPE_PLAYLISTS)))
  141. {
  142. mlAddToSendToStructW s;
  143. s.context=param2;
  144. s.desc=WASABI_API_LNGSTRINGW(IDS_FORMAT_CONVERTER);
  145. s.user32=(intptr_t)PluginMessageProc;
  146. SendMessage(plugin.hwndLibraryParent,WM_ML_IPC,(WPARAM)&s,ML_IPC_ADDTOSENDTOW);
  147. }
  148. }
  149. else if (message_type == ML_MSG_ONSENDTOSELECT)
  150. {
  151. if (param2 && param3 == (INT_PTR)PluginMessageProc)
  152. {
  153. if(param1 == ML_TYPE_FILENAMES)
  154. {
  155. PtrListWCharPtr fileList;
  156. TranscodePlaylistLoader loader(&fileList);
  157. const char * filenames = (const char *)param2;
  158. while(filenames && *filenames)
  159. {
  160. // try to load as playlist first
  161. if (AGAVE_API_PLAYLISTMANAGER->Load(AutoWide(filenames), &loader) != PLAYLISTMANAGER_SUCCESS)
  162. {
  163. // not a playlist.. just add it directly
  164. fileList.push_back(AutoWideDup(filenames));
  165. }
  166. filenames+=strlen(filenames)+1;
  167. }
  168. transcode(fileList,GetDialogBoxParent());
  169. //fileList.freeAll();
  170. for (auto file : fileList)
  171. {
  172. free((void*)file);
  173. }
  174. fileList.clear();
  175. return 1;
  176. }
  177. else if(param1 == ML_TYPE_FILENAMESW)
  178. {
  179. PtrListWCharPtr fileList;
  180. TranscodePlaylistLoader loader(&fileList);
  181. const wchar_t * filenames = (const wchar_t *)param2;
  182. while(filenames && *filenames)
  183. {
  184. // try to load as playlist first
  185. if (AGAVE_API_PLAYLISTMANAGER->Load(filenames, &loader) != PLAYLISTMANAGER_SUCCESS)
  186. {
  187. // not a playlist.. just add it directly
  188. fileList.push_back(filenames);
  189. }
  190. filenames+=wcslen(filenames)+1;
  191. }
  192. transcode(fileList,GetDialogBoxParent());
  193. return 1;
  194. }
  195. else if(param1 == ML_TYPE_ITEMRECORDLIST)
  196. {
  197. const itemRecordList *ico=(const itemRecordList*)param2;
  198. itemRecordListW list = {0,};
  199. convertRecordList(&list, ico);
  200. transcode(&list, GetDialogBoxParent());
  201. freeRecordList(&list);
  202. return 1;
  203. }
  204. else if(param1 == ML_TYPE_ITEMRECORDLISTW)
  205. {
  206. const itemRecordListW *list =(const itemRecordListW*)param2;
  207. transcode(list,GetDialogBoxParent());
  208. return 1;
  209. }
  210. else if (param1 == ML_TYPE_PLAYLIST)
  211. {
  212. mlPlaylist *playlist = (mlPlaylist *)param2;
  213. PtrListWCharPtr fileList;
  214. fileList.reserve(playlist->numItems);
  215. TranscodePlaylistLoader loader(&fileList);
  216. AGAVE_API_PLAYLISTMANAGER->Load(playlist->filename, &loader);
  217. transcode(fileList,GetDialogBoxParent());
  218. //fileList.freeAll();
  219. for (auto file : fileList)
  220. {
  221. free((void*)file);
  222. }
  223. fileList.clear();
  224. return 1;
  225. }
  226. else if (param1 == ML_TYPE_PLAYLISTS)
  227. {
  228. mlPlaylist **playlists = (mlPlaylist **)param2;
  229. PtrListWCharPtr fileList;
  230. while (playlists && *playlists)
  231. {
  232. mlPlaylist *playlist = *playlists;
  233. fileList.reserve(fileList.size() + playlist->numItems);
  234. TranscodePlaylistLoader loader(&fileList);
  235. AGAVE_API_PLAYLISTMANAGER->Load(playlist->filename, &loader);
  236. playlists++;
  237. }
  238. transcode(fileList,GetDialogBoxParent());
  239. //fileList.freeAll();
  240. for (auto file : fileList)
  241. {
  242. free((void*)file);
  243. }
  244. fileList.clear();
  245. return 1;
  246. }
  247. }
  248. }
  249. else if (message_type == ML_MSG_CONFIG)
  250. {
  251. transcodeConfig((HWND)param1);
  252. return 1;
  253. }
  254. return 0;
  255. }
  256. class TranscodeItem
  257. {
  258. public:
  259. itemRecordW ice;
  260. unsigned int fourcc;
  261. wchar_t *outfile;
  262. TranscodeItem( unsigned int fourcc, const wchar_t *folder, const wchar_t *outfile, const itemRecordW *i ) : fourcc( fourcc )
  263. {
  264. ZeroMemory( &ice, sizeof( ice ) );
  265. copyRecord( &ice, const_cast<itemRecordW *>( i ) ); // TODO: remove for 5.53. this just works around some 5.52 build weirdness
  266. makefn( folder, outfile );
  267. }
  268. TranscodeItem( unsigned int fourcc, const wchar_t *folder, const wchar_t *outfile, const wchar_t *i ) : fourcc( fourcc )
  269. {
  270. ZeroMemory( &ice, sizeof( ice ) );
  271. filenameToItemRecord( i, &ice );
  272. makefn( folder, outfile );
  273. }
  274. void makefn( const wchar_t *folder, const wchar_t *outfile )
  275. {
  276. if ( GetPrivateProfileInt( L"transcoder", L"usefilename", 0, inifile ) )
  277. {
  278. size_t len = wcslen( ice.filename ) + 10;
  279. this->outfile = (wchar_t *)calloc( len, sizeof( this->outfile[ 0 ] ) );
  280. StringCchCopyW( this->outfile, len, ice.filename );
  281. const wchar_t *extn = wcsrchr( outfile, L'.' );
  282. wchar_t *exto = wcsrchr( this->outfile, L'.' );
  283. if ( extn && exto && wcslen( extn ) < 10 )
  284. StringCchCopy( exto, len, extn );
  285. }
  286. else
  287. {
  288. wchar_t filename[ 2048 ] = { 0 };
  289. StringCchCopy( filename, 2048, outfile );
  290. FixReplacementVars( filename, 2048, &ice );
  291. FixFileLength( filename );
  292. PathCombine( filename, folder, filename );
  293. this->outfile = _wcsdup( filename );
  294. }
  295. }
  296. ~TranscodeItem()
  297. {
  298. free( outfile ); freeRecord( &ice );
  299. }
  300. };
  301. void getViewport( RECT *r, HWND wnd, int full, RECT *sr )
  302. {
  303. POINT *p = NULL;
  304. if ( p || sr || wnd )
  305. {
  306. HMONITOR hm = NULL;
  307. if ( sr )
  308. hm = MonitorFromRect( sr, MONITOR_DEFAULTTONEAREST );
  309. else if ( wnd )
  310. hm = MonitorFromWindow( wnd, MONITOR_DEFAULTTONEAREST );
  311. else if ( p )
  312. hm = MonitorFromPoint( *p, MONITOR_DEFAULTTONEAREST );
  313. if ( hm )
  314. {
  315. MONITORINFOEX mi;
  316. memset( &mi, 0, sizeof( mi ) );
  317. mi.cbSize = sizeof( mi );
  318. if ( GetMonitorInfoW( hm, &mi ) )
  319. {
  320. if ( !full )
  321. *r = mi.rcWork;
  322. else
  323. *r = mi.rcMonitor;
  324. return;
  325. }
  326. }
  327. }
  328. if ( full )
  329. { // this might be borked =)
  330. r->top = r->left = 0;
  331. r->right = GetSystemMetrics( SM_CXSCREEN );
  332. r->bottom = GetSystemMetrics( SM_CYSCREEN );
  333. }
  334. else
  335. {
  336. SystemParametersInfoW( SPI_GETWORKAREA, 0, r, 0 );
  337. }
  338. }
  339. BOOL windowOffScreen( HWND hwnd, POINT pt )
  340. {
  341. RECT r = { 0 }, wnd = { 0 }, sr = { 0 };
  342. GetWindowRect( hwnd, &wnd );
  343. sr.left = pt.x;
  344. sr.top = pt.y;
  345. sr.right = sr.left + ( wnd.right - wnd.left );
  346. sr.bottom = sr.top + ( wnd.bottom - wnd.top );
  347. getViewport( &r, hwnd, 0, &sr );
  348. return !PtInRect( &r, pt );
  349. }
  350. bool transcoding = false;
  351. bool transcoderIdle = false;
  352. int totalItems = 0;
  353. int itemsDone = 0;
  354. int itemsFailed = 0;
  355. static BOOL CALLBACK transcode_dlgproc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam)
  356. {
  357. static convertFileStructW * cfs;
  358. switch(uMsg)
  359. {
  360. case WM_INITDIALOG:
  361. {
  362. transcoderWnd = hwndDlg;
  363. cfs = (convertFileStructW *)calloc(1, sizeof(convertFileStructW));
  364. SendDlgItemMessage(hwndDlg,IDC_TRACKPROGRESS,PBM_SETRANGE32,0,100);
  365. SendDlgItemMessage(hwndDlg,IDC_TOTALPROGRESS,PBM_SETRANGE32,0,totalItems*100);
  366. SendDlgItemMessage(hwndDlg,IDC_TRACKPROGRESS,PBM_SETPOS,0,0);
  367. SendDlgItemMessage(hwndDlg,IDC_TOTALPROGRESS,PBM_SETPOS,0,0);
  368. PostMessage(hwndDlg,WM_TRANSCODE_START,0,0);
  369. // show edit info window and restore last position as applicable
  370. POINT pt = {GetPrivateProfileInt(L"transcoder", L"convert_x", -1, inifile),
  371. GetPrivateProfileInt(L"transcoder", L"convert_y", -1, inifile)};
  372. if (!windowOffScreen(hwndDlg, pt))
  373. SetWindowPos(hwndDlg, HWND_TOP, pt.x, pt.y, 0, 0, SWP_NOSIZE | SWP_SHOWWINDOW | SWP_NOSENDCHANGING);
  374. else
  375. ShowWindow(hwndDlg, SW_SHOWNA);
  376. }
  377. break;
  378. case WM_TRANSCODE_START:
  379. for(;;)
  380. {
  381. TranscodeItem * t = (TranscodeItem *)transcodeQueue.Peek();
  382. if(!t)
  383. {
  384. SetDlgItemText(hwndDlg,IDC_ABORT,WASABI_API_LNGSTRINGW(IDS_DONE));
  385. SendMessage(transcoderWnd,WM_TRANSCODE_UPDATEUI,0,0);
  386. transcoderIdle=true;
  387. return 0;
  388. }
  389. transcoderIdle=false;
  390. RecursiveCreateDirectory(t->outfile);
  391. ZeroMemory(cfs,sizeof(*cfs));
  392. cfs->callbackhwnd = hwndDlg;
  393. cfs->sourcefile = t->ice.filename;
  394. cfs->destfile = t->outfile;
  395. cfs->destformat[0] = t->fourcc;
  396. //cfs->destformat[1] = 44100;
  397. //cfs->destformat[2] = 16;
  398. //cfs->destformat[3] = 2;
  399. cfs->destformat[6] = mmioFOURCC('I','N','I',' ');
  400. cfs->destformat[7] = (intptr_t)inifileA;
  401. cfs->error = L"";
  402. SendDlgItemMessage(hwndDlg,IDC_TRACKPROGRESS,PBM_SETPOS,0,0);
  403. wchar_t buf[1024] = {0};
  404. StringCchPrintf(buf, 1024, L"%s - %s", t->ice.artist?t->ice.artist:L"", t->ice.title?t->ice.title:L"");
  405. SetDlgItemText(hwndDlg,IDC_CURRENTTRACK,buf);
  406. if(SendMessage(plugin.hwndWinampParent,WM_WA_IPC,(WPARAM)cfs,IPC_CONVERTFILEW)) break;
  407. else
  408. {
  409. if (cfs->error && *cfs->error)
  410. {
  411. MessageBox(hwndDlg, cfs->error, WASABI_API_LNGSTRINGW(IDS_TRANSCODING_FAILED), MB_ICONWARNING | MB_OK);
  412. }
  413. delete (TranscodeItem*)transcodeQueue.Poll();
  414. itemsDone++; itemsFailed++;
  415. }
  416. }
  417. case WM_TRANSCODE_ADD: // update totals, stuff added to queue
  418. SetWindowPos(hwndDlg,HWND_TOP,0,0,0,0,SWP_NOSIZE|SWP_NOMOVE);
  419. if(transcoderIdle)
  420. {
  421. SetDlgItemText(hwndDlg,IDC_ABORT,WASABI_API_LNGSTRINGW(IDS_ABORT));
  422. SendMessage(hwndDlg,WM_TRANSCODE_START,0,0);
  423. return 0;
  424. } // else update UI
  425. case WM_TRANSCODE_UPDATEUI:
  426. {
  427. SendDlgItemMessage(hwndDlg,IDC_TOTALPROGRESS,PBM_SETRANGE32,0,totalItems*100);
  428. SendDlgItemMessage(hwndDlg,IDC_TOTALPROGRESS,PBM_SETPOS,itemsDone*100,0);
  429. wchar_t buf[100] = {0};
  430. StringCchPrintfW(buf, 100, WASABI_API_LNGSTRINGW(IDS_TRACKS_DONE_REMAINING_FAILED),
  431. itemsDone-itemsFailed, totalItems-itemsDone, itemsFailed);
  432. SetDlgItemText(hwndDlg,IDC_TOTALCAPTION,buf);
  433. }
  434. break;
  435. case WM_WA_IPC:
  436. switch(lParam)
  437. {
  438. case IPC_CB_CONVERT_STATUS:
  439. if(wParam >= 0 && wParam <= 100)
  440. {
  441. SendDlgItemMessage(hwndDlg,IDC_TOTALPROGRESS,PBM_SETPOS,(int)wParam + itemsDone*100,0);
  442. SendDlgItemMessage(hwndDlg,IDC_TRACKPROGRESS,PBM_SETPOS,(int)wParam,0);
  443. }
  444. break;
  445. case IPC_CB_CONVERT_DONE:
  446. {
  447. SendDlgItemMessage(hwndDlg,IDC_TRACKPROGRESS,PBM_SETPOS,100,0);
  448. TranscodeItem * t = (TranscodeItem*)transcodeQueue.Poll();
  449. itemsDone++;
  450. cfs->callbackhwnd=NULL;
  451. SendMessage(plugin.hwndWinampParent,WM_WA_IPC,(WPARAM)cfs,IPC_CONVERTFILEW_END);
  452. copyTags(&t->ice,t->outfile);
  453. if (AGAVE_API_STATS)
  454. {
  455. AGAVE_API_STATS->IncrementStat(api_stats::TRANSCODE_COUNT);
  456. AGAVE_API_STATS->SetStat(api_stats::TRANSCODE_FORMAT, t->fourcc);
  457. }
  458. delete t;
  459. PostMessage(hwndDlg,WM_TRANSCODE_START,0,0);
  460. }
  461. break;
  462. }
  463. break;
  464. case WM_COMMAND:
  465. switch (LOWORD(wParam))
  466. {
  467. case IDC_ABORT:
  468. transcode_dlgproc(hwndDlg,WM_TRANSCODE_ABORT,0,0);
  469. break;
  470. }
  471. break;
  472. case WM_CLOSE:
  473. case WM_TRANSCODE_ABORT:
  474. {
  475. transcoding = false;
  476. cfs->callbackhwnd = NULL;
  477. if(!transcoderIdle) SendMessage(plugin.hwndWinampParent,WM_WA_IPC,(WPARAM)cfs,IPC_CONVERTFILEW_END);
  478. TranscodeItem * t;
  479. while((t = (TranscodeItem*)transcodeQueue.Poll()) != NULL)
  480. {
  481. // prompt to delete incomplete conversions
  482. if(PathFileExists(t->outfile))
  483. {
  484. wchar_t title[64] = {0}, prompt[512] = {0}, file[MAX_PATH] = {0};
  485. lstrcpyn(file, t->outfile, MAX_PATH);
  486. PathStripPath(file);
  487. StringCchPrintf(prompt, 512, WASABI_API_LNGSTRINGW(IDS_REMOVE_PARTIAL_FILE), file);
  488. if(MessageBox(hwndDlg, prompt,
  489. WASABI_API_LNGSTRINGW_BUF(IDS_TRANSCODING_ABORTED, title, 64), MB_YESNO) == IDYES)
  490. {
  491. DeleteFile(t->outfile);
  492. }
  493. }
  494. delete t;
  495. }
  496. RECT rect = {0};
  497. GetWindowRect(hwndDlg, &rect);
  498. wchar_t buf[16] = {0};
  499. StringCchPrintf(buf, 16, L"%d", rect.left);
  500. WritePrivateProfileString(L"transcoder", L"convert_x", buf, inifile);
  501. StringCchPrintf(buf, 16, L"%d", rect.top);
  502. WritePrivateProfileString(L"transcoder", L"convert_y", buf, inifile);
  503. EndDialog(hwndDlg,0);
  504. itemsDone = 0;
  505. totalItems = 0;
  506. itemsFailed = 0;
  507. transcoderWnd = NULL;
  508. transcoding = false;
  509. transcoderIdle = false;
  510. free(cfs);
  511. }
  512. break;
  513. }
  514. return 0;
  515. }
  516. void startTranscoding()
  517. {
  518. if(transcoding)
  519. {
  520. totalItems++;
  521. SendMessage(transcoderWnd,WM_TRANSCODE_ADD,0,0);
  522. }
  523. else
  524. {
  525. transcoding = true;
  526. totalItems=1;
  527. WASABI_API_CREATEDIALOGW(IDD_TRANSCODE, NULL, transcode_dlgproc);
  528. }
  529. }
  530. void addTrackToTranscodeQueue(const wchar_t * track, unsigned int format, const wchar_t* filepart, const wchar_t* folder)
  531. {
  532. transcodeQueue.Offer(new TranscodeItem(format, folder, filepart, track));
  533. startTranscoding();
  534. }
  535. void addTrackToTranscodeQueue(itemRecordW * track, unsigned int format, const wchar_t* filepart, const wchar_t* folder)
  536. {
  537. transcodeQueue.Offer(new TranscodeItem(format, folder, filepart, track));
  538. startTranscoding();
  539. }
  540. static void fourccToString(unsigned int f, wchar_t * str, int str_len)
  541. {
  542. char s[4] = {(char)(f&0xFF),(char)((f>>8)&0xFF),(char)((f>>16)&0xFF),0};
  543. StringCchCopy(str, str_len, AutoWide(s));
  544. CharLower(str);
  545. }
  546. wchar_t* GetDefaultSaveToFolder(wchar_t* path_to_store)
  547. {
  548. if(FAILED(SHGetFolderPath(NULL, CSIDL_MYMUSIC, NULL, SHGFP_TYPE_CURRENT, path_to_store)))
  549. {
  550. if(FAILED(SHGetFolderPath(NULL, CSIDL_PERSONAL, NULL, SHGFP_TYPE_CURRENT, path_to_store)))
  551. {
  552. // and if that all fails then do a reasonable default
  553. lstrcpyn(path_to_store, L"C:\\My Music", MAX_PATH);
  554. }
  555. // if there's no valid My Music folder (typically win2k) then default to %my_documents%\my music
  556. else
  557. {
  558. PathCombine(path_to_store, path_to_store, L"My Music");
  559. }
  560. }
  561. return path_to_store;
  562. }
  563. DWORD GetPrivateProfileStringUTF8(LPCSTR lpAppName, LPCSTR lpKeyName, LPCSTR lpDefault, LPTSTR lpReturnedString, DWORD nSize, LPCSTR lpFileName)
  564. {
  565. char utf8_text[2048] = {0};
  566. GetPrivateProfileStringA(lpAppName,lpKeyName,lpDefault,utf8_text, 2048, lpFileName);
  567. return MultiByteToWideCharSZ(CP_UTF8, 0, utf8_text, -1, lpReturnedString, nSize);
  568. }
  569. BOOL WritePrivateProfileStringUTF8(LPCSTR lpAppName, LPCSTR lpKeyName, LPCTSTR lpString, LPCSTR lpFileName)
  570. {
  571. return WritePrivateProfileStringA(lpAppName, lpKeyName, AutoChar(lpString, CP_UTF8), lpFileName);
  572. }
  573. class EncodableFormat
  574. {
  575. public:
  576. unsigned int fourcc;
  577. wchar_t *desc;
  578. EncodableFormat(unsigned int fourcc,wchar_t *desc) :
  579. fourcc(fourcc) {this->desc = _wcsdup(desc);}
  580. ~EncodableFormat() {free(desc);}
  581. };
  582. static void enumProc(intptr_t user_data, const char *desc, int fourcc) {
  583. ((C_ItemList*)user_data)->Add(new EncodableFormat((unsigned int)fourcc,AutoWide(desc)));
  584. }
  585. static void BuildEncodableFormatsList(C_ItemList * list, HWND winampWindow,wchar_t * inifile) {
  586. converterEnumFmtStruct e = {enumProc,(intptr_t)list};
  587. SendMessage(winampWindow,WM_WA_IPC,(WPARAM)&e,IPC_CONVERT_CONFIG_ENUMFMTS);
  588. }
  589. unsigned int transcodeGatherSettings(wchar_t *format, wchar_t *folder, int format_len, HWND parent)
  590. {
  591. if(GetPrivateProfileInt(L"transcoder",L"showconf",1,inifile))
  592. if(!transcodeConfig(parent))
  593. return 0;
  594. wchar_t tmp[MAX_PATH] = {0};
  595. GetPrivateProfileStringUTF8("transcoder", "fileformat","<Artist> - <Album>\\## - <Title>",format,1024,inifileA);
  596. GetPrivateProfileStringUTF8("transcoder", "fileroot", AutoChar(GetDefaultSaveToFolder(tmp), CP_UTF8), folder, MAX_PATH, inifileA);
  597. unsigned int fourcc = GetPrivateProfileInt(L"transcoder",L"format",mmioFOURCC('A','A','C','f'),inifile);
  598. char extA[8]=".";
  599. convertConfigItem c = {fourcc,"extension",&extA[1],7,inifileA};
  600. if(!SendMessage(plugin.hwndWinampParent,WM_WA_IPC,(WPARAM)&c,IPC_CONVERT_CONFIG_GET_ITEM))
  601. {
  602. // if there was an error, see if it's from an invalid fourcc and try to fallback
  603. C_ItemList * formats = new C_ItemList;
  604. BuildEncodableFormatsList(formats,plugin.hwndWinampParent,inifile);
  605. bool doFail = false;
  606. for(int i=0; i < formats->GetSize(); i++) {
  607. EncodableFormat * f = (EncodableFormat *)formats->Get(i);
  608. // if it exists then abort and fail as prior behaviour
  609. if(f->fourcc == fourcc)
  610. {
  611. doFail = true;
  612. break;
  613. }
  614. }
  615. if(!doFail)
  616. {
  617. fourcc = mmioFOURCC('A','A','C','f');
  618. c.format = fourcc;
  619. SendMessage(plugin.hwndWinampParent,WM_WA_IPC,(WPARAM)&c,IPC_CONVERT_CONFIG_GET_ITEM);
  620. }
  621. }
  622. if(extA[1]) StringCchCat(format, format_len, AutoWide(extA));
  623. else
  624. {
  625. wchar_t ext[8]=L".";
  626. fourccToString(fourcc,&ext[1], 8);
  627. StringCchCat(format, format_len, ext);
  628. }
  629. return fourcc;
  630. }
  631. void transcode( PtrListWCharPtr &filenames, HWND parent )
  632. {
  633. wchar_t format[ 2048 ] = { 0 }, folder[ MAX_PATH ] = { 0 };
  634. unsigned int fourcc = transcodeGatherSettings( format, folder, 2048, parent );
  635. if ( !fourcc )
  636. return;
  637. for ( const wchar_t *l_filename : filenames )
  638. addTrackToTranscodeQueue( l_filename, fourcc, format, folder );
  639. }
  640. void transcode(const itemRecordListW *ice, HWND parent)
  641. {
  642. wchar_t format[2048] = {0}, folder[MAX_PATH] = {0};
  643. unsigned int fourcc = transcodeGatherSettings(format, folder, 2048, parent);
  644. if(!fourcc) return;
  645. for(int i=0; i < ice->Size; i++) {
  646. addTrackToTranscodeQueue(&ice->Items[i],fourcc,format,folder);
  647. }
  648. }
  649. static void FreeEncodableFormatsList(C_ItemList * list) {
  650. int l = list->GetSize();
  651. while(--l >= 0) {
  652. delete ((EncodableFormat*)list->Get(l));
  653. list->Del(l);
  654. }
  655. }
  656. static void doConfigResizeChild(HWND parent, HWND child) {
  657. if (child) {
  658. RECT r;
  659. GetWindowRect(GetDlgItem(parent, IDC_ENC_CONFIG), &r);
  660. ScreenToClient(parent, (LPPOINT)&r);
  661. SetWindowPos(child, 0, r.left, r.top, 0, 0, SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER);
  662. ShowWindow(child, SW_SHOW);
  663. }
  664. }
  665. BOOL CALLBACK browseEnumProc(HWND hwnd, LPARAM lParam)
  666. {
  667. wchar_t cl[32] = {0};
  668. GetClassNameW(hwnd, cl, ARRAYSIZE(cl));
  669. if (!lstrcmpiW(cl, WC_TREEVIEW))
  670. {
  671. PostMessage(hwnd, TVM_ENSUREVISIBLE, 0, (LPARAM)TreeView_GetSelection(hwnd));
  672. return FALSE;
  673. }
  674. return TRUE;
  675. }
  676. int CALLBACK WINAPI BrowseCallbackProc(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData)
  677. {
  678. if(uMsg == BFFM_INITIALIZED)
  679. {
  680. wchar_t buf[4096]=L"";
  681. GetDlgItemText((HWND)lpData,IDC_ROOTDIR,buf,sizeof(buf)/sizeof(wchar_t));
  682. SendMessageW(hwnd, BFFM_SETSELECTIONW, 1, (LPARAM)buf);
  683. SetWindowText(hwnd,WASABI_API_LNGSTRINGW(IDS_SELECT_WHERE_TO_SAVE));
  684. // this is not nice but it fixes the selection not working correctly on all OSes
  685. EnumChildWindows(hwnd, browseEnumProc, 0);
  686. }
  687. return 0;
  688. }
  689. static BOOL CALLBACK config_dlgproc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam)
  690. {
  691. static C_ItemList * formats;
  692. static convertConfigStruct * ccs;
  693. switch (uMsg)
  694. {
  695. case WM_INITDIALOG:
  696. {
  697. bool usefn = !!GetPrivateProfileInt(L"transcoder", L"usefilename",0,inifile);
  698. if(GetPrivateProfileInt(L"transcoder", L"showconf", 1, inifile)) CheckDlgButton(hwndDlg,IDC_SHOWEVERY,BST_CHECKED);
  699. if(usefn) CheckDlgButton(hwndDlg,IDC_USE_FILENAME,BST_CHECKED);
  700. EnableWindow(GetDlgItem(hwndDlg, IDC_ROOTDIR),!usefn);
  701. EnableWindow(GetDlgItem(hwndDlg, IDC_BROWSE),!usefn);
  702. EnableWindow(GetDlgItem(hwndDlg, IDC_NAMING),!usefn);
  703. EnableWindow(GetDlgItem(hwndDlg, IDC_FORMATHELP),!usefn);
  704. wchar_t buf[4096]=L"", tmp[MAX_PATH]=L"";
  705. GetPrivateProfileStringUTF8("transcoder", "fileformat","<Artist> - <Album>\\## - <Title>",buf,4096,inifileA);
  706. SetDlgItemText(hwndDlg,IDC_NAMING,buf);
  707. GetPrivateProfileStringUTF8("transcoder", "fileroot", AutoChar(GetDefaultSaveToFolder(tmp), CP_UTF8), buf, 4096, inifileA);
  708. SetDlgItemText(hwndDlg,IDC_ROOTDIR,buf);
  709. formats = new C_ItemList;
  710. BuildEncodableFormatsList(formats,plugin.hwndWinampParent,inifile);
  711. ccs = (convertConfigStruct *)calloc(sizeof(convertConfigStruct),1);
  712. ccs->extra_data[6] = mmioFOURCC('I','N','I',' ');
  713. ccs->extra_data[7] = (int)inifileA;
  714. ccs->hwndParent = hwndDlg;
  715. ccs->format = GetPrivateProfileInt(L"transcoder",L"format",mmioFOURCC('A','A','C','f'),inifile);
  716. for(int i=0; i < formats->GetSize(); i++) {
  717. EncodableFormat * f = (EncodableFormat *)formats->Get(i);
  718. int a = SendDlgItemMessage(hwndDlg, IDC_ENCFORMAT, CB_ADDSTRING, 0, (LPARAM)f->desc);
  719. SendDlgItemMessage(hwndDlg, IDC_ENCFORMAT, CB_SETITEMDATA, (WPARAM)a, (LPARAM)f);
  720. if(f->fourcc == ccs->format)
  721. SendDlgItemMessage(hwndDlg, IDC_ENCFORMAT, CB_SETCURSEL, (WPARAM)a, 0);
  722. }
  723. // if there is no selection then force things to the correct default
  724. if(SendDlgItemMessage(hwndDlg, IDC_ENCFORMAT, CB_GETCURSEL, (WPARAM)0, 0) == CB_ERR) {
  725. for(int i=0; i < SendDlgItemMessage(hwndDlg, IDC_ENCFORMAT, CB_GETCOUNT, 0, 0); i++) {
  726. EncodableFormat * f = (EncodableFormat *)SendDlgItemMessage(hwndDlg, IDC_ENCFORMAT, CB_GETITEMDATA, (WPARAM)i, 0);
  727. if(f->fourcc == mmioFOURCC('A','A','C','f')) {
  728. ccs->format = f->fourcc;
  729. SendDlgItemMessage(hwndDlg, IDC_ENCFORMAT, CB_SETCURSEL, (WPARAM)i, 0);
  730. break;
  731. }
  732. }
  733. }
  734. HWND h = (HWND)SendMessage(plugin.hwndWinampParent, WM_WA_IPC, (WPARAM)ccs, IPC_CONVERT_CONFIG);
  735. doConfigResizeChild(hwndDlg, h);
  736. // show config window and restore last position as applicable
  737. POINT pt = {GetPrivateProfileInt(L"transcoder", L"showconf_x", -1, inifile),
  738. GetPrivateProfileInt(L"transcoder", L"showconf_y", -1, inifile)};
  739. if (!windowOffScreen(hwndDlg, pt))
  740. SetWindowPos(hwndDlg, HWND_TOP, pt.x, pt.y, 0, 0, SWP_NOSIZE | SWP_SHOWWINDOW | SWP_NOSENDCHANGING);
  741. }
  742. break;
  743. case WM_DESTROY:
  744. {
  745. SendMessage(plugin.hwndWinampParent, WM_WA_IPC, (WPARAM)ccs, IPC_CONVERT_CONFIG_END);
  746. free(ccs); ccs=0;
  747. FreeEncodableFormatsList(formats);
  748. delete formats; formats=0;
  749. }
  750. break;
  751. case WM_COMMAND:
  752. switch (LOWORD(wParam))
  753. {
  754. case IDC_USE_FILENAME:
  755. {
  756. bool usefn = IsDlgButtonChecked(hwndDlg,IDC_USE_FILENAME)!=0;
  757. EnableWindow(GetDlgItem(hwndDlg, IDC_ROOTDIR),!usefn);
  758. EnableWindow(GetDlgItem(hwndDlg, IDC_BROWSE),!usefn);
  759. EnableWindow(GetDlgItem(hwndDlg, IDC_NAMING),!usefn);
  760. EnableWindow(GetDlgItem(hwndDlg, IDC_FORMATHELP),!usefn);
  761. }
  762. break;
  763. case IDC_ENCFORMAT:
  764. if (HIWORD(wParam) != CBN_SELCHANGE) return 0;
  765. {
  766. int sel = SendDlgItemMessage(hwndDlg, IDC_ENCFORMAT, CB_GETCURSEL, 0, 0);
  767. if (sel != CB_ERR)
  768. {
  769. SendMessage(plugin.hwndWinampParent, WM_WA_IPC, (WPARAM)ccs, IPC_CONVERT_CONFIG_END);
  770. EncodableFormat * f = (EncodableFormat *)SendDlgItemMessage(hwndDlg, IDC_ENCFORMAT, CB_GETITEMDATA, sel, 0);
  771. ccs->format = f->fourcc;
  772. HWND h = (HWND)SendMessage(plugin.hwndWinampParent, WM_WA_IPC, (WPARAM)ccs, IPC_CONVERT_CONFIG);
  773. doConfigResizeChild(hwndDlg, h);
  774. }
  775. }
  776. break;
  777. case IDC_FORMATHELP:
  778. {
  779. wchar_t titleStr[64] = {0};
  780. MessageBox(hwndDlg,WASABI_API_LNGSTRINGW(IDS_FILENAME_FORMAT_HELP),
  781. WASABI_API_LNGSTRINGW_BUF(IDS_FILENAME_FORMAT_HELP_TITLE,titleStr,64), MB_OK);
  782. break;
  783. }
  784. case IDC_BROWSE:
  785. {
  786. BROWSEINFO bi = {0};
  787. LPMALLOC lpm = 0;
  788. wchar_t bffFileName[MAX_PATH] = {0};
  789. bi.hwndOwner = hwndDlg;
  790. bi.pszDisplayName = bffFileName;
  791. bi.lpszTitle = WASABI_API_LNGSTRINGW(IDS_CHOOSE_FOLDER);
  792. bi.ulFlags = BIF_RETURNONLYFSDIRS | BIF_EDITBOX | BIF_NEWDIALOGSTYLE;
  793. bi.lpfn = BrowseCallbackProc;
  794. bi.lParam = (LPARAM)hwndDlg;
  795. LPITEMIDLIST iil = SHBrowseForFolder(&bi);
  796. if(iil)
  797. {
  798. SHGetPathFromIDList(iil,bffFileName);
  799. SHGetMalloc(&lpm);
  800. lpm->Free(iil);
  801. SetDlgItemText(hwndDlg, IDC_ROOTDIR, bffFileName);
  802. }
  803. }
  804. break;
  805. case IDOK:
  806. case IDCANCEL:
  807. {
  808. DWORD fourcc=0;
  809. if (LOWORD(wParam) == IDOK)
  810. {
  811. wchar_t buf[4096]=L"";
  812. GetDlgItemText(hwndDlg,IDC_NAMING,buf,sizeof(buf)/sizeof(wchar_t));
  813. WritePrivateProfileStringUTF8("transcoder","fileformat",buf,inifileA);
  814. GetDlgItemText(hwndDlg,IDC_ROOTDIR,buf,sizeof(buf)/sizeof(wchar_t));
  815. WritePrivateProfileStringUTF8("transcoder","fileroot",buf,inifileA);
  816. WritePrivateProfileString(L"transcoder",L"showconf",IsDlgButtonChecked(hwndDlg,IDC_SHOWEVERY)?L"1":L"0",inifile);
  817. WritePrivateProfileString(L"transcoder",L"usefilename",IsDlgButtonChecked(hwndDlg,IDC_USE_FILENAME)?L"1":L"0",inifile);
  818. LRESULT esel = SendDlgItemMessage(hwndDlg, IDC_ENCFORMAT, CB_GETCURSEL, 0, 0);
  819. if (esel!=CB_ERR)
  820. {
  821. LRESULT data = SendDlgItemMessage(hwndDlg, IDC_ENCFORMAT, CB_GETITEMDATA, esel, 0);
  822. if (data != CB_ERR)
  823. {
  824. EncodableFormat * f = (EncodableFormat *)data;
  825. StringCchPrintf(buf, 4096, L"%d", f->fourcc);
  826. WritePrivateProfileString(L"transcoder",L"format",buf,inifile);
  827. fourcc=f->fourcc;
  828. }
  829. }
  830. }
  831. EndDialog(hwndDlg, (LOWORD(wParam) ? fourcc : 0));
  832. RECT rect = {0};
  833. GetWindowRect(hwndDlg, &rect);
  834. wchar_t buf[16] = {0};
  835. StringCchPrintf(buf, 16, L"%d", rect.left);
  836. WritePrivateProfileString(L"transcoder", L"showconf_x", buf, inifile);
  837. StringCchPrintf(buf, 16, L"%d", rect.top);
  838. WritePrivateProfileString(L"transcoder", L"showconf_y", buf, inifile);
  839. }
  840. break;
  841. }
  842. break;
  843. }
  844. return 0;
  845. }
  846. int transcodeConfig(HWND parent) { // returns fourcc
  847. return WASABI_API_DIALOGBOXW(IDD_TRANSCODE_CONFIG, parent, config_dlgproc);
  848. }
  849. // metadata shit
  850. extern wchar_t *guessTitles(const wchar_t *filename, int *tracknum,wchar_t **artist, wchar_t **album,wchar_t **title);
  851. #define atoi_NULLOK(s) ((s)?_wtoi(s):0)
  852. void filenameToItemRecord(const wchar_t *file, itemRecordW * ice)
  853. {
  854. int gtrack=0;
  855. wchar_t *gartist=NULL,*galbum=NULL,*gtitle=NULL;
  856. wchar_t *guessbuf = guessTitles(file,&gtrack,&gartist,&galbum,&gtitle);
  857. if(!gartist) gartist=L"";
  858. if(!galbum) galbum=L"";
  859. if(!gtitle) gtitle=L"";
  860. wchar_t buf[512] = {0};
  861. AGAVE_API_METADATA->GetExtendedFileInfo(file, L"title", buf, 512);
  862. if(buf[0]) { ice->title=_wcsdup(buf); gartist=L""; galbum=L""; gtrack=-1;}
  863. else ice->title=_wcsdup(gtitle);
  864. buf[0]=0;
  865. AGAVE_API_METADATA->GetExtendedFileInfo(file, L"album", buf, 512);
  866. if(buf[0]) ice->album=_wcsdup(buf);
  867. else ice->album=_wcsdup(galbum);
  868. buf[0]=0;
  869. AGAVE_API_METADATA->GetExtendedFileInfo(file, L"artist", buf, 512);
  870. if(buf[0]) ice->artist=_wcsdup(buf);
  871. else ice->artist=_wcsdup(gartist);
  872. buf[0]=0;
  873. AGAVE_API_METADATA->GetExtendedFileInfo(file, L"albumartist", buf, 512);
  874. if(buf[0]) ice->albumartist=_wcsdup(buf);
  875. else ice->albumartist=_wcsdup(ice->artist);
  876. buf[0]=0;
  877. AGAVE_API_METADATA->GetExtendedFileInfo(file, L"track", buf, 512);
  878. if(buf[0]) ice->track=atoi_NULLOK(buf);
  879. else ice->track=gtrack;
  880. buf[0]=0;
  881. AGAVE_API_METADATA->GetExtendedFileInfo(file, L"genre", buf, 512);
  882. ice->genre=_wcsdup(buf);
  883. buf[0]=0;
  884. AGAVE_API_METADATA->GetExtendedFileInfo(file, L"comment", buf, 512);
  885. ice->comment=_wcsdup(buf);
  886. buf[0]=0;
  887. AGAVE_API_METADATA->GetExtendedFileInfo(file, L"year", buf, 512);
  888. ice->year=atoi_NULLOK(buf);
  889. basicFileInfoStructW b={0};
  890. b.filename=const_cast<wchar_t *>(file); //benski> changed extendedFileInfoStruct but not basicFileInfoStruct, i'll have to do that later so we can get rid of this cast
  891. b.quickCheck=0;
  892. SendMessage(plugin.hwndWinampParent,WM_WA_IPC,(WPARAM)&b,IPC_GET_BASIC_FILE_INFOW);
  893. ice->length=b.length;
  894. ice->filename = _wcsdup(file);
  895. free(guessbuf);
  896. }
  897. void copyTags(const itemRecordW *in, const wchar_t *out)
  898. {
  899. // check if the old file still exists - if it does, we will let Winamp copy metadata for us
  900. if (wcscmp(in->filename, out) && PathFileExists(in->filename))
  901. {
  902. copyFileInfoStructW copy;
  903. copy.dest = out;
  904. copy.source = in->filename;
  905. if (SendMessage(plugin.hwndWinampParent, WM_WA_IPC, (WPARAM)&copy, IPC_COPY_EXTENDED_FILE_INFOW) == 0) // 0 indicates success here
  906. {
  907. AGAVE_API_ALBUMART->CopyAlbumArt(in->filename, out);
  908. return;
  909. }
  910. }
  911. wchar_t buf[32] = {0}, file[MAX_PATH] = {0};
  912. StringCchCopy(file, MAX_PATH, out);
  913. extendedFileInfoStructW e = {0};
  914. e.filename=file;
  915. e.metadata=L"album";
  916. e.ret=in->album;
  917. SendMessage(plugin.hwndWinampParent,WM_WA_IPC,(WPARAM)&e,IPC_SET_EXTENDED_FILE_INFOW);
  918. e.metadata=L"artist";
  919. e.ret=in->artist;
  920. SendMessage(plugin.hwndWinampParent,WM_WA_IPC,(WPARAM)&e,IPC_SET_EXTENDED_FILE_INFOW);
  921. e.metadata=L"albumartist";
  922. e.ret=in->albumartist;
  923. SendMessage(plugin.hwndWinampParent,WM_WA_IPC,(WPARAM)&e,IPC_SET_EXTENDED_FILE_INFOW);
  924. e.metadata=L"title";
  925. e.ret=in->title;
  926. SendMessage(plugin.hwndWinampParent,WM_WA_IPC,(WPARAM)&e,IPC_SET_EXTENDED_FILE_INFOW);
  927. e.metadata=L"track";
  928. StringCchPrintf(buf, 32, L"%d", in->track);
  929. e.ret=buf;
  930. SendMessage(plugin.hwndWinampParent,WM_WA_IPC,(WPARAM)&e,IPC_SET_EXTENDED_FILE_INFOW);
  931. e.metadata=L"genre";
  932. e.ret=in->genre;
  933. SendMessage(plugin.hwndWinampParent,WM_WA_IPC,(WPARAM)&e,IPC_SET_EXTENDED_FILE_INFOW);
  934. e.metadata=L"comment";
  935. e.ret=in->comment;
  936. SendMessage(plugin.hwndWinampParent,WM_WA_IPC,(WPARAM)&e,IPC_SET_EXTENDED_FILE_INFOW);
  937. if(in->year > 0)
  938. {
  939. e.metadata=L"year";
  940. StringCchPrintf(buf, 32, L"%d", in->year);
  941. e.ret=buf;
  942. SendMessage(plugin.hwndWinampParent,WM_WA_IPC,(WPARAM)&e,IPC_SET_EXTENDED_FILE_INFOW);
  943. }
  944. SendMessage(plugin.hwndWinampParent,WM_WA_IPC,(WPARAM)&e,IPC_WRITE_EXTENDED_FILE_INFO);
  945. }
  946. extern "C" {
  947. __declspec( dllexport ) winampMediaLibraryPlugin * winampGetMediaLibraryPlugin() {
  948. return &plugin;
  949. }
  950. __declspec( dllexport ) int winampUninstallPlugin(HINSTANCE hDllInst, HWND hwndDlg, int param) {
  951. // prompt to remove our settings with default as no (just incase)
  952. wchar_t title[256] = {0};
  953. StringCchPrintf(title, 256, WASABI_API_LNGSTRINGW(IDS_NULLSOFT_FORMAT_CONVERTER), PLUGIN_VERSION);
  954. if(MessageBox(hwndDlg,WASABI_API_LNGSTRINGW(IDS_DO_YOU_ALSO_WANT_TO_REMOVE_SETTINGS),
  955. title,MB_YESNO|MB_DEFBUTTON2) == IDYES)
  956. {
  957. DeleteFile(inifile);
  958. }
  959. // if not transcoding then can remove on the fly (5.37+)
  960. if(!IsWindow(transcoderWnd)){
  961. return ML_PLUGIN_UNINSTALL_NOW;
  962. }
  963. // otherwise allow for any prompting/full restart removal (default)
  964. return ML_PLUGIN_UNINSTALL_REBOOT;
  965. }
  966. };
  967. static HWND GetDialogBoxParent()
  968. {
  969. HWND parent = (HWND)SendMessage(plugin.hwndWinampParent, WM_WA_IPC, 0, IPC_GETDIALOGBOXPARENT);
  970. if (!parent || parent == (HWND)1)
  971. return plugin.hwndWinampParent;
  972. return parent;
  973. }