usbdevice.cpp 51 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913
  1. #include "usbdevice.h"
  2. #include "resource.h"
  3. #include "usbplaylist.h"
  4. #include "usbplaylistsaver.h"
  5. #include "api.h"
  6. #include "../winamp/wa_ipc.h"
  7. #include <tataki/bitmap/bitmap.h>
  8. #include <tataki/canvas/bltcanvas.h>
  9. #include <shlobj.h>
  10. #include <strsafe.h>
  11. #include <shlwapi.h>
  12. // from main.cpp
  13. extern PMPDevicePlugin plugin;
  14. extern std::vector<USBDevice*> devices;
  15. extern bool loading_devices[26];
  16. // from utils.cpp
  17. extern BOOL RecursiveCreateDirectory(wchar_t* buf);
  18. extern bool supportedFormat(wchar_t * file, wchar_t * supportedFormats);
  19. extern DeviceType detectDeviceType(wchar_t drive);
  20. extern __int64 fileSize(wchar_t * filename);
  21. extern void removebadchars(wchar_t *s);
  22. extern wchar_t * fixReplacementVars(wchar_t *str, int str_size, Device * dev, songid_t song);
  23. static INT_PTR CALLBACK prefs_dialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam);
  24. int CopyFile(const wchar_t *infile, const wchar_t *outfile, void * callbackContext, void (*callback)(void * callbackContext, wchar_t * status), int * killswitch);
  25. // called from ml_pmp
  26. extern BOOL EjectVolume(TCHAR cDriveLetter);
  27. void CopyAlbumArt(const wchar_t *source, const wchar_t *destination);
  28. __int64 USBDevice::getDeviceCapacityAvailable() // in bytes
  29. {
  30. ULARGE_INTEGER tfree={0,}, total={0,}, freeb={0,};
  31. wchar_t path[4]=L"x:\\";
  32. path[0]=drive;
  33. GetDiskFreeSpaceEx(path, &tfree, &total, &freeb);
  34. return freeb.QuadPart;
  35. }
  36. // called from ml_pmp
  37. __int64 USBDevice::getDeviceCapacityTotal()
  38. {
  39. // in bytes
  40. ULARGE_INTEGER tfree={0,}, total={0,}, freeb={0,};
  41. wchar_t path[4]=L"x:\\";
  42. path[0]=drive;
  43. GetDiskFreeSpaceEx(path, &tfree, &total, &freeb);
  44. return total.QuadPart;
  45. }
  46. // called from ml_pmp
  47. void USBDevice::Eject()
  48. {
  49. // if you ejected successfully, you MUST call PMP_IPC_DEVICEDISCONNECTED and delete this
  50. for(size_t i=0; i < devices.size(); i++)
  51. {
  52. USBDevice *device = devices.at(i);
  53. if (device == this)
  54. {
  55. if (EjectVolume(drive))
  56. {
  57. devices.erase(devices.begin() + i);
  58. SendMessage(plugin.hwndPortablesParent,WM_PMP_IPC,(intptr_t)this,PMP_IPC_DEVICEDISCONNECTED);
  59. delete this;
  60. break;
  61. }
  62. else
  63. {
  64. wchar_t titleStr[128] = {0};
  65. MessageBox(plugin.hwndLibraryParent,WASABI_API_LNGSTRINGW(IDS_FAILED_TO_EJECT_DRIVE), WASABI_API_LNGSTRINGW_BUF(IDS_ERROR,titleStr,128),0);
  66. break;
  67. }
  68. }
  69. }
  70. }
  71. // called from ml_pmp
  72. void USBDevice::Close()
  73. {
  74. // save any changes, and call PMP_IPC_DEVICEDISCONNECTED AND delete this
  75. for(size_t i=0; i < devices.size(); i++)
  76. {
  77. if(((USBDevice*)devices.at(i)) == this)
  78. {
  79. devices.erase(devices.begin() + i);
  80. SendMessage(plugin.hwndPortablesParent,WM_PMP_IPC,(intptr_t)this,PMP_IPC_DEVICEDISCONNECTED);
  81. delete this;
  82. break;
  83. }
  84. }
  85. }
  86. // called from ml_pmp
  87. // return 0 for success, -1 for failed or cancelled
  88. int USBDevice::transferTrackToDevice(const itemRecordW * track, // the track to transfer
  89. void * callbackContext, //pass this to the callback
  90. void (*callback)(void *callbackContext, wchar_t *status), // call this every so often so the GUI can be updated. Including when finished!
  91. songid_t * songid, // fill in the songid when you are finished
  92. int * killswitch) // if this gets set to anything other than zero, the transfer has been cancelled by the user
  93. {
  94. wchar_t fn[MAX_PATH] = L"X:\\";
  95. lstrcpyn(fn, songFormat, MAX_PATH);
  96. fn[0] = drive;
  97. wchar_t * src = track->filename;
  98. wchar_t ext[10] = {0};
  99. wchar_t *e = wcsrchr(src,L'.');
  100. if (e) lstrcpyn(ext, e, 10);
  101. bool transcodefile = false;
  102. if (transcoder && transcoder->ShouldTranscode(src))
  103. {
  104. int r = transcoder->CanTranscode(src, ext);
  105. if (r != 0 && r != -1) transcodefile = true;
  106. }
  107. UsbSong *s = new UsbSong();
  108. lstrcpyn(s->filename, src, MAX_PATH); //this will get written over, but for now we have this so that the user can keep the old filename
  109. fillMetaData(s); // TODO: benski> used cached info inside track (itemRecordW) if available
  110. fixReplacementVars(fn, MAX_PATH, this, (songid_t)s);
  111. StringCchCat(fn, MAX_PATH, ext); //place extension
  112. StringCchCopy(s->filename, MAX_PATH, fn);
  113. wchar_t * dir = wcsrchr(fn,L'\\');
  114. wchar_t * dir2 = wcsrchr(fn,L'/');
  115. wchar_t slash;
  116. if (dir2 > dir)
  117. {
  118. dir = dir2;
  119. slash=L'/';
  120. }
  121. else slash = L'\\';
  122. if (dir) *dir = 0;
  123. RecursiveCreateDirectory(fn);
  124. if (dir) *dir = slash;
  125. int r;
  126. if (transcodefile)
  127. {
  128. r = transcoder->TranscodeFile(src, fn, killswitch, callback, callbackContext);
  129. }
  130. else
  131. {
  132. r = CopyFile(src, fn, callbackContext, callback, killswitch);
  133. }
  134. if (r == 0)
  135. {
  136. // TODO: benski> do we need to update any fields from the transcoded filed?
  137. CopyAlbumArt(src, fn);
  138. writeRecordToDB(s);
  139. callback(callbackContext, WASABI_API_LNGSTRINGW(IDS_DONE));
  140. *songid = (songid_t)s;
  141. }
  142. else
  143. {
  144. callback(callbackContext, WASABI_API_LNGSTRINGW(IDS_TRANSFER_FAILED));
  145. delete s;
  146. }
  147. return r;
  148. }
  149. // called from ml_pmp
  150. int USBDevice::trackAddedToTransferQueue(const itemRecordW *track)
  151. {
  152. // return 0 to accept, -1 for "not enough space", -2 for "incorrect format"
  153. __int64 k = getTrackSizeOnDevice(track);
  154. if(!k) return -2;
  155. __int64 l = (__int64)k;
  156. __int64 avail = getDeviceCapacityAvailable();
  157. __int64 cmp = transferQueueLength;
  158. cmp += l;
  159. if(cmp > avail) return -1;
  160. else {
  161. transferQueueLength += l;
  162. return 0;
  163. }
  164. }
  165. // called from ml_pmp
  166. void USBDevice::trackRemovedFromTransferQueue(const itemRecordW *track)
  167. {
  168. transferQueueLength -= (__int64)getTrackSizeOnDevice(track);
  169. }
  170. // called from ml_pmp
  171. // return the amount of space that will be taken up on the device by the track (once it has been tranferred)
  172. // or 0 for incompatable. This is usually the filesize, unless you are transcoding. An estimate is acceptable.
  173. __int64 USBDevice::getTrackSizeOnDevice(const itemRecordW *track)
  174. {
  175. if(transcoder) {
  176. if(transcoder->ShouldTranscode(track->filename)) {
  177. int k = transcoder->CanTranscode(track->filename);
  178. if(k != -1 && k != 0) return k;
  179. return 0;
  180. } else return fileSize(track->filename);
  181. } else {
  182. if(!supportedFormat(track->filename,supportedFormats)) return 0;
  183. return fileSize(track->filename);
  184. }
  185. }
  186. // called from ml_pmp
  187. void USBDevice::deleteTrack(songid_t songid)
  188. {
  189. // physically remove from device. Be sure to remove it from all the playlists!
  190. UsbSong * s = (UsbSong*)songid;
  191. //errno == 2 is ENOENT
  192. if(!_wunlink(s->filename) || errno == 2) { //will continue delete if file was deleted successfully or file path does not exist in the first place (errno==2)
  193. for(size_t i=0; i < usbPlaylists.size(); i++) {
  194. USBPlaylist * pl = usbPlaylists.at(i);
  195. size_t l = pl->songs.size();
  196. while(l--)
  197. {
  198. if(((UsbSong*)pl->songs.at(l)) == s)
  199. {
  200. // remove the track and rewrite the playlist
  201. removeTrackFromPlaylist((int)i, (int)l);
  202. }
  203. }
  204. if(purgeFolders[0]=='1')
  205. {
  206. RemoveDirectory(s->filename);
  207. }
  208. }
  209. delete (UsbSong*)songid;
  210. } else {
  211. char titleStr[32] = {0};
  212. MessageBoxA(plugin.hwndLibraryParent,WASABI_API_LNGSTRING(IDS_TRACK_IN_USE),
  213. WASABI_API_LNGSTRING_BUF(IDS_ERROR,titleStr,32),0);
  214. }
  215. }
  216. // called from ml_pmp
  217. // optional. Will be called at a good time to save changes
  218. void USBDevice::commitChanges()
  219. {
  220. //update cache
  221. tag();
  222. cacheUpToDate = true;
  223. SendMessage(plugin.hwndWinampParent,WM_WA_IPC,(WPARAM)0,IPC_WRITE_EXTENDED_FILE_INFO);
  224. }
  225. // called from ml_pmp
  226. int USBDevice::getPlaylistCount()
  227. {
  228. // always at least 1. playlistnumber 0 is the Master Playlist containing all tracks.
  229. return (int)usbPlaylists.size();
  230. }
  231. // called from ml_pmp
  232. // PlaylistName(0) should return the name of the device.
  233. void USBDevice::getPlaylistName(int playlistnumber, wchar_t *buf, int len)
  234. {
  235. wchar_t * pathName = usbPlaylists.at(playlistnumber)->filename;
  236. if(playlistnumber != 0)
  237. {
  238. if(pathName[0])
  239. {
  240. wchar_t * playlistName = PathFindFileNameW(pathName);
  241. lstrcpyn(buf,playlistName,len);
  242. PathRemoveExtension(buf);
  243. }
  244. }
  245. else //playlist number = 0 -> this is the device
  246. {
  247. if(pathName[0])
  248. { //if we have a custom device name
  249. lstrcpyn(buf,pathName,len);
  250. }
  251. else
  252. {
  253. WASABI_API_LNGSTRINGW_BUF(IDS_USB_DRIVE_X,buf,len);
  254. wchar_t * x = wcsrchr(buf,L'X');
  255. if(x) *x = drive;
  256. }
  257. }
  258. }
  259. // called from ml_pmp
  260. int USBDevice::getPlaylistLength(int playlistnumber)
  261. {
  262. return (int)usbPlaylists.at(playlistnumber)->songs.size();
  263. }
  264. // called from ml_pmp
  265. songid_t USBDevice::getPlaylistTrack(int playlistnumber,int songnum)
  266. {
  267. // returns a songid
  268. return (songid_t) usbPlaylists.at(playlistnumber)->songs.at(songnum);
  269. }
  270. // called from ml_pmp
  271. void USBDevice::setPlaylistName(int playlistnumber, const wchar_t *buf)
  272. {
  273. // with playlistnumber==0, set the name of the device.
  274. USBPlaylist * pl = usbPlaylists.at(playlistnumber);
  275. if(playlistnumber==0)
  276. {
  277. WritePrivateProfileString(L"pmp_usb",L"customName",buf,iniFile);
  278. lstrcpyn(pl->filename,buf,sizeof(pl->filename)/sizeof(wchar_t));
  279. }
  280. else
  281. {
  282. wchar_t currentFilename[MAX_PATH] = {0};
  283. lstrcpynW(currentFilename, pl->filename, MAX_PATH);
  284. wchar_t * newFilename = const_cast<wchar_t *>(buf);
  285. if(wcslen(buf) >= MAX_PATH-1) newFilename[MAX_PATH-1]=0;
  286. while(newFilename && *newFilename && *newFilename == L'.') newFilename++;
  287. removebadchars(newFilename);
  288. StringCchPrintf(pl->filename,MAX_PATH,L"%s\\%s.m3u",pldir,newFilename);
  289. pl->filename[0]=drive;
  290. MoveFile(currentFilename, pl->filename);
  291. pl->dirty=true;
  292. }
  293. }
  294. // called from ml_pmp
  295. void USBDevice::playlistSwapItems(int playlistnumber, int posA, int posB)
  296. {
  297. // swap the songs at position posA and posB
  298. USBPlaylist * pl = (USBPlaylist*)usbPlaylists.at(playlistnumber);
  299. UsbSong* a = pl->songs.at(posA);
  300. UsbSong* b = pl->songs.at(posB);
  301. pl->songs.insert(pl->songs.begin() + posA, b);
  302. pl->songs.erase(pl->songs.begin() + posA + 1);
  303. pl->songs.insert(pl->songs.begin() + posB, a);
  304. pl->songs.erase(pl->songs.begin() + posB + 1);
  305. pl->dirty = true;
  306. }
  307. // called from ml_pmp
  308. void USBDevice::sortPlaylist(int playlistnumber, int sortBy)
  309. {
  310. // TODO: implement
  311. }
  312. // called from ml_pmp
  313. void USBDevice::addTrackToPlaylist(int playlistnumber, songid_t songid)
  314. {
  315. // adds songid to the end of the playlist
  316. UsbSong* song = (UsbSong *) songid;
  317. USBPlaylist * pl = (USBPlaylist*)usbPlaylists.at(playlistnumber);
  318. pl->songs.push_back(song);
  319. pl->dirty=true;
  320. }
  321. // called from ml_pmp
  322. void USBDevice::removeTrackFromPlaylist(int playlistnumber, int songnum)
  323. {
  324. //where songnum is the position of the track in the playlist
  325. USBPlaylist * pl = (USBPlaylist*)usbPlaylists.at(playlistnumber);
  326. pl->songs.erase(pl->songs.begin() + songnum);
  327. pl->dirty=true;
  328. }
  329. // called from ml_pmp
  330. void USBDevice::deletePlaylist(int playlistnumber)
  331. {
  332. USBPlaylist * pl = (USBPlaylist*)usbPlaylists.at(playlistnumber);
  333. _wunlink(pl->filename);
  334. usbPlaylists.erase(usbPlaylists.begin() + playlistnumber);
  335. delete pl;
  336. }
  337. // called from ml_pmp
  338. int USBDevice::newPlaylist(const wchar_t *name)
  339. {
  340. // create empty playlist, returns playlistnumber. -1 for failed.
  341. wchar_t plname[MAX_PATH] = {0};
  342. StringCchCopy(plname, MAX_PATH, name);
  343. removebadchars(plname);
  344. wchar_t buff[MAX_PATH] = {0};
  345. StringCchPrintf(buff, MAX_PATH, L"%s\\%s.m3u",pldir,plname);
  346. USBPlaylist * pl = new USBPlaylist(*this, buff, false);
  347. pl->filename[0]=drive;
  348. //Lets save the playlist right away
  349. USBPlaylistSaver playlistSaver(pl->filename, L"autosaved", pl);
  350. playlistSaver.Save();
  351. usbPlaylists.push_back(pl);
  352. return (int)usbPlaylists.size()-1;
  353. }
  354. // called from ml_pmp
  355. void USBDevice::getTrackArtist(songid_t songid, wchar_t *buf, int len)
  356. {
  357. UsbSong* song = (UsbSong*)songid;
  358. if (!song) return;
  359. buf[0] = L'\0';
  360. if(!loadedUpToDate)
  361. {
  362. this->fillMetaData(song);
  363. }
  364. StringCchCopy(buf, len, song->artist);
  365. }
  366. // called from ml_pmp
  367. void USBDevice::getTrackAlbum(songid_t songid, wchar_t *buf, int len)
  368. {
  369. UsbSong* song = (UsbSong*)songid;
  370. if (!song) return;
  371. buf[0] = L'\0';
  372. if(!loadedUpToDate)
  373. {
  374. this->fillMetaData(song);
  375. }
  376. StringCchCopy(buf, len, song->album);
  377. }
  378. // called from ml_pmp
  379. void USBDevice::getTrackTitle(songid_t songid, wchar_t *buf, int len)
  380. {
  381. UsbSong* song = (UsbSong*)songid;
  382. if (!song) return;
  383. if(!loadedUpToDate)
  384. {
  385. this->fillMetaData(song);
  386. }
  387. StringCchCopy(buf, len, song->title);
  388. }
  389. // called from ml_pmp
  390. int USBDevice::getTrackTrackNum(songid_t songid)
  391. {
  392. UsbSong* song = (UsbSong*)songid;
  393. if (!song) return 0;
  394. if(!loadedUpToDate)
  395. {
  396. this->fillMetaData(song);
  397. }
  398. return song->track;
  399. }
  400. // called from ml_pmp
  401. int USBDevice::getTrackDiscNum(songid_t songid)
  402. {
  403. UsbSong* song = (UsbSong*)songid;
  404. if (!song) return 0;
  405. if(!loadedUpToDate)
  406. {
  407. this->fillMetaData(song);
  408. }
  409. return song->discnum;
  410. }
  411. // called from ml_pmp
  412. void USBDevice::getTrackGenre(songid_t songid, wchar_t * buf, int len)
  413. {
  414. UsbSong* song = (UsbSong*)songid;
  415. if (!song) return;
  416. if(!loadedUpToDate)
  417. {
  418. this->fillMetaData(song);
  419. }
  420. StringCchCopy(buf, len, song->genre);
  421. }
  422. // called from ml_pmp
  423. int USBDevice::getTrackYear(songid_t songid)
  424. {
  425. UsbSong* song = (UsbSong*)songid;
  426. if (!song) return 0;
  427. if(!loadedUpToDate)
  428. {
  429. this->fillMetaData(song);
  430. }
  431. return song->year;
  432. }
  433. // called from ml_pmp
  434. __int64 USBDevice::getTrackSize(songid_t songid)
  435. {
  436. // in bytes
  437. UsbSong* song = (UsbSong*)songid;
  438. if (!song) return 0;
  439. if(!loadedUpToDate)
  440. {
  441. this->fillMetaData(song);
  442. }
  443. return song->size;
  444. }
  445. // called from ml_pmp
  446. int USBDevice::getTrackLength(songid_t songid)
  447. {
  448. // in millisecs
  449. UsbSong* song = (UsbSong*)songid;
  450. if (!song) return 0;
  451. if(!loadedUpToDate)
  452. {
  453. this->fillMetaData(song);
  454. }
  455. return song->length;
  456. }
  457. // called from ml_pmp
  458. int USBDevice::getTrackBitrate(songid_t songid)
  459. {
  460. // in kbps
  461. UsbSong* song = (UsbSong*)songid;
  462. if (!song) return 0;
  463. if(!loadedUpToDate)
  464. {
  465. this->fillMetaData(song);
  466. }
  467. return song->bitrate;
  468. }
  469. // called from ml_pmp
  470. int USBDevice::getTrackPlayCount(songid_t songid)
  471. {
  472. UsbSong* song = (UsbSong*)songid;
  473. if (!song) return 0;
  474. if(!loadedUpToDate)
  475. {
  476. this->fillMetaData(song);
  477. }
  478. return song->playcount;
  479. }
  480. // called from ml_pmp
  481. int USBDevice::getTrackRating(songid_t songid)
  482. {
  483. //0-5
  484. // TODO: implement
  485. return 0;
  486. }
  487. // called from ml_pmp
  488. __time64_t USBDevice::getTrackLastPlayed(songid_t songid)
  489. {
  490. // in unix time format
  491. // TODO: implement
  492. return 0;
  493. }
  494. // called from ml_pmp
  495. __time64_t USBDevice::getTrackLastUpdated(songid_t songid)
  496. {
  497. // in unix time format
  498. // TODO: implement
  499. return 0;
  500. }
  501. // called from ml_pmp
  502. void USBDevice::getTrackAlbumArtist(songid_t songid, wchar_t *buf, int len)
  503. {
  504. UsbSong* song = (UsbSong*)songid;
  505. if (!song) return;
  506. if(!loadedUpToDate)
  507. {
  508. this->fillMetaData(song);
  509. }
  510. StringCchCopy(buf, len, song->albumartist);
  511. }
  512. // called from ml_pmp
  513. void USBDevice::getTrackPublisher(songid_t songid, wchar_t *buf, int len)
  514. {
  515. UsbSong* song = (UsbSong*)songid;
  516. if (!song) return;
  517. if(!loadedUpToDate)
  518. {
  519. this->fillMetaData(song);
  520. }
  521. StringCchCopy(buf, len, song->publisher);
  522. }
  523. // called from ml_pmp
  524. void USBDevice::getTrackComposer(songid_t songid, wchar_t *buf, int len)
  525. {
  526. UsbSong* song = (UsbSong*)songid;
  527. if (!song) return;
  528. if(!loadedUpToDate)
  529. {
  530. this->fillMetaData(song);
  531. }
  532. StringCchCopy(buf, len, song->composer);
  533. }
  534. // called from ml_pmp
  535. int USBDevice::getTrackType(songid_t songid)
  536. {
  537. // TODO: implement
  538. return 0;
  539. }
  540. // called from ml_pmp
  541. void USBDevice::getTrackExtraInfo(songid_t songid, const wchar_t *field, wchar_t *buf, int len)
  542. {
  543. // TODO: implement
  544. //optional
  545. }
  546. // called from ml_pmp
  547. // feel free to ignore any you don't support
  548. void USBDevice::setTrackArtist(songid_t songid, const wchar_t *value)
  549. {
  550. UsbSong *song = (UsbSong *) songid;
  551. if (song)
  552. {
  553. updateTrackField(song, DEVICEVIEW_COL_ARTIST, value, FIELD_STRING);
  554. StringCchCopy(song->artist, FIELD_LENGTH, value);
  555. AGAVE_API_METADATA->SetExtendedFileInfo(song->filename, L"artist", value);
  556. }
  557. }
  558. // called from ml_pmp
  559. void USBDevice::setTrackAlbum(songid_t songid, const wchar_t *value)
  560. {
  561. UsbSong *song = (UsbSong *) songid;
  562. if (song)
  563. {
  564. updateTrackField(song, DEVICEVIEW_COL_ALBUM, value, FIELD_STRING);
  565. StringCchCopy(song->album, FIELD_LENGTH, value);
  566. AGAVE_API_METADATA->SetExtendedFileInfo(song->filename, L"album", value);
  567. }
  568. }
  569. // called from ml_pmp
  570. void USBDevice::setTrackTitle(songid_t songid, const wchar_t *value)
  571. {
  572. UsbSong *song = (UsbSong *) songid;
  573. if (song)
  574. {
  575. updateTrackField(song, DEVICEVIEW_COL_TITLE, value, FIELD_STRING);
  576. StringCchCopy(song->title, FIELD_LENGTH, value);
  577. AGAVE_API_METADATA->SetExtendedFileInfo(song->filename, L"title", value);
  578. }
  579. }
  580. // called from ml_pmp
  581. void USBDevice::setTrackTrackNum(songid_t songid, int value)
  582. {
  583. UsbSong *song = (UsbSong *) songid;
  584. if (song)
  585. {
  586. wchar_t track[FIELD_LENGTH] = {0};
  587. updateTrackField(song, DEVICEVIEW_COL_TRACK, &value, FIELD_INTEGER);
  588. song->track = value;
  589. StringCchPrintf(track, FIELD_LENGTH, L"%d", value);
  590. AGAVE_API_METADATA->SetExtendedFileInfo(song->filename, L"track", track);
  591. }
  592. }
  593. // called from ml_pmp
  594. void USBDevice::setTrackDiscNum(songid_t songid, int value)
  595. {
  596. UsbSong *song = (UsbSong *) songid;
  597. if (song)
  598. {
  599. wchar_t discNum[FIELD_LENGTH] = {0};
  600. updateTrackField(song, DEVICEVIEW_COL_DISC_NUMBER, &value, FIELD_INTEGER);
  601. song->discnum = value;
  602. StringCchPrintf(discNum, FIELD_LENGTH, L"%d", value);
  603. AGAVE_API_METADATA->SetExtendedFileInfo(song->filename, L"disc", discNum);
  604. }
  605. }
  606. // called from ml_pmp
  607. void USBDevice::setTrackGenre(songid_t songid, const wchar_t *value)
  608. {
  609. UsbSong *song = (UsbSong *) songid;
  610. if (song)
  611. {
  612. updateTrackField(song, DEVICEVIEW_COL_GENRE, value, FIELD_STRING);
  613. StringCchCopy(song->genre, FIELD_LENGTH, value);
  614. AGAVE_API_METADATA->SetExtendedFileInfo(song->filename, L"genre", value);
  615. }
  616. }
  617. // called from ml_pmp
  618. void USBDevice::setTrackYear(songid_t songid, int year)
  619. {
  620. UsbSong *song = (UsbSong *) songid;
  621. if (song)
  622. {
  623. wchar_t yearStr[FIELD_LENGTH] = {0};
  624. updateTrackField(song, DEVICEVIEW_COL_YEAR, &year, FIELD_INTEGER);
  625. song->year = year;
  626. StringCchPrintf(yearStr, FIELD_LENGTH, L"%d", year);
  627. AGAVE_API_METADATA->SetExtendedFileInfo(song->filename, L"year", yearStr);
  628. }
  629. }
  630. // called from ml_pmp
  631. void USBDevice::setTrackPlayCount(songid_t songid, int value)
  632. {
  633. UsbSong *song = (UsbSong *) songid;
  634. if (song)
  635. {
  636. wchar_t playCount[FIELD_LENGTH] = {0};
  637. updateTrackField(song, DEVICEVIEW_COL_PLAY_COUNT, &value, FIELD_INTEGER);
  638. song->playcount = value;
  639. StringCchPrintf(playCount, FIELD_LENGTH, L"%d", value);
  640. AGAVE_API_METADATA->SetExtendedFileInfo(song->filename, L"playcount", playCount);
  641. }
  642. }
  643. // called from ml_pmp
  644. void USBDevice::setTrackRating(songid_t songid, int value)
  645. {
  646. UsbSong *song = (UsbSong *) songid;
  647. if (song)
  648. {
  649. wchar_t rating[FIELD_LENGTH] = {0};
  650. updateTrackField(song, DEVICEVIEW_COL_PLAY_COUNT, &value, FIELD_INTEGER);
  651. song->playcount = value;
  652. StringCchPrintf(rating, FIELD_LENGTH, L"%d", value);
  653. AGAVE_API_METADATA->SetExtendedFileInfo(song->filename, L"rating", rating);
  654. }
  655. }
  656. // called from ml_pmp
  657. void USBDevice::setTrackLastPlayed(songid_t songid, __time64_t value)
  658. {
  659. // TODO: implement
  660. } // in unix time format
  661. // called from ml_pmp
  662. void USBDevice::setTrackLastUpdated(songid_t songid, __time64_t value)
  663. {
  664. // TODO: implement
  665. } // in unix time format
  666. // called from ml_pmp
  667. void USBDevice::setTrackAlbumArtist(songid_t songid, const wchar_t *value)
  668. {
  669. UsbSong *song = (UsbSong *) songid;
  670. if (song)
  671. {
  672. updateTrackField(song, DEVICEVIEW_COL_ALBUM_ARTIST, value, FIELD_STRING);
  673. StringCchCopy(song->albumartist, FIELD_LENGTH, value);
  674. AGAVE_API_METADATA->SetExtendedFileInfo(song->filename, L"albumartist", value);
  675. }
  676. }
  677. // called from ml_pmp
  678. void USBDevice::setTrackPublisher(songid_t songid, const wchar_t *value)
  679. {
  680. UsbSong *song = (UsbSong *) songid;
  681. if (song)
  682. {
  683. updateTrackField(song, DEVICEVIEW_COL_PUBLISHER, value, FIELD_STRING);
  684. StringCchCopy(song->publisher, FIELD_LENGTH, value);
  685. AGAVE_API_METADATA->SetExtendedFileInfo(song->filename, L"publisher", value);
  686. }
  687. }
  688. // called from ml_pmp
  689. void USBDevice::setTrackComposer(songid_t songid, const wchar_t *value)
  690. {
  691. UsbSong *song = (UsbSong *) songid;
  692. if (song)
  693. {
  694. updateTrackField(song, DEVICEVIEW_COL_COMPOSER, value, FIELD_STRING);
  695. StringCchCopy(song->composer, FIELD_LENGTH, value);
  696. AGAVE_API_METADATA->SetExtendedFileInfo(song->filename, L"composer", value);
  697. }
  698. }
  699. // called from ml_pmp
  700. void USBDevice::setTrackExtraInfo(songid_t songid, const wchar_t *field, const wchar_t *value)
  701. {
  702. // TODO: implement
  703. } //optional
  704. // called from ml_pmp
  705. bool USBDevice::playTracks(songid_t * songidList, int listLength, int startPlaybackAt, bool enqueue)
  706. {
  707. // return false if unsupported
  708. if(!enqueue) //clear playlist
  709. {
  710. SendMessage(plugin.hwndWinampParent,WM_WA_IPC,0,IPC_DELETE);
  711. }
  712. for(int i=0; i<listLength; i++)
  713. {
  714. UsbSong *curSong = (UsbSong*)songidList[i];
  715. if (curSong)
  716. {
  717. enqueueFileWithMetaStructW s={0};
  718. s.filename = _wcsdup(curSong->filename);
  719. s.title = _wcsdup(curSong->title);
  720. s.ext = NULL;
  721. s.length = curSong->length/1000;
  722. SendMessage(plugin.hwndWinampParent, WM_WA_IPC, (WPARAM)&s, IPC_PLAYFILEW);
  723. }
  724. else
  725. {
  726. char titleStr[32] = {0};
  727. MessageBoxA(plugin.hwndWinampParent,WASABI_API_LNGSTRING(IDS_CANNOT_OPEN_FILE),
  728. WASABI_API_LNGSTRING_BUF(IDS_ERROR,titleStr,32),0);
  729. }
  730. }
  731. if(!enqueue)
  732. {
  733. //play item startPlaybackAt
  734. SendMessage(plugin.hwndWinampParent,WM_WA_IPC,startPlaybackAt,IPC_SETPLAYLISTPOS);
  735. SendMessage(plugin.hwndWinampParent,WM_COMMAND,40047,0); //stop
  736. SendMessage(plugin.hwndWinampParent,WM_COMMAND,40045,0); //play
  737. }
  738. return true;
  739. }
  740. // called from ml_pmp
  741. intptr_t USBDevice::extraActions(intptr_t param1, intptr_t param2, intptr_t param3,intptr_t param4)
  742. {
  743. switch(param1)
  744. {
  745. case DEVICE_SET_ICON:
  746. {
  747. MLTREEIMAGE * i = (MLTREEIMAGE*)param2;
  748. i->hinst = plugin.hDllInstance;
  749. switch(devType)
  750. {
  751. case TYPE_PSP:
  752. i->resourceId = IDR_PSP_ICON;
  753. break;
  754. default:
  755. i->resourceId = IDR_USB_ICON;
  756. break;
  757. }
  758. }
  759. break;
  760. case DEVICE_GET_ICON:
  761. {
  762. if (param2 <= 16 && param3 <= 16)
  763. {
  764. // TODO: get the name of the DLL at load time
  765. StringCchPrintfW((wchar_t *)param4, 260, L"res://%s/PNG/#%u", L"pmp_usb.dll", (devType==TYPE_PSP)?IDR_PSP_ICON:IDR_USB_ICON);
  766. }
  767. }
  768. break;
  769. case DEVICE_SUPPORTED_METADATA:
  770. {
  771. intptr_t supported = SUPPORTS_ARTIST | SUPPORTS_ALBUM | SUPPORTS_TITLE | SUPPORTS_TRACKNUM | SUPPORTS_DISCNUM | SUPPORTS_GENRE |
  772. SUPPORTS_YEAR | SUPPORTS_SIZE | SUPPORTS_LENGTH | SUPPORTS_BITRATE | SUPPORTS_LASTUPDATED | SUPPORTS_ALBUMARTIST |
  773. SUPPORTS_COMPOSER | SUPPORTS_PUBLISHER | SUPPORTS_ALBUMART;
  774. return supported;
  775. }
  776. break;
  777. case DEVICE_CAN_RENAME_DEVICE:
  778. return 1;
  779. case DEVICE_GET_INI_FILE:
  780. StringCchCopy((wchar_t*)param2, MAX_PATH, iniFile);
  781. break;
  782. case DEVICE_GET_PREFS_DIALOG:
  783. if(param3 == 0)
  784. {
  785. pref_tab * p = (pref_tab *)param2;
  786. p->hinst = WASABI_API_LNG_HINST;
  787. p->dlg_proc = prefs_dialogProc;
  788. p->res_id = IDD_CONFIG;
  789. WASABI_API_LNGSTRINGW_BUF(IDS_ADVANCED,p->title,100);
  790. }
  791. break;
  792. case DEVICE_DONE_SETTING:
  793. UsbSong * song = (UsbSong *) param2;
  794. AGAVE_API_METADATA->WriteExtendedFileInfo(song->filename);
  795. return true;
  796. break;
  797. }
  798. return false;
  799. }
  800. // called from ml_pmp
  801. bool USBDevice::copyToHardDriveSupported()
  802. {
  803. return true;
  804. }
  805. // called from ml_pmp
  806. __int64 USBDevice::songSizeOnHardDrive(songid_t song)
  807. {
  808. // how big a song will be when copied back. Return -1 for not supported.
  809. // TODO: implement
  810. return 0;
  811. }
  812. // called from ml_pmp
  813. int USBDevice::copyToHardDrive(songid_t song, // the song to copy
  814. wchar_t * path, // path to copy to, in the form "c:\directory\song". The directory will already be created, you must append ".mp3" or whatever to this string! (there is space for at least 10 new characters).
  815. void * callbackContext, //pass this to the callback
  816. void (*callback)(void * callbackContext, wchar_t * status), // call this every so often so the GUI can be updated. Including when finished!
  817. int * killswitch // if this gets set to anything other than zero, the transfer has been cancelled by the user
  818. )
  819. {
  820. // -1 for failed/not supported. 0 for success.
  821. UsbSong* track = (UsbSong*)song;
  822. wchar_t * ext = PathFindExtensionW(track->filename);
  823. if(ext && (lstrlen(ext)<10)) StringCchCat(path,MAX_PATH, ext); // append correct extention
  824. return CopyFile(track->filename,path,callbackContext, callback, killswitch);
  825. }
  826. // called from ml_pmp
  827. // art functions
  828. void USBDevice::setArt(songid_t songid, void *buf, int w, int h)
  829. {
  830. //buf is in format ARGB32*
  831. // TODO: implement
  832. }
  833. // called from ml_pmp
  834. pmpart_t USBDevice::getArt(songid_t songid)
  835. {
  836. UsbSong *song = (UsbSong *)songid;
  837. ARGB32 *bits;
  838. int w, h;
  839. if (AGAVE_API_ALBUMART && AGAVE_API_ALBUMART->GetAlbumArt(song->filename, L"cover", &w, &h, &bits) == ALBUMART_SUCCESS && bits)
  840. {
  841. return (pmpart_t) new USBArt(bits, w, h);
  842. }
  843. return 0;
  844. }
  845. // called from ml_pmp
  846. void USBDevice::releaseArt(pmpart_t art)
  847. {
  848. USBArt *image = (USBArt *)art;
  849. delete image;
  850. }
  851. // called from ml_pmp
  852. int USBDevice::drawArt(pmpart_t art, HDC dc, int x, int y, int w, int h)
  853. {
  854. USBArt *image = (USBArt *)art;
  855. if (image)
  856. {
  857. HQSkinBitmap temp(image->bits, image->w, image->h); // wrap into a SkinBitmap (no copying involved)
  858. DCCanvas canvas(dc);
  859. temp.stretch(&canvas,x,y,w,h);
  860. return 1;
  861. }
  862. return 0;
  863. }
  864. // called from ml_pmp
  865. void USBDevice::getArtNaturalSize(pmpart_t art, int *w, int *h)
  866. {
  867. // TODO: implement
  868. USBArt *image = (USBArt *)art;
  869. if (image)
  870. {
  871. *w = image->w;
  872. *h = image->h;
  873. }
  874. }
  875. // called from ml_pmp
  876. void USBDevice::setArtNaturalSize(pmpart_t art, int w, int h)
  877. {
  878. // TODO: implement
  879. }
  880. // called from ml_pmp
  881. void USBDevice::getArtData(pmpart_t art, void* data)
  882. {
  883. USBArt *image = (USBArt *)art;
  884. if (image)
  885. memcpy(data, image->bits, image->w*image->h*sizeof(ARGB32));
  886. // data ARGB32* is at natural size
  887. }
  888. // called from ml_pmp
  889. bool USBDevice::artIsEqual(pmpart_t a, pmpart_t b)
  890. {
  891. if (a == b)
  892. return true;
  893. // TODO: implement
  894. return false;
  895. }
  896. //////////////////////////////////////////////////////////////////////////////////////////
  897. // Initialize class statics
  898. nde_database_t USBDevice::discDB = 0;
  899. // The getter that returns the master playlist
  900. // the playlist vector always carries a master playlist
  901. USBPlaylist* USBDevice::getMasterPlaylist()
  902. {
  903. for (std::vector<USBPlaylist*>::const_iterator e = usbPlaylists.begin(); e != usbPlaylists.end(); e++)
  904. {
  905. USBPlaylist* playlist = (*e);
  906. if (playlist->isMaster()) return playlist;
  907. }
  908. return NULL;
  909. }
  910. // constructor
  911. USBDevice::USBDevice(wchar_t drive, pmpDeviceLoading * load): transcoder(NULL) {
  912. deviceTable = 0;
  913. StringCchPrintf(ndeDataFile, 100, L"%c:\\winamp_metadata.dat", drive);
  914. StringCchPrintf(ndeIndexFile, 100, L"%c:\\winamp_metadata.idx", drive);
  915. load->dev = this;
  916. load->UpdateCaption = NULL;
  917. //pass load to ml_pmp, ml updates load->UpdateCaption and context
  918. SendMessage(plugin.hwndPortablesParent,WM_PMP_IPC,(intptr_t)load,PMP_IPC_DEVICELOADING);
  919. if(load->UpdateCaption) {
  920. wchar_t buf[100] = L"";
  921. WASABI_API_LNGSTRINGW_BUF(IDS_LOADING_DRIVE_X,buf,100);
  922. wchar_t * x = wcsrchr(buf,L'X');
  923. if(x) *x = drive;
  924. load->UpdateCaption(buf,load->context);
  925. }
  926. devType = detectDeviceType(drive);
  927. // load settings
  928. StringCchCopy(iniFile,MAX_PATH,L"x:\\pmp_usb.ini");
  929. iniFile[0]=drive;
  930. wchar_t customName[FIELD_LENGTH] = {0};
  931. GetPrivateProfileString(L"pmp_usb",L"pldir",devType==TYPE_PSP?L"X:\\PSP\\MUSIC":L"X:",pldir,sizeof(pldir)/sizeof(wchar_t),iniFile);
  932. GetPrivateProfileString(L"pmp_usb",L"songFormat",devType==TYPE_PSP?L"X:\\PSP\\MUSIC\\<Artist> - <Album>\\## - <Title>":L"X:\\<Artist>\\<Album>\\## - <Title>",songFormat,sizeof(songFormat)/sizeof(wchar_t),iniFile);
  933. GetPrivateProfileString(L"pmp_usb",L"supportedFormats",L"mp3;wav;wma;m4a;aac;ogg;flac",supportedFormats,sizeof(supportedFormats)/sizeof(wchar_t),iniFile);
  934. GetPrivateProfileString(L"pmp_usb",L"purgeFolders",L"1",purgeFolders,sizeof(purgeFolders)/sizeof(wchar_t),iniFile);
  935. GetPrivateProfileString(L"pmp_usb",L"customName",devType==TYPE_PSP?L"Sony PSP":L"",customName,sizeof(customName)/sizeof(wchar_t),iniFile);
  936. pl_write_mode = GetPrivateProfileInt(L"pmp_usb",L"pl_write_mode",0,iniFile);
  937. pldir[0] = drive;
  938. songFormat[0] = drive;
  939. transferQueueLength = 0;
  940. this->drive = drive;
  941. USBPlaylist * mpl = new USBPlaylist(*this, customName, true);
  942. usbPlaylists.push_back(mpl);
  943. wchar_t * pl = _wcsdup(pldir);
  944. pl[0] = drive;
  945. RecursiveCreateDirectory(pl);
  946. wchar_t root[3] = L"X:";
  947. root[0] = drive;
  948. openDeviceTable();
  949. fileProbe(root);
  950. // sort out and read playlists....
  951. if (WASABI_API_PLAYLISTMNGR != NULL && WASABI_API_PLAYLISTMNGR != (api_playlistmanager *)1)
  952. {
  953. for (std::vector<USBPlaylist*>::const_iterator e = usbPlaylists.begin(); e != usbPlaylists.end(); e++)
  954. {
  955. USBPlaylist* playlist = (*e);
  956. if (playlist && playlist->isMaster() == false)
  957. {
  958. WASABI_API_PLAYLISTMNGR->Load(playlist->getFilename(), playlist);
  959. }
  960. }
  961. }
  962. tag();
  963. devices.push_back(this);
  964. extern HWND config;
  965. if(config) PostMessage(config,WM_USER,0,0);
  966. SendMessage(plugin.hwndPortablesParent,WM_PMP_IPC,(intptr_t)this,PMP_IPC_DEVICECONNECTED);
  967. setupTranscoder();
  968. loading_devices[drive-'A']=false;
  969. }
  970. USBDevice::USBDevice() : transcoder(NULL), drive(0), devType(TYPE_OTHER), pl_write_mode(0), transferQueueLength(0), cacheUpToDate(false), loadedUpToDate(false)
  971. {
  972. deviceTable = 0;
  973. ZeroMemory(ndeDataFile, sizeof(ndeDataFile));
  974. ZeroMemory(ndeIndexFile, sizeof(ndeIndexFile));
  975. ZeroMemory(iniFile, sizeof(iniFile));
  976. ZeroMemory(pldir, sizeof(pldir));
  977. ZeroMemory(songFormat, sizeof(songFormat));
  978. ZeroMemory(supportedFormats, sizeof(supportedFormats));
  979. ZeroMemory(purgeFolders, sizeof(purgeFolders));
  980. }
  981. USBDevice::~USBDevice()
  982. {
  983. closeDeviceTable();
  984. if (transcoder) SendMessage(plugin.hwndPortablesParent,WM_PMP_IPC,(WPARAM)transcoder,PMP_IPC_RELEASE_TRANSCODER);
  985. }
  986. //read files from device's folder 'indir'
  987. void USBDevice::fileProbe(wchar_t * indir) {
  988. wchar_t dir[MAX_PATH] = {0};
  989. WIN32_FIND_DATA FindFileData = {0};
  990. StringCchPrintf(dir,MAX_PATH,L"%s\\*",indir);
  991. HANDLE hFind = FindFirstFile(dir, &FindFileData);
  992. if (hFind == INVALID_HANDLE_VALUE) return;
  993. do {
  994. if(wcscmp(FindFileData.cFileName,L".") && wcscmp(FindFileData.cFileName,L"..")) {
  995. wchar_t fullfile[MAX_PATH] = {0};
  996. StringCchPrintf(fullfile,MAX_PATH,L"%s\\%s",indir,FindFileData.cFileName);
  997. if(FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) //file is directory
  998. {
  999. fileProbe(fullfile); //call until we have found a file
  1000. }
  1001. else // found a file!
  1002. {
  1003. wchar_t * ext = wcsrchr(FindFileData.cFileName,'.');
  1004. if(!ext) continue; //no files with extensions in the directory
  1005. ext++;
  1006. if(!_wcsicmp(ext,L"m3u")) // its a playlist
  1007. {
  1008. USBPlaylist *playlist = new USBPlaylist(*this, fullfile, false);
  1009. usbPlaylists.push_back(playlist);
  1010. continue;
  1011. } //its a file
  1012. if(supportedFormat(fullfile,supportedFormats)) //check extension
  1013. {
  1014. UsbSong *s = new UsbSong();
  1015. lstrcpynW(s->filename, fullfile, MAX_PATH);
  1016. this->getMasterPlaylist()->songs.push_back(s); //add track to alltrack list (playlist 0)
  1017. }
  1018. }
  1019. }
  1020. } while(FindNextFile(hFind, &FindFileData) != 0);
  1021. FindClose(hFind);
  1022. }
  1023. int USBDevice::getFileInfoW(const wchar_t *filename, const wchar_t *metadata, wchar_t *dest, size_t len)
  1024. {
  1025. dest[0]=0;
  1026. return AGAVE_API_METADATA->GetExtendedFileInfo(filename, metadata, dest, len);
  1027. }
  1028. // read all metadata from the metadata wasabi service
  1029. void USBDevice::fillMetaData(UsbSong *t)
  1030. {
  1031. if (!t->filled)
  1032. {
  1033. wchar_t tmp[1024] = {0};
  1034. if (getFileInfoW(t->filename,L"artist",tmp,sizeof(tmp)/sizeof(wchar_t)) && tmp[0])
  1035. {
  1036. StringCchCopyW(t->artist, FIELD_LENGTH, tmp);
  1037. t->filled = true;
  1038. }
  1039. if (getFileInfoW(t->filename,L"title",tmp,sizeof(tmp)/sizeof(wchar_t)) && tmp[0])
  1040. {
  1041. StringCchCopyW(t->title, FIELD_LENGTH, tmp);
  1042. t->filled = true;
  1043. }
  1044. if (getFileInfoW(t->filename,L"album",tmp,sizeof(tmp)/sizeof(wchar_t)) && tmp[0])
  1045. {
  1046. StringCchCopyW(t->album, FIELD_LENGTH, tmp);
  1047. t->filled = true;
  1048. }
  1049. if (getFileInfoW(t->filename,L"composer",tmp,sizeof(tmp)/sizeof(wchar_t)) && tmp[0])
  1050. {
  1051. StringCchCopyW(t->composer, FIELD_LENGTH, tmp);
  1052. t->filled = true;
  1053. }
  1054. if (getFileInfoW(t->filename,L"publisher",tmp,sizeof(tmp)/sizeof(wchar_t)) && tmp[0])
  1055. {
  1056. StringCchCopyW(t->publisher, FIELD_LENGTH, tmp);
  1057. t->filled = true;
  1058. }
  1059. if (getFileInfoW(t->filename,L"albumartist",tmp,sizeof(tmp)/sizeof(wchar_t)) && tmp[0])
  1060. {
  1061. StringCchCopyW(t->albumartist, FIELD_LENGTH, tmp);
  1062. t->filled = true;
  1063. }
  1064. if (getFileInfoW(t->filename, L"length",tmp,sizeof(tmp)/sizeof(wchar_t)) && tmp[0])
  1065. {
  1066. t->length = _wtoi(tmp);
  1067. t->filled = true;
  1068. }
  1069. if (getFileInfoW(t->filename, L"track",tmp,sizeof(tmp)/sizeof(wchar_t)) && tmp[0])
  1070. {
  1071. t->track = _wtoi(tmp);
  1072. t->filled = true;
  1073. }
  1074. if (getFileInfoW(t->filename, L"disc",tmp,sizeof(tmp)/sizeof(wchar_t)) && tmp[0])
  1075. {
  1076. t->discnum = _wtoi(tmp);
  1077. t->filled = true;
  1078. }
  1079. if (getFileInfoW(t->filename, L"genre",tmp,sizeof(tmp)/sizeof(wchar_t)) && tmp[0])
  1080. {
  1081. StringCchCopyW(t->genre, FIELD_LENGTH, tmp);
  1082. t->filled = true;
  1083. }
  1084. if (getFileInfoW(t->filename, L"year",tmp,sizeof(tmp)/sizeof(wchar_t)) && tmp[0])
  1085. {
  1086. if (!wcsstr(tmp,L"__") && !wcsstr(tmp,L"/") && !wcsstr(tmp,L"\\") && !wcsstr(tmp,L"."))
  1087. {
  1088. wchar_t *p = tmp;
  1089. while (p && *p)
  1090. {
  1091. if (*p == L'_') *p=L'0';
  1092. p++;
  1093. }
  1094. t->year = _wtoi(tmp);
  1095. t->filled = true;
  1096. }
  1097. }
  1098. if (getFileInfoW(t->filename, L"bitrate",tmp,sizeof(tmp)/sizeof(wchar_t)) && tmp[0])
  1099. {
  1100. t->bitrate = _wtoi(tmp);
  1101. t->filled = true;
  1102. }
  1103. if (getFileInfoW(t->filename, L"size",tmp,sizeof(tmp)/sizeof(wchar_t)) && tmp[0])
  1104. {
  1105. t->size = _wtoi(tmp);
  1106. t->filled = true;
  1107. }
  1108. else
  1109. {
  1110. t->size = fileSize(t->filename);
  1111. t->filled = true;
  1112. }
  1113. if (getFileInfoW(t->filename, L"playcount",tmp,sizeof(tmp)/sizeof(wchar_t)) && tmp[0])
  1114. {
  1115. t->playcount = _wtoi(tmp);
  1116. t->filled = true;
  1117. }
  1118. }
  1119. }
  1120. int USBDevice::openDeviceDatabase()
  1121. {
  1122. Nullsoft::Utility::AutoLock lock(dbcs);
  1123. if (!discDB)
  1124. {
  1125. discDB = NDE_CreateDatabase(plugin.hDllInstance);
  1126. }
  1127. return NDE_USB_SUCCESS;
  1128. }
  1129. void USBDevice::createDeviceFields()
  1130. {
  1131. // create defaults
  1132. NDE_Table_NewColumnW(deviceTable, DEVICEVIEW_COL_FILENAME, L"filename", FIELD_FILENAME);
  1133. NDE_Table_NewColumnW(deviceTable, DEVICEVIEW_COL_ARTIST, L"artist", FIELD_STRING);
  1134. NDE_Table_NewColumnW(deviceTable, DEVICEVIEW_COL_ALBUM, L"album", FIELD_STRING);
  1135. NDE_Table_NewColumnW(deviceTable, DEVICEVIEW_COL_TITLE, L"title", FIELD_STRING);
  1136. NDE_Table_NewColumnW(deviceTable, DEVICEVIEW_COL_GENRE, L"genre", FIELD_STRING);
  1137. NDE_Table_NewColumnW(deviceTable, DEVICEVIEW_COL_ALBUM_ARTIST, L"albumartist", FIELD_STRING);
  1138. NDE_Table_NewColumnW(deviceTable, DEVICEVIEW_COL_PUBLISHER, L"publisher", FIELD_STRING);
  1139. NDE_Table_NewColumnW(deviceTable, DEVICEVIEW_COL_COMPOSER, L"composer", FIELD_STRING);
  1140. NDE_Table_NewColumnW(deviceTable, DEVICEVIEW_COL_YEAR, L"year", FIELD_INTEGER);
  1141. NDE_Table_NewColumnW(deviceTable, DEVICEVIEW_COL_TRACK, L"track", FIELD_INTEGER);
  1142. NDE_Table_NewColumnW(deviceTable, DEVICEVIEW_COL_BITRATE, L"bitrate", FIELD_INTEGER);
  1143. NDE_Table_NewColumnW(deviceTable, DEVICEVIEW_COL_DISC_NUMBER, L"discnumber", FIELD_INTEGER);
  1144. NDE_Table_NewColumnW(deviceTable, DEVICEVIEW_COL_LENGTH, L"length", FIELD_INTEGER);
  1145. NDE_Table_NewColumnW(deviceTable, DEVICEVIEW_COL_SIZE, L"size", FIELD_INTEGER);
  1146. NDE_Table_NewColumnW(deviceTable, DEVICEVIEW_COL_PLAY_COUNT, L"playcount", FIELD_INTEGER);
  1147. NDE_Table_PostColumns(deviceTable);
  1148. NDE_Table_AddIndexByIDW(deviceTable, 0, L"filename");
  1149. }
  1150. int USBDevice::openDeviceTable() {
  1151. Nullsoft::Utility::AutoLock lock(dbcs);
  1152. int ret = openDeviceDatabase();
  1153. if (ret != NDE_USB_SUCCESS)
  1154. return ret;
  1155. if (!deviceTable)
  1156. {
  1157. deviceTable = NDE_Database_OpenTable(discDB, ndeDataFile, ndeIndexFile,NDE_OPEN_ALWAYS,NDE_CACHE);
  1158. if (deviceTable) {
  1159. createDeviceFields();
  1160. }
  1161. }
  1162. return deviceTable?NDE_USB_SUCCESS:NDE_USB_FAILURE;
  1163. }
  1164. void USBDevice::closeDeviceTable()
  1165. {
  1166. if (deviceTable)
  1167. {
  1168. NDE_Table_Sync(deviceTable);
  1169. NDE_Database_CloseTable(discDB, deviceTable);
  1170. deviceTable=0;
  1171. }
  1172. }
  1173. void USBDevice::CloseDatabase()
  1174. {
  1175. if (discDB)
  1176. NDE_DestroyDatabase(discDB);
  1177. discDB=0;
  1178. }
  1179. static void db_setFieldInt(nde_scanner_t s, unsigned char id, int data)
  1180. {
  1181. nde_field_t f = NDE_Scanner_GetFieldByID(s, id);
  1182. if (!f) f = NDE_Scanner_NewFieldByID(s, id);
  1183. NDE_IntegerField_SetValue(f, data);
  1184. }
  1185. static void db_setFieldString(nde_scanner_t s, unsigned char id, const wchar_t *data)
  1186. {
  1187. nde_field_t f = NDE_Scanner_GetFieldByID(s, id);
  1188. if (!f) f = NDE_Scanner_NewFieldByID(s, id);
  1189. NDE_StringField_SetString(f, data);
  1190. }
  1191. static void db_removeField(nde_scanner_t s, unsigned char id)
  1192. {
  1193. nde_field_t f = NDE_Scanner_GetFieldByID(s, id);
  1194. if (f)
  1195. {
  1196. NDE_Scanner_DeleteField(s, f);
  1197. }
  1198. }
  1199. static int db_getFieldInt(nde_scanner_t s, unsigned char id, int defaultVal)
  1200. {
  1201. nde_field_t f = NDE_Scanner_GetFieldByID(s, id);
  1202. if (f)
  1203. {
  1204. return NDE_IntegerField_GetValue(f);
  1205. }
  1206. else
  1207. {
  1208. return defaultVal;
  1209. }
  1210. }
  1211. static wchar_t* db_getFieldString(nde_scanner_t s, unsigned char id)
  1212. {
  1213. nde_field_t f = NDE_Scanner_GetFieldByID(s, id);
  1214. if (f)
  1215. {
  1216. return NDE_StringField_GetString(f);
  1217. }
  1218. else
  1219. {
  1220. return 0;
  1221. }
  1222. }
  1223. void USBDevice::refreshNDECache(void) {
  1224. tag();
  1225. SendMessage(plugin.hwndWinampParent,WM_WA_IPC,(WPARAM)0,IPC_WRITE_EXTENDED_FILE_INFO);
  1226. }
  1227. int filenamecmp(const wchar_t *f1, const wchar_t *f2)
  1228. {
  1229. for (;;)
  1230. {
  1231. wchar_t c1 = *f1++;
  1232. wchar_t c2 = *f2++;
  1233. if (!c1 && !c2)
  1234. return 0;
  1235. if (!c1)
  1236. return -1;
  1237. if (!c2)
  1238. return 1;
  1239. c1 = towupper(c1);
  1240. c2 = towupper(c2);
  1241. if (c1 == '\\')
  1242. c1 = '/';
  1243. if (c2 == '\\')
  1244. c2 = '/';
  1245. if (c1 < c2)
  1246. return -1;
  1247. else if (c1 > c2)
  1248. return 1;
  1249. }
  1250. }
  1251. //
  1252. UsbSong *USBDevice::findSongInMasterPlaylist(const wchar_t *songfn) {
  1253. USBPlaylist* mpl = this->getMasterPlaylist();
  1254. for (std::vector<UsbSong*>::const_iterator e = mpl->songs.begin(); e != mpl->songs.end(); e++)
  1255. {
  1256. if (filenamecmp(songfn, (*e)->filename) == 0) {
  1257. return (*e);
  1258. }
  1259. }
  1260. return NULL;
  1261. }
  1262. void USBDevice::tag(void)
  1263. {
  1264. /**
  1265. loop thru the newly probed disk
  1266. check for updates on each of the songs
  1267. if there is an update or if metadata does not exist for the file, re-read the metadata
  1268. if there is no update and the song is found in the master playlist, just read from the db
  1269. */
  1270. USBPlaylist *mpl = this->getMasterPlaylist();
  1271. int top = (int)mpl->songs.size();
  1272. //first load in all songs data from ID3 - this is what we were trying to avoid
  1273. for(int i = 0; i < top; i++)
  1274. {
  1275. UsbSong *t = (UsbSong *)mpl->songs.at(i);
  1276. // now check if this song has changed
  1277. // check if the nde cache exists in the first place
  1278. if (songChanged(t))
  1279. {
  1280. this->fillMetaData(t);
  1281. // now since we've refreshed the metadata write to NDE
  1282. this->writeRecordToDB(t);
  1283. }
  1284. else
  1285. {
  1286. // read the record from NDE
  1287. if (this->readRecordFromDB(t) == false)
  1288. {
  1289. this->fillMetaData(t);
  1290. this->writeRecordToDB(t);
  1291. }
  1292. }
  1293. }
  1294. for (size_t i=0;i<usbPlaylists.size();i++)
  1295. {
  1296. USBPlaylist *pl = usbPlaylists[i];
  1297. if (pl->dirty)
  1298. {
  1299. // Lets delete the current playlist file
  1300. _wunlink(pl->filename);
  1301. USBPlaylistSaver playlistSaver(pl->filename, L"autosaved", pl);
  1302. playlistSaver.Save();
  1303. pl->dirty = false;
  1304. }
  1305. }
  1306. cacheUpToDate = true;
  1307. loadedUpToDate = true;
  1308. }
  1309. // check change in filetimes for the song
  1310. bool USBDevice::songChanged(UsbSong* song)
  1311. {
  1312. if (!song) return true;
  1313. if (!PathFileExists(ndeDataFile)) return true;
  1314. //For fLastAccess/LastWrite information, use GetFileAttributesEx
  1315. WIN32_FILE_ATTRIBUTE_DATA cacheFileInfo, tempInfo;
  1316. GetFileAttributesExW(ndeDataFile, GetFileExInfoStandard, (LPVOID)&cacheFileInfo);
  1317. if(song->filename)
  1318. {
  1319. GetFileAttributesExW(song->filename, GetFileExInfoStandard, (LPVOID)&tempInfo);
  1320. }
  1321. else
  1322. {
  1323. return true;
  1324. }
  1325. //cachetime - song time
  1326. if(CompareFileTime(&cacheFileInfo.ftLastWriteTime, &tempInfo.ftLastWriteTime) < 0)
  1327. {
  1328. return true;
  1329. }
  1330. return false;
  1331. }
  1332. // read metadata for a specific song from the NDE cache
  1333. bool USBDevice::readRecordFromDB(UsbSong* song)
  1334. {
  1335. if (!song) return false;
  1336. Nullsoft::Utility::AutoLock lock(dbcs);
  1337. openDeviceTable();
  1338. nde_scanner_t scanner = NDE_Table_CreateScanner(deviceTable);
  1339. if (NDE_Scanner_LocateFilename(scanner, DEVICEVIEW_COL_FILENAME, FIRST_RECORD, song->filename))
  1340. {
  1341. nde_field_t artist = NDE_Scanner_GetFieldByID(scanner, DEVICEVIEW_COL_ARTIST);
  1342. wchar_t* artistString = NDE_StringField_GetString(artist);
  1343. lstrcpyn(song->artist, artistString, FIELD_LENGTH);
  1344. nde_field_t album = NDE_Scanner_GetFieldByID(scanner, DEVICEVIEW_COL_ALBUM);
  1345. wchar_t* albumString = NDE_StringField_GetString(album);
  1346. lstrcpyn(song->album, albumString, FIELD_LENGTH);
  1347. nde_field_t albumArtist = NDE_Scanner_GetFieldByID(scanner, DEVICEVIEW_COL_ALBUM_ARTIST);
  1348. wchar_t* albumArtistString = NDE_StringField_GetString(albumArtist);
  1349. lstrcpyn(song->albumartist, albumArtistString, FIELD_LENGTH);
  1350. nde_field_t publisher = NDE_Scanner_GetFieldByID(scanner, DEVICEVIEW_COL_PUBLISHER);
  1351. wchar_t* publisherString = NDE_StringField_GetString(publisher);
  1352. lstrcpyn(song->publisher, publisherString, FIELD_LENGTH);
  1353. nde_field_t composer = NDE_Scanner_GetFieldByID(scanner, DEVICEVIEW_COL_COMPOSER);
  1354. wchar_t* composerString = NDE_StringField_GetString(composer);
  1355. lstrcpyn(song->composer, composerString, FIELD_LENGTH);
  1356. nde_field_t title = NDE_Scanner_GetFieldByID(scanner, DEVICEVIEW_COL_TITLE);
  1357. wchar_t* titleString = NDE_StringField_GetString(title);
  1358. lstrcpyn(song->title, titleString, FIELD_LENGTH);
  1359. nde_field_t genre = NDE_Scanner_GetFieldByID(scanner, DEVICEVIEW_COL_GENRE);
  1360. wchar_t* genreString = NDE_StringField_GetString(genre);
  1361. lstrcpyn(song->genre, genreString, FIELD_LENGTH);
  1362. nde_field_t track = NDE_Scanner_GetFieldByID(scanner, DEVICEVIEW_COL_TRACK);
  1363. int trackInt= NDE_IntegerField_GetValue(track);
  1364. song->track = trackInt;
  1365. nde_field_t year = NDE_Scanner_GetFieldByID(scanner, DEVICEVIEW_COL_YEAR);
  1366. int yearInt= NDE_IntegerField_GetValue(year);
  1367. song->year = yearInt;
  1368. nde_field_t discNumber = NDE_Scanner_GetFieldByID(scanner, DEVICEVIEW_COL_DISC_NUMBER);
  1369. int discNumberInt= NDE_IntegerField_GetValue(discNumber);
  1370. song->discnum = discNumberInt;
  1371. nde_field_t length = NDE_Scanner_GetFieldByID(scanner, DEVICEVIEW_COL_LENGTH);
  1372. int lengthInt= NDE_IntegerField_GetValue(length);
  1373. song->length = lengthInt;
  1374. nde_field_t bitrate = NDE_Scanner_GetFieldByID(scanner, DEVICEVIEW_COL_BITRATE);
  1375. int bitrateInt= NDE_IntegerField_GetValue(bitrate);
  1376. song->bitrate = bitrateInt;
  1377. nde_field_t size = NDE_Scanner_GetFieldByID(scanner, DEVICEVIEW_COL_SIZE);
  1378. int sizeInt= NDE_IntegerField_GetValue(size);
  1379. song->size = sizeInt;
  1380. nde_field_t playcount = NDE_Scanner_GetFieldByID(scanner, DEVICEVIEW_COL_PLAY_COUNT);
  1381. int playcountInt = NDE_IntegerField_GetValue(playcount);
  1382. song->playcount = playcountInt;
  1383. }
  1384. else
  1385. {
  1386. return false;
  1387. }
  1388. NDE_Table_DestroyScanner(deviceTable, scanner);
  1389. //closeDeviceTable();
  1390. return true;
  1391. }
  1392. // write a single record to the nde database
  1393. void USBDevice::writeRecordToDB(UsbSong* songToPrint) {
  1394. Nullsoft::Utility::AutoLock lock(dbcs);
  1395. openDeviceTable();
  1396. nde_scanner_t s = NDE_Table_CreateScanner(deviceTable);
  1397. if (! NDE_Scanner_LocateFilename(s, DEVICEVIEW_COL_FILENAME, FIRST_RECORD, songToPrint->filename))
  1398. {
  1399. NDE_Scanner_New(s);
  1400. }
  1401. if (songToPrint->filename)
  1402. {
  1403. db_setFieldString(s, DEVICEVIEW_COL_FILENAME, songToPrint->filename);
  1404. }
  1405. if (songToPrint->artist)
  1406. {
  1407. db_setFieldString(s, DEVICEVIEW_COL_ARTIST, songToPrint->artist);
  1408. }
  1409. if (songToPrint->albumartist)
  1410. {
  1411. db_setFieldString(s, DEVICEVIEW_COL_ALBUM_ARTIST, songToPrint->albumartist);
  1412. }
  1413. if (songToPrint->publisher)
  1414. {
  1415. db_setFieldString(s, DEVICEVIEW_COL_PUBLISHER, songToPrint->publisher);
  1416. }
  1417. if (songToPrint->composer)
  1418. {
  1419. db_setFieldString(s, DEVICEVIEW_COL_COMPOSER, songToPrint->composer);
  1420. }
  1421. if (songToPrint->album)
  1422. {
  1423. db_setFieldString(s, DEVICEVIEW_COL_ALBUM, songToPrint->album);
  1424. }
  1425. if (songToPrint->title)
  1426. {
  1427. db_setFieldString(s, DEVICEVIEW_COL_TITLE, songToPrint->title);
  1428. }
  1429. if (songToPrint->genre)
  1430. {
  1431. db_setFieldString(s, DEVICEVIEW_COL_GENRE, songToPrint->genre);
  1432. }
  1433. if (songToPrint->year)
  1434. {
  1435. db_setFieldInt(s, DEVICEVIEW_COL_YEAR, songToPrint->year);
  1436. }
  1437. if (songToPrint->track)
  1438. {
  1439. db_setFieldInt(s, DEVICEVIEW_COL_TRACK, songToPrint->track);
  1440. }
  1441. if (songToPrint->bitrate)
  1442. {
  1443. db_setFieldInt(s, DEVICEVIEW_COL_BITRATE, songToPrint->bitrate);
  1444. }
  1445. if (songToPrint->discnum)
  1446. {
  1447. db_setFieldInt(s, DEVICEVIEW_COL_DISC_NUMBER, songToPrint->discnum);
  1448. }
  1449. if (songToPrint->length)
  1450. {
  1451. db_setFieldInt(s, DEVICEVIEW_COL_LENGTH, songToPrint->length);
  1452. }
  1453. if (songToPrint->size)
  1454. {
  1455. db_setFieldInt(s, DEVICEVIEW_COL_SIZE, (int)songToPrint->size);
  1456. }
  1457. if (songToPrint->playcount)
  1458. {
  1459. db_setFieldInt(s, DEVICEVIEW_COL_PLAY_COUNT, songToPrint->playcount);
  1460. }
  1461. NDE_Scanner_Post(s);
  1462. NDE_Table_DestroyScanner(deviceTable, s);
  1463. //NDE_Table_Sync(deviceTable);
  1464. //closeDeviceTable();
  1465. }
  1466. void USBDevice::setupTranscoder() {
  1467. if(transcoder) SendMessage(plugin.hwndPortablesParent,WM_PMP_IPC,(WPARAM)transcoder,PMP_IPC_RELEASE_TRANSCODER);
  1468. transcoder = (Transcoder*)SendMessage(plugin.hwndPortablesParent,WM_PMP_IPC,(WPARAM)this,PMP_IPC_GET_TRANSCODER);
  1469. if(!transcoder) return;
  1470. wchar_t * p = supportedFormats;
  1471. while(p && *p) {
  1472. wchar_t * np = wcschr(p,L';');
  1473. if(np) *np = 0;
  1474. transcoder->AddAcceptableFormat(p);
  1475. if(np) { *np = L';'; p=np+1; }
  1476. else return;
  1477. }
  1478. }
  1479. BOOL CALLBACK browseEnumProc(HWND hwnd, LPARAM lParam)
  1480. {
  1481. wchar_t cl[32] = {0};
  1482. GetClassNameW(hwnd, cl, ARRAYSIZE(cl));
  1483. if (!lstrcmpiW(cl, WC_TREEVIEW))
  1484. {
  1485. PostMessage(hwnd, TVM_ENSUREVISIBLE, 0, (LPARAM)TreeView_GetSelection(hwnd));
  1486. return FALSE;
  1487. }
  1488. return TRUE;
  1489. }
  1490. wchar_t pldir[MAX_PATH] = {0};
  1491. int CALLBACK WINAPI BrowseCallbackProc(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData)
  1492. {
  1493. if(uMsg == BFFM_INITIALIZED)
  1494. {
  1495. SendMessageW(hwnd, BFFM_SETSELECTIONW, 1, (LPARAM)pldir);
  1496. // this is not nice but it fixes the selection not working correctly on all OSes
  1497. EnumChildWindows(hwnd, browseEnumProc, 0);
  1498. }
  1499. return 0;
  1500. }
  1501. static INT_PTR CALLBACK prefs_dialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam) {
  1502. static USBDevice * dev;
  1503. switch(uMsg) {
  1504. case WM_INITDIALOG:
  1505. {
  1506. prefsParam* p = (prefsParam*)lParam;
  1507. dev = (USBDevice*)p->dev;
  1508. p->config_tab_init(hwndDlg,p->parent);
  1509. SetDlgItemTextW(hwndDlg,IDC_NAMEFORMAT,dev->songFormat);
  1510. SetDlgItemTextW(hwndDlg,IDC_PLDIR,dev->pldir);
  1511. SetDlgItemTextW(hwndDlg,IDC_SUPPORTEDFORMATS,dev->supportedFormats);
  1512. if(dev->purgeFolders[0]=='1') CheckDlgButton(hwndDlg,IDC_PURGEFOLDERS,BST_CHECKED);
  1513. else CheckDlgButton(hwndDlg,IDC_PURGEFOLDERS,BST_UNCHECKED);
  1514. SendDlgItemMessageW(hwndDlg,IDC_PL_WRITE_COMBO,CB_ADDSTRING,0,(LPARAM)WASABI_API_LNGSTRINGW(IDS_SLASH_AT_START));
  1515. SendDlgItemMessageW(hwndDlg,IDC_PL_WRITE_COMBO,CB_ADDSTRING,0,(LPARAM)WASABI_API_LNGSTRINGW(IDS_DOT_AT_START));
  1516. SendDlgItemMessageW(hwndDlg,IDC_PL_WRITE_COMBO,CB_ADDSTRING,0,(LPARAM)WASABI_API_LNGSTRINGW(IDS_NO_SLASH_OR_DOT));
  1517. SendDlgItemMessage(hwndDlg,IDC_PL_WRITE_COMBO,CB_SETCURSEL,dev->pl_write_mode,0);
  1518. SetDlgItemTextW(hwndDlg,IDC_PL_WRITE_EG,WASABI_API_LNGSTRINGW(IDS_EG_SLASH+dev->pl_write_mode));
  1519. }
  1520. break;
  1521. case WM_COMMAND:
  1522. switch(LOWORD(wParam))
  1523. {
  1524. case IDC_NAMEFORMAT:
  1525. if(HIWORD(wParam)==EN_CHANGE)
  1526. {
  1527. GetDlgItemTextW(hwndDlg,IDC_NAMEFORMAT,dev->songFormat,sizeof(dev->songFormat)/sizeof(wchar_t));
  1528. WritePrivateProfileStringW(L"pmp_usb",L"songFormat",dev->songFormat,dev->iniFile);
  1529. }
  1530. break;
  1531. case IDC_PLDIR:
  1532. if(HIWORD(wParam)==EN_CHANGE)
  1533. {
  1534. GetDlgItemTextW(hwndDlg,IDC_PLDIR,dev->pldir,sizeof(dev->pldir)/sizeof(wchar_t));
  1535. WritePrivateProfileStringW(L"pmp_usb",L"pldir",dev->pldir,dev->iniFile);
  1536. }
  1537. break;
  1538. case IDC_SUPPORTEDFORMATS:
  1539. if(HIWORD(wParam)==EN_CHANGE)
  1540. {
  1541. GetDlgItemTextW(hwndDlg,IDC_SUPPORTEDFORMATS,dev->supportedFormats,sizeof(dev->supportedFormats)/sizeof(wchar_t));
  1542. WritePrivateProfileStringW(L"pmp_usb",L"supportedFormats",dev->supportedFormats,dev->iniFile);
  1543. }
  1544. break;
  1545. case IDC_REFRESHCACHE:
  1546. {
  1547. char titleStr[32] = {0};
  1548. dev->refreshNDECache();
  1549. MessageBoxA(hwndDlg,WASABI_API_LNGSTRING(IDS_CACHE_UPDATED),
  1550. WASABI_API_LNGSTRING_BUF(IDS_SUCCESS,titleStr,32),MB_OK);
  1551. break;
  1552. }
  1553. case IDC_PL_WRITE_COMBO:
  1554. {
  1555. dev->pl_write_mode = (int)SendMessage((HWND)lParam,CB_GETCURSEL,0,0);
  1556. SetDlgItemTextW(hwndDlg,IDC_PL_WRITE_EG,WASABI_API_LNGSTRINGW(IDS_EG_SLASH+dev->pl_write_mode));
  1557. wchar_t tmp[16] = {0};
  1558. StringCchPrintf(tmp, 16, L"%d", dev->pl_write_mode);
  1559. WritePrivateProfileStringW(L"pmp_usb",L"pl_write_mode",tmp,dev->iniFile);
  1560. break;
  1561. }
  1562. case IDC_FILENAMEHELP:
  1563. {
  1564. char titleStr[64] = {0};
  1565. MessageBoxA(hwndDlg,WASABI_API_LNGSTRING(IDS_FILENAME_FORMATTING_INFO),
  1566. WASABI_API_LNGSTRING_BUF(IDS_FILENAME_FORMAT_HELP,titleStr,64),MB_OK);
  1567. }
  1568. break;
  1569. case IDC_PLBROWSE:
  1570. {
  1571. wchar_t *tempWS;
  1572. BROWSEINFO bi = {0};
  1573. LPMALLOC lpm = 0;
  1574. wchar_t bffFileName[MAX_PATH] = {0};
  1575. bi.hwndOwner = hwndDlg;
  1576. bi.pszDisplayName = bffFileName;
  1577. bi.lpszTitle = WASABI_API_LNGSTRINGW(IDS_SELECT_FOLDER_TO_LOAD_PLAYLISTS);
  1578. bi.ulFlags = BIF_RETURNONLYFSDIRS | BIF_EDITBOX | BIF_NEWDIALOGSTYLE;
  1579. bi.lpfn = BrowseCallbackProc;
  1580. lstrcpynW(pldir, dev->pldir, MAX_PATH);
  1581. LPITEMIDLIST iil = SHBrowseForFolder(&bi);
  1582. if(iil)
  1583. {
  1584. SHGetPathFromIDListW(iil,bffFileName);
  1585. SHGetMalloc(&lpm);
  1586. // path is now in bffFileName
  1587. }
  1588. tempWS = _wcsdup(bffFileName);
  1589. if(tempWS[0] == dev->drive)
  1590. {
  1591. lstrcpynW(dev->pldir, tempWS, MAX_PATH);
  1592. SetDlgItemText(hwndDlg,IDC_PLDIR,tempWS);
  1593. }
  1594. else
  1595. {
  1596. if(bffFileName[0] != 0) //dont print error if the user selected 'cancel'
  1597. {
  1598. char titleStr[32] = {0};
  1599. MessageBoxA(hwndDlg,WASABI_API_LNGSTRING(IDS_ERR_SELECTED_PATH_NOT_ON_DEVICE),
  1600. WASABI_API_LNGSTRING_BUF(IDS_ERROR,titleStr,32), MB_OK);
  1601. }
  1602. }
  1603. free(tempWS);
  1604. }
  1605. break;
  1606. case IDC_FORMATSHELP:
  1607. {
  1608. char titleStr[64] = {0};
  1609. MessageBoxA(hwndDlg,WASABI_API_LNGSTRING(IDS_SUPPORTED_FORMAT_INFO),
  1610. WASABI_API_LNGSTRING_BUF(IDS_SUPPORTED_FORMAT_HELP,titleStr,64),MB_OK);
  1611. }
  1612. break;
  1613. case IDC_PURGEFOLDERS:
  1614. {
  1615. StringCchCopy(dev->purgeFolders, ARRAYSIZE(dev->purgeFolders),
  1616. ((IsDlgButtonChecked(hwndDlg,IDC_PURGEFOLDERS) == BST_CHECKED) ? L"1" : L"0"));
  1617. WritePrivateProfileStringW(L"pmp_usb",L"purgeFolders",dev->purgeFolders,dev->iniFile);
  1618. }
  1619. break;
  1620. case IDC_RESCAN:
  1621. {
  1622. //update changes
  1623. SetFileAttributesW(dev->iniFile,FILE_ATTRIBUTE_HIDDEN);
  1624. wchar_t driveletter = dev->drive; //hold on to driveletter before it goes away
  1625. //disconnect
  1626. dev->Close();
  1627. //connect
  1628. pmpDeviceLoading load;
  1629. dev = new USBDevice(driveletter,&load);
  1630. char titleStr[64] = {0};
  1631. MessageBoxA(hwndDlg,WASABI_API_LNGSTRING(IDS_RESCAN_COMPLETE_SAVED),
  1632. WASABI_API_LNGSTRING_BUF(IDS_RESCAN_COMPLETE,titleStr,64),MB_OK);
  1633. }
  1634. break;
  1635. }
  1636. }
  1637. return 0;
  1638. }
  1639. // update a track with new metadata (string)
  1640. void USBDevice::updateTrackField(UsbSong* song, unsigned int col, const void* newValue, int fieldType)
  1641. {
  1642. if (!song) return;
  1643. Nullsoft::Utility::AutoLock lock(dbcs);
  1644. openDeviceTable();
  1645. nde_scanner_t s = NDE_Table_CreateScanner(deviceTable);
  1646. if (NDE_Scanner_LocateFilename(s, DEVICEVIEW_COL_FILENAME, FIRST_RECORD, song->filename))
  1647. {
  1648. switch (fieldType)
  1649. {
  1650. case FIELD_STRING:
  1651. db_setFieldString(s, col, (wchar_t *)(newValue));
  1652. break;
  1653. case FIELD_INTEGER:
  1654. db_setFieldInt(s, col, *((int *)newValue));
  1655. default:
  1656. break;
  1657. }
  1658. }
  1659. NDE_Scanner_Post(s);
  1660. NDE_Table_DestroyScanner(deviceTable, s);
  1661. //NDE_Table_Sync(deviceTable);
  1662. //closeDeviceTable();
  1663. }
  1664. UsbSong::UsbSong() {
  1665. filename[0]=artist[0]=album[0]=title[0]=genre[0]=albumartist[0]=publisher[0]=composer[0]=0;
  1666. filled=year=track=length=discnum=bitrate=playcount=(int)(size=0);
  1667. }
  1668. USBArt::USBArt(ARGB32 *bits, int w, int h) :bits(bits), w(w), h(h)
  1669. {
  1670. }
  1671. USBArt::~USBArt()
  1672. {
  1673. if (bits)
  1674. WASABI_API_MEMMGR->sysFree(bits);
  1675. }