Main.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387
  1. #include "main.h"
  2. #include "DownloadsDialog.h"
  3. #include "DownloadsParse.h"
  4. #include "Preferences.h"
  5. #include "XMLWriter.h"
  6. #include "..\..\General\gen_ml/ml.h"
  7. #include "Defaults.h"
  8. #include "..\..\General\gen_ml/ml_ipc_0313.h"
  9. #include "api__ml_downloads.h"
  10. #include "Downloaded.h"
  11. #include "DownloadStatus.h"
  12. #include <api/service/waServiceFactory.h>
  13. #include <strsafe.h>
  14. wchar_t *ml_cfg = 0,
  15. xmlFileName[1024] = {0};
  16. ATOM VIEWPROP = 0;
  17. api_downloadManager *WAC_API_DOWNLOADMANAGER = 0;
  18. DownloadViewCallback *downloadViewCallback = 0;
  19. static int Init();
  20. static void Quit();
  21. static INT_PTR MessageProc(int message_type, INT_PTR param1, INT_PTR param2, INT_PTR param3);
  22. DWORD threadStorage=TLS_OUT_OF_INDEXES;
  23. extern "C" winampMediaLibraryPlugin plugin =
  24. {
  25. MLHDR_VER,
  26. "nullsoft(ml_downloads.dll)",
  27. Init,
  28. Quit,
  29. MessageProc,
  30. 0,
  31. 0,
  32. 0,
  33. };
  34. //static prefsDlgRecW preferences;
  35. //static wchar_t preferencesName[64] = {0};
  36. int downloads_treeItem = 0,
  37. podcast_parent = 0,
  38. no_auto_hide = 0;
  39. HANDLE hMainThread;
  40. HCURSOR hDragNDropCursor;
  41. int winampVersion = 0, dirty = 0;
  42. api_application *applicationApi = NULL;
  43. api_explorerfindfile *WASABI_API_EXPLORERFINDFILE = 0;
  44. // wasabi based services for localisation support
  45. api_language *WASABI_API_LNG = 0;
  46. HINSTANCE WASABI_API_LNG_HINST = 0, WASABI_API_ORIG_HINST = 0;
  47. int icons[4] = {-1, -1, -1, -1};
  48. int activeIcon = 0;
  49. int totalIcons = 4;
  50. static Nullsoft::Utility::LockGuard navigationLock;
  51. // used to get the downloads view parented to the podcast view
  52. #define CSTR_INVARIANT MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT)
  53. #define NAVITEM_PREFIX L"podcast_svc_"
  54. #define SERVICE_PODCAST 720
  55. enum
  56. {
  57. DOWNLOADS_TIMER_NAVNODE = 35784,
  58. };
  59. HNAVITEM Navigation_FindService(UINT serviceId)
  60. {
  61. HWND hLibrary = plugin.hwndLibraryParent;
  62. INT cchPrefix = ARRAYSIZE(NAVITEM_PREFIX) - 1;
  63. WCHAR szBuffer[256] = {0};
  64. NAVITEM itemInfo = {0};
  65. itemInfo.cbSize = sizeof(itemInfo);
  66. itemInfo.mask = NIMF_TEXTINVARIANT;
  67. itemInfo.cchInvariantMax = ARRAYSIZE(szBuffer);
  68. itemInfo.pszInvariant = szBuffer;
  69. itemInfo.hItem = MLNavCtrl_GetFirst(hLibrary);
  70. while(NULL != itemInfo.hItem)
  71. {
  72. if (FALSE != MLNavItem_GetInfo(hLibrary, &itemInfo) &&
  73. CSTR_EQUAL == CompareString(CSTR_INVARIANT, NORM_IGNORECASE, itemInfo.pszInvariant, cchPrefix,
  74. NAVITEM_PREFIX, cchPrefix))
  75. {
  76. return itemInfo.hItem;
  77. }
  78. itemInfo.hItem = MLNavItem_GetNext(hLibrary, itemInfo.hItem);
  79. }
  80. return NULL;
  81. }
  82. void Navigation_Update_Icon(void)
  83. {
  84. Nullsoft::Utility::AutoLock navlock(navigationLock);
  85. HNAVITEM hItem = NULL;
  86. if(downloads_treeItem)
  87. {
  88. hItem = MLNavCtrl_FindItemById(plugin.hwndLibraryParent,downloads_treeItem);
  89. }
  90. if (hItem)
  91. {
  92. NAVITEM item;
  93. item.cbSize = sizeof(NAVITEM);
  94. item.hItem = hItem;
  95. item.iSelectedImage = item.iImage = icons[activeIcon];
  96. activeIcon = (activeIcon + 1) % totalIcons;
  97. item.mask = NIMF_IMAGE | NIMF_IMAGESEL;
  98. MLNavItem_SetInfo(plugin.hwndLibraryParent, &item);
  99. }
  100. }
  101. BOOL Navigation_Update(void)
  102. {
  103. int activeDownloads = 0;
  104. int historyDownloads = 0;
  105. {
  106. Nullsoft::Utility::AutoLock historylock(downloadedFiles.downloadedLock);
  107. historyDownloads = (int)downloadedFiles.downloadList.size();
  108. }
  109. {
  110. Nullsoft::Utility::AutoLock statuslock(downloadStatus.statusLock);
  111. activeDownloads = (int)downloadStatus.downloads.size();
  112. }
  113. Nullsoft::Utility::AutoLock navlock(navigationLock);
  114. HNAVITEM hItem = NULL;
  115. if (downloads_treeItem)
  116. {
  117. hItem = MLNavCtrl_FindItemById(plugin.hwndLibraryParent,downloads_treeItem);
  118. }
  119. NAVINSERTSTRUCT nis = {0};
  120. nis.item.cbSize = sizeof(NAVITEM);
  121. nis.item.pszText = WASABI_API_LNGSTRINGW(IDS_DOWNLOADS);
  122. nis.item.iSelectedImage = nis.item.iImage = icons[0];
  123. WCHAR szName[256] = {0};
  124. if (activeDownloads && SUCCEEDED(StringCchPrintf(szName, ARRAYSIZE(szName), L"%s (%u)", WASABI_API_LNGSTRINGW(IDS_DOWNLOADS), activeDownloads)))
  125. nis.item.pszText = szName;
  126. if (activeDownloads > 0 || historyDownloads > 0 || no_auto_hide == 2)
  127. {
  128. if (!hItem)
  129. {
  130. nis.item.pszInvariant = NAVITEM_UNIQUESTR;
  131. nis.item.mask = NIMF_TEXT | NIMF_TEXTINVARIANT | NIMF_IMAGE | NIMF_IMAGESEL;
  132. if(podcast_parent) nis.hParent = Navigation_FindService(SERVICE_PODCAST);
  133. NAVITEM nvItem = {sizeof(NAVITEM),0,NIMF_ITEMID,};
  134. nvItem.hItem = MLNavCtrl_InsertItem(plugin.hwndLibraryParent, &nis);
  135. MLNavItem_GetInfo(plugin.hwndLibraryParent, &nvItem);
  136. downloads_treeItem = nvItem.id;
  137. }
  138. else
  139. {
  140. nis.item.hItem = hItem;
  141. nis.item.mask = NIMF_TEXT;
  142. MLNavItem_SetInfo(plugin.hwndLibraryParent, &nis.item);
  143. }
  144. }
  145. else if (hItem)
  146. {
  147. nis.item.hItem = hItem;
  148. nis.item.mask = NIMF_TEXT | NIMF_IMAGE | NIMF_IMAGESEL;
  149. MLNavItem_SetInfo(plugin.hwndLibraryParent, &nis.item);
  150. }
  151. return TRUE;
  152. }
  153. void CALLBACK Downloads_Nav_Timer(HWND hwnd, UINT uMsg, UINT_PTR eventId, ULONG elapsed)
  154. {
  155. switch (eventId)
  156. {
  157. case DOWNLOADS_TIMER_NAVNODE:
  158. if (downloadStatus.CurrentlyDownloading())
  159. Navigation_Update_Icon();
  160. break;
  161. }
  162. }
  163. int Init()
  164. {
  165. hMainThread = GetCurrentThread();
  166. hDragNDropCursor = LoadCursor( GetModuleHandle( L"gen_ml.dll" ), MAKEINTRESOURCE( ML_IDC_DRAGDROP ) );
  167. threadStorage = TlsAlloc();
  168. if ( 0 == VIEWPROP )
  169. {
  170. VIEWPROP = GlobalAddAtom( L"Nullsoft_DownloadsView" );
  171. if ( VIEWPROP == 0 )
  172. return ML_INIT_FAILURE;
  173. }
  174. winampVersion = (int)SendMessage( plugin.hwndWinampParent, WM_WA_IPC, 0, IPC_GETVERSION );
  175. waServiceFactory *sf = plugin.service->service_getServiceByGuid( DownloadManagerGUID );
  176. if ( !sf ) // no sense in continuing
  177. return ML_INIT_FAILURE;
  178. else
  179. WAC_API_DOWNLOADMANAGER = reinterpret_cast<api_downloadManager *>( sf->getInterface() );
  180. // loader so that we can get the localisation service api for use
  181. sf = plugin.service->service_getServiceByGuid( languageApiGUID );
  182. if ( sf )
  183. WASABI_API_LNG = reinterpret_cast<api_language*>( sf->getInterface() );
  184. sf = plugin.service->service_getServiceByGuid( applicationApiServiceGuid );
  185. if ( sf )
  186. WASABI_API_APP = reinterpret_cast<api_application*>( sf->getInterface() );
  187. sf = plugin.service->service_getServiceByGuid( ExplorerFindFileApiGUID );
  188. if ( sf )
  189. WASABI_API_EXPLORERFINDFILE = reinterpret_cast<api_explorerfindfile*>( sf->getInterface() );
  190. // need to have this initialised before we try to do anything with localisation features
  191. WASABI_API_START_LANG( plugin.hDllInstance, MlDownloadsLangGUID );
  192. static wchar_t szDescription[ 256 ];
  193. StringCchPrintf( szDescription, ARRAYSIZE( szDescription ), WASABI_API_LNGSTRINGW( IDS_PLUGIN_NAME ), PLUGIN_VERSION_MAJOR, PLUGIN_VERSION_MINOR );
  194. plugin.description = (char*)szDescription;
  195. mediaLibrary.library = plugin.hwndLibraryParent;
  196. mediaLibrary.winamp = plugin.hwndWinampParent;
  197. mediaLibrary.instance = plugin.hDllInstance;
  198. BuildDefaults( plugin.hwndWinampParent );
  199. mediaLibrary.BuildPath( L"Plugins\\ml\\downloads.xml", xmlFileName, 1024 );
  200. if ( PathFileExists( xmlFileName ) )
  201. {
  202. DownloadsParse downloader;
  203. downloader.DownloadFile( xmlFileName );
  204. }
  205. else
  206. {
  207. wchar_t xmlRssFileName[ 1024 ] = { 0 };
  208. mediaLibrary.BuildPath( L"Plugins\\ml\\feeds\\rss.xml", xmlRssFileName, 1024 );
  209. {
  210. DownloadsParse rssDownloader;
  211. rssDownloader.DownloadFile( xmlRssFileName );
  212. }
  213. }
  214. icons[ 0 ] = mediaLibrary.AddTreeImageBmp( IDB_TREEITEM_DOWNLOADS );
  215. icons[ 1 ] = mediaLibrary.AddTreeImageBmp( IDB_TREEITEM_DOWNLOADS1 );
  216. icons[ 2 ] = mediaLibrary.AddTreeImageBmp( IDB_TREEITEM_DOWNLOADS2 );
  217. icons[ 3 ] = mediaLibrary.AddTreeImageBmp( IDB_TREEITEM_DOWNLOADS3 );
  218. ml_cfg = (wchar_t *)SendMessage( plugin.hwndWinampParent, WM_WA_IPC, 0, IPC_GETMLINIFILEW );
  219. podcast_parent = ( !!GetPrivateProfileInt( L"gen_ml_config", L"podcast_parent", 0, ml_cfg ) );
  220. no_auto_hide = GetPrivateProfileInt( L"gen_ml_config", L"no_auto_hide", 0, ml_cfg );
  221. Navigation_Update();
  222. downloadViewCallback = new DownloadViewCallback();
  223. WAC_API_DOWNLOADMANAGER->RegisterStatusCallback( downloadViewCallback );
  224. SetTimer( plugin.hwndLibraryParent, DOWNLOADS_TIMER_NAVNODE, 1000, Downloads_Nav_Timer );
  225. return ML_INIT_SUCCESS;
  226. }
  227. void Quit()
  228. {
  229. KillTimer( plugin.hwndLibraryParent, DOWNLOADS_TIMER_NAVNODE );
  230. // If there are still files downloading, cancel download to remove incomplete downloaded files
  231. while ( downloadStatus.CurrentlyDownloading() )
  232. {
  233. Nullsoft::Utility::AutoLock lock(downloadStatus.statusLock);
  234. DownloadToken dltoken = downloadStatus.downloads.begin()->first;
  235. WAC_API_DOWNLOADMANAGER->CancelDownload(dltoken);
  236. }
  237. if (dirty)
  238. {
  239. SaveDownloads( xmlFileName, downloadedFiles );
  240. dirty = 0;
  241. }
  242. WAC_API_DOWNLOADMANAGER->UnregisterStatusCallback( downloadViewCallback );
  243. downloadViewCallback->Release();
  244. waServiceFactory *sf = plugin.service->service_getServiceByGuid( applicationApiServiceGuid );
  245. if ( sf != NULL )
  246. sf->releaseInterface(WASABI_API_APP);
  247. sf = plugin.service->service_getServiceByGuid(ExplorerFindFileApiGUID);
  248. if ( sf != NULL )
  249. sf->releaseInterface(WASABI_API_EXPLORERFINDFILE);
  250. sf = plugin.service->service_getServiceByGuid(DownloadManagerGUID);
  251. if ( sf != NULL )
  252. sf->releaseInterface(WAC_API_DOWNLOADMANAGER);
  253. if ( VIEWPROP != 0 )
  254. {
  255. GlobalDeleteAtom(VIEWPROP);
  256. VIEWPROP = 0;
  257. }
  258. }
  259. HWND CALLBACK DownloadDialog_Create( HWND hParent );
  260. INT_PTR MessageProc( int msg, INT_PTR param1, INT_PTR param2, INT_PTR param3 )
  261. {
  262. switch ( msg )
  263. {
  264. case ML_MSG_DOWNLOADS_VIEW_LOADED:
  265. return TRUE;
  266. case ML_MSG_DOWNLOADS_VIEW_POSITION:
  267. {
  268. // toggle the position of the node based on the preferences settings
  269. if ( param2 )
  270. {
  271. podcast_parent = (int)param1;
  272. if ( downloads_treeItem )
  273. {
  274. HNAVITEM hItem = MLNavCtrl_FindItemById( plugin.hwndLibraryParent, downloads_treeItem );
  275. if (hItem)
  276. {
  277. if ( MLNavCtrl_DeleteItem( plugin.hwndLibraryParent, hItem ) )
  278. {
  279. downloads_treeItem = 0;
  280. }
  281. }
  282. }
  283. }
  284. Navigation_Update();
  285. return 0;
  286. }
  287. case ML_MSG_TREE_ONCREATEVIEW:
  288. return ( param1 == downloads_treeItem ) ? (INT_PTR)DownloadDialog_Create( (HWND)param2 ) : 0;
  289. case ML_MSG_NO_CONFIG:
  290. return TRUE;
  291. case ML_MSG_NOTOKTOQUIT:
  292. if (downloadStatus.CurrentlyDownloading())
  293. {
  294. wchar_t titleStr[32] = {0};
  295. if ( MessageBox( plugin.hwndLibraryParent, WASABI_API_LNGSTRINGW( IDS_CANCEL_DOWNLOADS_AND_QUIT ), WASABI_API_LNGSTRINGW_BUF( IDS_CONFIRM_QUIT, titleStr, 32 ), MB_YESNO | MB_ICONQUESTION ) == IDNO )
  296. return TRUE;
  297. }
  298. return FALSE;
  299. case ML_MSG_WRITE_CONFIG:
  300. if ( dirty )
  301. {
  302. SaveDownloads( xmlFileName, downloadedFiles );
  303. dirty = 0;
  304. }
  305. break;
  306. case ML_MSG_VIEW_PLAY_ENQUEUE_CHANGE:
  307. enqueuedef = (int)param1;
  308. groupBtn = (int)param2;
  309. PostMessage( downloads_window, WM_APP + 104, param1, param2 );
  310. return 0;
  311. }
  312. return 0;
  313. }
  314. extern "C" __declspec(dllexport) winampMediaLibraryPlugin *winampGetMediaLibraryPlugin()
  315. {
  316. return &plugin;
  317. }