aboutsummaryrefslogtreecommitdiff
path: root/Src/Plugins/General/gen_ff/MediaDownloader.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Src/Plugins/General/gen_ff/MediaDownloader.cpp')
-rw-r--r--Src/Plugins/General/gen_ff/MediaDownloader.cpp307
1 files changed, 307 insertions, 0 deletions
diff --git a/Src/Plugins/General/gen_ff/MediaDownloader.cpp b/Src/Plugins/General/gen_ff/MediaDownloader.cpp
new file mode 100644
index 00000000..70a0f476
--- /dev/null
+++ b/Src/Plugins/General/gen_ff/MediaDownloader.cpp
@@ -0,0 +1,307 @@
+#include "precomp__gen_ff.h"
+#include "main.h"
+#include "../Agave/Language/api_language.h"
+#include "../../..\Components\wac_network\wac_network_http_receiver_api.h"
+#include "../nu/AutoWide.h"
+#include "../nu/AutoChar.h"
+#include "../nu/AutoCharFn.h"
+#include "wa2frontend.h"
+#include "resource.h"
+#include "../nu/ns_wc.h"
+#include "../nu/refcount.h"
+#include "api/skin/widgets/xuidownloadslist.h"
+
+#include <shlobj.h>
+#include <shlwapi.h>
+#include <api/script/objects/systemobj.h>
+
+extern wchar_t *INI_DIR;
+
+static void createDirForFileW(wchar_t *str)
+{
+ wchar_t *p = str;
+ if ((p[0] ==L'\\' || p[0] ==L'/') && (p[1] ==L'\\' || p[1] ==L'/'))
+ {
+ p += 2;
+ while (p && *p && *p !=L'\\' && *p !=L'/') p++;
+ if (!p || !*p) return ;
+ p++;
+ while (p && *p && *p !=L'\\' && *p !=L'/') p++;
+ }
+ else
+ {
+ while (p && *p && *p !=L'\\' && *p !=L'/') p++;
+ }
+
+ while (p && *p)
+ {
+ while (p && *p !=L'\\' && *p !=L'/' && *p) p = CharNextW(p);
+ if (p && *p)
+ {
+ wchar_t lp = *p;
+ *p = 0;
+ CreateDirectoryW(str, NULL);
+ *p++ = lp;
+ }
+ }
+}
+
+static wchar_t* defaultPathToStore()
+{
+ static wchar_t pathToStore[MAX_PATH] = {0};
+ if(FAILED(SHGetFolderPathW(NULL, CSIDL_MYMUSIC, NULL, SHGFP_TYPE_CURRENT, pathToStore)))
+ {
+ if(FAILED(SHGetFolderPathW(NULL, CSIDL_PERSONAL, NULL, SHGFP_TYPE_CURRENT, pathToStore)))
+ {
+ lstrcpynW(pathToStore, L"C:\\My Music", MAX_PATH);
+ }
+ }
+ return pathToStore;
+}
+
+static void GetPathToStore(wchar_t path_to_store[MAX_PATH])
+{
+ GetPrivateProfileStringW( L"gen_ml_config", L"extractpath", defaultPathToStore(), path_to_store, MAX_PATH, (const wchar_t *)SendMessageW( plugin.hwndParent, WM_WA_IPC, 0, IPC_GETMLINIFILEW ) );
+}
+
+void Winamp2FrontEnd::getDownloadPath(wchar_t path2store[MAX_PATH])
+{
+ GetPathToStore(path2store);
+}
+
+void Winamp2FrontEnd::setDownloadPath(const wchar_t * path2store)
+{
+ WritePrivateProfileStringA( "gen_ml_config", "extractpath", AutoChar( path2store, CP_UTF8 ), (const char *)SendMessageW( plugin.hwndParent, WM_WA_IPC, 0, IPC_GETMLINIFILE ) );
+}
+
+class DownloadCallback : public Countable<ifc_downloadManagerCallback>
+{
+public:
+ DownloadCallback( const wchar_t *destination_filepath, bool storeInMl = true, bool notifyDownloadsList = true )
+ {
+ WCSCPYN( this->destination_filepath, destination_filepath, MAX_PATH );
+
+ this->storeInMl = storeInMl;
+ this->notifyDownloadsList = notifyDownloadsList;
+ }
+
+
+ void OnFinish( DownloadToken token );
+
+ void OnError( DownloadToken token, int error )
+ {
+ if ( notifyDownloadsList )
+ DownloadsList::onDownloadError( token, error );
+
+ Release();
+ }
+
+ void OnCancel( DownloadToken token )
+ {
+ if ( notifyDownloadsList )
+ DownloadsList::onDownloadCancel( token );
+
+ Release();
+ }
+ void OnTick( DownloadToken token )
+ {
+ if ( notifyDownloadsList )
+ DownloadsList::onDownloadTick( token );
+ }
+
+ const wchar_t *getPreferredFilePath()
+ {
+ return destination_filepath;
+ }
+
+ bool getStoreInML()
+ {
+ return storeInMl;
+ }
+ REFERENCE_COUNT_IMPLEMENTATION;
+
+protected:
+ RECVS_DISPATCH;
+
+private:
+ bool storeInMl;
+ bool notifyDownloadsList;
+ wchar_t destination_filepath[ MAX_PATH ];
+};
+
+// TODO: benski> this is a big hack. we should have a MIME manager in Winamp
+struct
+{
+ const char *mime; const char *ext;
+}
+hack_mimes[] = { {"audio/mpeg", ".mp3"} };
+
+void DownloadCallback::OnFinish(DownloadToken token)
+{
+ api_httpreceiver *http = WAC_API_DOWNLOADMANAGER->GetReceiver(token);
+ if (http)
+ {
+ const char *extension = 0;
+ const char *headers = http->getallheaders();
+ // we're trying to figure out wtf kind of file this is
+
+ if (!extension) // just adding this if to make this easier to re-arrange
+ {
+ // 1) check if there's a content-disposition, it might have an extension
+ const char *content_disposition = http->getheader("content-disposition");
+ if (content_disposition)
+ {
+ const char *content_filename = strstr(content_disposition, "filename=");
+ if (content_filename && *content_filename)
+ {
+ content_filename+=9;
+ extension = PathFindExtensionA(content_filename);
+ }
+ }
+ }
+
+ if (!extension)
+ {
+ // 2) check MIME type for something good
+ const char *content_type = http->getheader("content-type");
+ if (content_type)
+ {
+ for (int i=0;i!=sizeof(hack_mimes)/sizeof(hack_mimes[0]);i++)
+ {
+ if (!strcmp(hack_mimes[i].mime, content_type))
+ {
+ extension=hack_mimes[i].ext;
+ }
+ }
+ }
+ }
+
+ const char *url = http->get_url();
+ if (!extension)
+ {
+ // 3) check if URL has an extension
+
+ if (url) // umm, we better have a URL :) but worth a check
+ {
+ extension = PathFindExtensionA(url);
+ }
+ }
+
+ if (!extension)
+ {
+ // 4) ask for winamp's default extension and use that (most likely mp3)
+ extension=".mp3"; // TODO: actually use the setting and not hardcode this :)
+ }
+
+ // then we rename the file
+ wchar_t temppath[MAX_PATH-14] = {0};
+ wchar_t filename[MAX_PATH] = {0};
+
+ GetTempPathW(MAX_PATH-14, temppath);
+ GetTempFileNameW(temppath, L"atf", 0, filename);
+ PathRemoveExtensionW(filename);
+ PathAddExtensionW(filename, AutoWide(extension));
+
+ const wchar_t *downloadDest = WAC_API_DOWNLOADMANAGER->GetLocation(token);
+ MoveFileW(downloadDest, filename);
+
+ // then we build a filename with ATF
+ wchar_t formatted_filename[MAX_PATH] = {0}, path_to_store[MAX_PATH] = {0};
+ if (!WCSICMP(this->getPreferredFilePath(), L""))
+ GetPathToStore(path_to_store);
+ else
+ WCSCPYN(path_to_store, this->getPreferredFilePath(), MAX_PATH);
+
+ // TODO: benski> this is very temporary
+ char temp_filename[MAX_PATH] = {0}, *t = temp_filename,
+ *tfn = PathFindFileNameA(url);
+
+ while(tfn && *tfn)
+ {
+ if(*tfn == '%')
+ {
+ if(_strnicmp(tfn,"%20",3))
+ {
+ *t = *tfn;
+ }
+ else{
+ *t = ' ';
+ tfn = CharNextA(tfn);
+ tfn = CharNextA(tfn);
+ }
+ }
+ else
+ {
+ *t = *tfn;
+ }
+ tfn = CharNextA(tfn);
+ t = CharNextA(t);
+ }
+
+ *t = 0;
+
+ PathCombineW(formatted_filename, path_to_store, AutoWide(temp_filename));
+ createDirForFileW(formatted_filename);
+
+ // then move the file there
+ if (!MoveFileW(filename, formatted_filename))
+ {
+ CopyFileW(filename, formatted_filename, FALSE);
+ DeleteFileW(filename);
+ }
+
+ //Std::messageBox(formatted_filename, filename, 0);
+ if (this->getStoreInML() && PathFileExistsW(formatted_filename))
+ {
+ // then add to the media library :)
+ // TOOD: benski> use api_mldb because it's more thread-friendly than SendMessageW
+ HWND library = wa2.getMediaLibrary();
+ LMDB_FILE_ADD_INFOW fi = {const_cast<wchar_t *>(formatted_filename), -1, -1};
+ SendMessageW(library, WM_ML_IPC, (WPARAM)&fi, ML_IPC_DB_ADDORUPDATEFILEW);
+ PostMessage(library, WM_ML_IPC, 0, ML_IPC_DB_SYNCDB);
+ }
+
+ if (notifyDownloadsList)
+ DownloadsList::onDownloadEnd(token, const_cast<wchar_t *>(formatted_filename));
+
+ SystemObject::onDownloadFinished(AutoWide(url), true, formatted_filename);
+
+ Release();
+
+ return;
+ }
+
+ if (notifyDownloadsList)
+ DownloadsList::onDownloadEnd(token, NULL);
+
+ Release();
+}
+
+int Winamp2FrontEnd::DownloadFile( const char *url, const wchar_t *destfilepath, bool addToMl, bool notifyDownloadsList )
+{
+ DownloadCallback *callback = new DownloadCallback( destfilepath, addToMl, notifyDownloadsList );
+ DownloadToken dt = WAC_API_DOWNLOADMANAGER->Download( url, callback );
+
+ // Notify <DownloadsList/>
+ if ( notifyDownloadsList )
+ DownloadsList::onDownloadStart( url, dt );
+
+ return 0;
+ /*
+ HTTPRETRIEVEFILEW func = (HTTPRETRIEVEFILEW) SendMessageW(hwnd_winamp, WM_WA_IPC, 0, IPC_GETHTTPGETTERW);
+ if (func || func == (HTTPRETRIEVEFILEW)1)
+ return func(NULL, url, destfilename, title);
+ else
+ return 0;
+ */
+}
+
+#define CBCLASS DownloadCallback
+START_DISPATCH;
+REFERENCE_COUNTED;
+VCB( IFC_DOWNLOADMANAGERCALLBACK_ONFINISH, OnFinish )
+VCB( IFC_DOWNLOADMANAGERCALLBACK_ONTICK, OnTick )
+VCB( IFC_DOWNLOADMANAGERCALLBACK_ONERROR, OnError )
+VCB( IFC_DOWNLOADMANAGERCALLBACK_ONCANCEL, OnCancel )
+END_DISPATCH;
+#undef CBCLASS