AMNWatcher.cpp 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  1. #include "main.h"
  2. #include "./amnwatcher.h"
  3. #include <shlobj.h>
  4. #include <strsafe.h>
  5. #include "playlists.h"
  6. #include "PlaylistManager.h"
  7. #include "PlaylistView.h"
  8. waServiceFactory *AMNWatcher::watcherFactory = NULL;
  9. BOOL IsMusicNowWantUs(void)
  10. {
  11. HKEY key;
  12. DWORD value = 0, length = sizeof(DWORD);
  13. if (ERROR_SUCCESS == RegOpenKeyExW( HKEY_CURRENT_USER, L"Software\\AOL Music Now\\UserPreferences", 0, KEY_QUERY_VALUE, &key ))
  14. {
  15. long retCode = RegQueryValueExW(key, L"IntegrateWithWinamp", NULL, NULL, (LPBYTE) & value, &length);
  16. if (ERROR_SUCCESS != retCode) value = TRUE;
  17. RegCloseKey(key);
  18. }
  19. return value;
  20. }
  21. BOOL GetMusicNowPlaylistPath(LPWSTR *pathNew, LPWSTR *pathOld) // CAUTION!!! this function will allocate memory for the string using malloc
  22. {
  23. // first check rgistry
  24. HKEY key;
  25. *pathNew = NULL;
  26. *pathOld = NULL;
  27. if (ERROR_SUCCESS == RegOpenKeyExW( HKEY_CURRENT_USER, L"Software\\AOL Music Now\\UserPreferences", 0, KEY_QUERY_VALUE, &key ))
  28. {
  29. const wchar_t *rPath = L"PlaylistDirectory";
  30. DWORD length;
  31. if (ERROR_SUCCESS == RegQueryValueExW(key, rPath, NULL, NULL, NULL, &length)) // try registry ( for future)
  32. {
  33. *pathNew = (LPWSTR)malloc(length);
  34. if (ERROR_SUCCESS != RegQueryValueExW(key, rPath, NULL, NULL, (LPBYTE)*pathNew, &length)) { free(*pathNew); *pathNew = NULL; }
  35. }
  36. RegCloseKey(key);
  37. if (*pathNew && !PathFileExists(*pathNew)) { free(*pathNew); *pathNew = NULL; } //check that path is actualy exist
  38. LPITEMIDLIST pidl;
  39. if (S_OK == SHGetSpecialFolderLocation(NULL, CSIDL_PERSONAL, &pidl))
  40. {
  41. wchar_t path[MAX_PATH*4] = {0};
  42. if(SHGetPathFromIDListW(pidl, path))
  43. {
  44. const wchar_t *suffix = L"Music Now Playlists";
  45. int cchLen = lstrlenW(path) + lstrlenW(suffix) + 32;
  46. if (!*pathNew) // no luck - use deafult's
  47. {
  48. *pathNew = (LPWSTR)malloc(cchLen*sizeof(wchar_t));
  49. StringCchPrintfW(*pathNew, cchLen, L"%s\\%s", path, suffix);
  50. if (!PathFileExists(*pathNew)) {free(*pathNew); *pathNew = NULL; }// i give up - can't find anything
  51. }
  52. // now let's try old path
  53. *pathOld = (LPWSTR)malloc(cchLen*sizeof(wchar_t));
  54. StringCchPrintfW(*pathOld, cchLen, L"%s\\AOL %s", path, suffix);
  55. if (!PathFileExists(*pathOld)) { free(*pathOld); *pathOld = NULL; }
  56. }
  57. CoTaskMemFree(pidl);
  58. }
  59. }
  60. return (NULL != *pathNew) || (NULL != *pathOld);
  61. }
  62. AMNWatcher::AMNWatcher(void) : watcherOld(NULL), watcherNew(NULL), dirty(FALSE)
  63. {}
  64. AMNWatcher::~AMNWatcher(void)
  65. {
  66. //Destroy(); // have to just let it leak. you should call Destroy() manually
  67. }
  68. int AMNWatcher::Init(api_service *service, const wchar_t *trackPath)
  69. {
  70. BOOL retCode = FALSE;
  71. if (!IsMusicNowWantUs()) return retCode;
  72. if (watcherFactory) return retCode;
  73. LPWSTR pathNew, pathOld;
  74. if (!GetMusicNowPlaylistPath(&pathNew, &pathOld)) return retCode;
  75. int cchLen = lstrlenW(pathNew);
  76. if (cchLen > 1 && pathNew[cchLen -1] == L'\\') pathNew[cchLen -1] = 0x00;
  77. cchLen = lstrlenW(pathOld);
  78. if (cchLen > 1 && pathOld[cchLen -1] == L'\\') pathOld[cchLen -1] = 0x00;
  79. watcherFactory = service->service_getServiceByGuid(watcherGUID);
  80. if (watcherFactory)
  81. {
  82. if (pathNew)
  83. {
  84. watcherNew = (api_watcher*)watcherFactory->getInterface();
  85. watcherNew->Create( L"WAMN_PLS_NEW", pathNew, TRUE, WATCHER_TRACKMODE_CENTRAL, OnWatcherNotify);
  86. }
  87. if (pathOld)
  88. {
  89. watcherOld = (api_watcher*)watcherFactory->getInterface();
  90. watcherOld->Create( L"WAMN_PLS_OLD", pathOld, TRUE, WATCHER_TRACKMODE_CENTRAL, OnWatcherNotify);
  91. }
  92. for (int i = 0; i < 2; i++)
  93. {
  94. api_watcher *watcher = (i) ? watcherOld : watcherNew;
  95. if (!watcher) continue;
  96. watcher->SetExtensionFilter(L"WPL", WATCHER_FILTERTYPE_INCLUDE);
  97. watcher->SetUserData(this);
  98. watcher->SetCallBack(OnWatcherNotify);
  99. watcher->SetTrackingPath(trackPath);
  100. watcher->Start();
  101. watcher->ForceScan(FALSE, SCANPRIORITY_IDLE);
  102. }
  103. }
  104. free(pathNew);
  105. free(pathOld);
  106. return TRUE;
  107. }
  108. void AMNWatcher::Destroy(void)
  109. {
  110. if (watcherNew)
  111. {
  112. watcherNew->Stop();
  113. watcherFactory->releaseInterface(watcherNew);
  114. watcherNew = NULL;
  115. }
  116. if (watcherOld)
  117. {
  118. watcherOld->Stop();
  119. watcherFactory->releaseInterface(watcherOld);
  120. watcherOld = NULL;
  121. }
  122. }
  123. int AMNWatcher::OnWatcherNotify(api_watcher *sender, UINT message, LONG_PTR param, void* userdata)
  124. {
  125. UNREFERENCED_PARAMETER(sender);
  126. AMNWatcher *watcher = (AMNWatcher*)userdata;
  127. if (WATCHER_MSG_FILE == message)
  128. {
  129. WATCHERCHANGEINFO *info = (WATCHERCHANGEINFO*)param;
  130. // ignore some names
  131. if (info->cchFile >= 21) // can be "AOL Music Now - Auido.wpl" or "AOL Music Now - Video.wpl"
  132. {
  133. const wchar_t *testname = info->file + info->cchFile - 21;
  134. if (CSTR_EQUAL == CompareString(LOCALE_USER_DEFAULT, NULL, testname, 9, L"Music Now", 9)) return 1;
  135. }
  136. else if ( 17 == info->cchFile && CSTR_EQUAL == CompareString(LOCALE_USER_DEFAULT, NULL, info->file, 13, L"AOL Music Now", 13)) return 1;
  137. wchar_t fullName[MAX_PATH*4];
  138. PathCombineW(fullName, info->path, info->file);
  139. size_t i(0);
  140. switch (info->state)
  141. {
  142. case WATCHER_FILESTATE_ADDED:
  143. case WATCHER_FILESTATE_CHANGED:
  144. {
  145. if (!info->file)
  146. break;
  147. wchar_t *title = _wcsdup(info->file);
  148. unsigned int len = lstrlen(title);
  149. while (len && title[len] != '.') len--;
  150. if (len != 0) title[len] = 0x00;
  151. while (i != playlists.size() && lstrcmpW(fullName, playlists.at(i).filename)) i++;
  152. if ( i == playlists.size())
  153. {
  154. AddPlaylist(title, fullName, TRUE, playlistManager->CountItems(fullName));
  155. watcher->dirty = TRUE;
  156. }
  157. else
  158. {
  159. int length = playlistManager->GetLengthMilliseconds(fullName);
  160. int numItems = (int)playlistManager->CountItems(fullName);
  161. if (playlists.at(i).length != length || playlists.at(i).numItems != numItems)
  162. {
  163. StringCchCopy(playlists.at(i).title, 1024, title);
  164. playlists.at(i).length = length;
  165. playlists.at(i).numItems = numItems;
  166. HWND hwnd = (HWND) SendMessage(plugin.hwndLibraryParent, WM_ML_IPC, 0, ML_IPC_GETCURRENTVIEW);
  167. if (hwnd)
  168. {
  169. wchar_t* title = (wchar_t*)GetPropW(hwnd, L"TITLE");
  170. if (title && 0 == lstrcmp(title, playlists[i].title)) SendMessage(hwnd, WM_PLAYLIST_RELOAD, 0, 0);
  171. }
  172. watcher->dirty = TRUE;
  173. }
  174. }
  175. free(title);
  176. }
  177. break;
  178. case WATCHER_FILESTATE_REMOVED:
  179. {
  180. for ( i = 0; i < playlists.size(); i++)
  181. {
  182. if (0 == lstrcmpW(fullName, playlists.at(i).filename))
  183. {
  184. HWND hwnd = (HWND) SendMessage(plugin.hwndLibraryParent, WM_ML_IPC, 0, ML_IPC_GETCURRENTVIEW);
  185. if (hwnd)
  186. {
  187. wchar_t* title = (wchar_t *)GetPropW(hwnd, L"TITLE");
  188. if (title && 0 == lstrcmp(title, playlists[i].title)) SendMessage(hwnd, WM_PLAYLIST_UNLOAD, 0, 0);
  189. }
  190. if (playlists.at(i).treeId)
  191. mediaLibrary.RemoveTreeItem(playlists.at(i).treeId);
  192. playlists.eraseAt(i);
  193. i--;
  194. watcher->dirty = TRUE;
  195. break;
  196. }
  197. }
  198. }
  199. break;
  200. }
  201. }
  202. else if (WATCHER_MSG_STATUS == message)
  203. {
  204. if (STATUS_SCANER_STOPPED == param || STATUS_SCANER_FINISHED == param)
  205. {
  206. if (watcher->dirty)
  207. {
  208. SavePlaylists();
  209. RefreshPlaylistsList();
  210. watcher->dirty = FALSE;
  211. }
  212. }
  213. }
  214. return 1;
  215. }