ImporterAPI.cpp 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299
  1. #include "ImporterAPI.h"
  2. #include "../xml/obj_xml.h"
  3. #include "importer.h"
  4. #include "resource.h"
  5. #include "api__ml_impex.h"
  6. #include "../plist/loader.h"
  7. #include <api/service/waservicefactory.h>
  8. #include <shlobj.h>
  9. extern winampMediaLibraryPlugin plugin;
  10. int Load(const wchar_t *filename, obj_xml *parser)
  11. {
  12. if (!parser)
  13. return 1; // no sense in continuing if there's no parser available
  14. HANDLE file = CreateFileW(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, NULL, NULL);
  15. if (file == INVALID_HANDLE_VALUE)
  16. return 1;
  17. while (true)
  18. {
  19. char data[1024] = {0};
  20. DWORD bytesRead = 0;
  21. if (ReadFile(file, data, 1024, &bytesRead, NULL) && bytesRead)
  22. {
  23. parser->xmlreader_feed(data, bytesRead);
  24. }
  25. else
  26. break;
  27. }
  28. CloseHandle(file);
  29. parser->xmlreader_feed(0, 0);
  30. return 0;
  31. }
  32. static bool GetiTunesPreferencesPath(wchar_t *path, size_t path_cch)
  33. {
  34. wchar_t appdata[MAX_PATH] = {0};
  35. SHGetSpecialFolderPathW(NULL, appdata, CSIDL_APPDATA, FALSE);
  36. StringCchPrintf(path, path_cch, L"%s\\Apple Computer\\iTunes\\iTunesPrefs.xml", appdata);
  37. return true;
  38. }
  39. static bool GetiTunesLibraryPath(wchar_t *path, size_t path_cch)
  40. {
  41. wchar_t itunes_pref[MAX_PATH] = {0};
  42. if (GetiTunesPreferencesPath(itunes_pref, MAX_PATH))
  43. {
  44. plistLoader it;
  45. obj_xml *parser=0;
  46. waServiceFactory *factory = plugin.service->service_getServiceByGuid(obj_xmlGUID);
  47. if (factory)
  48. parser = (obj_xml *)factory->getInterface();
  49. if (parser)
  50. {
  51. // load the XML, this creates an iTunes DB in memory, and returns the root key
  52. parser->xmlreader_open();
  53. parser->xmlreader_registerCallback(L"plist\f*", &it);
  54. Load(itunes_pref, parser);
  55. parser->xmlreader_unregisterCallback(&it);
  56. parser->xmlreader_close();
  57. plistKey *root_key = &it;
  58. plistData *root_dict = root_key->getData();
  59. if (root_dict)
  60. {
  61. plistKey *prefs_key = ((plistDict*)root_dict)->getKey(L"User Preferences");
  62. if (prefs_key)
  63. {
  64. plistData *prefs_dict= prefs_key->getData();
  65. if (prefs_dict)
  66. {
  67. plistKey *location_key = ((plistDict*)prefs_dict)->getKey(L"iTunes Library XML Location:1");
  68. if (location_key)
  69. {
  70. plistData *location_data = location_key->getData();
  71. if (location_data)
  72. {
  73. plistRaw *location_data_raw = (plistRaw *)location_data;
  74. if (location_data_raw)
  75. {
  76. int size;
  77. const wchar_t *mem = (const wchar_t *)location_data_raw->getMem(&size);
  78. if (mem)
  79. {
  80. memcpy(path, mem, size);
  81. path[size/2]=0;
  82. return true;
  83. }
  84. }
  85. }
  86. }
  87. }
  88. }
  89. }
  90. }
  91. }
  92. return false;
  93. }
  94. // -----------------------------------------------------------------------
  95. // import status window proc
  96. // -----------------------------------------------------------------------
  97. static BOOL CALLBACK import_dlgproc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam)
  98. {
  99. switch (uMsg)
  100. {
  101. case WM_INITDIALOG:
  102. {
  103. SetWindowLongPtr(hwndDlg, GWLP_USERDATA, lParam);
  104. // show import progress controls
  105. ShowWindow(GetDlgItem(hwndDlg, IDC_PROCESSING_STATE), SW_HIDE);
  106. ShowWindow(GetDlgItem(hwndDlg, IDC_PROGRESS_PERCENT), SW_SHOWNORMAL);
  107. ShowWindow(GetDlgItem(hwndDlg, IDC_TRACKS), SW_SHOWNORMAL);
  108. SetWindowText(hwndDlg,WASABI_API_LNGSTRINGW(IDS_IMPORTING_DATABASE));
  109. SetDlgItemText(hwndDlg, IDC_PROCESSING_STATE, WASABI_API_LNGSTRINGW(IDS_LOADING_XML));
  110. SendMessage(GetDlgItem(hwndDlg, IDC_PROGRESS_PERCENT), PBM_SETRANGE, 0, MAKELPARAM(0, 100));
  111. SendDlgItemMessage(hwndDlg, IDC_PROGRESS_PERCENT, PBM_SETPOS, 0, 0);
  112. setDialogIcon(hwndDlg);
  113. SetTimer(hwndDlg, 666, 250, 0);
  114. SetForegroundWindow(hwndDlg);
  115. return 0;
  116. }
  117. case WM_TIMER:
  118. if (wParam == 666)
  119. {
  120. int *progress = (int *)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
  121. if (progress[0] == -666)
  122. {
  123. KillTimer(hwndDlg, 666);
  124. EndDialog(hwndDlg, 0);
  125. }
  126. else
  127. {
  128. // display progress
  129. SetDlgItemText(hwndDlg, IDC_TRACKS, StringPrintfW(WASABI_API_LNGSTRINGW(IDS_TRACKS_IMPORTED_X), progress[0]));
  130. SendDlgItemMessage(hwndDlg, IDC_PROGRESS_PERCENT, PBM_SETPOS, (int)((double)progress[0]/progress[1]*100.0), 0);
  131. }
  132. }
  133. break;
  134. case WM_COMMAND:
  135. {
  136. int wID = LOWORD(wParam);
  137. switch (wID) {
  138. case IDOK:
  139. case IDCANCEL:
  140. EndDialog(hwndDlg, wID);
  141. break;
  142. }
  143. }
  144. return 0;
  145. }
  146. return 0;
  147. }
  148. static DWORD CALLBACK ImportThread(LPVOID param)
  149. {
  150. WASABI_API_DIALOGBOXPARAMW(IDD_INFODIALOG, NULL, import_dlgproc, (LPARAM)param);
  151. return 0;
  152. }
  153. int ImporterAPI::ImportFromFile(HWND parent, const wchar_t *library_file)
  154. {
  155. // create an XML parser
  156. obj_xml *parser=0;
  157. waServiceFactory *factory = plugin.service->service_getServiceByGuid(obj_xmlGUID);
  158. if (factory)
  159. parser = (obj_xml *)factory->getInterface();
  160. if (parser)
  161. {
  162. // create status window
  163. int progress[2] = {0};
  164. DWORD threadId = 0;
  165. HANDLE importThread = CreateThread(0, 0, ImportThread, progress, 0, &threadId);
  166. // create an iTunes XML library reader
  167. plistLoader it;
  168. // load the XML, this creates an iTunes DB in memory, and returns the root key
  169. parser->xmlreader_open();
  170. parser->xmlreader_registerCallback(L"plist\f*", &it);
  171. Load(library_file, parser);
  172. parser->xmlreader_unregisterCallback(&it);
  173. parser->xmlreader_close();
  174. plistKey *root_key = &it;
  175. // we start at the root key
  176. if (root_key) {
  177. // the root key contains a dictionary
  178. plistData *root_dict = root_key->getData();
  179. if (root_dict && root_dict->getType() == PLISTDATA_DICT) {
  180. // that dictionary contains a number of keys, one of which contains a dictionary of tracks
  181. plistKey *tracks_key = ((plistDict*)root_dict)->getKey(L"Tracks");
  182. plistData *tracks_dict = tracks_key?tracks_key->getData():0;
  183. if (tracks_dict && tracks_dict->getType() == PLISTDATA_DICT) {
  184. // we have the tracks dictionary ...
  185. plistDict *tracks = (plistDict *)tracks_dict;
  186. progress[1]=tracks?tracks->getNumKeys():0;
  187. // ... now enumerate tracks
  188. for (int i=0;i<progress[1];i++) {
  189. // each track is a key in the tracks dictionary, and contains a dictionary of properties
  190. plistKey *track_key = tracks->enumKey(i);
  191. plistData *track_dict = track_key->getData();
  192. // prepare an item record
  193. itemRecordW ir;
  194. MEMZERO(&ir, sizeof(ir));
  195. ir.year = ir.track = ir.length = -1;
  196. ir.lastplay = -1;
  197. ir.type = 0; // this makes it an Audio file (unless otherwise specified
  198. if (track_dict->getType() == PLISTDATA_DICT) {
  199. // we have the track's dictionary of properties...
  200. plistDict *track = (plistDict *)track_dict;
  201. int tn = track->getNumKeys();
  202. // ... now enumerate the properties
  203. for (int j=0;j<tn;j++) {
  204. plistKey *prop = track->enumKey(j);
  205. Importer_AddKeyToItemRecord(prop, ir);
  206. }
  207. // add or update the file
  208. SendMessage(plugin.hwndLibraryParent, WM_ML_IPC, (WPARAM)&ir, ML_IPC_DB_ADDORUPDATEITEMW);
  209. // free the record
  210. freeRecord(&ir);
  211. // show progress
  212. ++progress[0];
  213. }
  214. }
  215. }
  216. }
  217. }
  218. //done
  219. progress[0]=-666;
  220. if (importThread)
  221. {
  222. WaitForSingleObject(importThread, INFINITE);
  223. CloseHandle(importThread);
  224. }
  225. // tell gen_ml we modified the db
  226. SendMessage(plugin.hwndLibraryParent, WM_ML_IPC, 0, ML_IPC_DB_SYNCDB);
  227. factory->releaseInterface(parser);
  228. }
  229. else
  230. return DISPATCH_FAILURE;
  231. return DISPATCH_SUCCESS;
  232. }
  233. bool ImporterAPI::iTunesExists()
  234. {
  235. wchar_t itunes_path[MAX_PATH] = {0};
  236. if (GetiTunesPreferencesPath(itunes_path, MAX_PATH))
  237. {
  238. return GetFileAttributesW(itunes_path) != INVALID_FILE_ATTRIBUTES;
  239. }
  240. return false;
  241. }
  242. int ImporterAPI::ImportFromiTunes(HWND parent)
  243. {
  244. wchar_t itunes_path[MAX_PATH] = {0};
  245. if (GetiTunesLibraryPath(itunes_path, MAX_PATH))
  246. {
  247. return ImportFromFile(parent, itunes_path);
  248. }
  249. return DISPATCH_FAILURE;
  250. }
  251. int ImportPlaylists(HWND parent, const wchar_t *library_file);
  252. int ImporterAPI::ImportPlaylistsFromiTunes(HWND parent)
  253. {
  254. wchar_t itunes_path[MAX_PATH] = {0};
  255. if (GetiTunesLibraryPath(itunes_path, MAX_PATH))
  256. {
  257. return ImportPlaylists(parent, itunes_path);
  258. }
  259. return DISPATCH_FAILURE;
  260. }
  261. #define CBCLASS ImporterAPI
  262. START_DISPATCH;
  263. CB(API_ITUNES_IMPORTER_ITUNESEXISTS, iTunesExists)
  264. CB(API_ITUNES_IMPORTER_IMPORTFROMFILE, ImportFromFile)
  265. CB(API_ITUNES_IMPORTER_IMPORTFROMITUNES, ImportFromiTunes)
  266. CB(API_ITUNES_IMPORTER_IMPORTPLAYLISTSFROMITUNES, ImportPlaylistsFromiTunes)
  267. END_DISPATCH;
  268. #undef CBCLASS