device.cpp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797
  1. #include "main.h"
  2. #include "device.h"
  3. #include "XMLString.h"
  4. #include "api.h"
  5. #include "../xml/obj_xml.h"
  6. #include "../xml/ifc_xmlreaderparams.h"
  7. #include <api/service/waServiceFactory.h>
  8. #include "SongListDownloader.h"
  9. #include "SongDownloader.h"
  10. #include "RenameDownloader.h"
  11. #include "resource.h"
  12. #include "PlaylistSync.h"
  13. #include "nu/AutoWide.h"
  14. #include "images.h"
  15. #include <mmsystem.h> // for mmioFOURCC
  16. #include <strsafe.h>
  17. #include <shlwapi.h>
  18. TemplateDevice::TemplateDevice(WifiDevice *device, const char *root_url, DeviceInfo *in_device_info, TrackList *track_list, PlaylistsList *playlists_list)
  19. : url(strdup(root_url))
  20. {
  21. DeviceInfo_Copy(&device_info, in_device_info);
  22. //tracks.own(*track_list);
  23. for (auto track : tracks)
  24. {
  25. delete track;
  26. }
  27. tracks.clear();
  28. tracks.assign(track_list->begin(), track_list->end());
  29. track_list->clear();
  30. //playlists.own(*playlists_list);
  31. for (auto playlist : playlists)
  32. {
  33. delete playlist;
  34. }
  35. playlists.clear();
  36. playlists.assign(playlists_list->begin(), playlists_list->end());
  37. playlists_list->clear();
  38. transcoder=0;
  39. transferQueueLength=0;
  40. transcoder = (Transcoder*)SendMessage(plugin.hwndPortablesParent,WM_PMP_IPC,(WPARAM)this,PMP_IPC_GET_TRANSCODER);
  41. if(transcoder)
  42. {
  43. transcoder->AddAcceptableFormat(L"m4a");
  44. transcoder->AddAcceptableFormat(L"mp3");
  45. transcoder->AddAcceptableFormat(L"wav");
  46. transcoder->AddAcceptableFormat(L"m4v");
  47. transcoder->AddAcceptableFormat(L"mp4");
  48. transcoder->AddAcceptableFormat(L"avi");
  49. transcoder->AddAcceptableFormat(L"3gp");
  50. transcoder->AddAcceptableFormat(L"mid");
  51. transcoder->AddAcceptableFormat(L"ogg");
  52. }
  53. }
  54. TemplateDevice::~TemplateDevice()
  55. {
  56. free(url);
  57. //tracks.deleteAll();
  58. for (auto track : tracks)
  59. {
  60. delete track;
  61. }
  62. tracks.clear();
  63. //playlists.deleteAll();
  64. for (auto playlist : playlists)
  65. {
  66. delete playlist;
  67. }
  68. playlists.clear();
  69. if (transcoder)
  70. SendMessage(plugin.hwndPortablesParent,WM_PMP_IPC,(WPARAM)transcoder,PMP_IPC_RELEASE_TRANSCODER);
  71. transcoder=0;
  72. }
  73. __int64 TemplateDevice::getDeviceCapacityAvailable() // in bytes
  74. {
  75. return device_info.total_space - device_info.used_space;
  76. }
  77. __int64 TemplateDevice::getDeviceCapacityTotal()
  78. {
  79. return device_info.total_space;
  80. }
  81. void TemplateDevice::Eject()
  82. {
  83. SendMessage(plugin.hwndPortablesParent,WM_PMP_IPC,(intptr_t)this,PMP_IPC_DEVICEDISCONNECTED);
  84. }
  85. void TemplateDevice::Close()
  86. {
  87. SendMessage(plugin.hwndPortablesParent,WM_PMP_IPC,(intptr_t)this,PMP_IPC_DEVICEDISCONNECTED);
  88. }
  89. void TemplateDevice::CloseAsync()
  90. {
  91. PostMessage(plugin.hwndPortablesParent,WM_PMP_IPC,(intptr_t)this,PMP_IPC_DEVICEDISCONNECTED);
  92. }
  93. int PostFile(const char *url, const wchar_t *filename, const itemRecordW *track, obj_xml *parser, int *killswitch,
  94. void (*callback)(void *callbackContext, wchar_t *status), void *context, char *new_item_id, size_t new_item_id_len);
  95. int PostAlbumArt(const char *url, const itemRecordW *track, obj_xml *parser, int *killswitch, void (*callback)(void *callbackContext, wchar_t *status), void *context);
  96. static int64_t FileSize64(const wchar_t * filename)
  97. {
  98. WIN32_FIND_DATA f={0};
  99. HANDLE h = FindFirstFileW(filename,&f);
  100. if(h == INVALID_HANDLE_VALUE) return -1;
  101. FindClose(h);
  102. ULARGE_INTEGER i;
  103. i.HighPart = f.nFileSizeHigh;
  104. i.LowPart = f.nFileSizeLow;
  105. return i.QuadPart;
  106. }
  107. // return 0 for success, -1 for failed or cancelled
  108. int TemplateDevice::transferTrackToDevice(const itemRecordW *track, // the track to transfer
  109. void * callbackContext, //pass this to the callback
  110. void (*callback)(void *callbackContext, wchar_t *status), // call this every so often so the GUI can be updated. Including when finished!
  111. songid_t * songid, // fill in the songid when you are finished
  112. int * killswitch // if this gets set to anything other than zero, the transfer has been cancelled by the user
  113. )
  114. {
  115. wchar_t newfile[MAX_PATH] = {0};
  116. wchar_t *filename = track->filename;
  117. bool delete_file = false;
  118. if(transcoder && transcoder->ShouldTranscode(track->filename))
  119. {
  120. wchar_t ext[10] = {0};
  121. int r = transcoder->CanTranscode(track->filename, ext, track->length);
  122. if(r != 0 && r != -1)
  123. {
  124. transcoder->GetTempFilePath(ext,newfile);
  125. if(transcoder->TranscodeFile(track->filename,newfile,killswitch,callback,callbackContext)) return -1;
  126. filename = newfile;
  127. delete_file=true;
  128. }
  129. }
  130. char new_item_id[512] = {0};
  131. char upload_url[555] = {0};
  132. StringCbPrintfA(upload_url, sizeof(upload_url), "%s/upload", url);
  133. if (PostFile(upload_url, filename, track, 0, killswitch, callback, callbackContext, new_item_id, 512) == 0 && new_item_id[0])
  134. {
  135. StringCbPrintfA(upload_url, sizeof(upload_url), "%s/albumart/%s", url, new_item_id);
  136. PostAlbumArt(upload_url, track, 0, killswitch, callback, callbackContext);
  137. callback(callbackContext, WASABI_API_LNGSTRINGW(IDS_COMPLETED));
  138. WifiTrack *new_track = new WifiTrack(new_item_id, track, filename);
  139. *songid = (songid_t)new_track;
  140. device_info.used_space += FileSize64(filename); // TODO: count album art also. or re-query for device info
  141. if (delete_file)
  142. DeleteFile(filename);
  143. return 0;
  144. }
  145. else
  146. {
  147. callback(callbackContext, L"Failed");
  148. if (delete_file)
  149. DeleteFile(filename);
  150. return -1;
  151. }
  152. }
  153. int TemplateDevice::trackAddedToTransferQueue(const itemRecordW *track)
  154. {
  155. // return 0 to accept, -1 for "not enough space", -2 for "incorrect format"
  156. __int64 l;
  157. if(transcoder && transcoder->ShouldTranscode(track->filename))
  158. {
  159. int k = transcoder->CanTranscode(track->filename, 0, track->length);
  160. if(k == -1) return -2;
  161. if(k == 0) l = (__int64)FileSize64(track->filename);
  162. else l = (__int64)k;
  163. }
  164. else
  165. {
  166. l = FileSize64(track->filename);
  167. }
  168. int64_t avail = getDeviceCapacityAvailable();
  169. int64_t cmp = transferQueueLength;
  170. cmp += l;
  171. cmp += 3000000LL;
  172. if(cmp > avail)
  173. return -1;
  174. else
  175. {
  176. transferQueueLength += l;
  177. return 0;
  178. }
  179. }
  180. void TemplateDevice::trackRemovedFromTransferQueue(const itemRecordW *track)
  181. {
  182. int64_t l = FileSize64(track->filename);
  183. if(transcoder && transcoder->ShouldTranscode(track->filename))
  184. {
  185. int k = transcoder->CanTranscode(track->filename, 0, track->length);
  186. if(k != -1 && k != 0) l = (__int64)k;
  187. }
  188. transferQueueLength -= l;
  189. }
  190. // return the amount of space that will be taken up on the device by the track (once it has been tranferred)
  191. // or 0 for incompatable. This is usually the filesize, unless you are transcoding. An estimate is acceptable.
  192. __int64 TemplateDevice::getTrackSizeOnDevice(const itemRecordW *track)
  193. {
  194. if(transcoder && transcoder->ShouldTranscode(track->filename))
  195. {
  196. int k = transcoder->CanTranscode(track->filename, 0, track->length);
  197. if(k != -1 && k != 0) return k;
  198. }
  199. return track->filesize;
  200. }
  201. int HTTP_Delete(const char *url);
  202. void TemplateDevice::deleteTrack(songid_t songid)
  203. {
  204. // physically remove from device. Be sure to remove it from all the playlists!
  205. WifiTrack *track = (WifiTrack *)songid;
  206. char delete_url[1024] = {0};
  207. StringCbPrintfA(delete_url, sizeof(delete_url), "%s/file/%S", url, track->id);
  208. HTTP_Delete(delete_url);
  209. again1:
  210. for (WifiPlaylist::TrackList::iterator itr2=tracks.begin(); itr2 != tracks.end(); itr2++)
  211. {
  212. WifiTrack *trackitr = *itr2;
  213. if (!wcscmp(trackitr->id, track->id))
  214. {
  215. tracks.erase(itr2);
  216. if (trackitr != track)
  217. delete trackitr;
  218. goto again1; // iterator was invalidated
  219. }
  220. }
  221. for (PlaylistsList::iterator itr=playlists.begin();itr!=playlists.end();itr++)
  222. {
  223. WifiPlaylist *playlist = *itr;
  224. again2:
  225. for (WifiPlaylist::TrackList::iterator itr2=playlist->tracks.begin(); itr2 != playlist->tracks.end(); itr2++)
  226. {
  227. WifiTrack *trackitr = *itr2;
  228. if (!wcscmp(trackitr->id, track->id))
  229. {
  230. playlist->tracks.erase(itr2);
  231. if (trackitr != track)
  232. delete trackitr;
  233. goto again2; // iterator was invalidated
  234. }
  235. }
  236. }
  237. delete track;
  238. }
  239. void TemplateDevice::commitChanges()
  240. {
  241. // optional. Will be called at a good time to save changes
  242. }
  243. int TemplateDevice::getPlaylistCount()
  244. {
  245. // always at least 1. playlistnumber 0 is the Master Playlist containing all tracks.
  246. return 1 + (int)playlists.size();
  247. }
  248. // PlaylistName(0) should return the name of the device.
  249. void TemplateDevice::getPlaylistName(int playlistnumber, wchar_t *buf, int len)
  250. {
  251. if (playlistnumber == 0)
  252. {
  253. StringCchCopy(buf, len, device_info.name);
  254. }
  255. else
  256. {
  257. WifiPlaylist *playlist = playlists[playlistnumber-1];
  258. StringCchCopy(buf, len, playlist->name);
  259. }
  260. }
  261. int TemplateDevice::getPlaylistLength(int playlistnumber)
  262. {
  263. if (playlistnumber == 0)
  264. {
  265. size_t size = tracks.size();
  266. return (int)size;
  267. }
  268. else
  269. {
  270. WifiPlaylist *playlist = playlists[playlistnumber-1];
  271. size_t size = playlist->tracks.size();
  272. return (int)size;
  273. }
  274. }
  275. songid_t TemplateDevice::getPlaylistTrack(int playlistnumber,int songnum)
  276. {
  277. if (playlistnumber == 0)
  278. {
  279. WifiTrack *track = tracks[songnum];
  280. return (songid_t)track;
  281. }
  282. else
  283. {
  284. WifiPlaylist *playlist = playlists[playlistnumber-1];
  285. WifiTrack *track = playlist->tracks[songnum];
  286. return (songid_t)track;
  287. }
  288. }
  289. void TemplateDevice::setPlaylistName(int playlistnumber, const wchar_t *buf)
  290. {
  291. if (playlistnumber == 0) // playlist 0 is the device itself
  292. {
  293. RenameDevice(url, buf);
  294. StringCbCopy(device_info.name, sizeof(device_info.name), buf);
  295. }
  296. else
  297. {
  298. WifiPlaylist *playlist = playlists[playlistnumber-1];
  299. playlist->SetName(buf);
  300. Sync_RenamePlaylist(url, playlist->id, buf);
  301. }
  302. }
  303. void TemplateDevice::playlistSwapItems(int playlistnumber, int posA, int posB)
  304. {
  305. // swap the songs at position posA and posB
  306. // TODO: implement
  307. }
  308. void TemplateDevice::sortPlaylist(int playlistnumber, int sortBy)
  309. {
  310. // TODO: implement
  311. }
  312. void TemplateDevice::addTrackToPlaylist(int playlistnumber, songid_t songid)
  313. {
  314. // adds songid to the end of the playlist
  315. WifiTrack *track = (WifiTrack *)songid;
  316. if (playlistnumber == 0)
  317. {
  318. tracks.push_back(track);
  319. }
  320. else
  321. {
  322. playlists[playlistnumber - 1]->tracks.push_back(new WifiTrack(*track));
  323. Sync_AddToPlaylist(url, playlists[playlistnumber-1]->id, track->id);
  324. }
  325. }
  326. void TemplateDevice::removeTrackFromPlaylist(int playlistnumber, int songnum)
  327. {
  328. //where songnum is the position of the track in the playlist
  329. if (playlistnumber == 0)
  330. {
  331. tracks.erase(tracks.begin() + songnum);
  332. }
  333. else
  334. {
  335. WifiPlaylist *playlist = playlists[playlistnumber-1];
  336. WifiTrack *track = playlist->tracks[songnum];
  337. Sync_RemoveFromPlaylist(url, playlist->id, track->id);
  338. }
  339. }
  340. void TemplateDevice::deletePlaylist(int playlistnumber)
  341. {
  342. if (playlistnumber == 0)
  343. {
  344. }
  345. else
  346. {
  347. WifiPlaylist *playlist = playlists[playlistnumber-1];
  348. Sync_DeletePlaylist(url, playlist->id);
  349. playlists.erase(playlists.begin() + playlistnumber-1);
  350. }
  351. }
  352. int TemplateDevice::newPlaylist(const wchar_t *name)
  353. {
  354. // create empty playlist, returns playlistnumber. -1 for failed.
  355. WifiPlaylist *new_playlist = Sync_NewPlaylist(url, name);
  356. if (new_playlist)
  357. {
  358. playlists.push_back(new_playlist);
  359. return (int)playlists.size();
  360. }
  361. return -1;
  362. }
  363. void TemplateDevice::getTrackArtist(songid_t songid, wchar_t *buf, int len)
  364. {
  365. WifiTrack *track = (WifiTrack *)songid;
  366. StringCchCopy(buf, len, track->artist);
  367. }
  368. void TemplateDevice::getTrackAlbum(songid_t songid, wchar_t *buf, int len)
  369. {
  370. WifiTrack *track = (WifiTrack *)songid;
  371. StringCchCopy(buf, len, track->album);
  372. }
  373. void TemplateDevice::getTrackTitle(songid_t songid, wchar_t *buf, int len)
  374. {
  375. WifiTrack *track = (WifiTrack *)songid;
  376. StringCchCopy(buf, len, track->title);
  377. }
  378. int TemplateDevice::getTrackTrackNum(songid_t songid)
  379. {
  380. WifiTrack *track = (WifiTrack *)songid;
  381. return track->track;
  382. }
  383. int TemplateDevice::getTrackDiscNum(songid_t songid)
  384. {
  385. // TODO: implement
  386. return 0;
  387. }
  388. void TemplateDevice::getTrackGenre(songid_t songid, wchar_t * buf, int len)
  389. {
  390. buf[0]=0;
  391. }
  392. int TemplateDevice::getTrackYear(songid_t songid)
  393. {
  394. WifiTrack *track = (WifiTrack *)songid;
  395. return track->year;
  396. }
  397. __int64 TemplateDevice::getTrackSize(songid_t songid)
  398. {
  399. WifiTrack *track = (WifiTrack *)songid;
  400. return track->size;
  401. }
  402. int TemplateDevice::getTrackLength(songid_t songid)
  403. {
  404. WifiTrack *track = (WifiTrack *)songid;
  405. return track->duration;
  406. }
  407. int TemplateDevice::getTrackBitrate(songid_t songid)
  408. {
  409. return 128;
  410. }
  411. int TemplateDevice::getTrackPlayCount(songid_t songid)
  412. {
  413. return 0;
  414. }
  415. int TemplateDevice::getTrackRating(songid_t songid)
  416. {
  417. return 0;
  418. }
  419. __time64_t TemplateDevice::getTrackLastPlayed(songid_t songid)
  420. {
  421. return 0;
  422. }
  423. __time64_t TemplateDevice::getTrackLastUpdated(songid_t songid)
  424. {
  425. WifiTrack *track = (WifiTrack *)songid;
  426. return track->last_updated;
  427. }
  428. void TemplateDevice::getTrackAlbumArtist(songid_t songid, wchar_t *buf, int len)
  429. {
  430. buf[0]=0;
  431. }
  432. void TemplateDevice::getTrackPublisher(songid_t songid, wchar_t *buf, int len)
  433. {
  434. buf[0]=0;
  435. }
  436. void TemplateDevice::getTrackComposer(songid_t songid, wchar_t *buf, int len)
  437. {
  438. WifiTrack *track = (WifiTrack *)songid;
  439. StringCchCopy(buf, len, track->composer);
  440. }
  441. int TemplateDevice::getTrackType(songid_t songid)
  442. {
  443. return 0;
  444. }
  445. void TemplateDevice::getTrackExtraInfo(songid_t songid, const wchar_t *field, wchar_t *buf, int len)
  446. {
  447. // TODO: implement
  448. //optional
  449. }
  450. // feel free to ignore any you don't support
  451. void TemplateDevice::setTrackArtist(songid_t songid, const wchar_t *value)
  452. {
  453. // TODO: implement
  454. }
  455. void TemplateDevice::setTrackAlbum(songid_t songid, const wchar_t *value)
  456. {
  457. // TODO: implement
  458. }
  459. void TemplateDevice::setTrackTitle(songid_t songid, const wchar_t *value)
  460. {
  461. // TODO: implement
  462. }
  463. void TemplateDevice::setTrackTrackNum(songid_t songid, int value)
  464. {
  465. // TODO: implement
  466. }
  467. void TemplateDevice::setTrackDiscNum(songid_t songid, int value)
  468. {
  469. // TODO: implement
  470. }
  471. void TemplateDevice::setTrackGenre(songid_t songid, const wchar_t *value)
  472. {
  473. // TODO: implement
  474. }
  475. void TemplateDevice::setTrackYear(songid_t songid, int year)
  476. {
  477. // TODO: implement
  478. }
  479. void TemplateDevice::setTrackPlayCount(songid_t songid, int value)
  480. {
  481. // TODO: implement
  482. }
  483. void TemplateDevice::setTrackRating(songid_t songid, int value)
  484. {
  485. // TODO: implement
  486. }
  487. void TemplateDevice::setTrackLastPlayed(songid_t songid, __time64_t value)
  488. {
  489. // TODO: implement
  490. } // in unix time format
  491. void TemplateDevice::setTrackLastUpdated(songid_t songid, __time64_t value)
  492. {
  493. // TODO: implement
  494. } // in unix time format
  495. void TemplateDevice::setTrackAlbumArtist(songid_t songid, const wchar_t *value)
  496. {
  497. // TODO: implement
  498. }
  499. void TemplateDevice::setTrackPublisher(songid_t songid, const wchar_t *value)
  500. {
  501. // TODO: implement
  502. }
  503. void TemplateDevice::setTrackComposer(songid_t songid, const wchar_t *value)
  504. {
  505. // TODO: implement
  506. }
  507. void TemplateDevice::setTrackExtraInfo(songid_t songid, const wchar_t *field, const wchar_t *value)
  508. {
  509. // TODO: implement
  510. } //optional
  511. bool TemplateDevice::playTracks(songid_t * songidList, int listLength, int startPlaybackAt, bool enqueue)
  512. {
  513. if(!enqueue) //clear playlist
  514. {
  515. SendMessage(plugin.hwndWinampParent,WM_WA_IPC,0,IPC_DELETE);
  516. }
  517. for(int i=0; i<listLength; i++)
  518. {
  519. WifiTrack*curSong = (WifiTrack *)songidList[i];
  520. if (curSong)
  521. {
  522. wchar_t fn[1024] = {0};
  523. if (curSong->mime_type && !_wcsicmp(curSong->mime_type, L"audio/mp4"))
  524. StringCbPrintf(fn, sizeof(fn), L"%S/file/%s?=.m4a", url, curSong->id);
  525. else if (curSong->mime_type && !_wcsicmp(curSong->mime_type, L"audio/x-ms-wma"))
  526. StringCbPrintf(fn, sizeof(fn), L"%S/file/%s?=.wma", url, curSong->id);
  527. else if (curSong->mime_type && (!_wcsicmp(curSong->mime_type, L"application/ogg") || !_wcsicmp(curSong->mime_type, L"audio/ogg")))
  528. StringCbPrintf(fn, sizeof(fn), L"%S/file/%s?=.ogg", url, curSong->id);
  529. else
  530. StringCbPrintf(fn, sizeof(fn), L"%S/file/%s", url, curSong->id);
  531. enqueueFileWithMetaStructW s={0};
  532. s.filename = fn;
  533. s.title = _wcsdup(curSong->title);
  534. s.ext = NULL;
  535. s.length = curSong->duration/1000;
  536. SendMessage(plugin.hwndWinampParent, WM_WA_IPC, (WPARAM)&s, IPC_PLAYFILEW);
  537. }
  538. else
  539. {
  540. //char titleStr[32];
  541. //MessageBoxA(plugin.hwndWinampParent,WASABI_API_LNGSTRING(IDS_CANNOT_OPEN_FILE),
  542. // WASABI_API_LNGSTRING_BUF(IDS_ERROR,titleStr,32),0);
  543. }
  544. }
  545. if(!enqueue)
  546. {
  547. //play item startPlaybackAt
  548. SendMessage(plugin.hwndWinampParent,WM_WA_IPC,startPlaybackAt,IPC_SETPLAYLISTPOS);
  549. SendMessage(plugin.hwndWinampParent,WM_COMMAND,40047,0); //stop
  550. SendMessage(plugin.hwndWinampParent,WM_COMMAND,40045,0); //play
  551. }
  552. return true;
  553. }
  554. static const intptr_t encoder_blacklist[] =
  555. {
  556. mmioFOURCC('W','M','A',' '),
  557. mmioFOURCC('A','A','C','H'),
  558. mmioFOURCC('A','A','C','P'),
  559. mmioFOURCC('A','A','C','r'),
  560. mmioFOURCC('F','L','A','C'),
  561. mmioFOURCC('M','P','2',' '),
  562. mmioFOURCC('A','D','T','S'),
  563. };
  564. intptr_t TemplateDevice::extraActions(intptr_t param1, intptr_t param2, intptr_t param3,intptr_t param4)
  565. {
  566. switch(param1)
  567. {
  568. case DEVICE_SET_ICON: // icons
  569. {
  570. MLTREEIMAGE * i = (MLTREEIMAGE*)param2;
  571. const ModelInfo *modelInfo;
  572. i->hinst = plugin.hDllInstance;
  573. modelInfo = device_info.modelInfo;
  574. if (NULL == modelInfo || NULL == modelInfo->smallIcon)
  575. {
  576. modelInfo = GetDefaultModelInfo();
  577. if (NULL == modelInfo)
  578. break;
  579. }
  580. i->resourceId = (int)(intptr_t)modelInfo->smallIcon;
  581. }
  582. break;
  583. case DEVICE_CAN_RENAME_DEVICE:
  584. return 1;
  585. case DEVICE_GET_ICON:
  586. ModelInfo_GetIconPath(device_info.modelInfo, (int)param2, (int)param3, (wchar_t*)param4, 260, TRUE);
  587. break;
  588. case DEVICE_GET_CONNECTION_TYPE:
  589. {
  590. const char **type = (const char **)param2;
  591. *type = "WiFi";
  592. return 1;
  593. }
  594. case DEVICE_SUPPORTS_PODCASTS:
  595. return 1; // we don't support podcasts
  596. case DEVICE_GET_MODEL:
  597. ModelInfo_CopyDisplayName(device_info.modelInfo, (wchar_t*)param2, param3);
  598. return 1;
  599. case DEVICE_SUPPORTED_METADATA:
  600. {
  601. intptr_t supported = SUPPORTS_ARTIST | SUPPORTS_ALBUM | SUPPORTS_TITLE | SUPPORTS_TRACKNUM /*| SUPPORTS_DISCNUM | SUPPORTS_GENRE */|
  602. SUPPORTS_YEAR | SUPPORTS_SIZE | SUPPORTS_LENGTH /*| SUPPORTS_BITRATE */| SUPPORTS_LASTUPDATED /*| SUPPORTS_ALBUMARTIST */|
  603. SUPPORTS_COMPOSER /*| SUPPORTS_PUBLISHER | SUPPORTS_ALBUMART*/;
  604. return supported;
  605. }
  606. break;
  607. case DEVICE_VETO_ENCODER:
  608. {
  609. for (size_t i=0;i<sizeof(encoder_blacklist)/sizeof(*encoder_blacklist);i++)
  610. {
  611. if (param2 == encoder_blacklist[i])
  612. return 1;
  613. }
  614. }
  615. return 0;
  616. }
  617. // TODO: implement more
  618. return 0;
  619. }
  620. bool TemplateDevice::copyToHardDriveSupported()
  621. {
  622. return true;
  623. }
  624. __int64 TemplateDevice::songSizeOnHardDrive(songid_t song)
  625. {
  626. WifiTrack *track = (WifiTrack *)song;
  627. return track->size;
  628. }
  629. int TemplateDevice::copyToHardDrive(songid_t song, // the song to copy
  630. 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).
  631. void * callbackContext, //pass this to the callback
  632. void (*callback)(void * callbackContext, wchar_t * status), // call this every so often so the GUI can be updated. Including when finished!
  633. int * killswitch // if this gets set to anything other than zero, the transfer has been cancelled by the user
  634. )
  635. {
  636. WifiTrack *track = (WifiTrack *)song;
  637. char download_url[1024] = {0};
  638. StringCbPrintfA(download_url, sizeof(download_url), "%s/file/%S", url, track->id);
  639. HANDLE event = CreateEvent(0, FALSE, FALSE, 0);
  640. if (!_wcsicmp(track->mime_type, L"audio/mpeg"))
  641. wcsncat(path, L".mp3", MAX_PATH);
  642. else if (!_wcsicmp(track->mime_type, L"audio/mp4"))
  643. wcsncat(path, L".m4a", MAX_PATH);
  644. else if (!_wcsicmp(track->mime_type, L"audio/x-ms-wma"))
  645. wcsncat(path, L".wma", MAX_PATH);
  646. else if (!_wcsicmp(track->mime_type, L"application/ogg") || !_wcsicmp(track->mime_type, L"audio/ogg") )
  647. wcsncat(path, L".ogg", MAX_PATH);
  648. // TODO: more
  649. SongDownloader *song_downloader = new SongDownloader(path, event, callback, callbackContext);
  650. song_downloader->AddRef();
  651. WAC_API_DOWNLOADMANAGER->DownloadEx(download_url, song_downloader, api_downloadManager::DOWNLOADEX_CALLBACK);
  652. WaitForSingleObject(event, INFINITE);
  653. song_downloader->Release();
  654. return 0; // TODO: check error code
  655. }
  656. // art functions
  657. void TemplateDevice::setArt(songid_t songid, void *buf, int w, int h)
  658. {
  659. //buf is in format ARGB32*
  660. // TODO: implement
  661. }
  662. pmpart_t TemplateDevice::getArt(songid_t songid)
  663. {
  664. // TODO: implement
  665. return 0;
  666. }
  667. void TemplateDevice::releaseArt(pmpart_t art)
  668. {
  669. // TODO: implement
  670. }
  671. int TemplateDevice::drawArt(pmpart_t art, HDC dc, int x, int y, int w, int h)
  672. {
  673. // TODO: implement
  674. return 0;
  675. }
  676. void TemplateDevice::getArtNaturalSize(pmpart_t art, int *w, int *h)
  677. {
  678. // TODO: implement
  679. }
  680. void TemplateDevice::setArtNaturalSize(pmpart_t art, int w, int h)
  681. {
  682. // TODO: implement
  683. }
  684. void TemplateDevice::getArtData(pmpart_t art, void* data)
  685. {
  686. // data ARGB32* is at natural size
  687. // TODO: implement
  688. }
  689. bool TemplateDevice::artIsEqual(pmpart_t a, pmpart_t b)
  690. {
  691. // TODO: implement
  692. return false;
  693. }