mirror of
https://github.com/WinampDesktop/winamp.git
synced 2025-06-17 16:35:45 -04:00
Initial community commit
This commit is contained in:
51
Src/Plugins/Library/ml_wire/AtomParse.h
Normal file
51
Src/Plugins/Library/ml_wire/AtomParse.h
Normal file
@ -0,0 +1,51 @@
|
||||
#ifndef NULLSOFT_ATOMPARSEH
|
||||
#define NULLSOFT_ATOMPARSEH
|
||||
#if 0
|
||||
#include "RFCDate.h"
|
||||
#include "XMLNode.h"
|
||||
#include "Feeds.h"
|
||||
#include "../nu/AutoChar.h"
|
||||
#include "ChannelSync.h"
|
||||
|
||||
void ReadAtomItem(XMLNode *item, Channel &channel)
|
||||
{
|
||||
}
|
||||
|
||||
void ReadAtomChannel(XMLNode *node, Channel &newChannel)
|
||||
{
|
||||
XMLNode *curNode = 0;
|
||||
curNode = node->Get(L"title");
|
||||
if (curNode)
|
||||
newChanneltitle = curNode->content;
|
||||
|
||||
curNode = node->Get(L"subtitle");
|
||||
if (curNode)
|
||||
newChannel.description = curNode->content;
|
||||
|
||||
XMLNode::NodeList &links = node->GetList(L"link");
|
||||
XMLNode::NodeList::iterator linkItr;
|
||||
for (linkItr=links.begin();linkItr!=links.end();linkItr++)
|
||||
{
|
||||
if ((*linkItr)->properties[L"rel"].empty()
|
||||
|| (*linkItr)->properties[L"rel"]== L"alternate")
|
||||
newChannel.link = (*linkItr)->properties[L"href"];
|
||||
}
|
||||
|
||||
XMLNode::NodeList &entries = node->GetList(L"entry");
|
||||
XMLNode::NodeList::iterator entryItr;
|
||||
for (entryItr=entries.begin();entryItr!=entries.end();entryItr++)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
void ReadAtom(XMLNode *atom, ChannelSync *sync)
|
||||
{
|
||||
sync->BeginChannelSync();
|
||||
Channel newChannel;
|
||||
ReadAtomChannel(atom, newChannel);
|
||||
sync->NewChannel(newChannel);
|
||||
|
||||
sync->EndChannelSync();
|
||||
}
|
||||
#endif
|
||||
#endif
|
338
Src/Plugins/Library/ml_wire/BackgroundDownloader.cpp
Normal file
338
Src/Plugins/Library/ml_wire/BackgroundDownloader.cpp
Normal file
@ -0,0 +1,338 @@
|
||||
#include <vector>
|
||||
#include <atomic>
|
||||
|
||||
#include "Main.h"
|
||||
#include "Downloaded.h"
|
||||
#include "BackgroundDownloader.h"
|
||||
|
||||
#include "Feeds.h"
|
||||
#include "DownloadStatus.h"
|
||||
#include "DownloadsDialog.h"
|
||||
#include "api__ml_wire.h"
|
||||
#include "api/service/waServiceFactory.h"
|
||||
#include "../../..\Components\wac_network\wac_network_http_receiver_api.h"
|
||||
|
||||
|
||||
using namespace Nullsoft::Utility;
|
||||
|
||||
#define SIMULTANEOUS_DOWNLOADS 2
|
||||
std::vector<DownloadToken> downloadsQueue;
|
||||
LockGuard downloadsQueueLock;
|
||||
|
||||
class DownloaderCallback : public ifc_downloadManagerCallback
|
||||
{
|
||||
public:
|
||||
DownloaderCallback( const wchar_t *url, const wchar_t *destination_filepath, const wchar_t *channel, const wchar_t *item, __time64_t publishDate )
|
||||
{
|
||||
this->hFile = INVALID_HANDLE_VALUE;
|
||||
this->url = _wcsdup( url );
|
||||
this->destination_filepath = _wcsdup( destination_filepath );
|
||||
this->channel = _wcsdup( channel );
|
||||
this->item = _wcsdup( item );
|
||||
this->publishDate = publishDate;
|
||||
this->totalSize = 0;
|
||||
this->downloaded = 0;
|
||||
}
|
||||
|
||||
void OnInit(DownloadToken token)
|
||||
{
|
||||
// ---- Inform the download status service of our presence----
|
||||
downloadStatus.AddDownloadThread(token, this->channel, this->item, this->destination_filepath);
|
||||
}
|
||||
|
||||
void OnConnect(DownloadToken token)
|
||||
{
|
||||
// ---- retrieve total size
|
||||
api_httpreceiver *http = WAC_API_DOWNLOADMANAGER->GetReceiver(token);
|
||||
if (http)
|
||||
{
|
||||
this->totalSize = http->content_length();
|
||||
}
|
||||
|
||||
// ---- create file handle
|
||||
hFile = CreateFile(destination_filepath, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if ( hFile == INVALID_HANDLE_VALUE )
|
||||
{
|
||||
WAC_API_DOWNLOADMANAGER->CancelDownload(token);
|
||||
}
|
||||
}
|
||||
|
||||
void OnData(DownloadToken token, void *data, size_t datalen)
|
||||
{
|
||||
// ---- OnConnect copied here due to dlmgr OnData called first
|
||||
// ---- retrieve total size
|
||||
api_httpreceiver *http = WAC_API_DOWNLOADMANAGER->GetReceiver(token);
|
||||
if ( !this->totalSize && http )
|
||||
{
|
||||
this->totalSize = http->content_length();
|
||||
}
|
||||
|
||||
if ( hFile == INVALID_HANDLE_VALUE )
|
||||
{
|
||||
// ---- create file handle
|
||||
hFile = CreateFile(destination_filepath, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if ( hFile == INVALID_HANDLE_VALUE )
|
||||
{
|
||||
WAC_API_DOWNLOADMANAGER->CancelDownload(token);
|
||||
return;
|
||||
}
|
||||
}
|
||||
// ---- OnConnect to be removed once dlmgr is fixed
|
||||
|
||||
// ---- OnData
|
||||
// ---- if file handle is invalid, then cancel download
|
||||
if ( hFile == INVALID_HANDLE_VALUE )
|
||||
{
|
||||
WAC_API_DOWNLOADMANAGER->CancelDownload(token);
|
||||
return;
|
||||
}
|
||||
|
||||
this->downloaded = (size_t)WAC_API_DOWNLOADMANAGER->GetBytesDownloaded(token);
|
||||
|
||||
if ( datalen > 0 )
|
||||
{
|
||||
// ---- hFile is valid handle, and write to disk
|
||||
DWORD numWritten = 0;
|
||||
WriteFile(hFile, data,(DWORD)datalen, &numWritten, FALSE);
|
||||
|
||||
// ---- failed writing the number of datalen characters, cancel download
|
||||
if (numWritten != datalen)
|
||||
{
|
||||
WAC_API_DOWNLOADMANAGER->CancelDownload(token);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// if killswitch is turned on, then cancel download
|
||||
if ( downloadStatus.UpdateStatus(token, this->downloaded, this->totalSize) )
|
||||
{
|
||||
WAC_API_DOWNLOADMANAGER->CancelDownload(token);
|
||||
}
|
||||
}
|
||||
|
||||
void OnCancel(DownloadToken token)
|
||||
{
|
||||
if ( hFile != INVALID_HANDLE_VALUE )
|
||||
{
|
||||
CloseHandle(hFile);
|
||||
DeleteFile(destination_filepath);
|
||||
}
|
||||
DownloadsUpdated(token,NULL);
|
||||
downloadStatus.DownloadThreadDone(token);
|
||||
|
||||
|
||||
{
|
||||
AutoLock lock( downloadsQueueLock );
|
||||
|
||||
size_t l_index = 0;
|
||||
for ( DownloadToken &l_download_token : downloadsQueue )
|
||||
{
|
||||
if ( l_download_token == token )
|
||||
{
|
||||
downloadsQueue.erase( downloadsQueue.begin() + l_index );
|
||||
break;
|
||||
}
|
||||
|
||||
++l_index;
|
||||
}
|
||||
}
|
||||
|
||||
for ( DownloadToken &l_download_token : downloadsQueue )
|
||||
{
|
||||
if ( WAC_API_DOWNLOADMANAGER->IsPending( l_download_token ) )
|
||||
{
|
||||
WAC_API_DOWNLOADMANAGER->ResumePendingDownload( l_download_token );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
this->Release();
|
||||
}
|
||||
|
||||
void OnError(DownloadToken token, int error)
|
||||
{
|
||||
if ( hFile != INVALID_HANDLE_VALUE )
|
||||
{
|
||||
CloseHandle(hFile);
|
||||
DeleteFile(destination_filepath);
|
||||
}
|
||||
DownloadsUpdated(token,NULL);
|
||||
downloadStatus.DownloadThreadDone(token);
|
||||
|
||||
{
|
||||
AutoLock lock(downloadsQueueLock);
|
||||
for (size_t index = 0; index < downloadsQueue.size(); index++)
|
||||
{
|
||||
if (downloadsQueue.at(index) == token)
|
||||
{
|
||||
downloadsQueue.erase(downloadsQueue.begin() + index);
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (size_t index = 0; index < downloadsQueue.size(); index++)
|
||||
{
|
||||
if(WAC_API_DOWNLOADMANAGER->IsPending(downloadsQueue.at(index)))
|
||||
{
|
||||
WAC_API_DOWNLOADMANAGER->ResumePendingDownload(downloadsQueue.at(index));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
this->Release();
|
||||
}
|
||||
|
||||
void OnFinish( DownloadToken token )
|
||||
{
|
||||
if ( hFile != INVALID_HANDLE_VALUE )
|
||||
{
|
||||
CloseHandle( hFile );
|
||||
|
||||
DownloadedFile *data = new DownloadedFile( this->url, this->destination_filepath, this->channel, this->item, this->publishDate );
|
||||
data->bytesDownloaded = this->downloaded;
|
||||
data->totalSize = this->totalSize;
|
||||
{
|
||||
AutoLock lock( downloadedFiles );
|
||||
downloadedFiles.downloadList.push_back( *data );
|
||||
addToLibrary_thread( *data );
|
||||
|
||||
AddPodcastData( *data );
|
||||
|
||||
DownloadsUpdated( token, &downloadedFiles.downloadList[ downloadedFiles.downloadList.size() - 1 ] );
|
||||
}
|
||||
downloadStatus.DownloadThreadDone( token );
|
||||
delete data;
|
||||
}
|
||||
else
|
||||
{
|
||||
DownloadsUpdated( token, NULL );
|
||||
downloadStatus.DownloadThreadDone( token );
|
||||
}
|
||||
|
||||
{
|
||||
AutoLock lock( downloadsQueueLock );
|
||||
size_t l_index = 0;
|
||||
for ( DownloadToken &l_download_token : downloadsQueue )
|
||||
{
|
||||
if ( l_download_token == token )
|
||||
{
|
||||
downloadsQueue.erase( downloadsQueue.begin() + l_index );
|
||||
break;
|
||||
}
|
||||
|
||||
++l_index;
|
||||
}
|
||||
|
||||
for ( DownloadToken &l_download_token : downloadsQueue )
|
||||
{
|
||||
if ( WAC_API_DOWNLOADMANAGER->IsPending( l_download_token ) )
|
||||
{
|
||||
WAC_API_DOWNLOADMANAGER->ResumePendingDownload( l_download_token );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this->Release();
|
||||
}
|
||||
|
||||
|
||||
int GetSource( wchar_t *source, size_t source_cch )
|
||||
{
|
||||
return wcscpy_s( source, source_cch, this->channel );
|
||||
}
|
||||
|
||||
int GetTitle( wchar_t *title, size_t title_cch )
|
||||
{
|
||||
return wcscpy_s( title, title_cch, this->item );
|
||||
}
|
||||
|
||||
int GetLocation( wchar_t *location, size_t location_cch )
|
||||
{
|
||||
return wcscpy_s( location, location_cch, this->destination_filepath );
|
||||
}
|
||||
|
||||
|
||||
size_t AddRef()
|
||||
{
|
||||
return _ref_count.fetch_add( 1 );
|
||||
}
|
||||
|
||||
size_t Release()
|
||||
{
|
||||
if ( _ref_count.load() == 0 )
|
||||
return _ref_count.load();
|
||||
|
||||
LONG r = _ref_count.fetch_sub( 1 );
|
||||
if ( r == 0 )
|
||||
delete( this );
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
private: // private destructor so no one accidentally calls delete directly on this reference counted object
|
||||
~DownloaderCallback()
|
||||
{
|
||||
if ( url )
|
||||
free( url );
|
||||
|
||||
if ( destination_filepath )
|
||||
free( destination_filepath );
|
||||
|
||||
if ( channel )
|
||||
free( channel );
|
||||
|
||||
if ( item )
|
||||
free( item );
|
||||
}
|
||||
|
||||
protected:
|
||||
RECVS_DISPATCH;
|
||||
|
||||
private:
|
||||
HANDLE hFile;
|
||||
wchar_t *url;
|
||||
wchar_t *destination_filepath;
|
||||
wchar_t *channel;
|
||||
wchar_t *item;
|
||||
__time64_t publishDate;
|
||||
size_t totalSize;
|
||||
size_t downloaded;
|
||||
|
||||
std::atomic<std::size_t> _ref_count = 1;
|
||||
};
|
||||
|
||||
void BackgroundDownloader::Download( const wchar_t *url, const wchar_t *savePath, const wchar_t *channel, const wchar_t *item, __time64_t publishDate )
|
||||
{
|
||||
DownloaderCallback *callback = new DownloaderCallback( url, savePath, channel, item, publishDate );
|
||||
{
|
||||
Nullsoft::Utility::AutoLock lock( downloadsQueueLock );
|
||||
if ( downloadsQueue.size() < SIMULTANEOUS_DOWNLOADS )
|
||||
{
|
||||
DownloadToken dt = WAC_API_DOWNLOADMANAGER->DownloadEx( AutoChar( url ), callback, api_downloadManager::DOWNLOADEX_CALLBACK | api_downloadManager::DOWNLOADEX_UI );
|
||||
downloadsQueue.push_back( dt );
|
||||
}
|
||||
else
|
||||
{
|
||||
DownloadToken dt = WAC_API_DOWNLOADMANAGER->DownloadEx( AutoChar( url ), callback, api_downloadManager::DOWNLOADEX_CALLBACK | api_downloadManager::DOWNLOADEX_PENDING | api_downloadManager::DOWNLOADEX_UI );
|
||||
downloadsQueue.push_back( dt );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BackgroundDownloader downloader;
|
||||
|
||||
#define CBCLASS DownloaderCallback
|
||||
START_DISPATCH;
|
||||
VCB( IFC_DOWNLOADMANAGERCALLBACK_ONFINISH, OnFinish )
|
||||
VCB( IFC_DOWNLOADMANAGERCALLBACK_ONCANCEL, OnCancel )
|
||||
VCB( IFC_DOWNLOADMANAGERCALLBACK_ONERROR, OnError )
|
||||
VCB( IFC_DOWNLOADMANAGERCALLBACK_ONDATA, OnData )
|
||||
VCB( IFC_DOWNLOADMANAGERCALLBACK_ONCONNECT, OnConnect )
|
||||
VCB( IFC_DOWNLOADMANAGERCALLBACK_ONINIT, OnInit )
|
||||
CB( IFC_DOWNLOADMANAGERCALLBACK_GETSOURCE, GetSource )
|
||||
CB( IFC_DOWNLOADMANAGERCALLBACK_GETTITLE, GetTitle )
|
||||
CB( IFC_DOWNLOADMANAGERCALLBACK_GETLOCATION, GetLocation )
|
||||
CB( ADDREF, AddRef )
|
||||
CB( RELEASE, Release )
|
||||
END_DISPATCH;
|
||||
#undef CBCLASS
|
18
Src/Plugins/Library/ml_wire/BackgroundDownloader.h
Normal file
18
Src/Plugins/Library/ml_wire/BackgroundDownloader.h
Normal file
@ -0,0 +1,18 @@
|
||||
#ifndef NULLSOFT_BACKGROUNDDOWNLOADERH
|
||||
#define NULLSOFT_BACKGROUNDDOWNLOADERH
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
class BackgroundDownloader
|
||||
{
|
||||
public:
|
||||
//void SetSpeed(int kilobytesPerSecond);
|
||||
|
||||
void Download(const wchar_t *url, const wchar_t *savePath,
|
||||
const wchar_t *channel, const wchar_t *item, __time64_t publishDate);
|
||||
|
||||
//void Shutdown();
|
||||
};
|
||||
|
||||
extern BackgroundDownloader downloader;
|
||||
#endif
|
14
Src/Plugins/Library/ml_wire/ChannelCheck.h
Normal file
14
Src/Plugins/Library/ml_wire/ChannelCheck.h
Normal file
@ -0,0 +1,14 @@
|
||||
#ifndef NULLSOFT_CHANNELCHECKH
|
||||
#define NULLSOFT_CHANNELCHECKH
|
||||
#include "ChannelSync.h"
|
||||
class ChannelCheck : public ChannelSync
|
||||
{
|
||||
public:
|
||||
void NewChannel(const Channel &newChannel)
|
||||
{
|
||||
channel=newChannel;
|
||||
}
|
||||
Channel channel;
|
||||
};
|
||||
|
||||
#endif
|
33
Src/Plugins/Library/ml_wire/ChannelRefresher.cpp
Normal file
33
Src/Plugins/Library/ml_wire/ChannelRefresher.cpp
Normal file
@ -0,0 +1,33 @@
|
||||
#include "main.h"
|
||||
#include "ChannelRefresher.h"
|
||||
#include <algorithm>
|
||||
|
||||
#include "./subscriptionView.h"
|
||||
|
||||
using namespace Nullsoft::Utility;
|
||||
void ChannelRefresher::BeginChannelSync()
|
||||
{}
|
||||
|
||||
void ChannelRefresher::NewChannel(const Channel &newChannel)
|
||||
{
|
||||
AutoLock lock (channels LOCKNAME("ChannelRefresher::NewChannel"));
|
||||
ChannelList::iterator found;
|
||||
for (found=channels.begin();found!=channels.end(); found++)
|
||||
{
|
||||
if (!wcscmp(found->url, newChannel.url))
|
||||
break;
|
||||
}
|
||||
if (found != channels.end())
|
||||
{
|
||||
// todo, redo category indexing as necessary.
|
||||
found->UpdateFrom(newChannel);
|
||||
found->lastUpdate = _time64(0);
|
||||
found->needsRefresh = false;
|
||||
}
|
||||
}
|
||||
|
||||
void ChannelRefresher::EndChannelSync()
|
||||
{
|
||||
HWND wnd = SubscriptionView_FindWindow();
|
||||
SubscriptionView_RefreshChannels(wnd, TRUE);
|
||||
}
|
14
Src/Plugins/Library/ml_wire/ChannelRefresher.h
Normal file
14
Src/Plugins/Library/ml_wire/ChannelRefresher.h
Normal file
@ -0,0 +1,14 @@
|
||||
#ifndef NULLSOFT_CHANNELREFRESHERH
|
||||
#define NULLSOFT_CHANNELREFRESHERH
|
||||
|
||||
#include "ChannelSync.h"
|
||||
class ChannelRefresher: public ChannelSync
|
||||
{
|
||||
public:
|
||||
void BeginChannelSync();
|
||||
void NewChannel(const Channel &newChannel);
|
||||
void EndChannelSync();
|
||||
|
||||
};
|
||||
|
||||
#endif
|
31
Src/Plugins/Library/ml_wire/ChannelSync.h
Normal file
31
Src/Plugins/Library/ml_wire/ChannelSync.h
Normal file
@ -0,0 +1,31 @@
|
||||
#ifndef NULLSOFT_CHANNELSYNCH
|
||||
#define NULLSOFT_CHANNELSYNCH
|
||||
|
||||
#include "Feeds.h"
|
||||
|
||||
/*
|
||||
ChannelSync is a virtual base class (aka interface) used by the RSS downloader.
|
||||
When you instantiate a downloader, you are required to give it a pointer to this interface.
|
||||
|
||||
The downloader will call:
|
||||
|
||||
BeginChannelSync();
|
||||
for (;;) // however many it encounters
|
||||
NewChannel(newChannel); // called once for each channel it downloads
|
||||
EndChannelSync();
|
||||
|
||||
If you have a class or data structure that wants updates, you'll have to mix-in
|
||||
this interface or implement a data-structure-babysitter class (or however you want to deal with it)
|
||||
|
||||
See the "WireManager" for an example of how to use it
|
||||
*/
|
||||
|
||||
class ChannelSync
|
||||
{
|
||||
public:
|
||||
virtual void BeginChannelSync() {}
|
||||
virtual void NewChannel(const Channel &newChannel) = 0;
|
||||
virtual void EndChannelSync() {}}
|
||||
;
|
||||
|
||||
#endif
|
235
Src/Plugins/Library/ml_wire/Cloud.cpp
Normal file
235
Src/Plugins/Library/ml_wire/Cloud.cpp
Normal file
@ -0,0 +1,235 @@
|
||||
#include "main.h"
|
||||
#include "api__ml_wire.h"
|
||||
#include "Cloud.h"
|
||||
#include "FeedParse.h"
|
||||
#include "Defaults.h"
|
||||
#include "./subscriptionView.h"
|
||||
#include "ChannelRefresher.h"
|
||||
#include "Util.h"
|
||||
#include <algorithm>
|
||||
#include <strsafe.h>
|
||||
|
||||
/* benski> TODO rewrite Callback() so we don't have to reserve a thread */
|
||||
using namespace Nullsoft::Utility;
|
||||
|
||||
#define CLOUD_TICK_MS 60000
|
||||
ChannelRefresher channelRefresher;
|
||||
|
||||
static bool kill = false;
|
||||
|
||||
static __time64_t RetrieveMinimalUpdateTime()
|
||||
{
|
||||
__time64_t minUpdateTime = 0;
|
||||
|
||||
AutoLock lock (channels LOCKNAME("RetrieveMinimalUpdateTime"));
|
||||
ChannelList::iterator itr;
|
||||
for (itr=channels.begin(); itr!=channels.end(); itr++)
|
||||
{
|
||||
if (itr->useDefaultUpdate)
|
||||
{
|
||||
if ( !updateTime ) autoUpdate = 0;
|
||||
if ( autoUpdate && (!minUpdateTime || minUpdateTime && (updateTime < minUpdateTime)) )
|
||||
{
|
||||
minUpdateTime = updateTime;
|
||||
}
|
||||
}
|
||||
else // use the custom values
|
||||
{
|
||||
if ( !itr->updateTime ) itr->autoUpdate = 0;
|
||||
if ( itr->autoUpdate && (!minUpdateTime || minUpdateTime && (itr->updateTime < minUpdateTime)) )
|
||||
{
|
||||
minUpdateTime = itr->updateTime;
|
||||
}
|
||||
}
|
||||
}
|
||||
return minUpdateTime;
|
||||
}
|
||||
|
||||
int Cloud::CloudThreadPoolFunc(HANDLE handle, void *user_data, intptr_t id)
|
||||
{
|
||||
Cloud *cloud = (Cloud *)user_data;
|
||||
if (kill)
|
||||
{
|
||||
WASABI_API_THREADPOOL->RemoveHandle(0, cloud->cloudEvent);
|
||||
CloseHandle(cloud->cloudEvent);
|
||||
WASABI_API_THREADPOOL->RemoveHandle(0, cloud->cloudTimerEvent);
|
||||
cloud->cloudTimerEvent.Close();
|
||||
SetEvent(cloud->cloudDone);
|
||||
return 0;
|
||||
}
|
||||
|
||||
cloud->Callback();
|
||||
|
||||
// set waitable timer, overwrite previouse value if any
|
||||
if (!kill)
|
||||
{
|
||||
__time64_t timeToWait = RetrieveMinimalUpdateTime();
|
||||
if ( timeToWait )
|
||||
cloud->cloudTimerEvent.Wait(timeToWait * 1000);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
Cloud::Cloud() : cloudThread(0), cloudEvent(0), statusText(0)
|
||||
{}
|
||||
|
||||
Cloud::~Cloud()
|
||||
{
|
||||
free(statusText);
|
||||
}
|
||||
|
||||
void Cloud::Quit()
|
||||
{
|
||||
cloudDone= CreateEvent(NULL, FALSE, FALSE, NULL);
|
||||
kill = true;
|
||||
SetEvent(cloudEvent);
|
||||
WaitForSingleObject(cloudDone, INFINITE);
|
||||
CloseHandle(cloudDone);
|
||||
}
|
||||
|
||||
void Cloud::RefreshAll()
|
||||
{
|
||||
AutoLock lock (channels LOCKNAME("RefreshAll"));
|
||||
ChannelList::iterator itr;
|
||||
for (itr = channels.begin();itr != channels.end();itr++)
|
||||
{
|
||||
itr->needsRefresh = true;
|
||||
}
|
||||
|
||||
}
|
||||
void Cloud::Init()
|
||||
{
|
||||
// setup a periodic callback so we can check on our times
|
||||
cloudEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
|
||||
|
||||
cloudThread = WASABI_API_THREADPOOL->ReserveThread(0);
|
||||
|
||||
WASABI_API_THREADPOOL->AddHandle(cloudThread, cloudEvent, CloudThreadPoolFunc, this, 0, 0);
|
||||
|
||||
WASABI_API_THREADPOOL->AddHandle(cloudThread, cloudTimerEvent, CloudThreadPoolFunc, this, 1, 0);
|
||||
__time64_t timeToWait = RetrieveMinimalUpdateTime();
|
||||
if ( timeToWait )
|
||||
cloudTimerEvent.Wait(timeToWait * 1000);
|
||||
}
|
||||
|
||||
void Cloud::Refresh(Channel &channel)
|
||||
{
|
||||
wchar_t lang_buf[1024] = {0};
|
||||
WASABI_API_LNGSTRINGW_BUF(IDS_RECEIVING_UPDATES_FOR, lang_buf, 1024);
|
||||
if (channel.title)
|
||||
StringCbCat(lang_buf, sizeof(lang_buf), channel.title);
|
||||
else
|
||||
lang_buf[0]=0;
|
||||
SetStatus(lang_buf);
|
||||
size_t oldSize = channel.items.size();
|
||||
|
||||
FeedParse downloader(&channelRefresher, false);
|
||||
downloader.DownloadURL(channel.url);
|
||||
|
||||
if (channel.items.size() > oldSize)
|
||||
{
|
||||
WASABI_API_LNGSTRINGW_BUF(IDS_GOT_NEW_ITEMS_FOR, lang_buf, 1024);
|
||||
StringCbCat(lang_buf, sizeof(lang_buf), channel.title);
|
||||
SetStatus(lang_buf);
|
||||
}
|
||||
else
|
||||
SetStatus(L"");
|
||||
}
|
||||
|
||||
void Cloud::GetStatus(wchar_t *status, size_t len)
|
||||
{
|
||||
AutoLock lock (statusGuard);
|
||||
if (statusText)
|
||||
StringCchCopy(status, len, statusText);
|
||||
else
|
||||
status[0]=0;
|
||||
}
|
||||
|
||||
void Cloud::SetStatus(const wchar_t *newStatus)
|
||||
{
|
||||
AutoLock lock (statusGuard);
|
||||
free(statusText);
|
||||
statusText = _wcsdup(newStatus);
|
||||
|
||||
HWND hView = SubscriptionView_FindWindow();
|
||||
if (NULL != hView)
|
||||
SubscriptionView_SetStatus(hView, statusText);
|
||||
}
|
||||
|
||||
/* --- Private Methods of class Cloud --- */
|
||||
|
||||
|
||||
static void ForceLastUpdate(const Channel &channel)
|
||||
{
|
||||
AutoLock lock (channels LOCKNAME("ChannelRefresher::NewChannel"));
|
||||
ChannelList::iterator found;
|
||||
for (found=channels.begin();found!=channels.end(); found++)
|
||||
{
|
||||
if (!wcscmp(found->url, channel.url))
|
||||
break;
|
||||
}
|
||||
if (found != channels.end())
|
||||
{
|
||||
found->lastUpdate = _time64(0);
|
||||
found->needsRefresh = false;
|
||||
}
|
||||
}
|
||||
/*
|
||||
@private
|
||||
checks all channels and updates any that requiring refreshing.
|
||||
*/
|
||||
void Cloud::Callback()
|
||||
{
|
||||
__time64_t curTime = _time64(0);
|
||||
|
||||
size_t i = 0;
|
||||
Channel temp;
|
||||
bool refreshed = false;
|
||||
|
||||
while (true) // we need to lock the channels object before we check its size, etc, so we can't just use a "for" loop.
|
||||
{
|
||||
{ // we want to minimize how long we have to lock, so we'll make a copy of the channel data
|
||||
AutoLock lock (channels LOCKNAME("Callback"));
|
||||
if (i >= channels.size())
|
||||
break;
|
||||
temp = channels[i]; // make a copy the data so we can safely release the lock
|
||||
channels[i].needsRefresh = false; // have to set this now. if the site is down or 404, then the refresh will never "complete".
|
||||
} // end locking scope
|
||||
|
||||
if (temp.needsRefresh) // need an immediate refresh? (usually set when the user clicks refresh or update-on-launch is on)
|
||||
{
|
||||
Refresh(temp);
|
||||
refreshed = true;
|
||||
}
|
||||
else if (temp.useDefaultUpdate) // this flag is set unless the user chose custom update values
|
||||
{
|
||||
if (!updateTime) autoUpdate = 0;
|
||||
if (autoUpdate && (temp.lastUpdate + updateTime) <= curTime)
|
||||
{
|
||||
Refresh(temp);
|
||||
ForceLastUpdate(temp);
|
||||
refreshed = true;
|
||||
}
|
||||
}
|
||||
else // use the custom values
|
||||
{
|
||||
if (temp.updateTime == 0) temp.autoUpdate = 0;
|
||||
if (temp.autoUpdate && (temp.lastUpdate + temp.updateTime) <= curTime)
|
||||
{
|
||||
Refresh(temp);
|
||||
ForceLastUpdate(temp);
|
||||
refreshed = true;
|
||||
}
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
// if we're refreshing then save out
|
||||
if (refreshed)
|
||||
{
|
||||
SaveAll();
|
||||
}
|
||||
}
|
35
Src/Plugins/Library/ml_wire/Cloud.h
Normal file
35
Src/Plugins/Library/ml_wire/Cloud.h
Normal file
@ -0,0 +1,35 @@
|
||||
#ifndef NULLSOFT_CLOUDH
|
||||
#define NULLSOFT_CLOUDH
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include "Feeds.h"
|
||||
#include "../nu/threadpool/api_threadpool.h"
|
||||
#include "../nu/threadpool/timerhandle.hpp"
|
||||
#include "../nu/AutoLock.h"
|
||||
|
||||
class Cloud
|
||||
{
|
||||
public:
|
||||
Cloud();
|
||||
~Cloud();
|
||||
void Init();
|
||||
void Quit();
|
||||
void Refresh( Channel &channel );
|
||||
void GetStatus( wchar_t *status, size_t len );
|
||||
void RefreshAll();
|
||||
void Pulse() { SetEvent( cloudEvent ); }
|
||||
|
||||
private:
|
||||
static DWORD WINAPI CloudThread( void *param );
|
||||
void SetStatus( const wchar_t *newStatus );
|
||||
void Callback();
|
||||
ThreadID *cloudThread;
|
||||
wchar_t *statusText;
|
||||
Nullsoft::Utility::LockGuard statusGuard;
|
||||
HANDLE cloudEvent, cloudDone;
|
||||
TimerHandle cloudTimerEvent;
|
||||
static int CloudThreadPoolFunc( HANDLE handle, void *user_data, intptr_t param );
|
||||
};
|
||||
|
||||
#endif
|
12
Src/Plugins/Library/ml_wire/DESIGN.txt
Normal file
12
Src/Plugins/Library/ml_wire/DESIGN.txt
Normal file
@ -0,0 +1,12 @@
|
||||
|
||||
|
||||
|
||||
|
||||
major components:
|
||||
|
||||
Cloud
|
||||
-----
|
||||
|
||||
The cloud is the object which is responsible for doing period updates on RSS feeds.
|
||||
It automatically scans the feeds. You can manually refresh via the Refresh(string url) method
|
||||
|
40
Src/Plugins/Library/ml_wire/Defaults.cpp
Normal file
40
Src/Plugins/Library/ml_wire/Defaults.cpp
Normal file
@ -0,0 +1,40 @@
|
||||
#include "main.h"
|
||||
#include "Defaults.h"
|
||||
#include <shlobj.h>
|
||||
wchar_t defaultDownloadPath[MAX_PATH] = {0},
|
||||
serviceUrl[1024] = {0};
|
||||
__time64_t updateTime = 60 /* 1 minute */ * 60 /* 1 hour */ * 24 /* 1 day */;
|
||||
int autoDownloadEpisodes = 1;
|
||||
bool autoUpdate = true;
|
||||
bool autoDownload = true;
|
||||
bool updateOnLaunch = false;
|
||||
bool needToMakePodcastsView=true;
|
||||
|
||||
static BOOL UtilGetSpecialFolderPath( HWND hwnd, wchar_t *path, int folder )
|
||||
{
|
||||
ITEMIDLIST *pidl; // Shell Item ID List ptr
|
||||
IMalloc *imalloc; // Shell IMalloc interface ptr
|
||||
BOOL result; // Return value
|
||||
|
||||
if ( SHGetSpecialFolderLocation( hwnd, folder, &pidl ) != NOERROR )
|
||||
return FALSE;
|
||||
|
||||
result = SHGetPathFromIDList( pidl, path );
|
||||
|
||||
if ( SHGetMalloc( &imalloc ) == NOERROR )
|
||||
{
|
||||
imalloc->Free( pidl );
|
||||
imalloc->Release();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void BuildDefaultDownloadPath( HWND hwnd )
|
||||
{
|
||||
wchar_t defaultPath[ MAX_PATH ] = L"";
|
||||
if ( !UtilGetSpecialFolderPath( hwnd, defaultPath, CSIDL_MYMUSIC ) )
|
||||
UtilGetSpecialFolderPath( hwnd, defaultPath, CSIDL_PERSONAL );
|
||||
|
||||
lstrcpyn( defaultDownloadPath, defaultPath, MAX_PATH );
|
||||
}
|
34
Src/Plugins/Library/ml_wire/Defaults.h
Normal file
34
Src/Plugins/Library/ml_wire/Defaults.h
Normal file
@ -0,0 +1,34 @@
|
||||
#ifndef NULLSOFT_DEFAULTSH
|
||||
#define NULLSOFT_DEFAULTSH
|
||||
#include <windows.h>
|
||||
extern wchar_t defaultDownloadPath[MAX_PATH], serviceUrl[1024];
|
||||
extern __time64_t updateTime;
|
||||
extern int autoDownloadEpisodes;
|
||||
extern bool autoUpdate;
|
||||
extern bool autoDownload;
|
||||
extern bool updateOnLaunch;
|
||||
extern float htmlDividerPercent;
|
||||
extern float channelDividerPercent;
|
||||
extern int itemTitleWidth;
|
||||
extern int itemDateWidth;
|
||||
extern int itemMediaWidth;
|
||||
extern int itemSizeWidth;
|
||||
|
||||
#define DOWNLOADSCHANNELWIDTHDEFAULT 200
|
||||
#define DOWNLOADSITEMWIDTHDEFAULT 200
|
||||
#define DOWNLOADSPROGRESSWIDTHDEFAULT 100
|
||||
#define DOWNLOADSPATHWIDTHDEFAULTS 200
|
||||
|
||||
extern int downloadsChannelWidth;
|
||||
extern int downloadsItemWidth;
|
||||
extern int downloadsProgressWidth;
|
||||
extern int downloadsPathWidth;
|
||||
|
||||
extern bool needToMakePodcastsView;
|
||||
|
||||
extern int currentItemSort;
|
||||
extern bool itemSortAscending;
|
||||
extern bool channelSortAscending;
|
||||
extern int channelLastSelection;
|
||||
void BuildDefaultDownloadPath(HWND);
|
||||
#endif
|
1
Src/Plugins/Library/ml_wire/DownloadManager.cpp
Normal file
1
Src/Plugins/Library/ml_wire/DownloadManager.cpp
Normal file
@ -0,0 +1 @@
|
||||
#include "main.h"
|
153
Src/Plugins/Library/ml_wire/DownloadStatus.cpp
Normal file
153
Src/Plugins/Library/ml_wire/DownloadStatus.cpp
Normal file
@ -0,0 +1,153 @@
|
||||
#include "main.h"
|
||||
#include "api__ml_wire.h"
|
||||
#include "DownloadStatus.h"
|
||||
#include "DownloadsDialog.h"
|
||||
#include "./navigation.h"
|
||||
|
||||
#include <strsafe.h>
|
||||
|
||||
DownloadStatus downloadStatus;
|
||||
|
||||
using namespace Nullsoft::Utility;
|
||||
|
||||
DownloadStatus::Status::Status()
|
||||
{
|
||||
Init();
|
||||
}
|
||||
|
||||
DownloadStatus::Status::Status( size_t _downloaded, size_t _maxSize, const wchar_t *_channel, const wchar_t *_item, const wchar_t *_path )
|
||||
{
|
||||
Init();
|
||||
|
||||
downloaded = _downloaded;
|
||||
maxSize = _maxSize;
|
||||
channel = _wcsdup( _channel );
|
||||
item = _wcsdup( _item );
|
||||
path = _wcsdup( _path );
|
||||
}
|
||||
|
||||
const DownloadStatus::Status &DownloadStatus::Status::operator =( const DownloadStatus::Status © )
|
||||
{
|
||||
Reset();
|
||||
Init();
|
||||
|
||||
downloaded = copy.downloaded;
|
||||
maxSize = copy.maxSize;
|
||||
channel = _wcsdup( copy.channel );
|
||||
item = _wcsdup( copy.item );
|
||||
path = _wcsdup( copy.path );
|
||||
killswitch = copy.killswitch;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
DownloadStatus::Status::~Status()
|
||||
{
|
||||
Reset();
|
||||
}
|
||||
|
||||
void DownloadStatus::Status::Init()
|
||||
{
|
||||
downloaded = 0;
|
||||
maxSize = 0;
|
||||
killswitch = 0;
|
||||
channel = 0;
|
||||
item = 0;
|
||||
path = 0;
|
||||
}
|
||||
|
||||
void DownloadStatus::Status::Reset()
|
||||
{
|
||||
if ( channel )
|
||||
{
|
||||
free( channel );
|
||||
channel = 0;
|
||||
}
|
||||
|
||||
if ( item )
|
||||
{
|
||||
free( item );
|
||||
item = 0;
|
||||
}
|
||||
|
||||
if ( path )
|
||||
{
|
||||
free( path );
|
||||
path = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void DownloadStatus::AddDownloadThread(DownloadToken token, const wchar_t *channel, const wchar_t *item, const wchar_t *path)
|
||||
{
|
||||
{
|
||||
AutoLock lock(statusLock);
|
||||
downloads[token] = Status(0,0,channel,item,path);
|
||||
DownloadsUpdated(downloads[token],token);
|
||||
}
|
||||
|
||||
Navigation_ShowService(SERVICE_DOWNLOADS, SHOWMODE_AUTO);
|
||||
}
|
||||
|
||||
void DownloadStatus::DownloadThreadDone(DownloadToken token)
|
||||
{
|
||||
{
|
||||
AutoLock lock(statusLock);
|
||||
downloads.erase(token);
|
||||
}
|
||||
|
||||
Navigation_ShowService(SERVICE_DOWNLOADS, SHOWMODE_AUTO);
|
||||
}
|
||||
|
||||
bool DownloadStatus::UpdateStatus(DownloadToken token, size_t downloaded, size_t maxSize)
|
||||
{
|
||||
AutoLock lock(statusLock);
|
||||
downloads[token].downloaded = downloaded;
|
||||
downloads[token].maxSize = maxSize;
|
||||
|
||||
return !!downloads[token].killswitch;
|
||||
}
|
||||
|
||||
bool DownloadStatus::CurrentlyDownloading()
|
||||
{
|
||||
AutoLock lock(statusLock);
|
||||
return !downloads.empty();
|
||||
}
|
||||
|
||||
void DownloadStatus::GetStatusString( wchar_t *status, size_t len )
|
||||
{
|
||||
AutoLock lock( statusLock );
|
||||
Downloads::iterator itr;
|
||||
size_t bytesDownloaded = 0, bytesTotal = 0, numDownloads = 0;
|
||||
bool unknownTotal = false;
|
||||
for ( itr = downloads.begin(); itr != downloads.end(); itr++ )
|
||||
{
|
||||
Status &dlstatus = itr->second;
|
||||
if ( dlstatus.maxSize )
|
||||
{
|
||||
numDownloads++;
|
||||
bytesDownloaded += dlstatus.downloaded;
|
||||
bytesTotal += dlstatus.maxSize;
|
||||
}
|
||||
else // don't have a max size
|
||||
{
|
||||
if ( dlstatus.downloaded ) // if we've downloaded some then we just don't know the total
|
||||
{
|
||||
unknownTotal = true;
|
||||
numDownloads++;
|
||||
bytesDownloaded += dlstatus.downloaded;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( 0 == numDownloads )
|
||||
{
|
||||
status[ 0 ] = L'\0';
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( unknownTotal || bytesTotal == 0 )
|
||||
StringCchPrintf( status, len, WASABI_API_LNGSTRINGW( IDS_DOWNLOADING_KB_COMPLETE ), numDownloads, bytesDownloaded / 1024);
|
||||
else
|
||||
StringCchPrintf( status, len, WASABI_API_LNGSTRINGW( IDS_DOWNLOADING_KB_PROGRESS ), numDownloads, bytesDownloaded / 1024, bytesTotal / 1024, MulDiv( (int)bytesDownloaded, 100, (int)bytesTotal ) );
|
||||
}
|
||||
}
|
41
Src/Plugins/Library/ml_wire/DownloadStatus.h
Normal file
41
Src/Plugins/Library/ml_wire/DownloadStatus.h
Normal file
@ -0,0 +1,41 @@
|
||||
#ifndef NULLSOFT_DOWNLOADSTATUSH
|
||||
#define NULLSOFT_DOWNLOADSTATUSH
|
||||
|
||||
#include "../nu/AutoLock.h"
|
||||
#include <map>
|
||||
|
||||
|
||||
class DownloadStatus
|
||||
{
|
||||
public:
|
||||
class Status
|
||||
{
|
||||
public:
|
||||
Status();
|
||||
~Status();
|
||||
const Status &operator =(const Status ©);
|
||||
Status(size_t _downloaded, size_t _maxSize, const wchar_t *channel, const wchar_t *item, const wchar_t *path);
|
||||
size_t downloaded, maxSize;
|
||||
|
||||
int killswitch;
|
||||
wchar_t *channel;
|
||||
wchar_t *item;
|
||||
wchar_t *path;
|
||||
private:
|
||||
|
||||
void Init();
|
||||
void Reset();
|
||||
};
|
||||
|
||||
void AddDownloadThread(DownloadToken token, const wchar_t *channel, const wchar_t *item, const wchar_t *path);
|
||||
void DownloadThreadDone(DownloadToken token);
|
||||
bool UpdateStatus(DownloadToken token, size_t downloaded, size_t maxSize);
|
||||
bool CurrentlyDownloading();
|
||||
void GetStatusString(wchar_t *status, size_t len);
|
||||
typedef std::map<DownloadToken, Status> Downloads;
|
||||
Downloads downloads;
|
||||
Nullsoft::Utility::LockGuard statusLock;
|
||||
};
|
||||
|
||||
extern DownloadStatus downloadStatus;
|
||||
#endif
|
222
Src/Plugins/Library/ml_wire/DownloadThread.cpp
Normal file
222
Src/Plugins/Library/ml_wire/DownloadThread.cpp
Normal file
@ -0,0 +1,222 @@
|
||||
#include "Main.h"
|
||||
|
||||
#pragma warning(disable:4786)
|
||||
|
||||
#include "DownloadThread.h"
|
||||
#include "api__ml_wire.h"
|
||||
#include "api/service/waServiceFactory.h"
|
||||
#include "../../..\Components\wac_network\wac_network_http_receiver_api.h"
|
||||
#include "errors.h"
|
||||
#include <strsafe.h>
|
||||
|
||||
extern int winampVersion;
|
||||
|
||||
#define USER_AGENT_SIZE (10 /*User-Agent*/ + 2 /*: */ + 6 /*Winamp*/ + 1 /*/*/ + 1 /*5*/ + 3/*.21*/ + 1 /*Null*/)
|
||||
void SetUserAgent( api_httpreceiver *http )
|
||||
{
|
||||
char user_agent[ USER_AGENT_SIZE ] = { 0 };
|
||||
int bigVer = ( ( winampVersion & 0x0000FF00 ) >> 12 );
|
||||
int smallVer = ( ( winampVersion & 0x000000FF ) );
|
||||
StringCchPrintfA( user_agent, USER_AGENT_SIZE, "User-Agent: Winamp/%01x.%02x", bigVer, smallVer );
|
||||
http->addheader( user_agent );
|
||||
}
|
||||
|
||||
#define HTTP_BUFFER_SIZE 32768
|
||||
|
||||
static int FeedXMLHTTP( api_httpreceiver *http, obj_xml *parser, bool *noData )
|
||||
{
|
||||
char downloadedData[ HTTP_BUFFER_SIZE ] = { 0 };
|
||||
int xmlResult = API_XML_SUCCESS;
|
||||
int downloadSize = http->get_bytes( downloadedData, HTTP_BUFFER_SIZE );
|
||||
if ( downloadSize )
|
||||
{
|
||||
xmlResult = parser->xmlreader_feed( (void *)downloadedData, downloadSize );
|
||||
*noData = false;
|
||||
}
|
||||
else
|
||||
*noData = true;
|
||||
|
||||
return xmlResult;
|
||||
}
|
||||
|
||||
|
||||
DownloadThread::DownloadThread() : parser( 0 ), parserFactory( 0 )
|
||||
{
|
||||
parserFactory = plugin.service->service_getServiceByGuid( obj_xmlGUID );
|
||||
if ( parserFactory )
|
||||
parser = (obj_xml *)parserFactory->getInterface();
|
||||
|
||||
if ( parser )
|
||||
{
|
||||
parser->xmlreader_setCaseSensitive();
|
||||
parser->xmlreader_registerCallback( L"*", &xmlDOM );
|
||||
parser->xmlreader_open();
|
||||
}
|
||||
}
|
||||
|
||||
DownloadThread::~DownloadThread()
|
||||
{
|
||||
if ( parser )
|
||||
{
|
||||
parser->xmlreader_unregisterCallback( &xmlDOM );
|
||||
parser->xmlreader_close();
|
||||
}
|
||||
|
||||
if ( parserFactory && parser )
|
||||
parserFactory->releaseInterface( parser );
|
||||
|
||||
parserFactory = 0;
|
||||
parser = 0;
|
||||
}
|
||||
|
||||
void URLToFileName( wchar_t *url )
|
||||
{
|
||||
while ( url && *url != 0 )
|
||||
{
|
||||
switch ( *url )
|
||||
{
|
||||
case ':':
|
||||
case '/':
|
||||
case '\\':
|
||||
case '*':
|
||||
case '?':
|
||||
case '"':
|
||||
case '<':
|
||||
case '>':
|
||||
case '|':
|
||||
*url = '_';
|
||||
}
|
||||
url++;
|
||||
}
|
||||
}
|
||||
|
||||
#define FILE_BUFFER_SIZE 32768
|
||||
void DownloadThread::DownloadFile( const wchar_t *fileName )
|
||||
{
|
||||
if ( !parser )
|
||||
return; // no sense in continuing if there's no parser available
|
||||
|
||||
HANDLE file = CreateFile( fileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL );
|
||||
if ( file == INVALID_HANDLE_VALUE )
|
||||
return;
|
||||
|
||||
while ( true )
|
||||
{
|
||||
char data[ FILE_BUFFER_SIZE ] = { 0 };
|
||||
DWORD bytesRead = 0;
|
||||
if ( ReadFile( file, data, FILE_BUFFER_SIZE, &bytesRead, NULL ) && bytesRead )
|
||||
{
|
||||
parser->xmlreader_feed( (void *)data, bytesRead );
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
CloseHandle( file );
|
||||
parser->xmlreader_feed( 0, 0 );
|
||||
ReadNodes( fileName );
|
||||
}
|
||||
|
||||
#ifdef _DEBUG
|
||||
#include <iostream>
|
||||
void ShowAllHeaders( api_httpreceiver *http )
|
||||
{
|
||||
std::cout << "--------------------" << std::endl;
|
||||
const char *blah = http->getallheaders();
|
||||
while ( blah && *blah )
|
||||
{
|
||||
std::cout << blah << std::endl;
|
||||
blah += strlen( blah ) + 1;
|
||||
}
|
||||
}
|
||||
#else
|
||||
#define ShowAllHeaders(x)
|
||||
#endif
|
||||
|
||||
int RunXMLDownload( api_httpreceiver *http, obj_xml *parser )
|
||||
{
|
||||
int ret;
|
||||
bool noData;
|
||||
do
|
||||
{
|
||||
Sleep( 50 );
|
||||
ret = http->run();
|
||||
if ( FeedXMLHTTP( http, parser, &noData ) != API_XML_SUCCESS )
|
||||
return DOWNLOAD_ERROR_PARSING_XML;
|
||||
} while ( ret == HTTPRECEIVER_RUN_OK );
|
||||
|
||||
// finish off the data
|
||||
do
|
||||
{
|
||||
if ( FeedXMLHTTP( http, parser, &noData ) != API_XML_SUCCESS )
|
||||
return DOWNLOAD_ERROR_PARSING_XML;
|
||||
} while ( !noData );
|
||||
|
||||
parser->xmlreader_feed( 0, 0 );
|
||||
if ( ret != HTTPRECEIVER_RUN_ERROR )
|
||||
return DOWNLOAD_SUCCESS;
|
||||
else
|
||||
return DOWNLOAD_CONNECTIONRESET;
|
||||
}
|
||||
|
||||
|
||||
int DownloadThread::DownloadURL( const wchar_t *url )
|
||||
{
|
||||
if ( !parser )
|
||||
return DOWNLOAD_NOPARSER; // no sense in continuing if there's no parser available
|
||||
|
||||
api_httpreceiver *http = 0;
|
||||
waServiceFactory *sf = plugin.service->service_getServiceByGuid( httpreceiverGUID );
|
||||
if ( sf )
|
||||
http = (api_httpreceiver *)sf->getInterface();
|
||||
|
||||
if ( !http )
|
||||
return DOWNLOAD_NOHTTP;
|
||||
|
||||
http->AllowCompression();
|
||||
http->open( API_DNS_AUTODNS, HTTP_BUFFER_SIZE, mediaLibrary.GetProxy() );
|
||||
|
||||
SetUserAgent( http );
|
||||
|
||||
http->connect( AutoChar( url ) );
|
||||
int ret;
|
||||
|
||||
do
|
||||
{
|
||||
Sleep( 50 );
|
||||
ret = http->run();
|
||||
if ( ret == -1 ) // connection failed
|
||||
break;
|
||||
|
||||
// ---- check our reply code ----
|
||||
int status = http->get_status();
|
||||
switch ( status )
|
||||
{
|
||||
case HTTPRECEIVER_STATUS_CONNECTING:
|
||||
case HTTPRECEIVER_STATUS_READING_HEADERS:
|
||||
break;
|
||||
|
||||
case HTTPRECEIVER_STATUS_READING_CONTENT:
|
||||
{
|
||||
ShowAllHeaders( http ); // benski> don't cut, only enabled in debug mode
|
||||
int downloadError;
|
||||
downloadError = RunXMLDownload( http, parser );
|
||||
if ( downloadError == DOWNLOAD_SUCCESS )
|
||||
ReadNodes( url );
|
||||
sf->releaseInterface( http );
|
||||
return downloadError;
|
||||
}
|
||||
break;
|
||||
case HTTPRECEIVER_STATUS_ERROR:
|
||||
default:
|
||||
sf->releaseInterface( http );
|
||||
return DOWNLOAD_404;
|
||||
}
|
||||
} while ( ret == HTTPRECEIVER_RUN_OK );
|
||||
|
||||
const char *er = http->geterrorstr();
|
||||
|
||||
sf->releaseInterface( http );
|
||||
|
||||
return DOWNLOAD_404;
|
||||
}
|
28
Src/Plugins/Library/ml_wire/DownloadThread.h
Normal file
28
Src/Plugins/Library/ml_wire/DownloadThread.h
Normal file
@ -0,0 +1,28 @@
|
||||
#ifndef NULLSOFT_DOWNLOADTHREADH
|
||||
#define NULLSOFT_DOWNLOADTHREADH
|
||||
|
||||
#include "../xml/obj_xml.h"
|
||||
#include "../xml/XMLDOM.h"
|
||||
#include "../nu/Alias.h"
|
||||
#include "api__ml_wire.h"
|
||||
#include <api/service/waServiceFactory.h>
|
||||
|
||||
|
||||
class DownloadThread
|
||||
{
|
||||
public:
|
||||
DownloadThread();
|
||||
virtual ~DownloadThread();
|
||||
|
||||
virtual void ReadNodes(const wchar_t *url) = 0;
|
||||
|
||||
int DownloadURL(const wchar_t *url);
|
||||
void DownloadFile(const wchar_t *fileName);
|
||||
protected:
|
||||
XMLDOM xmlDOM;
|
||||
private:
|
||||
obj_xml *parser;
|
||||
waServiceFactory *parserFactory;
|
||||
|
||||
};
|
||||
#endif
|
121
Src/Plugins/Library/ml_wire/Downloaded.cpp
Normal file
121
Src/Plugins/Library/ml_wire/Downloaded.cpp
Normal file
@ -0,0 +1,121 @@
|
||||
#include "main.h"
|
||||
#include "Downloaded.h"
|
||||
|
||||
DownloadList downloadedFiles;
|
||||
using namespace Nullsoft::Utility;
|
||||
Nullsoft::Utility::LockGuard downloadedLock;
|
||||
|
||||
DownloadedFile::DownloadedFile()
|
||||
{
|
||||
Init();
|
||||
}
|
||||
|
||||
DownloadedFile::DownloadedFile(const wchar_t *_url, const wchar_t *_path, const wchar_t *_channel, const wchar_t *_item, __time64_t publishDate)
|
||||
{
|
||||
Init();
|
||||
|
||||
this->publishDate = publishDate;
|
||||
|
||||
SetChannel( _channel );
|
||||
SetItem( _item );
|
||||
SetPath( _path );
|
||||
SetURL( _url );
|
||||
}
|
||||
|
||||
DownloadedFile::DownloadedFile( const DownloadedFile © )
|
||||
{
|
||||
Init();
|
||||
|
||||
operator =( copy );
|
||||
}
|
||||
|
||||
DownloadedFile::~DownloadedFile()
|
||||
{
|
||||
Reset();
|
||||
}
|
||||
|
||||
|
||||
void DownloadedFile::Init()
|
||||
{
|
||||
url = 0;
|
||||
path = 0;
|
||||
channel = 0;
|
||||
item = 0;
|
||||
bytesDownloaded = 0;
|
||||
totalSize = 0;
|
||||
publishDate = 0;
|
||||
}
|
||||
|
||||
void DownloadedFile::Reset()
|
||||
{
|
||||
if ( url )
|
||||
{
|
||||
free( url );
|
||||
url = 0;
|
||||
}
|
||||
|
||||
if ( path )
|
||||
{
|
||||
free( path );
|
||||
path = 0;
|
||||
}
|
||||
|
||||
if ( channel )
|
||||
{
|
||||
free( channel );
|
||||
channel = 0;
|
||||
}
|
||||
|
||||
if ( item )
|
||||
{
|
||||
free( item );
|
||||
item = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void DownloadedFile::SetPath( const wchar_t *_path )
|
||||
{
|
||||
if ( path )
|
||||
free( path );
|
||||
|
||||
path = _wcsdup( _path );
|
||||
}
|
||||
|
||||
void DownloadedFile::SetURL( const wchar_t *_url )
|
||||
{
|
||||
if ( url )
|
||||
free( url );
|
||||
|
||||
url = _wcsdup( _url );
|
||||
}
|
||||
|
||||
void DownloadedFile::SetItem( const wchar_t *_item )
|
||||
{
|
||||
free( item );
|
||||
item = _wcsdup( _item );
|
||||
}
|
||||
|
||||
void DownloadedFile::SetChannel( const wchar_t *_channel )
|
||||
{
|
||||
free( channel );
|
||||
channel = _wcsdup( _channel );
|
||||
}
|
||||
|
||||
const DownloadedFile &DownloadedFile::operator =( const DownloadedFile © )
|
||||
{
|
||||
Reset();
|
||||
Init();
|
||||
|
||||
SetChannel( copy.channel );
|
||||
SetItem( copy.item );
|
||||
|
||||
bytesDownloaded = copy.bytesDownloaded;
|
||||
totalSize = copy.totalSize;
|
||||
publishDate = copy.publishDate;
|
||||
downloadDate = copy.downloadDate;
|
||||
|
||||
SetPath( copy.path );
|
||||
SetURL( copy.url );
|
||||
|
||||
return *this;
|
||||
}
|
79
Src/Plugins/Library/ml_wire/Downloaded.h
Normal file
79
Src/Plugins/Library/ml_wire/Downloaded.h
Normal file
@ -0,0 +1,79 @@
|
||||
#ifndef NULLSOFT_DOWNLOADEDH
|
||||
#define NULLSOFT_DOWNLOADEDH
|
||||
|
||||
#include "../nu/AutoLock.h"
|
||||
#include "../nu/AutoCharFn.h"
|
||||
#include "..\..\General\gen_ml/ml.h"
|
||||
#include <vector>
|
||||
#include "../nu/MediaLibraryInterface.h"
|
||||
|
||||
class DownloadedFile
|
||||
{
|
||||
public:
|
||||
DownloadedFile();
|
||||
DownloadedFile( const wchar_t *_url, const wchar_t *_path, const wchar_t *_channel, const wchar_t *_item, __time64_t publishDate );
|
||||
DownloadedFile( const DownloadedFile © );
|
||||
~DownloadedFile();
|
||||
|
||||
const DownloadedFile &operator =( const DownloadedFile © );
|
||||
|
||||
void SetPath( const wchar_t *_path );
|
||||
void SetURL( const wchar_t *_url );
|
||||
void SetItem( const wchar_t *_item );
|
||||
void SetChannel( const wchar_t *_channel );
|
||||
|
||||
size_t bytesDownloaded = 0;
|
||||
size_t totalSize = 0;
|
||||
|
||||
__time64_t publishDate;
|
||||
__time64_t downloadDate = 0;
|
||||
|
||||
wchar_t *path = 0;
|
||||
wchar_t *url = 0;
|
||||
wchar_t *channel = 0;
|
||||
wchar_t *item = 0;
|
||||
|
||||
|
||||
private:
|
||||
void Init();
|
||||
void Reset();
|
||||
};
|
||||
|
||||
class DownloadList
|
||||
{
|
||||
public:
|
||||
typedef std::vector<DownloadedFile> DownloadedFileList;
|
||||
typedef DownloadedFileList::iterator iterator;
|
||||
typedef DownloadedFileList::const_iterator const_iterator;
|
||||
|
||||
operator Nullsoft::Utility::LockGuard &() { return downloadedLock; }
|
||||
|
||||
void Remove( size_t index ) { downloadList.erase( downloadList.begin() + index ); }
|
||||
|
||||
bool RemoveAndDelete( int index )
|
||||
{
|
||||
SendMessage( mediaLibrary.library, WM_ML_IPC, (WPARAM)downloadList[ index ].path, ML_IPC_DB_REMOVEITEMW );
|
||||
|
||||
if ( !DeleteFile( downloadList[ index ].path ) && GetLastError() != ERROR_FILE_NOT_FOUND )
|
||||
return false;
|
||||
|
||||
downloadList.erase( downloadList.begin() + index );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
DownloadedFileList downloadList;
|
||||
Nullsoft::Utility::LockGuard downloadedLock;
|
||||
|
||||
iterator begin() { return downloadList.begin(); }
|
||||
iterator end() { return downloadList.end(); }
|
||||
};
|
||||
|
||||
extern DownloadList downloadedFiles;
|
||||
extern int downloadsItemSort;
|
||||
extern bool downloadsSortAscending;
|
||||
|
||||
void CleanupDownloads();
|
||||
__time64_t filetime(const wchar_t *file);
|
||||
|
||||
#endif
|
1453
Src/Plugins/Library/ml_wire/DownloadsDialog.cpp
Normal file
1453
Src/Plugins/Library/ml_wire/DownloadsDialog.cpp
Normal file
File diff suppressed because it is too large
Load Diff
13
Src/Plugins/Library/ml_wire/DownloadsDialog.h
Normal file
13
Src/Plugins/Library/ml_wire/DownloadsDialog.h
Normal file
@ -0,0 +1,13 @@
|
||||
#ifndef NULLSOFT_DOWNLOADSDIALOGH
|
||||
#define NULLSOFT_DOWNLOADSDIALOGH
|
||||
|
||||
#include "DownloadStatus.h"
|
||||
|
||||
class OmService;
|
||||
HWND CALLBACK DownloadDialog_Create(HWND hParent, OmService *service);
|
||||
|
||||
void DownloadsUpdated();
|
||||
void DownloadsUpdated( DownloadToken token, const DownloadedFile *f );
|
||||
void DownloadsUpdated( const DownloadStatus::Status &s, DownloadToken token );
|
||||
|
||||
#endif
|
204
Src/Plugins/Library/ml_wire/DownloadsParse.cpp
Normal file
204
Src/Plugins/Library/ml_wire/DownloadsParse.cpp
Normal file
@ -0,0 +1,204 @@
|
||||
#include "Main.h"
|
||||
#include "DownloadsParse.h"
|
||||
#include "Downloaded.h"
|
||||
#include "Defaults.h"
|
||||
#include "ParseUtil.h"
|
||||
#include <wchar.h>
|
||||
#include <locale.h>
|
||||
|
||||
static __time64_t filetime( const wchar_t *file )
|
||||
{
|
||||
if ( !file || !*file )
|
||||
return 0;
|
||||
|
||||
WIN32_FIND_DATA f = { 0 };
|
||||
|
||||
HANDLE h = FindFirstFile( file, &f );
|
||||
if ( h == INVALID_HANDLE_VALUE )
|
||||
return 0;
|
||||
|
||||
FindClose( h );
|
||||
SYSTEMTIME s = { 0 };
|
||||
FileTimeToSystemTime( &f.ftCreationTime, &s );
|
||||
|
||||
tm t = { 0 };
|
||||
t.tm_year = s.wYear - 1900;
|
||||
t.tm_mon = s.wMonth - 1;
|
||||
t.tm_mday = s.wDay;
|
||||
t.tm_hour = s.wHour;
|
||||
t.tm_min = s.wMinute;
|
||||
t.tm_sec = s.wMinute;
|
||||
|
||||
return _mktime64( &t );
|
||||
}
|
||||
|
||||
static void ReadDownload( const XMLNode *item, bool addToLib = false )
|
||||
{
|
||||
DownloadedFile newDownloaded;
|
||||
|
||||
const wchar_t *channel = GetContent( item, L"channel" );
|
||||
newDownloaded.SetChannel( channel );
|
||||
|
||||
const wchar_t *item_str = GetContent( item, L"item" );
|
||||
newDownloaded.SetItem( item_str );
|
||||
|
||||
const wchar_t *url = GetContent( item, L"url" );
|
||||
newDownloaded.SetURL( url );
|
||||
|
||||
const wchar_t *path = GetContent( item, L"path" );
|
||||
newDownloaded.SetPath( path );
|
||||
|
||||
const wchar_t *publishDate = GetContent( item, L"publishDate" );
|
||||
|
||||
if ( publishDate && publishDate[ 0 ] )
|
||||
newDownloaded.publishDate = _wtoi( publishDate );
|
||||
else
|
||||
newDownloaded.publishDate = filetime( newDownloaded.path );
|
||||
|
||||
if ( addToLib )
|
||||
addToLibrary( newDownloaded );
|
||||
|
||||
downloadedFiles.downloadList.push_back( newDownloaded );
|
||||
}
|
||||
|
||||
static void ReadPreferences( const XMLNode *item )
|
||||
{
|
||||
const XMLNode *curNode;
|
||||
|
||||
curNode = item->Get(L"download");
|
||||
if ( curNode )
|
||||
{
|
||||
const wchar_t *prop = curNode->GetProperty( L"downloadpath" );
|
||||
if ( prop )
|
||||
lstrcpyn( defaultDownloadPath, prop, MAX_PATH );
|
||||
|
||||
autoDownload = PropertyIsTrue( curNode, L"autodownload" );
|
||||
|
||||
prop = curNode->GetProperty( L"autoDownloadEpisodes" );
|
||||
if ( prop )
|
||||
autoDownloadEpisodes = _wtoi( prop );
|
||||
needToMakePodcastsView = PropertyIsTrue( curNode, L"needToMakePodcastsView" );
|
||||
}
|
||||
|
||||
curNode = item->Get(L"update");
|
||||
if ( curNode )
|
||||
{
|
||||
const wchar_t *prop = curNode->GetProperty( L"updatetime" );
|
||||
if ( prop )
|
||||
updateTime = _wtoi64( prop );
|
||||
|
||||
autoUpdate = PropertyIsTrue( curNode, L"autoupdate" );
|
||||
updateOnLaunch = PropertyIsTrue( curNode, L"updateonlaunch" );
|
||||
}
|
||||
|
||||
curNode = item->Get(L"subscriptions");
|
||||
if ( curNode )
|
||||
{
|
||||
_locale_t C_locale = WASABI_API_LNG->Get_C_NumericLocale();
|
||||
const wchar_t *prop = curNode->GetProperty( L"htmldivider" );
|
||||
if ( prop )
|
||||
htmlDividerPercent = (float)_wtof_l( prop, C_locale );
|
||||
|
||||
prop = curNode->GetProperty( L"channeldivider" );
|
||||
if ( prop && prop[ 0 ] )
|
||||
channelDividerPercent = (float)_wtof_l( prop, C_locale );
|
||||
|
||||
prop = curNode->GetProperty( L"itemtitlewidth" );
|
||||
if ( prop && prop[ 0 ] )
|
||||
itemTitleWidth = _wtoi( prop );
|
||||
|
||||
prop = curNode->GetProperty( L"itemdatewidth" );
|
||||
if ( prop && prop[ 0 ] )
|
||||
itemDateWidth = _wtoi( prop );
|
||||
|
||||
prop = curNode->GetProperty( L"itemmediawidth" );
|
||||
if ( prop && prop[ 0 ] )
|
||||
itemMediaWidth = _wtoi( prop );
|
||||
|
||||
prop = curNode->GetProperty( L"itemsizewidth" );
|
||||
if ( prop && prop[ 0 ] )
|
||||
itemSizeWidth = _wtoi( prop );
|
||||
|
||||
prop = curNode->GetProperty( L"currentitemsort" );
|
||||
if ( prop && prop[ 0 ] )
|
||||
currentItemSort = _wtoi( prop );
|
||||
|
||||
itemSortAscending = !PropertyIsFalse( curNode, L"itemsortascending" );
|
||||
|
||||
channelSortAscending = !PropertyIsFalse( curNode, L"channelsortascending" );
|
||||
|
||||
prop = curNode->GetProperty( L"channelLastSelection" );
|
||||
if ( prop && prop[ 0 ] )
|
||||
channelLastSelection = _wtoi( prop );
|
||||
}
|
||||
|
||||
curNode = item->Get(L"downloadsView");
|
||||
if ( curNode )
|
||||
{
|
||||
const wchar_t *prop = curNode->GetProperty( L"downloadsChannelWidth" );
|
||||
if ( prop && prop[ 0 ] )
|
||||
downloadsChannelWidth = _wtoi( prop );
|
||||
if ( downloadsChannelWidth <= 0 )
|
||||
downloadsChannelWidth = DOWNLOADSCHANNELWIDTHDEFAULT;
|
||||
|
||||
prop = curNode->GetProperty( L"downloadsItemWidth" );
|
||||
if ( prop && prop[ 0 ] )
|
||||
downloadsItemWidth = _wtoi( prop );
|
||||
if ( downloadsItemWidth <= 0 )
|
||||
downloadsItemWidth = DOWNLOADSITEMWIDTHDEFAULT;
|
||||
|
||||
prop = curNode->GetProperty( L"downloadsProgressWidth" );
|
||||
if ( prop && prop[ 0 ] )
|
||||
downloadsProgressWidth = _wtoi( prop );
|
||||
if ( downloadsProgressWidth <= 0 )
|
||||
downloadsProgressWidth = DOWNLOADSPROGRESSWIDTHDEFAULT;
|
||||
|
||||
prop = curNode->GetProperty( L"downloadsPathWidth" );
|
||||
if ( prop && prop[ 0 ] )
|
||||
downloadsPathWidth = _wtoi( prop );
|
||||
if ( downloadsPathWidth <= 0 )
|
||||
downloadsPathWidth = DOWNLOADSPATHWIDTHDEFAULTS;
|
||||
|
||||
prop = curNode->GetProperty( L"downloadsItemSort" );
|
||||
if ( prop && prop[ 0 ] )
|
||||
downloadsItemSort = _wtoi( prop );
|
||||
|
||||
downloadsSortAscending = !PropertyIsFalse( curNode, L"downloadsSortAscending" );
|
||||
}
|
||||
|
||||
curNode = item->Get(L"service");
|
||||
if ( curNode )
|
||||
{
|
||||
const wchar_t *prop = curNode->GetProperty( L"url" );
|
||||
if ( prop )
|
||||
lstrcpyn( serviceUrl, prop, MAX_PATH );
|
||||
}
|
||||
}
|
||||
|
||||
void DownloadsParse::ReadNodes( const wchar_t *url )
|
||||
{
|
||||
XMLNode::NodeList::const_iterator itr;
|
||||
const XMLNode *curNode = xmlDOM.GetRoot();
|
||||
|
||||
curNode = curNode->Get( L"winamp:preferences" );
|
||||
if ( curNode )
|
||||
{
|
||||
int version = 1;
|
||||
const wchar_t *prop = curNode->GetProperty( L"version" );
|
||||
if ( prop && prop[ 0 ] )
|
||||
version = _wtoi( prop );
|
||||
|
||||
ReadPreferences( curNode );
|
||||
|
||||
curNode = curNode->Get( L"downloads" );
|
||||
if ( curNode )
|
||||
{
|
||||
const XMLNode::NodeList *downloadsList = curNode->GetList( L"download" );
|
||||
if ( downloadsList )
|
||||
{
|
||||
for ( itr = downloadsList->begin(); itr != downloadsList->end(); itr++ )
|
||||
ReadDownload( *itr, version < 2 );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
13
Src/Plugins/Library/ml_wire/DownloadsParse.h
Normal file
13
Src/Plugins/Library/ml_wire/DownloadsParse.h
Normal file
@ -0,0 +1,13 @@
|
||||
#ifndef NULLSOFT_DOWNLOADSPARSEH
|
||||
#define NULLSOFT_DOWNLOADSPARSEH
|
||||
|
||||
#include "DownloadThread.h"
|
||||
|
||||
class DownloadsParse : public DownloadThread
|
||||
{
|
||||
public:
|
||||
virtual void ReadNodes(const wchar_t *url);
|
||||
|
||||
};
|
||||
|
||||
#endif
|
85
Src/Plugins/Library/ml_wire/ExternalCOM.cpp
Normal file
85
Src/Plugins/Library/ml_wire/ExternalCOM.cpp
Normal file
@ -0,0 +1,85 @@
|
||||
#include "main.h"
|
||||
#include "./externalCOM.h"
|
||||
#include "./util.h"
|
||||
#include "./rssCOM.h"
|
||||
|
||||
#define DISPTABLE_CLASS ExternalCOM
|
||||
|
||||
DISPTABLE_BEGIN()
|
||||
DISPENTRY_ADD(DISPATCH_PODCAST, L"Podcast", OnPodcast)
|
||||
DISPTABLE_END
|
||||
|
||||
#undef DISPTABLE_CLASS
|
||||
|
||||
ExternalCOM::ExternalCOM()
|
||||
{}
|
||||
|
||||
ExternalCOM::~ExternalCOM()
|
||||
{}
|
||||
|
||||
HRESULT ExternalCOM::CreateInstance(ExternalCOM **instance)
|
||||
{
|
||||
if (NULL == instance) return E_POINTER;
|
||||
|
||||
*instance = new ExternalCOM();
|
||||
if (NULL == *instance) return E_OUTOFMEMORY;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP_( ULONG ) ExternalCOM::AddRef( void )
|
||||
{
|
||||
return _ref.fetch_add( 1 );
|
||||
}
|
||||
|
||||
STDMETHODIMP_( ULONG ) ExternalCOM::Release( void )
|
||||
{
|
||||
if ( 0 == _ref.load() )
|
||||
return _ref.load();
|
||||
|
||||
LONG r = _ref.fetch_sub( 1 );
|
||||
if ( 0 == r )
|
||||
delete( this );
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
STDMETHODIMP ExternalCOM::QueryInterface(REFIID riid, PVOID *ppvObject)
|
||||
{
|
||||
if (NULL == ppvObject) return E_POINTER;
|
||||
|
||||
if (IsEqualIID(riid, IID_IDispatch))
|
||||
*ppvObject = static_cast<IDispatch*>(this);
|
||||
else if (IsEqualIID(riid, IID_IUnknown))
|
||||
*ppvObject = static_cast<IUnknown*>(this);
|
||||
else
|
||||
{
|
||||
*ppvObject = NULL;
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
AddRef();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
HRESULT ExternalCOM::OnPodcast(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr)
|
||||
{
|
||||
if (NULL != pvarResult)
|
||||
{
|
||||
VariantInit(pvarResult);
|
||||
|
||||
RssCOM *rss;
|
||||
if (SUCCEEDED(RssCOM::CreateInstance(&rss)))
|
||||
{
|
||||
V_VT(pvarResult) = VT_DISPATCH;
|
||||
V_DISPATCH(pvarResult) = rss;
|
||||
}
|
||||
else
|
||||
{
|
||||
V_VT(pvarResult) = VT_NULL;
|
||||
}
|
||||
|
||||
}
|
||||
return S_OK;
|
||||
}
|
40
Src/Plugins/Library/ml_wire/ExternalCOM.h
Normal file
40
Src/Plugins/Library/ml_wire/ExternalCOM.h
Normal file
@ -0,0 +1,40 @@
|
||||
#ifndef NULLSOFT_PODCAST_PLUGIN_EXTERNAL_HEADER
|
||||
#define NULLSOFT_PODCAST_PLUGIN_EXTERNAL_HEADER
|
||||
|
||||
#if defined(_MSC_VER) && (_MSC_VER >= 1020)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <wtypes.h>
|
||||
#include <atomic>
|
||||
|
||||
#include "../nu/dispatchTable.h"
|
||||
|
||||
class ExternalCOM : public IDispatch
|
||||
{
|
||||
public:
|
||||
typedef enum
|
||||
{
|
||||
DISPATCH_PODCAST = 777,
|
||||
} DispatchCodes;
|
||||
|
||||
protected:
|
||||
ExternalCOM();
|
||||
~ExternalCOM();
|
||||
|
||||
public:
|
||||
static HRESULT CreateInstance(ExternalCOM **instance);
|
||||
|
||||
/* IUnknown*/
|
||||
STDMETHOD(QueryInterface)(REFIID riid, PVOID *ppvObject);
|
||||
STDMETHOD_(ULONG, AddRef)(void);
|
||||
STDMETHOD_(ULONG, Release)(void);
|
||||
|
||||
protected:
|
||||
DISPTABLE_INCLUDE();
|
||||
DISPHANDLER_REGISTER(OnPodcast);
|
||||
|
||||
std::atomic<std::size_t> _ref = 1;
|
||||
};
|
||||
|
||||
#endif //NULLSOFT_PODCAST_PLUGIN_EXTERNAL_HEADER
|
64
Src/Plugins/Library/ml_wire/Factory.cpp
Normal file
64
Src/Plugins/Library/ml_wire/Factory.cpp
Normal file
@ -0,0 +1,64 @@
|
||||
#include "api__ml_wire.h"
|
||||
#include "Factory.h"
|
||||
#include "Wire.h"
|
||||
|
||||
static const char serviceName[] = "Podcasts";
|
||||
|
||||
FOURCC PodcastsFactory::GetServiceType()
|
||||
{
|
||||
return WaSvc::UNIQUE;
|
||||
}
|
||||
|
||||
const char *PodcastsFactory::GetServiceName()
|
||||
{
|
||||
return serviceName;
|
||||
}
|
||||
|
||||
GUID PodcastsFactory::GetGUID()
|
||||
{
|
||||
return api_podcastsGUID;
|
||||
}
|
||||
|
||||
void *PodcastsFactory::GetInterface( int global_lock )
|
||||
{
|
||||
// if (global_lock)
|
||||
// plugin.service->service_lock(this, (void *)ifc);
|
||||
return &channels;
|
||||
}
|
||||
|
||||
int PodcastsFactory::SupportNonLockingInterface()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
int PodcastsFactory::ReleaseInterface( void *ifc )
|
||||
{
|
||||
//plugin.service->service_unlock(ifc);
|
||||
return 1;
|
||||
}
|
||||
|
||||
const char *PodcastsFactory::GetTestString()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int PodcastsFactory::ServiceNotify( int msg, int param1, int param2 )
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
#ifdef CBCLASS
|
||||
#undef CBCLASS
|
||||
#endif
|
||||
|
||||
#define CBCLASS PodcastsFactory
|
||||
START_DISPATCH;
|
||||
CB( WASERVICEFACTORY_GETSERVICETYPE, GetServiceType )
|
||||
CB( WASERVICEFACTORY_GETSERVICENAME, GetServiceName )
|
||||
CB( WASERVICEFACTORY_GETGUID, GetGUID )
|
||||
CB( WASERVICEFACTORY_GETINTERFACE, GetInterface )
|
||||
CB( WASERVICEFACTORY_SUPPORTNONLOCKINGGETINTERFACE, SupportNonLockingInterface )
|
||||
CB( WASERVICEFACTORY_RELEASEINTERFACE, ReleaseInterface )
|
||||
CB( WASERVICEFACTORY_GETTESTSTRING, GetTestString )
|
||||
CB( WASERVICEFACTORY_SERVICENOTIFY, ServiceNotify )
|
||||
END_DISPATCH;
|
22
Src/Plugins/Library/ml_wire/Factory.h
Normal file
22
Src/Plugins/Library/ml_wire/Factory.h
Normal file
@ -0,0 +1,22 @@
|
||||
#ifndef NULLSOFT_ML_WIRE_FACTORY_H
|
||||
#define NULLSOFT_ML_WIRE_FACTORY_H
|
||||
#include "api__ml_wire.h"
|
||||
#include <api/service/waservicefactory.h>
|
||||
#include <api/service/services.h>
|
||||
|
||||
class PodcastsFactory : public waServiceFactory
|
||||
{
|
||||
public:
|
||||
FOURCC GetServiceType();
|
||||
const char *GetServiceName();
|
||||
GUID GetGUID();
|
||||
void *GetInterface(int global_lock);
|
||||
int SupportNonLockingInterface();
|
||||
int ReleaseInterface(void *ifc);
|
||||
const char *GetTestString();
|
||||
int ServiceNotify(int msg, int param1, int param2);
|
||||
|
||||
protected:
|
||||
RECVS_DISPATCH;
|
||||
};
|
||||
#endif
|
38
Src/Plugins/Library/ml_wire/FeedParse.cpp
Normal file
38
Src/Plugins/Library/ml_wire/FeedParse.cpp
Normal file
@ -0,0 +1,38 @@
|
||||
#include "Main.h"
|
||||
#include "FeedParse.h"
|
||||
|
||||
|
||||
#include "RFCDate.h"
|
||||
|
||||
#include "RSSParse.h"
|
||||
#include "AtomParse.h"
|
||||
#ifdef DEBUG
|
||||
#include <iostream>
|
||||
static void DisplayNodes(XMLNode &node)
|
||||
{
|
||||
XMLNode::NodeMap::iterator nodeItr;
|
||||
for (nodeItr = node.nodes.begin();nodeItr != node.nodes.end(); nodeItr++)
|
||||
{
|
||||
|
||||
for (XMLNode::NodeList::iterator itr = nodeItr->second.begin(); itr != nodeItr->second.end(); itr++)
|
||||
{
|
||||
std::wcerr << L"<" << nodeItr->first << L">" << std::endl;
|
||||
DisplayNodes(**itr);
|
||||
std::wcerr << L"</" << nodeItr->first << L">" << std::endl;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void FeedParse::ReadNodes(const wchar_t *url)
|
||||
{
|
||||
const XMLNode *curNode = xmlDOM.GetRoot();
|
||||
|
||||
curNode = curNode->Get(L"rss");
|
||||
if (curNode)
|
||||
{
|
||||
ReadRSS(curNode, sync, loadingOwnFeed, url);
|
||||
return ;
|
||||
}
|
||||
}
|
24
Src/Plugins/Library/ml_wire/FeedParse.h
Normal file
24
Src/Plugins/Library/ml_wire/FeedParse.h
Normal file
@ -0,0 +1,24 @@
|
||||
#ifndef NULLSOFT_FEEDPARSEH
|
||||
#define NULLSOFT_FEEDPARSEH
|
||||
|
||||
#include "DownloadThread.h"
|
||||
#include "ChannelSync.h"
|
||||
class FeedParse : public DownloadThread
|
||||
{
|
||||
public:
|
||||
FeedParse(ChannelSync *_sync, bool doWinampSpecificTags = false)
|
||||
: sync(_sync), loadingOwnFeed(doWinampSpecificTags)
|
||||
{}
|
||||
|
||||
~FeedParse()
|
||||
{
|
||||
sync = 0;
|
||||
}
|
||||
|
||||
virtual void ReadNodes(const wchar_t *url);
|
||||
private:
|
||||
ChannelSync *sync;
|
||||
bool loadingOwnFeed;
|
||||
};
|
||||
|
||||
#endif
|
37
Src/Plugins/Library/ml_wire/FeedUtil.cpp
Normal file
37
Src/Plugins/Library/ml_wire/FeedUtil.cpp
Normal file
@ -0,0 +1,37 @@
|
||||
#include "main.h"
|
||||
#include "FeedUtil.h"
|
||||
#include "ChannelCheck.h"
|
||||
#include "FeedParse.h"
|
||||
#include "errors.h"
|
||||
#include "./defaults.h"
|
||||
|
||||
|
||||
int DownloadFeedInformation(Channel &newFeed)
|
||||
{
|
||||
ChannelCheck check;
|
||||
FeedParse downloader(&check, false);
|
||||
|
||||
int ret = downloader.DownloadURL(newFeed.url);
|
||||
if (ret != DOWNLOAD_SUCCESS)
|
||||
return ret;
|
||||
|
||||
if (!check.channel.title || !check.channel.title[0])
|
||||
return DOWNLOAD_NOTRSS;
|
||||
|
||||
newFeed.SetTitle(check.channel.title);
|
||||
if (check.channel.ttl)
|
||||
{
|
||||
newFeed.updateTime = check.channel.ttl * 60;
|
||||
newFeed.autoUpdate = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
newFeed.updateTime = ::updateTime;
|
||||
newFeed.autoUpdate = ::autoUpdate;
|
||||
}
|
||||
|
||||
if (check.channel.url && check.channel.url[0])
|
||||
newFeed.SetURL(check.channel.url);
|
||||
|
||||
return DOWNLOAD_SUCCESS;
|
||||
}
|
8
Src/Plugins/Library/ml_wire/FeedUtil.h
Normal file
8
Src/Plugins/Library/ml_wire/FeedUtil.h
Normal file
@ -0,0 +1,8 @@
|
||||
#ifndef NULLSOFT_FEEDUTILH
|
||||
#define NULLSOFT_FEEDUTILH
|
||||
|
||||
#include "Feeds.h"
|
||||
|
||||
|
||||
int DownloadFeedInformation(Channel &channel);
|
||||
#endif
|
298
Src/Plugins/Library/ml_wire/Feeds.cpp
Normal file
298
Src/Plugins/Library/ml_wire/Feeds.cpp
Normal file
@ -0,0 +1,298 @@
|
||||
#include "main.h"
|
||||
#include "Feeds.h"
|
||||
#include "./util.h"
|
||||
#include "./defaults.h"
|
||||
#include <algorithm>
|
||||
#include <shlwapi.h>
|
||||
#include "BackgroundDownloader.h"
|
||||
#include <strsafe.h>
|
||||
|
||||
static bool operator == (const RSS::Item &a, const RSS::Item &b)
|
||||
{
|
||||
if(a.guid && a.guid[0] && b.guid && b.guid[0])
|
||||
return !wcscmp(a.guid, b.guid);
|
||||
|
||||
if(a.publishDate && b.publishDate)
|
||||
return a.publishDate == b.publishDate;
|
||||
|
||||
if (a.url && a.url[0] && b.url && b.url[0])
|
||||
return !wcscmp(a.url, b.url);
|
||||
|
||||
return a.url == b.url;
|
||||
}
|
||||
|
||||
Channel::Channel()
|
||||
{
|
||||
Init();
|
||||
}
|
||||
|
||||
Channel::Channel(const Channel ©)
|
||||
{
|
||||
Init();
|
||||
operator =(copy);
|
||||
}
|
||||
|
||||
const Channel &Channel::operator =(const Channel ©)
|
||||
{
|
||||
Reset();
|
||||
Init();
|
||||
url = _wcsdup(copy.url);
|
||||
title = _wcsdup(copy.title);
|
||||
link = _wcsdup(copy.link);
|
||||
description = _wcsdup(copy.description);
|
||||
ttl=copy.ttl;
|
||||
updateTime=copy.updateTime;
|
||||
lastUpdate=copy.lastUpdate;
|
||||
autoDownloadEpisodes=copy.autoDownloadEpisodes;
|
||||
autoDownload=copy.autoDownload;
|
||||
autoUpdate=copy.autoUpdate;
|
||||
useDefaultUpdate=copy.useDefaultUpdate;
|
||||
needsRefresh=copy.needsRefresh;
|
||||
items=copy.items;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Channel::~Channel()
|
||||
{
|
||||
Reset();
|
||||
}
|
||||
|
||||
void Channel::Init()
|
||||
{
|
||||
url =0;
|
||||
title = 0;
|
||||
link = 0;
|
||||
description = 0;
|
||||
ttl=0;
|
||||
lastUpdate=0;
|
||||
autoUpdate = ::autoUpdate;
|
||||
updateTime = ::updateTime;
|
||||
autoDownload = ::autoDownload;
|
||||
autoDownloadEpisodes = ::autoDownloadEpisodes;
|
||||
useDefaultUpdate=true;
|
||||
needsRefresh=false;
|
||||
}
|
||||
|
||||
void Channel::Reset()
|
||||
{
|
||||
free(url);
|
||||
free(title);
|
||||
free(link);
|
||||
free(description);
|
||||
}
|
||||
|
||||
void Channel::UpdateFrom(const Channel ©)
|
||||
{
|
||||
if (copy.url && copy.url[0])
|
||||
SetURL(copy.url);
|
||||
|
||||
SetTitle(copy.title);
|
||||
SetLink(copy.link);
|
||||
SetDescription(copy.description);
|
||||
if (copy.ttl)
|
||||
ttl=copy.ttl;
|
||||
|
||||
ItemList::const_iterator itr;
|
||||
|
||||
for (itr=copy.items.begin();itr!=copy.items.end();itr++)
|
||||
{
|
||||
const RSS::Item &b = *itr;
|
||||
if ( b.url && b.url[0] )
|
||||
{
|
||||
((RSS::Item*)&b)->downloaded = IsPodcastDownloaded(b.url);
|
||||
}
|
||||
}
|
||||
|
||||
// update to the latest default setting
|
||||
if (useDefaultUpdate)
|
||||
{
|
||||
autoUpdate = ::autoUpdate;
|
||||
updateTime = ::updateTime;
|
||||
autoDownload = ::autoDownload;
|
||||
autoDownloadEpisodes = ::autoDownloadEpisodes;
|
||||
}
|
||||
|
||||
items.clear(); // benski> added for 5.23
|
||||
for (itr=copy.items.begin();itr!=copy.items.end();itr++)
|
||||
{
|
||||
items.insert(items.begin(), *itr);
|
||||
}
|
||||
|
||||
if(autoDownload)
|
||||
{
|
||||
SortByDate();
|
||||
size_t idx = items.size();
|
||||
if (idx)
|
||||
{
|
||||
int episodeCount = 0;
|
||||
do
|
||||
{
|
||||
idx--;
|
||||
const RSS::Item &b = items[idx];
|
||||
if(b.url && b.url[0])
|
||||
{
|
||||
episodeCount++;
|
||||
if (!b.downloaded)
|
||||
{
|
||||
WCHAR szPath[MAX_PATH *2] = {0};
|
||||
if (SUCCEEDED(((RSS::Item*)&b)->GetDownloadFileName(title, szPath, ARRAYSIZE(szPath), TRUE)))
|
||||
{
|
||||
wchar_t* url = urlencode(b.url);
|
||||
downloader.Download(url, szPath, title, b.itemName, b.publishDate);
|
||||
((RSS::Item*)&b)->downloaded = true;
|
||||
free(url);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
} while (episodeCount<autoDownloadEpisodes && idx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool Channel::operator == (const Channel &compare)
|
||||
{
|
||||
// changed from basing on the title as this allows for podcasts
|
||||
// with the same name to still work instead of being mangled as
|
||||
// was able to happen when this based things on the title value
|
||||
if (!compare.url || !compare.url[0])
|
||||
return false;
|
||||
return !wcscmp(url, compare.url);
|
||||
}
|
||||
|
||||
bool TitleMediaSort(const RSS::Item &item1, const RSS::Item &item2)
|
||||
{
|
||||
return (CSTR_LESS_THAN == CompareStringW(LOCALE_USER_DEFAULT, NORM_IGNORECASE, item1.itemName, -1, item2.itemName, -1));
|
||||
}
|
||||
|
||||
void Channel::SortByTitle()
|
||||
{
|
||||
std::sort(items.begin(), items.end(), TitleMediaSort);
|
||||
}
|
||||
|
||||
static bool ItemMediaSort(const RSS::Item &item1, const RSS::Item &item2)
|
||||
{
|
||||
if (!item1.url || !item1.url[0])
|
||||
return false;
|
||||
|
||||
if (!item2.url || !item2.url[0])
|
||||
return true;
|
||||
|
||||
if (!item2.listened)
|
||||
return false;
|
||||
|
||||
if (item1.listened)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ParseDuration(const wchar_t *duration, int *out_hours, int *out_minutes, int *out_seconds);
|
||||
static bool ItemMediaTimeSort(const RSS::Item &item1, const RSS::Item &item2)
|
||||
{
|
||||
if (!item1.duration || !item1.duration[0])
|
||||
return false;
|
||||
|
||||
if (!item2.duration || !item2.duration[0])
|
||||
return true;
|
||||
|
||||
int h1, h2, m1, m2, s1, s2;
|
||||
if (!ParseDuration(item1.duration, &h1, &m1, &s1))
|
||||
return false;
|
||||
|
||||
if (!ParseDuration(item2.duration, &h2, &m2, &s2))
|
||||
return true;
|
||||
|
||||
if (h1 < h2)
|
||||
return true;
|
||||
else if (h1 > h2)
|
||||
return false;
|
||||
|
||||
if (m1 < m2)
|
||||
return true;
|
||||
else if (m1 > m2)
|
||||
return false;
|
||||
|
||||
if (s1 < s2)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool ItemMediaSizeSort(const RSS::Item &item1, const RSS::Item &item2)
|
||||
{
|
||||
if (!item1.size)
|
||||
return false;
|
||||
|
||||
if (!item2.size)
|
||||
return true;
|
||||
|
||||
return item1.size < item2.size;
|
||||
}
|
||||
|
||||
void Channel::SortByMedia()
|
||||
{
|
||||
std::sort(items.begin(), items.end(), ItemMediaSort);
|
||||
}
|
||||
|
||||
void Channel::SortByMediaTime()
|
||||
{
|
||||
std::sort(items.begin(), items.end(), ItemMediaTimeSort);
|
||||
}
|
||||
|
||||
void Channel::SortByMediaSize()
|
||||
{
|
||||
std::sort(items.begin(), items.end(), ItemMediaSizeSort);
|
||||
}
|
||||
|
||||
bool ItemDateSort(const RSS::Item &item1, const RSS::Item &item2)
|
||||
{
|
||||
return (item1.publishDate < item2.publishDate);
|
||||
}
|
||||
|
||||
void Channel::SortByDate()
|
||||
{
|
||||
std::sort(items.begin(), items.end(), ItemDateSort);
|
||||
}
|
||||
|
||||
int Channel::GetTitle(wchar_t *str, size_t len)
|
||||
{
|
||||
if (str && len)
|
||||
{
|
||||
str[0]=0;
|
||||
if (title && title[0])
|
||||
StringCchCopyW(str, len, title);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
void Channel::SetURL(const wchar_t *val)
|
||||
{
|
||||
free(url);
|
||||
url = _wcsdup(val);
|
||||
}
|
||||
|
||||
void Channel::SetTitle(const wchar_t *val)
|
||||
{
|
||||
free(title);
|
||||
title = _wcsdup(val);
|
||||
}
|
||||
|
||||
void Channel::SetLink(const wchar_t *val)
|
||||
{
|
||||
free(link);
|
||||
link = _wcsdup(val);
|
||||
}
|
||||
|
||||
void Channel::SetDescription(const wchar_t *val)
|
||||
{
|
||||
free(description);
|
||||
description = _wcsdup(val);
|
||||
}
|
||||
|
||||
#undef CBCLASS
|
||||
#define CBCLASS Channel
|
||||
START_DISPATCH;
|
||||
CB(IFC_PODCAST_GETTITLE, GetTitle)
|
||||
END_DISPATCH;
|
||||
#undef CBCLASS
|
50
Src/Plugins/Library/ml_wire/Feeds.h
Normal file
50
Src/Plugins/Library/ml_wire/Feeds.h
Normal file
@ -0,0 +1,50 @@
|
||||
#ifndef NULLSOFT_FEEDSH
|
||||
#define NULLSOFT_FEEDSH
|
||||
|
||||
#include "ifc_podcast.h"
|
||||
#include "Item.h"
|
||||
#include <vector>
|
||||
|
||||
class Channel : public ifc_podcast
|
||||
{
|
||||
public:
|
||||
typedef std::vector<RSS::Item> ItemList;
|
||||
Channel();
|
||||
Channel(const Channel ©);
|
||||
const Channel &operator =(const Channel ©);
|
||||
~Channel();
|
||||
void SortByTitle(), SortByMedia(), SortByMediaTime(), SortByDate(), SortByMediaSize();
|
||||
bool operator == (const Channel &compare);
|
||||
//void operator = (const Channel ©);
|
||||
void UpdateFrom(const Channel ©);
|
||||
|
||||
unsigned int ttl;
|
||||
__time64_t updateTime, lastUpdate;
|
||||
int autoDownloadEpisodes;
|
||||
bool autoUpdate;
|
||||
bool useDefaultUpdate;
|
||||
bool autoDownload;
|
||||
bool needsRefresh;
|
||||
// TODO: std::wstring downloadLocation;
|
||||
ItemList items;
|
||||
|
||||
void SetURL(const wchar_t *val);
|
||||
void SetTitle(const wchar_t *val);
|
||||
void SetLink(const wchar_t *val);
|
||||
void SetDescription(const wchar_t *val);
|
||||
|
||||
wchar_t *url, *title, *link, *description;
|
||||
|
||||
public: // ifc_podcast interface
|
||||
int GetTitle(wchar_t *str, size_t len);
|
||||
|
||||
private:
|
||||
void Init();
|
||||
void Reset();
|
||||
|
||||
|
||||
protected:
|
||||
RECVS_DISPATCH;
|
||||
};
|
||||
|
||||
#endif
|
5
Src/Plugins/Library/ml_wire/FeedsDialog.h
Normal file
5
Src/Plugins/Library/ml_wire/FeedsDialog.h
Normal file
@ -0,0 +1,5 @@
|
||||
#ifndef NULLSOFT_FEEDSDIALOGH
|
||||
#define NULLSOFT_FEEDSDIALOGH
|
||||
|
||||
BOOL CALLBACK FeedsProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
||||
#endif
|
174
Src/Plugins/Library/ml_wire/Item.cpp
Normal file
174
Src/Plugins/Library/ml_wire/Item.cpp
Normal file
@ -0,0 +1,174 @@
|
||||
#include "Item.h"
|
||||
#include "util.h"
|
||||
#include "defaults.h"
|
||||
#include <shlwapi.h>
|
||||
#include <strsafe.h>
|
||||
|
||||
void RSS::Item::Reset()
|
||||
{
|
||||
free(itemName);
|
||||
free(url);
|
||||
free(sourceUrl);
|
||||
free(guid);
|
||||
free(description);
|
||||
free(link);
|
||||
free(duration);
|
||||
}
|
||||
|
||||
void RSS::Item::Init()
|
||||
{
|
||||
listened = false;
|
||||
publishDate = 0;
|
||||
generatedDate = true;
|
||||
downloaded=false;
|
||||
itemName=0;
|
||||
url=0;
|
||||
sourceUrl=0;
|
||||
guid=0;
|
||||
description=0;
|
||||
link=0;
|
||||
duration=0;
|
||||
size=0;
|
||||
}
|
||||
|
||||
RSS::Item::Item()
|
||||
{
|
||||
Init();
|
||||
}
|
||||
|
||||
RSS::Item::~Item()
|
||||
{
|
||||
Reset();
|
||||
}
|
||||
|
||||
RSS::Item::Item(const RSS::Item ©)
|
||||
{
|
||||
Init();
|
||||
operator =(copy);
|
||||
}
|
||||
|
||||
const RSS::Item &RSS::Item::operator =(const RSS::Item ©)
|
||||
{
|
||||
Reset();
|
||||
Init();
|
||||
listened=copy.listened;
|
||||
publishDate = copy.publishDate;
|
||||
generatedDate = copy.generatedDate;
|
||||
downloaded=copy.downloaded;
|
||||
itemName=_wcsdup(copy.itemName);
|
||||
url=_wcsdup(copy.url);
|
||||
sourceUrl=_wcsdup(copy.sourceUrl);
|
||||
guid=_wcsdup(copy.guid);
|
||||
description=_wcsdup(copy.description);
|
||||
link=_wcsdup(copy.link);
|
||||
duration=wcsdup(copy.duration);
|
||||
size = copy.size;
|
||||
return *this;
|
||||
}
|
||||
|
||||
HRESULT RSS::Item::GetDownloadFileName(const wchar_t *channelName, wchar_t *buffer, int bufferMax, BOOL fValidatePath) const
|
||||
{
|
||||
if (NULL == buffer || NULL == channelName) return E_INVALIDARG;
|
||||
buffer[0] = L'\0';
|
||||
|
||||
WCHAR szBuffer[MAX_PATH] = {0};
|
||||
|
||||
if (FAILED(StringCchCopyN(szBuffer, ARRAYSIZE(szBuffer), channelName, 100)))
|
||||
return E_UNEXPECTED;
|
||||
|
||||
Plugin_CleanDirectory(szBuffer);
|
||||
Plugin_ReplaceBadPathChars(szBuffer);
|
||||
|
||||
if (L'\0' == *szBuffer)
|
||||
StringCchCopy(szBuffer, ARRAYSIZE(szBuffer), L"UnknownChannel");
|
||||
|
||||
if (FALSE == PathCombine(buffer, defaultDownloadPath, szBuffer))
|
||||
return E_FAIL;
|
||||
|
||||
if (FALSE != fValidatePath && FAILED(Plugin_EnsurePathExist(buffer)))
|
||||
return E_FAIL;
|
||||
|
||||
LPWSTR cursor = szBuffer;
|
||||
size_t remaining = ARRAYSIZE(szBuffer);
|
||||
|
||||
tm* time = _localtime64(&publishDate);
|
||||
if(NULL != time && publishDate > 0)
|
||||
{
|
||||
StringCchPrintfEx(cursor, remaining, &cursor, &remaining, STRSAFE_NULL_ON_FAILURE,
|
||||
L"%04d-%02d-%02d - ", time->tm_year+1900, time->tm_mon+1, time->tm_mday);
|
||||
}
|
||||
|
||||
LPWSTR t = cursor;
|
||||
if (FAILED(StringCchCopyNEx(cursor, remaining, itemName, 100, &cursor, &remaining, 0)))
|
||||
return E_UNEXPECTED;
|
||||
|
||||
INT offset = Plugin_CleanDirectory(t);
|
||||
if (0 != offset)
|
||||
{
|
||||
remaining += offset;
|
||||
cursor -= offset;
|
||||
}
|
||||
|
||||
if (t == cursor)
|
||||
StringCchCopyEx(cursor, remaining, L"UnknownItem", &cursor, &remaining, 0);
|
||||
else
|
||||
Plugin_ReplaceBadPathChars(t);
|
||||
|
||||
if (FAILED(Plugin_FileExtensionFromUrl(cursor, (INT)remaining, url, L".mp3")))
|
||||
return E_UNEXPECTED;
|
||||
|
||||
if (FALSE == PathAppend(buffer, szBuffer))
|
||||
return E_FAIL;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
void RSS::MutableItem::SetLink(const wchar_t *value)
|
||||
{
|
||||
free(link);
|
||||
link = _wcsdup(value);
|
||||
}
|
||||
|
||||
void RSS::MutableItem::SetItemName(const wchar_t *value)
|
||||
{
|
||||
free(itemName);
|
||||
itemName = _wcsdup(value);
|
||||
}
|
||||
|
||||
void RSS::MutableItem::SetURL(const wchar_t *value)
|
||||
{
|
||||
free(url);
|
||||
url = _wcsdup(value);
|
||||
}
|
||||
|
||||
void RSS::MutableItem::SetSourceURL(const wchar_t *value)
|
||||
{
|
||||
free(sourceUrl);
|
||||
sourceUrl = _wcsdup(value);
|
||||
}
|
||||
|
||||
void RSS::MutableItem::SetGUID(const wchar_t *value)
|
||||
{
|
||||
free(guid);
|
||||
guid = _wcsdup(value);
|
||||
}
|
||||
|
||||
void RSS::MutableItem::SetDescription(const wchar_t *value)
|
||||
{
|
||||
free(description);
|
||||
description = _wcsdup(value);
|
||||
}
|
||||
|
||||
void RSS::MutableItem::SetDuration(const wchar_t *value)
|
||||
{
|
||||
free(duration);
|
||||
duration = _wcsdup(value);
|
||||
}
|
||||
|
||||
void RSS::MutableItem::SetSize(const wchar_t * _size)
|
||||
{
|
||||
if (_size)
|
||||
size = _wtoi64(_size);
|
||||
else
|
||||
size=0;
|
||||
}
|
50
Src/Plugins/Library/ml_wire/Item.h
Normal file
50
Src/Plugins/Library/ml_wire/Item.h
Normal file
@ -0,0 +1,50 @@
|
||||
#pragma once
|
||||
#include <bfc/platform/types.h>
|
||||
#include <time.h>
|
||||
#include <windows.h>
|
||||
|
||||
namespace RSS
|
||||
{
|
||||
class Item
|
||||
{
|
||||
public:
|
||||
Item();
|
||||
~Item();
|
||||
Item(const Item ©);
|
||||
const Item &operator =(const Item ©);
|
||||
|
||||
HRESULT GetDownloadFileName(const wchar_t *channelName, wchar_t *buffer, int bufferMax, BOOL fValidatePath) const;
|
||||
bool listened;
|
||||
bool downloaded;
|
||||
__time64_t publishDate;
|
||||
bool generatedDate;
|
||||
|
||||
//protected:
|
||||
wchar_t *itemName;
|
||||
wchar_t *url;
|
||||
wchar_t *sourceUrl;
|
||||
wchar_t *guid;
|
||||
wchar_t *description;
|
||||
wchar_t *link;
|
||||
wchar_t *duration;
|
||||
int64_t size;
|
||||
|
||||
private:
|
||||
void Init();
|
||||
void Reset();
|
||||
};
|
||||
|
||||
class MutableItem : public Item
|
||||
{
|
||||
public:
|
||||
void SetItemName(const wchar_t *value);
|
||||
void SetLink(const wchar_t *value);
|
||||
void SetURL(const wchar_t *value);
|
||||
void SetSourceURL(const wchar_t *value);
|
||||
void SetGUID(const wchar_t *value);
|
||||
void SetDescription(const wchar_t *value);
|
||||
void SetDuration(const wchar_t *value);
|
||||
void SetSize(const wchar_t * _size);
|
||||
};
|
||||
|
||||
}
|
94
Src/Plugins/Library/ml_wire/JSAPI2_Creator.cpp
Normal file
94
Src/Plugins/Library/ml_wire/JSAPI2_Creator.cpp
Normal file
@ -0,0 +1,94 @@
|
||||
#include "main.h"
|
||||
#include "JSAPI2_Creator.h"
|
||||
#include "JSAPI2_PodcastsAPI.h"
|
||||
#include "api__ml_wire.h"
|
||||
|
||||
IDispatch *JSAPI2_Creator::CreateAPI(const wchar_t *name, const wchar_t *key, JSAPI::ifc_info *info)
|
||||
{
|
||||
if (!_wcsicmp(name, L"Podcasts"))
|
||||
return new JSAPI2::PodcastsAPI(key, info);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
int JSAPI2_Creator::PromptForAuthorization(HWND parent, const wchar_t *group, const wchar_t *action, const wchar_t *authorization_key, JSAPI2::api_security::AuthorizationData *data)
|
||||
{
|
||||
if (group && !_wcsicmp(group, L"podcasts"))
|
||||
{
|
||||
const wchar_t *title_str = AGAVE_API_JSAPI2_SECURITY->GetAssociatedName(authorization_key);
|
||||
return AGAVE_API_JSAPI2_SECURITY->SecurityPrompt(parent, title_str, L"This service is trying to subscribe you to a podcast.", JSAPI2::svc_apicreator::AUTHORIZATION_FLAG_GROUP_ONLY);
|
||||
}
|
||||
else
|
||||
return JSAPI2::svc_apicreator::AUTHORIZATION_UNDEFINED;
|
||||
}
|
||||
|
||||
|
||||
#define CBCLASS JSAPI2_Creator
|
||||
START_DISPATCH;
|
||||
CB(JSAPI2_SVC_APICREATOR_CREATEAPI, CreateAPI);
|
||||
CB(JSAPI2_SVC_APICREATOR_PROMPTFORAUTHORIZATION, PromptForAuthorization);
|
||||
END_DISPATCH;
|
||||
#undef CBCLASS
|
||||
|
||||
static JSAPI2_Creator jsapi2_svc;
|
||||
static const char serviceName[] = "Podcast Javascript Objects";
|
||||
|
||||
// {EE2C54DB-E609-410a-A962-573BA2F9C3AC}
|
||||
static const GUID jsapi2_factory_guid =
|
||||
{ 0xee2c54db, 0xe609, 0x410a, { 0xa9, 0x62, 0x57, 0x3b, 0xa2, 0xf9, 0xc3, 0xac } };
|
||||
|
||||
FOURCC JSAPI2Factory::GetServiceType()
|
||||
{
|
||||
return jsapi2_svc.getServiceType();
|
||||
}
|
||||
|
||||
const char *JSAPI2Factory::GetServiceName()
|
||||
{
|
||||
return serviceName;
|
||||
}
|
||||
|
||||
GUID JSAPI2Factory::GetGUID()
|
||||
{
|
||||
return jsapi2_factory_guid;
|
||||
}
|
||||
|
||||
void *JSAPI2Factory::GetInterface(int global_lock)
|
||||
{
|
||||
// if (global_lock)
|
||||
// plugin.service->service_lock(this, (void *)ifc);
|
||||
return &jsapi2_svc;
|
||||
}
|
||||
|
||||
int JSAPI2Factory::SupportNonLockingInterface()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
int JSAPI2Factory::ReleaseInterface(void *ifc)
|
||||
{
|
||||
//plugin.service->service_unlock(ifc);
|
||||
return 1;
|
||||
}
|
||||
|
||||
const char *JSAPI2Factory::GetTestString()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int JSAPI2Factory::ServiceNotify(int msg, int param1, int param2)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
#define CBCLASS JSAPI2Factory
|
||||
START_DISPATCH;
|
||||
CB(WASERVICEFACTORY_GETSERVICETYPE, GetServiceType)
|
||||
CB(WASERVICEFACTORY_GETSERVICENAME, GetServiceName)
|
||||
CB(WASERVICEFACTORY_GETGUID, GetGUID)
|
||||
CB(WASERVICEFACTORY_GETINTERFACE, GetInterface)
|
||||
CB(WASERVICEFACTORY_SUPPORTNONLOCKINGGETINTERFACE, SupportNonLockingInterface)
|
||||
CB(WASERVICEFACTORY_RELEASEINTERFACE, ReleaseInterface)
|
||||
CB(WASERVICEFACTORY_GETTESTSTRING, GetTestString)
|
||||
CB(WASERVICEFACTORY_SERVICENOTIFY, ServiceNotify)
|
||||
END_DISPATCH;
|
||||
#undef CBCLASS
|
31
Src/Plugins/Library/ml_wire/JSAPI2_Creator.h
Normal file
31
Src/Plugins/Library/ml_wire/JSAPI2_Creator.h
Normal file
@ -0,0 +1,31 @@
|
||||
#pragma once
|
||||
|
||||
#include "../Winamp/JSAPI2_svc_apicreator.h"
|
||||
|
||||
#include <api/service/waservicefactory.h>
|
||||
#include <api/service/services.h>
|
||||
|
||||
class JSAPI2Factory : public waServiceFactory
|
||||
{
|
||||
public:
|
||||
FOURCC GetServiceType();
|
||||
const char *GetServiceName();
|
||||
GUID GetGUID();
|
||||
void *GetInterface(int global_lock);
|
||||
int SupportNonLockingInterface();
|
||||
int ReleaseInterface(void *ifc);
|
||||
const char *GetTestString();
|
||||
int ServiceNotify(int msg, int param1, int param2);
|
||||
|
||||
protected:
|
||||
RECVS_DISPATCH;
|
||||
};
|
||||
|
||||
|
||||
class JSAPI2_Creator : public JSAPI2::svc_apicreator
|
||||
{
|
||||
IDispatch *CreateAPI(const wchar_t *name, const wchar_t *key, JSAPI::ifc_info *info);
|
||||
int PromptForAuthorization(HWND parent, const wchar_t *group, const wchar_t *action, const wchar_t *authorization_key, JSAPI2::api_security::AuthorizationData *data);
|
||||
protected:
|
||||
RECVS_DISPATCH;
|
||||
};
|
109
Src/Plugins/Library/ml_wire/JSAPI2_PodcastsAPI.cpp
Normal file
109
Src/Plugins/Library/ml_wire/JSAPI2_PodcastsAPI.cpp
Normal file
@ -0,0 +1,109 @@
|
||||
#include "JSAPI2_PodcastsAPI.h"
|
||||
#include "../Winamp/JSAPI.h"
|
||||
#include "api__ml_wire.h"
|
||||
#include "./rssCOM.h"
|
||||
|
||||
JSAPI2::PodcastsAPI::PodcastsAPI( const wchar_t *_key, JSAPI::ifc_info *_info )
|
||||
{
|
||||
info = _info;
|
||||
key = _key;
|
||||
}
|
||||
|
||||
enum
|
||||
{
|
||||
DISP_PODCASTS_SUBSCRIBE,
|
||||
};
|
||||
|
||||
#define DISP_TABLE \
|
||||
CHECK_ID(Subscribe, DISP_PODCASTS_SUBSCRIBE)\
|
||||
|
||||
#define CHECK_ID(str, id) if (wcscmp(rgszNames[i], L## #str) == 0) { rgdispid[i] = id; continue; }
|
||||
HRESULT JSAPI2::PodcastsAPI::GetIDsOfNames(REFIID riid, OLECHAR FAR* FAR* rgszNames, unsigned int cNames, LCID lcid, DISPID FAR* rgdispid)
|
||||
{
|
||||
bool unknowns = false;
|
||||
for (unsigned int i = 0;i != cNames;i++)
|
||||
{
|
||||
DISP_TABLE
|
||||
|
||||
rgdispid[i] = DISPID_UNKNOWN;
|
||||
unknowns = true;
|
||||
|
||||
}
|
||||
if (unknowns)
|
||||
return DISP_E_UNKNOWNNAME;
|
||||
else
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT JSAPI2::PodcastsAPI::GetTypeInfo(unsigned int itinfo, LCID lcid, ITypeInfo FAR* FAR* pptinfo)
|
||||
{
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
HRESULT JSAPI2::PodcastsAPI::GetTypeInfoCount(unsigned int FAR * pctinfo)
|
||||
{
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
HRESULT JSAPI2::PodcastsAPI::Subscribe(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr)
|
||||
{
|
||||
JSAPI_VERIFY_METHOD(wFlags);
|
||||
JSAPI_VERIFY_PARAMCOUNT(pdispparams, 1);
|
||||
|
||||
if (AGAVE_API_JSAPI2_SECURITY->GetActionAuthorization(L"podcasts", L"subscribe", key, info, JSAPI2::api_security::ACTION_PROMPT) == JSAPI2::api_security::ACTION_ALLOWED)
|
||||
{
|
||||
RssCOM::SubscribeUrl(JSAPI_PARAM(pdispparams, 1).bstrVal, pvarResult);
|
||||
}
|
||||
else
|
||||
{
|
||||
JSAPI_INIT_RESULT(pvarResult, VT_BOOL);
|
||||
JSAPI_SET_RESULT(pvarResult, boolVal, VARIANT_FALSE);
|
||||
}
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
#undef CHECK_ID
|
||||
#define CHECK_ID(str, id) case id: return str(wFlags, pdispparams, pvarResult, puArgErr);
|
||||
HRESULT JSAPI2::PodcastsAPI::Invoke(DISPID dispid, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, EXCEPINFO FAR * pexecinfo, unsigned int FAR *puArgErr)
|
||||
{
|
||||
switch (dispid)
|
||||
{
|
||||
DISP_TABLE
|
||||
}
|
||||
return DISP_E_MEMBERNOTFOUND;
|
||||
}
|
||||
|
||||
STDMETHODIMP JSAPI2::PodcastsAPI::QueryInterface(REFIID riid, PVOID *ppvObject)
|
||||
{
|
||||
if (!ppvObject)
|
||||
return E_POINTER;
|
||||
|
||||
else if (IsEqualIID(riid, IID_IDispatch))
|
||||
*ppvObject = (IDispatch *)this;
|
||||
else if (IsEqualIID(riid, IID_IUnknown))
|
||||
*ppvObject = this;
|
||||
else
|
||||
{
|
||||
*ppvObject = NULL;
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
AddRef();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
ULONG JSAPI2::PodcastsAPI::AddRef(void)
|
||||
{
|
||||
return _refCount.fetch_add( 1 );
|
||||
}
|
||||
|
||||
|
||||
ULONG JSAPI2::PodcastsAPI::Release( void )
|
||||
{
|
||||
LONG lRef = _refCount.fetch_sub( 1 );
|
||||
if ( lRef == 0 )
|
||||
delete this;
|
||||
|
||||
return lRef;
|
||||
}
|
30
Src/Plugins/Library/ml_wire/JSAPI2_PodcastsAPI.h
Normal file
30
Src/Plugins/Library/ml_wire/JSAPI2_PodcastsAPI.h
Normal file
@ -0,0 +1,30 @@
|
||||
#pragma once
|
||||
|
||||
#include <ocidl.h>
|
||||
#include <atomic>
|
||||
|
||||
#include "../Winamp/JSAPI_Info.h"
|
||||
|
||||
namespace JSAPI2
|
||||
{
|
||||
class PodcastsAPI : public IDispatch
|
||||
{
|
||||
public:
|
||||
PodcastsAPI(const wchar_t *_key, JSAPI::ifc_info *info);
|
||||
STDMETHOD(QueryInterface)(REFIID riid, PVOID *ppvObject);
|
||||
STDMETHOD_(ULONG, AddRef)(void);
|
||||
STDMETHOD_(ULONG, Release)(void);
|
||||
// *** IDispatch Methods ***
|
||||
STDMETHOD (GetIDsOfNames)(REFIID riid, OLECHAR FAR* FAR* rgszNames, unsigned int cNames, LCID lcid, DISPID FAR* rgdispid);
|
||||
STDMETHOD (GetTypeInfo)(unsigned int itinfo, LCID lcid, ITypeInfo FAR* FAR* pptinfo);
|
||||
STDMETHOD (GetTypeInfoCount)(unsigned int FAR * pctinfo);
|
||||
STDMETHOD (Invoke)(DISPID dispid, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, EXCEPINFO FAR * pexecinfo, unsigned int FAR *puArgErr);
|
||||
private:
|
||||
const wchar_t *key;
|
||||
volatile std::atomic<std::size_t> _refCount = 1;
|
||||
JSAPI::ifc_info *info;
|
||||
|
||||
STDMETHOD (Subscribe)(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr);
|
||||
|
||||
};
|
||||
}
|
100
Src/Plugins/Library/ml_wire/Loader.cpp
Normal file
100
Src/Plugins/Library/ml_wire/Loader.cpp
Normal file
@ -0,0 +1,100 @@
|
||||
#include "main.h"
|
||||
#include "api.h"
|
||||
#include "../winamp/wa_ipc.h"
|
||||
#include "DownloadStatus.h"
|
||||
using namespace Nullsoft::Utility;
|
||||
static WNDPROC wa_oldWndProc=0;
|
||||
|
||||
/* protocol must be all lower case */
|
||||
bool ProtocolMatch(const char *file, const char *protocol)
|
||||
{
|
||||
size_t protSize = strlen(protocol);
|
||||
for (size_t i=0;i!=protSize;i++)
|
||||
{
|
||||
if (!file[i]
|
||||
|| tolower(file[i]) != protocol[i])
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
LRESULT CALLBACK LoaderProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
#if 0 // not ready to take links yet... too buggy/weird at this point ...
|
||||
if (uMsg == WM_COPYDATA)
|
||||
{
|
||||
COPYDATASTRUCT *copyData = (COPYDATASTRUCT *)lParam;
|
||||
if (copyData->dwData == IPC_ENQUEUEFILE)
|
||||
{
|
||||
const char *file = (const char *)copyData->lpData;
|
||||
if (ProtocolMatch(file, "feed://"))
|
||||
{
|
||||
Channel newFeed;
|
||||
newFeed.url = AutoWide((const char *)copyData->lpData);
|
||||
if (DownloadFeedInformation(newFeed)==DOWNLOADRSS_SUCCESS)
|
||||
{
|
||||
AutoLock lock(channels);
|
||||
channels.push_back(newFeed);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
if (ProtocolMatch(file, "http://"))
|
||||
{
|
||||
// nothing for now, we want to do a head request tho
|
||||
JNL_HTTPGet head;
|
||||
head.connect(file, 0, "HEAD");
|
||||
int ret;
|
||||
do
|
||||
{
|
||||
ret = head.run();
|
||||
Sleep(50);
|
||||
} while (ret != -1 && ret != 1);
|
||||
|
||||
if (ret!=-1)
|
||||
{
|
||||
char *contentType = head.getheader("Content-Type");
|
||||
// if (contentType)
|
||||
//MessageBoxA(NULL, contentType, contentType, MB_OK);
|
||||
if (strstr(contentType, "application/rss+xml") == contentType)
|
||||
{
|
||||
MessageBox(NULL, L"woo!", L"woo!", MB_OK);
|
||||
return 0;
|
||||
}
|
||||
if (strstr(contentType, "application/xml") == contentType)
|
||||
{
|
||||
MessageBox(NULL, L"regular xml", L"application/xml", MB_OK);
|
||||
return 0;
|
||||
}
|
||||
if (strstr(contentType, "text/xml") == contentType)
|
||||
{
|
||||
MessageBox(NULL, L"regular xml", L"text/xml", MB_OK);
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (wa_oldWndProc)
|
||||
return CallWindowProc(wa_oldWndProc, hwnd, uMsg, wParam, lParam);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
void BuildLoader(HWND winampWindow)
|
||||
{
|
||||
if (IsWindowUnicode(winampWindow))
|
||||
wa_oldWndProc=(WNDPROC) SetWindowLongPtrW(winampWindow,GWLP_WNDPROC,(LONG_PTR)LoaderProc);
|
||||
else
|
||||
wa_oldWndProc=(WNDPROC) SetWindowLongPtrA(winampWindow,GWLP_WNDPROC,(LONG_PTR)LoaderProc);
|
||||
}
|
||||
|
||||
void DestroyLoader(HWND winampWindow)
|
||||
{
|
||||
//if (wa_oldWndProc)
|
||||
// SetWindowLong(winampWindow,GWL_WNDPROC,(LONG)wa_oldWndProc);
|
||||
//wa_oldWndProc=0;
|
||||
}
|
6
Src/Plugins/Library/ml_wire/Loader.h
Normal file
6
Src/Plugins/Library/ml_wire/Loader.h
Normal file
@ -0,0 +1,6 @@
|
||||
#ifndef NULLSOFT_LOADERH
|
||||
#define NULLSOFT_LOADERH
|
||||
|
||||
void BuildLoader(HWND winampWindow);
|
||||
|
||||
#endif
|
469
Src/Plugins/Library/ml_wire/Main.cpp
Normal file
469
Src/Plugins/Library/ml_wire/Main.cpp
Normal file
@ -0,0 +1,469 @@
|
||||
#include "main.h"
|
||||
#include "Cloud.h"
|
||||
#include "DownloadThread.h"
|
||||
#include "OPMLParse.h"
|
||||
#include "FeedsDialog.h"
|
||||
#include "DownloadsParse.h"
|
||||
#include "XMLWriter.h"
|
||||
#include "FeedParse.h"
|
||||
#include "DownloadsDialog.h"
|
||||
#include "Preferences.h"
|
||||
#include "..\..\General\gen_ml/ml.h"
|
||||
#include "Defaults.h"
|
||||
#include "Wire.h"
|
||||
#include "..\..\General\gen_ml/ml_ipc_0313.h"
|
||||
#include "RSSCOM.h"
|
||||
|
||||
#include "api__ml_wire.h"
|
||||
#include "Downloaded.h"
|
||||
#include "DownloadStatus.h"
|
||||
#include "Factory.h"
|
||||
#include "JSAPI2_Creator.h"
|
||||
#include "./navigation.h"
|
||||
|
||||
#include <strsafe.h>
|
||||
|
||||
#include "PCastFactory.h"
|
||||
|
||||
Cloud cloud;
|
||||
WireManager channelMgr;
|
||||
|
||||
int treeId = 0, allId = 0
|
||||
#if 0
|
||||
, discoverId = 0
|
||||
#endif
|
||||
;
|
||||
MLTREEITEMW downloadsTree;
|
||||
wchar_t downloadsStr[64] = {0}, *ml_cfg = 0,
|
||||
feedsXmlFileName[1024] = {0},
|
||||
feedsXmlFileNameBackup[1024] = {0},
|
||||
rssXmlFileName[1024] = {0},
|
||||
rssXmlFileNameBackup[1024] = {0};
|
||||
|
||||
ATOM VIEWPROP = 0;
|
||||
|
||||
api_downloadManager *WAC_API_DOWNLOADMANAGER = 0;
|
||||
|
||||
static int Init();
|
||||
static void Quit();
|
||||
static INT_PTR MessageProc(int message_type, INT_PTR param1, INT_PTR param2, INT_PTR param3);
|
||||
|
||||
DWORD threadStorage=TLS_OUT_OF_INDEXES;
|
||||
extern "C" winampMediaLibraryPlugin plugin =
|
||||
{
|
||||
MLHDR_VER,
|
||||
"nullsoft(ml_wire.dll)",
|
||||
Init,
|
||||
Quit,
|
||||
MessageProc,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
};
|
||||
|
||||
static prefsDlgRecW preferences;
|
||||
|
||||
static wchar_t preferencesName[64] = {0};
|
||||
void SaveChannels(ChannelList &channels)
|
||||
{
|
||||
// generate a backup of the feeds.xml to cope with it being wiped randomly for some
|
||||
// people or it not being able to be saved in time e.g. during a forced OS shutdown
|
||||
CopyFile(feedsXmlFileName, feedsXmlFileNameBackup, FALSE);
|
||||
SaveChannels(feedsXmlFileName, channels);
|
||||
}
|
||||
|
||||
void SaveAll(bool rss_only)
|
||||
{
|
||||
if (AGAVE_API_STATS)
|
||||
AGAVE_API_STATS->SetStat(api_stats::PODCAST_COUNT, (int)channels.size());
|
||||
|
||||
if(!rss_only)
|
||||
SaveChannels(channels);
|
||||
|
||||
// generate a backup of the rss.xml to cope with it being wiped randomly for some
|
||||
// people or it not being able to be saved in time e.g. during a forced OS shutdown
|
||||
CopyFile(rssXmlFileName, rssXmlFileNameBackup, FALSE);
|
||||
SaveSettings(rssXmlFileName, downloadedFiles);
|
||||
}
|
||||
|
||||
static PodcastsFactory podcastsFactory;
|
||||
|
||||
HANDLE hMainThread = NULL;
|
||||
|
||||
HCURSOR hDragNDropCursor = NULL;
|
||||
int winampVersion = 0;
|
||||
|
||||
JSAPI2::api_security *AGAVE_API_JSAPI2_SECURITY = 0;
|
||||
JSAPI2Factory jsapi2Creator;
|
||||
|
||||
obj_ombrowser *browserManager = NULL;
|
||||
api_application *applicationApi = NULL;
|
||||
api_stats *AGAVE_API_STATS = 0;
|
||||
api_threadpool *WASABI_API_THREADPOOL = 0;
|
||||
api_explorerfindfile *WASABI_API_EXPLORERFINDFILE = 0;
|
||||
|
||||
// wasabi based services for localisation support
|
||||
api_language *WASABI_API_LNG = 0;
|
||||
HINSTANCE WASABI_API_LNG_HINST = 0;
|
||||
HINSTANCE WASABI_API_ORIG_HINST = 0;
|
||||
|
||||
static PCastFactory pcastFactory;
|
||||
|
||||
static void CALLBACK InitTimer(HWND hwnd, UINT uMsg, UINT_PTR eventId, ULONG elapsed)
|
||||
{
|
||||
KillTimer(hwnd, eventId);
|
||||
|
||||
{
|
||||
Nullsoft::Utility::AutoLock lock (channels LOCKNAME("feeds.xml load!"));
|
||||
|
||||
FeedParse downloader(&channelMgr, true);
|
||||
downloader.DownloadFile(feedsXmlFileName);
|
||||
if (AGAVE_API_STATS)
|
||||
AGAVE_API_STATS->SetStat(api_stats::PODCAST_COUNT, (int)channels.size());
|
||||
}
|
||||
|
||||
if (updateOnLaunch)
|
||||
{
|
||||
cloud.RefreshAll();
|
||||
}
|
||||
|
||||
cloud.Init();
|
||||
cloud.Pulse();
|
||||
}
|
||||
|
||||
int Init()
|
||||
{
|
||||
hMainThread = GetCurrentThread();
|
||||
hDragNDropCursor = LoadCursor( GetModuleHandle( L"gen_ml.dll" ), MAKEINTRESOURCE( ML_IDC_DRAGDROP ) );
|
||||
threadStorage = TlsAlloc();
|
||||
|
||||
if ( 0 == VIEWPROP )
|
||||
{
|
||||
VIEWPROP = GlobalAddAtom( L"Nullsoft_PodcastView" );
|
||||
if ( VIEWPROP == 0 )
|
||||
return 1;
|
||||
}
|
||||
|
||||
winampVersion = SendMessage( plugin.hwndWinampParent, WM_WA_IPC, 0, IPC_GETVERSION );
|
||||
ml_cfg = (wchar_t*)SendMessage(plugin.hwndWinampParent, WM_WA_IPC, 0, IPC_GETMLINIFILEW);
|
||||
|
||||
plugin.service->service_register( &podcastsFactory );
|
||||
plugin.service->service_register( &jsapi2Creator );
|
||||
plugin.service->service_register( &pcastFactory );
|
||||
|
||||
// loader so that we can get the localisation service api for use
|
||||
waServiceFactory *sf = plugin.service->service_getServiceByGuid( languageApiGUID );
|
||||
if ( sf )
|
||||
WASABI_API_LNG = reinterpret_cast<api_language*>( sf->getInterface() );
|
||||
|
||||
sf = plugin.service->service_getServiceByGuid( JSAPI2::api_securityGUID );
|
||||
if ( sf )
|
||||
AGAVE_API_JSAPI2_SECURITY = reinterpret_cast<JSAPI2::api_security*>( sf->getInterface() );
|
||||
|
||||
sf = plugin.service->service_getServiceByGuid( applicationApiServiceGuid );
|
||||
if ( sf )
|
||||
WASABI_API_APP = reinterpret_cast<api_application*>( sf->getInterface() );
|
||||
|
||||
sf = plugin.service->service_getServiceByGuid( OBJ_OmBrowser );
|
||||
if ( sf )
|
||||
OMBROWSERMNGR = reinterpret_cast<obj_ombrowser*>( sf->getInterface() );
|
||||
|
||||
sf = plugin.service->service_getServiceByGuid( AnonymousStatsGUID );
|
||||
if ( sf )
|
||||
AGAVE_API_STATS = reinterpret_cast<api_stats*>( sf->getInterface() );
|
||||
|
||||
sf = plugin.service->service_getServiceByGuid( ThreadPoolGUID );
|
||||
if ( sf )
|
||||
WASABI_API_THREADPOOL = reinterpret_cast<api_threadpool*>( sf->getInterface() );
|
||||
|
||||
sf = plugin.service->service_getServiceByGuid( DownloadManagerGUID );
|
||||
if ( sf )
|
||||
WAC_API_DOWNLOADMANAGER = reinterpret_cast<api_downloadManager*>( sf->getInterface() );
|
||||
|
||||
sf = plugin.service->service_getServiceByGuid( ExplorerFindFileApiGUID );
|
||||
if ( sf )
|
||||
WASABI_API_EXPLORERFINDFILE = reinterpret_cast<api_explorerfindfile*>( sf->getInterface() );
|
||||
|
||||
// need to have this initialised before we try to do anything with localisation features
|
||||
WASABI_API_START_LANG( plugin.hDllInstance, MlWireLangGUID );
|
||||
|
||||
static wchar_t szDescription[ 256 ];
|
||||
StringCchPrintfW( szDescription, ARRAYSIZE( szDescription ), WASABI_API_LNGSTRINGW( IDS_PLUGIN_NAME ), PLUGIN_VERSION_MAJOR, PLUGIN_VERSION_MINOR );
|
||||
plugin.description = (char*)szDescription;
|
||||
|
||||
mediaLibrary.library = plugin.hwndLibraryParent;
|
||||
mediaLibrary.winamp = plugin.hwndWinampParent;
|
||||
mediaLibrary.instance = plugin.hDllInstance;
|
||||
|
||||
RssCOM *rss;
|
||||
if (SUCCEEDED(RssCOM::CreateInstance(&rss)))
|
||||
{
|
||||
DispatchInfo dispatchInfo;
|
||||
dispatchInfo.name = (LPWSTR)rss->GetName();
|
||||
dispatchInfo.dispatch = rss;
|
||||
|
||||
SENDWAIPC(plugin.hwndWinampParent, IPC_ADD_DISPATCH_OBJECT, (WPARAM)&dispatchInfo);
|
||||
rss->Release();
|
||||
}
|
||||
|
||||
BuildDefaultDownloadPath( plugin.hwndWinampParent );
|
||||
|
||||
preferences.hInst = WASABI_API_LNG_HINST;
|
||||
preferences.dlgID = IDD_PREFERENCES;
|
||||
preferences.proc = (void *)PreferencesDialogProc;
|
||||
preferences.name = WASABI_API_LNGSTRINGW_BUF( IDS_PODCAST_DIRECTORY, preferencesName, 64 );
|
||||
preferences.where = 6;
|
||||
|
||||
mediaLibrary.AddPreferences( preferences );
|
||||
|
||||
wchar_t g_path[MAX_PATH] = {0};
|
||||
mediaLibrary.BuildPath( L"Plugins\\ml\\feeds", g_path, MAX_PATH );
|
||||
CreateDirectoryW( g_path, NULL );
|
||||
|
||||
wchar_t oldxmlFileName[1024] = {0}, oldxmlFileNameBackup[ 1024 ] = { 0 };
|
||||
mediaLibrary.BuildPath( L"Plugins\\ml\\rss.xml", oldxmlFileName, 1024 );
|
||||
mediaLibrary.BuildPath( L"Plugins\\ml\\feeds\\rss.xml", rssXmlFileName, 1024 );
|
||||
mediaLibrary.BuildPath( L"Plugins\\ml\\rss.xml.backup", oldxmlFileNameBackup, 1024 );
|
||||
mediaLibrary.BuildPath( L"Plugins\\ml\\feeds\\rss.xml.backup", rssXmlFileNameBackup, 1024 );
|
||||
|
||||
if ( PathFileExists( oldxmlFileName ) && !PathFileExists(rssXmlFileName))
|
||||
{
|
||||
MoveFile( oldxmlFileName, rssXmlFileName );
|
||||
MoveFile( oldxmlFileNameBackup, rssXmlFileNameBackup );
|
||||
}
|
||||
|
||||
{
|
||||
DownloadsParse downloader;
|
||||
downloader.DownloadFile(rssXmlFileName);
|
||||
}
|
||||
|
||||
mediaLibrary.BuildPath( L"Plugins\\ml\\feeds.xml", oldxmlFileName, 1024 );
|
||||
mediaLibrary.BuildPath( L"Plugins\\ml\\feeds\\feeds.xml", feedsXmlFileName, 1024 );
|
||||
mediaLibrary.BuildPath( L"Plugins\\ml\\feeds.xml.backup", oldxmlFileNameBackup, 1024 );
|
||||
mediaLibrary.BuildPath( L"Plugins\\ml\\feeds\\feeds.xml.backup", feedsXmlFileNameBackup, 1024 );
|
||||
|
||||
if ( PathFileExists( oldxmlFileName ) && !PathFileExists( feedsXmlFileName ) )
|
||||
{
|
||||
MoveFile( oldxmlFileName, feedsXmlFileName );
|
||||
MoveFile( oldxmlFileNameBackup, feedsXmlFileNameBackup );
|
||||
}
|
||||
|
||||
Navigation_Initialize();
|
||||
SetTimer( plugin.hwndLibraryParent, 0x498, 10, InitTimer );
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Quit()
|
||||
{
|
||||
// If there are still files downloading, cancel download to remove incomplete downloaded files
|
||||
while ( downloadStatus.CurrentlyDownloading() )
|
||||
{
|
||||
Nullsoft::Utility::AutoLock lock( downloadStatus.statusLock );
|
||||
DownloadToken dltoken = downloadStatus.downloads.begin()->first;
|
||||
WAC_API_DOWNLOADMANAGER->CancelDownload( dltoken );
|
||||
}
|
||||
|
||||
cloud.Quit();
|
||||
CloseDatabase();
|
||||
|
||||
plugin.service->service_deregister( &podcastsFactory );
|
||||
plugin.service->service_deregister( &jsapi2Creator );
|
||||
|
||||
waServiceFactory *sf = plugin.service->service_getServiceByGuid( OBJ_OmBrowser );
|
||||
if ( sf != NULL )
|
||||
sf->releaseInterface( OMBROWSERMNGR );
|
||||
|
||||
sf = plugin.service->service_getServiceByGuid( applicationApiServiceGuid );
|
||||
if ( sf != NULL )
|
||||
sf->releaseInterface(WASABI_API_APP);
|
||||
|
||||
sf = plugin.service->service_getServiceByGuid(AnonymousStatsGUID);
|
||||
if ( sf != NULL )
|
||||
sf->releaseInterface(AGAVE_API_STATS);
|
||||
|
||||
sf = plugin.service->service_getServiceByGuid(ThreadPoolGUID);
|
||||
if ( sf != NULL )
|
||||
sf->releaseInterface(WASABI_API_THREADPOOL);
|
||||
|
||||
sf = plugin.service->service_getServiceByGuid(ExplorerFindFileApiGUID);
|
||||
if ( sf != NULL )
|
||||
sf->releaseInterface(WASABI_API_EXPLORERFINDFILE);
|
||||
|
||||
sf = plugin.service->service_getServiceByGuid(DownloadManagerGUID);
|
||||
if ( sf != NULL )
|
||||
sf->releaseInterface(WAC_API_DOWNLOADMANAGER);
|
||||
|
||||
if ( VIEWPROP != 0 )
|
||||
{
|
||||
GlobalDeleteAtom(VIEWPROP);
|
||||
VIEWPROP = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static INT_PTR Podcast_OnContextMenu( INT_PTR param1, HWND hHost, POINTS pts)
|
||||
{
|
||||
HNAVITEM hItem = (HNAVITEM)param1;
|
||||
HNAVITEM myItem = Navigation_FindService( SERVICE_PODCAST, NULL, NULL);
|
||||
|
||||
HNAVITEM podcastItem = MLNavItem_GetChild( plugin.hwndLibraryParent, myItem);
|
||||
HNAVITEM subscriptionItem = Navigation_FindService( SERVICE_SUBSCRIPTION, podcastItem, NULL);
|
||||
|
||||
if ( hItem != myItem && hItem != subscriptionItem )
|
||||
return FALSE;
|
||||
|
||||
POINT pt;
|
||||
POINTSTOPOINT( pt, pts );
|
||||
if ( pt.x == -1 || pt.y == -1 )
|
||||
{
|
||||
NAVITEMGETRECT itemRect;
|
||||
itemRect.fItem = FALSE;
|
||||
itemRect.hItem = hItem;
|
||||
if ( MLNavItem_GetRect( plugin.hwndLibraryParent, &itemRect ) )
|
||||
{
|
||||
MapWindowPoints( hHost, HWND_DESKTOP, (POINT*)&itemRect.rc, 2 );
|
||||
pt.x = itemRect.rc.left + 2;
|
||||
pt.y = itemRect.rc.top + 2;
|
||||
}
|
||||
}
|
||||
|
||||
HMENU hMenu = WASABI_API_LOADMENU( IDR_MENU1 );
|
||||
int subMenuId = ( hItem == subscriptionItem )? 4 : 3;
|
||||
|
||||
HMENU subMenu = ( NULL != hMenu ) ? GetSubMenu( hMenu, subMenuId ) : NULL;
|
||||
if ( subMenu != NULL )
|
||||
{
|
||||
INT r = Menu_TrackPopup( plugin.hwndLibraryParent, subMenu, TPM_LEFTALIGN | TPM_TOPALIGN | TPM_NONOTIFY | TPM_RETURNCMD | TPM_RIGHTBUTTON | TPM_LEFTBUTTON, pt.x, pt.y, hHost, NULL );
|
||||
|
||||
switch(r)
|
||||
{
|
||||
case ID_NAVIGATION_DIRECTORY:
|
||||
MLNavItem_Select( plugin.hwndLibraryParent, myItem );
|
||||
break;
|
||||
case ID_NAVIGATION_PREFERENCES:
|
||||
SENDWAIPC( plugin.hwndWinampParent, IPC_OPENPREFSTOPAGE, &preferences );
|
||||
break;
|
||||
case ID_NAVIGATION_HELP:
|
||||
SENDWAIPC( plugin.hwndWinampParent, IPC_OPEN_URL, L"https://help.winamp.com/hc/articles/8112346487060-Podcast-Directory" );
|
||||
break;
|
||||
case ID_NAVIGATION_REFRESHALL:
|
||||
cloud.RefreshAll();
|
||||
cloud.Pulse();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( hMenu != NULL )
|
||||
DestroyMenu( hMenu );
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
INT_PTR MessageProc( int msg, INT_PTR param1, INT_PTR param2, INT_PTR param3 )
|
||||
{
|
||||
INT_PTR result = 0;
|
||||
if ( Navigation_ProcessMessage( msg, param1, param2, param3, &result ) != FALSE )
|
||||
return result;
|
||||
|
||||
switch ( msg )
|
||||
{
|
||||
case ML_MSG_NOTOKTOQUIT:
|
||||
{
|
||||
if (downloadStatus.CurrentlyDownloading())
|
||||
{
|
||||
wchar_t titleStr[32] = {0};
|
||||
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 )
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
case ML_MSG_CONFIG:
|
||||
mediaLibrary.GoToPreferences(preferences._id);
|
||||
return TRUE;
|
||||
case ML_MSG_NAVIGATION_CONTEXTMENU:
|
||||
return Podcast_OnContextMenu( param1, (HWND)param2, MAKEPOINTS( param3 ) );
|
||||
case ML_MSG_VIEW_PLAY_ENQUEUE_CHANGE:
|
||||
enqueuedef = param1;
|
||||
groupBtn = param2;
|
||||
PostMessage( current_window, WM_APP + 104, param1, param2 );
|
||||
return 0;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
#define TREE_IMAGE_LOCAL_PODCASTS 108
|
||||
|
||||
void addToLibrary(const DownloadedFile& d)
|
||||
{
|
||||
itemRecordW item = { 0 };
|
||||
|
||||
item.year = -1;
|
||||
item.track = -1;
|
||||
item.tracks = -1;
|
||||
item.length = -1;
|
||||
item.rating = -1;
|
||||
item.lastplay = -1;
|
||||
item.lastupd = -1;
|
||||
item.filetime = -1;
|
||||
item.filesize = -1;
|
||||
item.bitrate = -1;
|
||||
item.type = -1;
|
||||
item.disc = -1;
|
||||
item.discs = -1;
|
||||
item.bpm = -1;
|
||||
item.playcount = -1;
|
||||
item.filename = _wcsdup( d.path );
|
||||
|
||||
setRecordExtendedItem(&item,L"ispodcast",L"1");
|
||||
setRecordExtendedItem(&item,L"podcastchannel",d.channel);
|
||||
|
||||
wchar_t buf[40] = {0};
|
||||
_i64tow(d.publishDate,buf,10);
|
||||
if(d.publishDate)
|
||||
setRecordExtendedItem(&item,L"podcastpubdate",buf);
|
||||
|
||||
LMDB_FILE_ADD_INFOW fai = {item.filename,-1,-1};
|
||||
SendMessage(plugin.hwndLibraryParent, WM_ML_IPC, (WPARAM)&fai, ML_IPC_DB_ADDORUPDATEFILEW);
|
||||
SendMessage(plugin.hwndLibraryParent, WM_ML_IPC, (WPARAM)&item, ML_IPC_DB_UPDATEITEMW);
|
||||
PostMessage(plugin.hwndLibraryParent, WM_ML_IPC, 0, ML_IPC_DB_SYNCDB);
|
||||
freeRecord(&item);
|
||||
|
||||
if(needToMakePodcastsView) {
|
||||
mlSmartViewInfo m = { sizeof( mlSmartViewInfo ),2,L"Podcasts", L"ispodcast = 1",461315,TREE_IMAGE_LOCAL_PODCASTS,0 };
|
||||
WASABI_API_LNGSTRINGW_BUF( IDS_PODCASTS, m.smartViewName, 128 );
|
||||
SendMessage( plugin.hwndLibraryParent, WM_ML_IPC, (WPARAM)&m, ML_IPC_SMARTVIEW_ADD );
|
||||
needToMakePodcastsView = false;
|
||||
}
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
const DownloadedFile *d;
|
||||
volatile UINT done;
|
||||
} apc_addtolib_waiter;
|
||||
|
||||
static VOID CALLBACK apc_addtolib(ULONG_PTR dwParam)
|
||||
{
|
||||
apc_addtolib_waiter *w = (apc_addtolib_waiter *)dwParam;
|
||||
addToLibrary(*w->d);
|
||||
w->done=1;
|
||||
}
|
||||
|
||||
void addToLibrary_thread(const DownloadedFile& d)
|
||||
{
|
||||
apc_addtolib_waiter w = { &d, 0 };
|
||||
if ( !QueueUserAPC( apc_addtolib, hMainThread, (ULONG_PTR)&w ) )
|
||||
return;
|
||||
|
||||
while ( !w.done )
|
||||
SleepEx( 5, true );
|
||||
}
|
||||
|
||||
|
||||
extern "C" __declspec(dllexport) winampMediaLibraryPlugin *winampGetMediaLibraryPlugin()
|
||||
{
|
||||
return &plugin;
|
||||
}
|
69
Src/Plugins/Library/ml_wire/Main.h
Normal file
69
Src/Plugins/Library/ml_wire/Main.h
Normal file
@ -0,0 +1,69 @@
|
||||
#ifndef NULLSOFT_MAINH
|
||||
#define NULLSOFT_MAINH
|
||||
|
||||
#include "Wire.h"
|
||||
#include "Downloaded.h"
|
||||
|
||||
#define PLUGIN_VERSION_MAJOR 1
|
||||
#define PLUGIN_VERSION_MINOR 80
|
||||
|
||||
#define SERVICE_PODCAST 720
|
||||
#define SERVICE_SUBSCRIPTION 721
|
||||
#define SERVICE_DOWNLOADS 722
|
||||
|
||||
#define BAD_CHANNEL ((size_t)-1)
|
||||
#define BAD_ITEM ((size_t)-1)
|
||||
|
||||
void SaveChannels(ChannelList &channels);
|
||||
void SaveAll(bool rss_only=false);
|
||||
void HookTerminate();
|
||||
|
||||
void DestroyLoader(HWND);
|
||||
void BuildLoader(HWND);
|
||||
extern int winampVersion;
|
||||
void addToLibrary(const DownloadedFile& d); // call in winamp main thread only
|
||||
void addToLibrary_thread(const DownloadedFile& d); // call from any thread
|
||||
|
||||
bool AddPodcastData(const DownloadedFile &data);
|
||||
bool IsPodcastDownloaded(const wchar_t *url);
|
||||
void CloseDatabase();
|
||||
|
||||
#include "resource.h"
|
||||
#include "../nu/DialogSkinner.h"
|
||||
#include "../nu/MediaLibraryInterface.h"
|
||||
#include "../nu/AutoChar.h"
|
||||
#include "../nu/AutoWide.h"
|
||||
#include "../nu/AutoLock.h"
|
||||
#include "..\..\General\gen_ml/menu.h"
|
||||
#include <windows.h>
|
||||
#include <shlwapi.h>
|
||||
|
||||
extern ATOM VIEWPROP;
|
||||
extern winampMediaLibraryPlugin plugin;
|
||||
|
||||
#include "../Components/wac_downloadManager/wac_downloadManager_api.h"
|
||||
|
||||
#define ML_ENQDEF_VAL() (!!GetPrivateProfileInt(L"gen_ml_config", L"enqueuedef", 0, ml_cfg))
|
||||
#define ML_GROUPBTN_VAL() (!!GetPrivateProfileInt(L"gen_ml_config", L"groupbtn", 1, ml_cfg))
|
||||
extern wchar_t* ml_cfg;
|
||||
wchar_t *urlencode(wchar_t *p);
|
||||
|
||||
extern HWND current_window;
|
||||
extern int groupBtn, enqueuedef, customAllowed;
|
||||
extern viewButtons view;
|
||||
|
||||
void SwapPlayEnqueueInMenu(HMENU listMenu);
|
||||
void SyncMenuWithAccelerators(HWND hwndDlg, HMENU menu);
|
||||
void Downloads_UpdateButtonText(HWND hwndDlg, int _enqueuedef);
|
||||
void listbuild(wchar_t **buf, int &buf_size, int &buf_pos, const wchar_t *tbuf);
|
||||
|
||||
enum
|
||||
{
|
||||
BPM_ECHO_WM_COMMAND=0x1, // send WM_COMMAND and return value
|
||||
BPM_WM_COMMAND = 0x2, // just send WM_COMMAND
|
||||
};
|
||||
|
||||
BOOL Downloads_ButtonPopupMenu(HWND hwndDlg, int buttonId, HMENU menu, int flags=0);
|
||||
void UpdateMenuItems(HWND hwndDlg, HMENU menu);
|
||||
|
||||
#endif
|
7
Src/Plugins/Library/ml_wire/MessageProcessor.cpp
Normal file
7
Src/Plugins/Library/ml_wire/MessageProcessor.cpp
Normal file
@ -0,0 +1,7 @@
|
||||
#include "main.h"
|
||||
#include "MessageProcessor.h"
|
||||
|
||||
#define CBCLASS MessageProcessor
|
||||
START_DISPATCH;
|
||||
CB(API_MESSAGEPROCESSOR_PROCESS_MESSAGE, ProcessMessage)
|
||||
END_DISPATCH;
|
35
Src/Plugins/Library/ml_wire/MessageProcessor.h
Normal file
35
Src/Plugins/Library/ml_wire/MessageProcessor.h
Normal file
@ -0,0 +1,35 @@
|
||||
#ifndef NULLSOFT_ML_WIRE_MESSAGEPROCESSOR_H
|
||||
#define NULLSOFT_ML_WIRE_MESSAGEPROCESSOR_H
|
||||
|
||||
#include <api/application/api_messageprocessor.h>
|
||||
#include "main.h"
|
||||
#ifndef WM_FORWARDMSG
|
||||
#define WM_FORWARDMSG 0x037F
|
||||
#endif
|
||||
|
||||
class MessageProcessor : public api_messageprocessor
|
||||
{
|
||||
public:
|
||||
bool ProcessMessage(MSG *msg)
|
||||
{
|
||||
|
||||
if (msg->message < WM_KEYFIRST || msg->message > WM_KEYLAST)
|
||||
return false;
|
||||
|
||||
HWND hWndCtl = ::GetFocus();
|
||||
|
||||
if (IsChild(browserHWND, hWndCtl))
|
||||
{
|
||||
// find a direct child of the dialog from the window that has focus
|
||||
while(::GetParent(hWndCtl) != browserHWND)
|
||||
hWndCtl = ::GetParent(hWndCtl);
|
||||
|
||||
if (activeBrowser->translateKey(*msg))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
protected:
|
||||
RECVS_DISPATCH;
|
||||
};
|
||||
#endif
|
33
Src/Plugins/Library/ml_wire/OPMLParse.cpp
Normal file
33
Src/Plugins/Library/ml_wire/OPMLParse.cpp
Normal file
@ -0,0 +1,33 @@
|
||||
#if 0
|
||||
#include "main.h"
|
||||
#include "OPMLParse.h"
|
||||
|
||||
#ifdef DEBUG
|
||||
#include <iostream>
|
||||
static void DisplayNodes(XMLNode &node)
|
||||
{
|
||||
XMLNode::NodeMap::iterator nodeItr;
|
||||
for (nodeItr = node.nodes.begin();nodeItr != node.nodes.end(); nodeItr++)
|
||||
{
|
||||
|
||||
for (XMLNode::NodeList::iterator itr = nodeItr->second.begin(); itr != nodeItr->second.end(); itr++)
|
||||
{
|
||||
std::wcerr << L"<" << nodeItr->first << L">" << std::endl;
|
||||
DisplayNodes(**itr);
|
||||
std::wcerr << L"</" << nodeItr->first << L">" << std::endl;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void OPMLParse::ReadNodes(const wchar_t *url)
|
||||
{
|
||||
// DisplayNodes(xmlNode);
|
||||
Alias<XMLNode> curNode;
|
||||
curNode = xmlNode.Get(L"opml");
|
||||
if (!curNode)
|
||||
return;
|
||||
|
||||
}
|
||||
#endif
|
28
Src/Plugins/Library/ml_wire/OPMLParse.h
Normal file
28
Src/Plugins/Library/ml_wire/OPMLParse.h
Normal file
@ -0,0 +1,28 @@
|
||||
#ifndef NULLSOFT_OPMLPARSEH
|
||||
#define NULLSOFT_OPMLPARSEH
|
||||
|
||||
#include "DownloadThread.h"
|
||||
#include "ChannelSync.h"
|
||||
class OPMLParse : public DownloadThread
|
||||
{
|
||||
public:
|
||||
OPMLParse(ChannelSync *_sync)
|
||||
: sync(_sync)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
~OPMLParse()
|
||||
{
|
||||
sync = 0;
|
||||
}
|
||||
|
||||
virtual void ReadNodes(const wchar_t *url);
|
||||
|
||||
private:
|
||||
|
||||
ChannelSync *sync;
|
||||
};
|
||||
|
||||
#endif
|
60
Src/Plugins/Library/ml_wire/PCastFactory.cpp
Normal file
60
Src/Plugins/Library/ml_wire/PCastFactory.cpp
Normal file
@ -0,0 +1,60 @@
|
||||
#include "api__ml_wire.h"
|
||||
#include ".\pcastfactory.h"
|
||||
#include "Wire.h"
|
||||
|
||||
static PCastURIHandler PCastUH;
|
||||
|
||||
static const char serviceName[] = "PCast";
|
||||
|
||||
FOURCC PCastFactory::GetServiceType()
|
||||
{
|
||||
return svc_urihandler::getServiceType();
|
||||
}
|
||||
|
||||
const char *PCastFactory::GetServiceName()
|
||||
{
|
||||
return serviceName;
|
||||
}
|
||||
|
||||
void *PCastFactory::GetInterface(int global_lock)
|
||||
{
|
||||
// if (global_lock)
|
||||
// plugin.service->service_lock(this, (void *)ifc);
|
||||
return &PCastUH;
|
||||
}
|
||||
|
||||
int PCastFactory::SupportNonLockingInterface()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
int PCastFactory::ReleaseInterface(void *ifc)
|
||||
{
|
||||
//plugin.service->service_unlock(ifc);
|
||||
return 1;
|
||||
}
|
||||
|
||||
const char *PCastFactory::GetTestString()
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int PCastFactory::ServiceNotify(int msg, int param1, int param2)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CBCLASS
|
||||
#undef CBCLASS
|
||||
#endif
|
||||
|
||||
#define CBCLASS PCastFactory
|
||||
START_DISPATCH;
|
||||
CB( WASERVICEFACTORY_GETSERVICETYPE, GetServiceType )
|
||||
CB( WASERVICEFACTORY_GETSERVICENAME, GetServiceName )
|
||||
CB( WASERVICEFACTORY_GETINTERFACE, GetInterface )
|
||||
CB( WASERVICEFACTORY_SUPPORTNONLOCKINGGETINTERFACE, SupportNonLockingInterface )
|
||||
CB( WASERVICEFACTORY_RELEASEINTERFACE, ReleaseInterface )
|
||||
CB( WASERVICEFACTORY_GETTESTSTRING, GetTestString )
|
||||
CB( WASERVICEFACTORY_SERVICENOTIFY, ServiceNotify )
|
||||
END_DISPATCH;
|
24
Src/Plugins/Library/ml_wire/PCastFactory.h
Normal file
24
Src/Plugins/Library/ml_wire/PCastFactory.h
Normal file
@ -0,0 +1,24 @@
|
||||
#pragma once
|
||||
|
||||
#include "api__ml_wire.h"
|
||||
|
||||
#include "api/service/waservicefactory.h"
|
||||
#include "api/service/services.h"
|
||||
|
||||
#include "PCastURIHandler.h"
|
||||
|
||||
class PCastFactory : public waServiceFactory
|
||||
{
|
||||
public:
|
||||
FOURCC GetServiceType();
|
||||
const char *GetServiceName();
|
||||
GUID GetGUID();
|
||||
void *GetInterface(int global_lock);
|
||||
int SupportNonLockingInterface();
|
||||
int ReleaseInterface(void *ifc);
|
||||
const char *GetTestString();
|
||||
int ServiceNotify(int msg, int param1, int param2);
|
||||
|
||||
protected:
|
||||
RECVS_DISPATCH;
|
||||
};
|
258
Src/Plugins/Library/ml_wire/PCastURIHandler.cpp
Normal file
258
Src/Plugins/Library/ml_wire/PCastURIHandler.cpp
Normal file
@ -0,0 +1,258 @@
|
||||
#include "main.h"
|
||||
#include "./pcasturihandler.h"
|
||||
#include "./Feeds.h"
|
||||
#include "./FeedUtil.h"
|
||||
#include "../nu/AutoLock.h"
|
||||
#include "./wire.h"
|
||||
#include "./errors.h"
|
||||
//#include "../Agave/URIHandler/svc_urihandler.h"
|
||||
//#include <api/service/waservicefactory.h>
|
||||
#include "api__ml_wire.h"
|
||||
#include "./cloud.h"
|
||||
#include "./SubscriptionView.h"
|
||||
#include "./resource.h"
|
||||
#include "navigation.h"
|
||||
#include "..\..\General\gen_ml/ml_ipc_0313.h"
|
||||
#include <strsafe.h>
|
||||
|
||||
using namespace Nullsoft::Utility;
|
||||
|
||||
extern ChannelList channels;
|
||||
extern Cloud cloud;
|
||||
|
||||
|
||||
static uint8_t quickhex(wchar_t c)
|
||||
{
|
||||
int hexvalue = c;
|
||||
if (hexvalue & 0x10)
|
||||
hexvalue &= ~0x30;
|
||||
else
|
||||
{
|
||||
hexvalue &= 0xF;
|
||||
hexvalue += 9;
|
||||
}
|
||||
return hexvalue;
|
||||
}
|
||||
|
||||
static uint8_t DecodeEscape(const wchar_t *&str)
|
||||
{
|
||||
uint8_t a = quickhex(*++str);
|
||||
uint8_t b = quickhex(*++str);
|
||||
str++;
|
||||
return a * 16 + b;
|
||||
}
|
||||
|
||||
static void DecodeEscapedUTF8(wchar_t *&output, const wchar_t *&input)
|
||||
{
|
||||
uint8_t utf8_data[1024] = {0}; // hopefully big enough!!
|
||||
int num_utf8_words=0;
|
||||
bool error=false;
|
||||
|
||||
while (input && *input == '%' && num_utf8_words < sizeof(utf8_data))
|
||||
{
|
||||
if (iswxdigit(input[1]) && iswxdigit(input[2]))
|
||||
{
|
||||
utf8_data[num_utf8_words++]=DecodeEscape(input);
|
||||
}
|
||||
else if (input[1] == '%')
|
||||
{
|
||||
input+=2;
|
||||
utf8_data[num_utf8_words++]='%';
|
||||
}
|
||||
else
|
||||
{
|
||||
error = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int len = MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)utf8_data, num_utf8_words, 0, 0);
|
||||
MultiByteToWideChar(CP_UTF8, 0, (LPCSTR)utf8_data, num_utf8_words, output, len);
|
||||
output += len;
|
||||
|
||||
if (error)
|
||||
{
|
||||
*output++ = *input++;
|
||||
}
|
||||
}
|
||||
|
||||
static void UrlDecode(const wchar_t *input, wchar_t *output, size_t len)
|
||||
{
|
||||
const wchar_t *stop = output+len-4; // give ourself a cushion large enough to hold a full UTF-16 sequence
|
||||
const wchar_t *itr = input;
|
||||
while (itr && *itr)
|
||||
{
|
||||
if (output >= stop)
|
||||
{
|
||||
*output=0;
|
||||
return;
|
||||
}
|
||||
|
||||
switch (*itr)
|
||||
{
|
||||
case '%':
|
||||
DecodeEscapedUTF8(output, itr);
|
||||
break;
|
||||
case '&':
|
||||
*output = 0;
|
||||
return;
|
||||
default:
|
||||
*output++ = *itr++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
*output = 0;
|
||||
}
|
||||
// first parameter has param name either null or = terminated, second is null terminated
|
||||
static bool ParamCompare(const wchar_t *url_param, const wchar_t *param_name)
|
||||
{
|
||||
while (url_param && *url_param && *param_name && *url_param!=L'=')
|
||||
{
|
||||
if (*url_param++ != *param_name++)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool get_request_parm(const wchar_t *params, const wchar_t *param_name, wchar_t *value, size_t value_len)
|
||||
{
|
||||
size_t param_name_len = wcslen(param_name);
|
||||
const wchar_t *t=params;
|
||||
while (t && *t && *t != L'?') // find start of parameters
|
||||
t++;
|
||||
|
||||
while (t && *t)
|
||||
{
|
||||
t++; // skip ? or &
|
||||
if (ParamCompare(t, param_name))
|
||||
{
|
||||
while (t && *t && *t != L'=' && *t != '&') // find start of value
|
||||
t++;
|
||||
switch(*t)
|
||||
{
|
||||
case L'=':
|
||||
UrlDecode(++t, value, value_len);
|
||||
return true;
|
||||
case 0:
|
||||
case L'&': // no value
|
||||
*value=0;
|
||||
return true;
|
||||
default: // shouldn't get here
|
||||
return false;
|
||||
}
|
||||
}
|
||||
while (t && *t && *t != L'&') // find next parameter
|
||||
t++;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int PCastURIHandler::ProcessFilename(const wchar_t *filename)
|
||||
{
|
||||
if (
|
||||
(wcsnicmp(filename, L"pcast://", 8)) == 0 ||
|
||||
(wcsnicmp(filename, L"feed://", 7) == 0) ||
|
||||
(wcsnicmp(filename, L"winamp://Podcast/Subscribe", 26) == 0) ||
|
||||
(wcsnicmp(filename, L"winamp://Podcast/Search", 23) == 0)
|
||||
)
|
||||
{
|
||||
wchar_t *tempFilename = NULL;
|
||||
wchar_t url[1024] = {0};
|
||||
if (wcsnicmp(filename, L"winamp://Podcast/Subscribe", 26) == 0)
|
||||
{
|
||||
// extract/decode and use the url= parameter
|
||||
if (get_request_parm(filename, L"url", url, 1024) && url[0])
|
||||
{
|
||||
tempFilename = wcsdup(url);
|
||||
}
|
||||
else
|
||||
{
|
||||
// did not find a url parameter
|
||||
return NOT_HANDLED;
|
||||
}
|
||||
}
|
||||
else if (wcsnicmp(filename, L"winamp://Podcast/Search", 23) == 0)
|
||||
{
|
||||
// TODO: maybe: if (get_request_parm(filename, L"url", url, 1024) && url[0])
|
||||
{
|
||||
HNAVITEM hItem = Navigation_FindService(SERVICE_PODCAST, NULL, NULL);
|
||||
MLNavItem_Select(plugin.hwndLibraryParent, hItem);
|
||||
return HANDLED;
|
||||
}
|
||||
/*
|
||||
else
|
||||
{
|
||||
// did not find a url parameter
|
||||
return NOT_HANDLED;
|
||||
}
|
||||
*/
|
||||
}
|
||||
else
|
||||
{
|
||||
// Use the full filename
|
||||
tempFilename = wcsdup(filename);
|
||||
}
|
||||
|
||||
// subscription confirmation
|
||||
WCHAR szText[1024] = {0}, szBuffer[1024] = {0};
|
||||
WASABI_API_LNGSTRINGW_BUF(IDS_PODCAST_SUBSCRIPTION_PROMP, szBuffer, ARRAYSIZE(szBuffer));
|
||||
StringCchPrintf(szText, ARRAYSIZE(szText), szBuffer, tempFilename);
|
||||
|
||||
WASABI_API_LNGSTRINGW_BUF(IDS_PODCAST_SUBSCRIPTION_HEADER, szBuffer, ARRAYSIZE(szBuffer));
|
||||
|
||||
if (IDYES == MessageBox(plugin.hwndLibraryParent, szText, szBuffer, MB_YESNO | MB_ICONQUESTION | MB_TOPMOST | MB_SETFOREGROUND) )
|
||||
{
|
||||
// add feed to channels, pulse the cloud, refresh the UI pane.
|
||||
Channel newFeed;
|
||||
newFeed.SetURL(tempFilename);
|
||||
if (DownloadFeedInformation(newFeed)==DOWNLOAD_SUCCESS)
|
||||
{
|
||||
channels.channelGuard.Lock();
|
||||
channels.AddChannel(newFeed);
|
||||
channels.channelGuard.Unlock();
|
||||
cloud.Pulse();
|
||||
HWND hView = SubscriptionView_FindWindow();
|
||||
if (NULL != hView)
|
||||
{
|
||||
SubscriptionView_RefreshChannels(hView, TRUE);
|
||||
}
|
||||
else
|
||||
{
|
||||
HNAVITEM myItem = Navigation_FindService(SERVICE_PODCAST, NULL, NULL);
|
||||
HNAVITEM podcastItem = MLNavItem_GetChild(plugin.hwndLibraryParent, myItem);
|
||||
HNAVITEM subscriptionItem = Navigation_FindService(SERVICE_SUBSCRIPTION, podcastItem, NULL);
|
||||
MLNavItem_Select(plugin.hwndLibraryParent, subscriptionItem);
|
||||
}
|
||||
}
|
||||
free(tempFilename);
|
||||
|
||||
return HANDLED;
|
||||
|
||||
}
|
||||
else
|
||||
free(tempFilename);
|
||||
}
|
||||
return NOT_HANDLED;
|
||||
}
|
||||
|
||||
int PCastURIHandler::IsMine(const wchar_t *filename)
|
||||
{
|
||||
int i = 0;
|
||||
if (
|
||||
(wcsnicmp(filename, L"pcast://", 8)) == 0 ||
|
||||
(wcsnicmp(filename, L"feed://", 7) == 0) ||
|
||||
(wcsnicmp(filename, L"winamp://Podcast/Subscribe", 26) == 0) ||
|
||||
(wcsnicmp(filename, L"winamp://Podcast/Search", 23) == 0)
|
||||
)
|
||||
return HANDLED;
|
||||
else
|
||||
return NOT_HANDLED;
|
||||
}
|
||||
|
||||
#define CBCLASS PCastURIHandler
|
||||
START_DISPATCH;
|
||||
CB(PROCESSFILENAME, ProcessFilename);
|
||||
CB(ISMINE, IsMine);
|
||||
END_DISPATCH;
|
||||
#undef CBCLASS
|
21
Src/Plugins/Library/ml_wire/PCastURIHandler.h
Normal file
21
Src/Plugins/Library/ml_wire/PCastURIHandler.h
Normal file
@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
|
||||
#include "../Agave/URIHandler/svc_urihandler.h"
|
||||
|
||||
// {DA5F8547-5D53-49d9-B9EC-C59318D11798}
|
||||
static const GUID pcast_uri_handler_guid =
|
||||
{ 0xda5f8547, 0x5d53, 0x49d9, { 0xb9, 0xec, 0xc5, 0x93, 0x18, 0xd1, 0x17, 0x98 } };
|
||||
|
||||
|
||||
class PCastURIHandler :
|
||||
public svc_urihandler
|
||||
{
|
||||
public:
|
||||
static const char *getServiceName() { return "PCast URI Handler"; }
|
||||
static GUID getServiceGuid() { return pcast_uri_handler_guid; }
|
||||
int ProcessFilename(const wchar_t *filename);
|
||||
int IsMine(const wchar_t *filename); // just like ProcessFilename but don't actually process
|
||||
|
||||
protected:
|
||||
RECVS_DISPATCH;
|
||||
};
|
43
Src/Plugins/Library/ml_wire/ParseUtil.cpp
Normal file
43
Src/Plugins/Library/ml_wire/ParseUtil.cpp
Normal file
@ -0,0 +1,43 @@
|
||||
#include "ParseUtil.h"
|
||||
|
||||
bool PropertyIsTrue( const XMLNode *item, const wchar_t *property )
|
||||
{
|
||||
if ( !item )
|
||||
return false;
|
||||
|
||||
const wchar_t *value = item->GetProperty( property );
|
||||
if ( !value )
|
||||
return false;
|
||||
|
||||
return !_wcsicmp( value, L"true" );
|
||||
}
|
||||
|
||||
bool PropertyIsFalse( const XMLNode *item, const wchar_t *property )
|
||||
{
|
||||
if ( !item )
|
||||
return false;
|
||||
|
||||
const wchar_t *value = item->GetProperty( property );
|
||||
if ( !value )
|
||||
return false;
|
||||
|
||||
return !_wcsicmp( value, L"false" );
|
||||
}
|
||||
|
||||
const wchar_t *GetContent( const XMLNode *item, const wchar_t *tag )
|
||||
{
|
||||
const XMLNode *curNode = item->Get( tag );
|
||||
if ( curNode )
|
||||
return curNode->GetContent();
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
const wchar_t *GetProperty( const XMLNode *item, const wchar_t *tag, const wchar_t *property )
|
||||
{
|
||||
const XMLNode *curNode = item->Get( tag );
|
||||
if ( curNode )
|
||||
return curNode->GetProperty( property );
|
||||
else
|
||||
return 0;
|
||||
}
|
8
Src/Plugins/Library/ml_wire/ParseUtil.h
Normal file
8
Src/Plugins/Library/ml_wire/ParseUtil.h
Normal file
@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
#include "../xml/XMLNode.h"
|
||||
#include <bfc/platform/types.h>
|
||||
bool PropertyIsTrue(const XMLNode *item, const wchar_t *property);
|
||||
// not necessarily the opposite of PropertyIsTrue (returns false when field is empty
|
||||
bool PropertyIsFalse(const XMLNode *item, const wchar_t *property);
|
||||
const wchar_t *GetContent(const XMLNode *item, const wchar_t *tag);
|
||||
const wchar_t *GetProperty(const XMLNode *item, const wchar_t *tag, const wchar_t *property);
|
160
Src/Plugins/Library/ml_wire/Preferences.cpp
Normal file
160
Src/Plugins/Library/ml_wire/Preferences.cpp
Normal file
@ -0,0 +1,160 @@
|
||||
#include "main.h"
|
||||
#include "api__ml_wire.h"
|
||||
#include "../winamp/wa_ipc.h"
|
||||
#include "Defaults.h"
|
||||
#include "UpdateTime.h"
|
||||
#include "UpdateAutoDownload.h"
|
||||
#include "./cloud.h"
|
||||
#include <shlobj.h>
|
||||
|
||||
extern Cloud cloud;
|
||||
|
||||
void Preferences_Init(HWND hwndDlg)
|
||||
{
|
||||
WCHAR szBuffer[256] = {0};
|
||||
for (int i = 0;i < Update::TIME_NUMENTRIES;i++)
|
||||
{
|
||||
const wchar_t *str = Update::GetTitle(i, szBuffer, ARRAYSIZE(szBuffer));
|
||||
SendMessage(GetDlgItem(hwndDlg, IDC_UPDATELIST), CB_ADDSTRING, 0, (LPARAM) str);
|
||||
}
|
||||
int selection = Update::GetSelection(updateTime, autoUpdate);
|
||||
SendMessage(GetDlgItem(hwndDlg, IDC_UPDATELIST), CB_SETCURSEL, selection, 0);
|
||||
|
||||
WCHAR adBuffer[256] = {0};
|
||||
for (int i = 0;i < UpdateAutoDownload::AUTODOWNLOAD_NUMENTRIES;i++)
|
||||
{
|
||||
const wchar_t *str = UpdateAutoDownload::GetTitle(i, adBuffer, ARRAYSIZE(adBuffer));
|
||||
SendMessage(GetDlgItem(hwndDlg, IDC_AUTODOWNLOADLIST), CB_ADDSTRING, 0, (LPARAM) str);
|
||||
}
|
||||
selection = UpdateAutoDownload::GetSelection(autoDownloadEpisodes, autoDownload);
|
||||
SendMessage(GetDlgItem(hwndDlg, IDC_AUTODOWNLOADLIST), CB_SETCURSEL, selection, 0);
|
||||
|
||||
SetDlgItemText(hwndDlg, IDC_DOWNLOADLOCATION, defaultDownloadPath);
|
||||
SetDlgItemText(hwndDlg, IDC_DIRECTORYURL, serviceUrl);
|
||||
CheckDlgButton(hwndDlg, IDC_UPDATEONLAUNCH, updateOnLaunch?BST_CHECKED:BST_UNCHECKED);
|
||||
}
|
||||
|
||||
BOOL CALLBACK browseEnumProc(HWND hwnd, LPARAM lParam)
|
||||
{
|
||||
wchar_t cl[32] = {0};
|
||||
GetClassNameW(hwnd, cl, ARRAYSIZE(cl));
|
||||
if (!lstrcmpiW(cl, WC_TREEVIEW))
|
||||
{
|
||||
PostMessage(hwnd, TVM_ENSUREVISIBLE, 0, (LPARAM)TreeView_GetSelection(hwnd));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
int CALLBACK WINAPI BrowseCallbackProc(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData)
|
||||
{
|
||||
if(uMsg == BFFM_INITIALIZED)
|
||||
{
|
||||
SendMessageW(hwnd, BFFM_SETSELECTIONW, 1, (LPARAM)defaultDownloadPath);
|
||||
|
||||
// this is not nice but it fixes the selection not working correctly on all OSes
|
||||
EnumChildWindows(hwnd, browseEnumProc, 0);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Preferences_Browse(HWND hwndDlg)
|
||||
{
|
||||
wchar_t folder[MAX_PATH] = {0};
|
||||
BROWSEINFO browse = {0};
|
||||
lstrcpyn(folder, defaultDownloadPath, MAX_PATH);
|
||||
browse.hwndOwner = hwndDlg;
|
||||
browse.lpszTitle = WASABI_API_LNGSTRINGW(IDS_CHOOSE_FOLDER);
|
||||
browse.ulFlags = BIF_RETURNONLYFSDIRS | BIF_NEWDIALOGSTYLE;
|
||||
browse.lpfn = BrowseCallbackProc;
|
||||
LPITEMIDLIST itemList = SHBrowseForFolder(&browse);
|
||||
if (itemList)
|
||||
{
|
||||
SHGetPathFromIDList(itemList, folder);
|
||||
lstrcpyn(defaultDownloadPath, folder, MAX_PATH);
|
||||
SetWindowText(GetDlgItem(hwndDlg, IDC_DOWNLOADLOCATION), folder);
|
||||
LPMALLOC malloc;
|
||||
SHGetMalloc(&malloc);
|
||||
malloc->Free(itemList);
|
||||
}
|
||||
}
|
||||
|
||||
void Preferences_UpdateOnLaunch( HWND hwndDlg )
|
||||
{
|
||||
updateOnLaunch = ( IsDlgButtonChecked( hwndDlg, IDC_UPDATEONLAUNCH ) == BST_CHECKED );
|
||||
}
|
||||
|
||||
void Preferences_UpdateList(HWND hwndDlg)
|
||||
{
|
||||
LRESULT timeSelection;
|
||||
timeSelection = SendMessage(GetDlgItem(hwndDlg, IDC_UPDATELIST), CB_GETCURSEL, 0, 0);
|
||||
if (timeSelection != CB_ERR)
|
||||
{
|
||||
autoUpdate = Update::GetAutoUpdate(timeSelection);
|
||||
updateTime = Update::GetTime(timeSelection);
|
||||
if ( autoUpdate )
|
||||
cloud.Pulse(); // update the waitable timer
|
||||
}
|
||||
}
|
||||
|
||||
void Preferences_AutoDownloadList(HWND hwndDlg)
|
||||
{
|
||||
LRESULT episodeSelection;
|
||||
episodeSelection = SendMessage(GetDlgItem(hwndDlg, IDC_AUTODOWNLOADLIST), CB_GETCURSEL, 0, 0);
|
||||
if (episodeSelection != CB_ERR)
|
||||
{
|
||||
autoDownload = UpdateAutoDownload::GetAutoDownload(episodeSelection);
|
||||
autoDownloadEpisodes = UpdateAutoDownload::GetAutoDownloadEpisodes(episodeSelection);
|
||||
}
|
||||
}
|
||||
|
||||
BOOL CALLBACK PreferencesDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
switch (uMsg)
|
||||
{
|
||||
case WM_INITDIALOG:
|
||||
Preferences_Init(hwndDlg);
|
||||
break;
|
||||
case WM_COMMAND:
|
||||
switch (LOWORD(wParam))
|
||||
{
|
||||
case IDC_BROWSE:
|
||||
Preferences_Browse(hwndDlg);
|
||||
break;
|
||||
case IDC_UPDATELIST:
|
||||
Preferences_UpdateList(hwndDlg);
|
||||
break;
|
||||
case IDC_AUTODOWNLOADLIST:
|
||||
Preferences_AutoDownloadList(hwndDlg);
|
||||
break;
|
||||
case IDC_UPDATEONLAUNCH:
|
||||
Preferences_UpdateOnLaunch(hwndDlg);
|
||||
break;
|
||||
case IDC_DOWNLOADLOCATION:
|
||||
if (HIWORD(wParam) == EN_CHANGE)
|
||||
{
|
||||
GetDlgItemText(hwndDlg, IDC_DOWNLOADLOCATION, defaultDownloadPath, MAX_PATH);
|
||||
if (!PathFileExists(defaultDownloadPath))
|
||||
{
|
||||
BuildDefaultDownloadPath(plugin.hwndWinampParent);
|
||||
SetDlgItemText(hwndDlg, IDC_DOWNLOADLOCATION, defaultDownloadPath);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case IDC_DIRECTORYURL:
|
||||
if (HIWORD(wParam) == EN_CHANGE)
|
||||
{
|
||||
GetDlgItemText(hwndDlg, IDC_DIRECTORYURL, serviceUrl, ARRAYSIZE(serviceUrl));
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case WM_DESTROY:
|
||||
// ensure we save the changed settings
|
||||
SaveAll(true);
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
6
Src/Plugins/Library/ml_wire/Preferences.h
Normal file
6
Src/Plugins/Library/ml_wire/Preferences.h
Normal file
@ -0,0 +1,6 @@
|
||||
#ifndef NULLSOFT_PREFERENCESH
|
||||
#define NULLSOFT_PREFERENCESH
|
||||
|
||||
BOOL CALLBACK PreferencesDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
||||
|
||||
#endif
|
216
Src/Plugins/Library/ml_wire/RFCDate.cpp
Normal file
216
Src/Plugins/Library/ml_wire/RFCDate.cpp
Normal file
@ -0,0 +1,216 @@
|
||||
#include "main.h"
|
||||
#include "RFCDate.h"
|
||||
#include <strsafe.h>
|
||||
|
||||
void MakeDateString(__time64_t convertTime, wchar_t *date_str, size_t len)
|
||||
{
|
||||
SYSTEMTIME sysTime = {0};
|
||||
tm *newtime = _localtime64(&convertTime);
|
||||
|
||||
sysTime.wYear = newtime->tm_year + 1900;
|
||||
sysTime.wMonth = newtime->tm_mon + 1;
|
||||
sysTime.wDayOfWeek = newtime->tm_wday;
|
||||
sysTime.wDay = newtime->tm_mday;
|
||||
sysTime.wHour = newtime->tm_hour;
|
||||
sysTime.wMinute = newtime->tm_min;
|
||||
sysTime.wSecond = newtime->tm_sec;
|
||||
|
||||
GetDateFormat(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &sysTime, NULL, date_str, (int)len);
|
||||
|
||||
}
|
||||
|
||||
void MakeRFCDateString(__time64_t convertTime, wchar_t *data_str, size_t len)
|
||||
{
|
||||
SYSTEMTIME sysTime = {0};
|
||||
tm *newtime = _gmtime64(&convertTime);
|
||||
|
||||
sysTime.wYear = newtime->tm_year + 1900;
|
||||
sysTime.wMonth = newtime->tm_mon + 1;
|
||||
sysTime.wDayOfWeek = newtime->tm_wday;
|
||||
sysTime.wDay = newtime->tm_mday;
|
||||
sysTime.wHour = newtime->tm_hour;
|
||||
sysTime.wMinute = newtime->tm_min;
|
||||
sysTime.wSecond = newtime->tm_sec;
|
||||
|
||||
wchar_t rfcDate[64] = {0}, rfcTime[64] = {0};
|
||||
GetDateFormat(MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT), 0, &sysTime, L"ddd',' d MMM yyyy ", rfcDate, 64);
|
||||
GetTimeFormat(MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT), 0, &sysTime, L"HH':'mm':'ss 'GMT'", rfcTime, 64);
|
||||
StringCchPrintf(data_str,len,L"%s%s",rfcDate,rfcTime);
|
||||
}
|
||||
|
||||
static int getMonthOfYear(const wchar_t *str);
|
||||
static int validateTime(struct tm *tmloc, int gmoffset);
|
||||
static const wchar_t *getNextField(const wchar_t *pos);
|
||||
static int getGMOffset(const wchar_t *str);
|
||||
|
||||
enum
|
||||
{
|
||||
DAY_OF_MONTH = 0,
|
||||
MONTH_OF_YEAR,
|
||||
YEAR,
|
||||
TIME,
|
||||
TIMEZONE,
|
||||
DATE_END
|
||||
};
|
||||
|
||||
__time64_t MakeRFCDate(const wchar_t *date)
|
||||
{
|
||||
__time64_t result = 0;
|
||||
const wchar_t *pos = date;
|
||||
tm tmloc = {0};
|
||||
const wchar_t *strmin;
|
||||
const wchar_t *strsec;
|
||||
int gmoffset = 1;
|
||||
int state = DAY_OF_MONTH;
|
||||
tzset();
|
||||
/* skip weekday if present */
|
||||
while (pos && *pos && !iswdigit(*pos)) pos++;
|
||||
|
||||
do
|
||||
{
|
||||
switch (state)
|
||||
{
|
||||
case DAY_OF_MONTH:
|
||||
tmloc.tm_mday = _wtoi(pos);
|
||||
break;
|
||||
case MONTH_OF_YEAR:
|
||||
tmloc.tm_mon = getMonthOfYear(pos);
|
||||
break;
|
||||
case YEAR:
|
||||
{
|
||||
/* TODO: we're only accepting 4-digit dates...*/
|
||||
const wchar_t *test = pos; int numDigits = 0;
|
||||
while (iswdigit(*test) && *test) { test++; numDigits++; }
|
||||
if (numDigits == 2) // let's hope we never have 2 digit years!
|
||||
tmloc.tm_year = _wtoi(pos) + 100; // assume 2 digit years are 20xx
|
||||
else
|
||||
tmloc.tm_year = _wtoi(pos) - 1900;
|
||||
}
|
||||
break;
|
||||
case TIME:
|
||||
strmin = wcschr(pos, L':');
|
||||
strsec = strmin ? wcschr(strmin + 1, L':') : 0;
|
||||
|
||||
tmloc.tm_hour = _wtoi(pos);
|
||||
if (!strmin) return _time64(0);
|
||||
tmloc.tm_min = _wtoi(strmin + 1);
|
||||
if (!strsec) return _time64(0);
|
||||
tmloc.tm_sec = _wtoi(strsec + 1);
|
||||
break;
|
||||
case TIMEZONE:
|
||||
gmoffset = getGMOffset(pos);
|
||||
break;
|
||||
case DATE_END:
|
||||
pos = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
state++;
|
||||
}
|
||||
while ((pos = getNextField(pos)));
|
||||
|
||||
tmloc.tm_isdst = 0; //_daylight;
|
||||
|
||||
if (validateTime(&tmloc, gmoffset))
|
||||
{
|
||||
result = _mktime64(&tmloc) - _timezone;
|
||||
//if (_daylight)
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
const wchar_t *getNextField(const wchar_t *pos)
|
||||
{
|
||||
if (!pos)
|
||||
return 0;
|
||||
while (pos && *pos && !iswspace(*pos)) pos++;
|
||||
while (pos && *pos && iswspace(*pos)) pos++;
|
||||
|
||||
return ((pos && *pos) ? pos : 0);
|
||||
}
|
||||
|
||||
int validateTime(struct tm *tmloc, int gmoffset)
|
||||
{
|
||||
int result = 1;
|
||||
|
||||
if (tmloc->tm_mday < 1 || tmloc->tm_mday > 31 ||
|
||||
tmloc->tm_mon < 0 || tmloc->tm_mon > 11 ||
|
||||
tmloc->tm_year < 0 || tmloc->tm_year > 2000 ||
|
||||
tmloc->tm_hour < 0 || tmloc->tm_hour > 23 ||
|
||||
tmloc->tm_min < 0 || tmloc->tm_min > 59 ||
|
||||
tmloc->tm_sec < 0 || tmloc->tm_sec > 59 ||
|
||||
gmoffset == 1)
|
||||
result = 0;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int getMonthOfYear(const wchar_t *str)
|
||||
{
|
||||
int mon = -1;
|
||||
/* This is not the most efficient way to determine
|
||||
the month (we could use integer comparisons, for instance)
|
||||
but I don't think this will be a performance bottleneck :)
|
||||
*/
|
||||
|
||||
if (!wcsnicmp(str, L"Jan", 3))
|
||||
mon = 0;
|
||||
else if (!wcsnicmp(str, L"Feb", 3))
|
||||
mon = 1;
|
||||
else if (!wcsnicmp(str, L"Mar", 3))
|
||||
mon = 2;
|
||||
else if (!wcsnicmp(str, L"Apr", 3))
|
||||
mon = 3;
|
||||
else if (!wcsnicmp(str, L"May", 3))
|
||||
mon = 4;
|
||||
else if (!wcsnicmp(str, L"Jun", 3))
|
||||
mon = 5;
|
||||
else if (!wcsnicmp(str, L"Jul", 3))
|
||||
mon = 6;
|
||||
else if (!wcsnicmp(str, L"Aug", 3))
|
||||
mon = 7;
|
||||
else if (!wcsnicmp(str, L"Sep", 3))
|
||||
mon = 8;
|
||||
else if (!wcsnicmp(str, L"Oct", 3))
|
||||
mon = 9;
|
||||
else if (!wcsnicmp(str, L"Nov", 3))
|
||||
mon = 10;
|
||||
else if (!wcsnicmp(str, L"Dec", 3))
|
||||
mon = 11;
|
||||
|
||||
return mon;
|
||||
}
|
||||
|
||||
int getGMOffset(const wchar_t *str)
|
||||
{
|
||||
int secs = 0;
|
||||
/* See note in getMonthOfYear() */
|
||||
|
||||
if (!wcsnicmp(str, L"UT", 2) || !wcsnicmp(str, L"GMT", 3))
|
||||
secs = 0;
|
||||
else if (!wcsnicmp(str, L"EDT", 3))
|
||||
secs = -4 * 3600;
|
||||
else if (!wcsnicmp(str, L"PST", 3))
|
||||
secs = -8 * 3600;
|
||||
else if (!wcsnicmp(str, L"EST", 3) || !wcsnicmp(str, L"CDT", 3))
|
||||
secs = -5 * 3600;
|
||||
else if (!wcsnicmp(str, L"MST", 3) || !wcsnicmp(str, L"PDT", 3))
|
||||
secs = -7 * 3600;
|
||||
else if (!wcsnicmp(str, L"CST", 3) || !wcsnicmp(str, L"MDT", 3))
|
||||
secs = -6 * 3600;
|
||||
else if ( (str[0] == L'+' || str[0] == L'-') &&
|
||||
iswdigit(str[1]) && iswdigit(str[2]) &&
|
||||
iswdigit(str[3]) && iswdigit(str[4]))
|
||||
{
|
||||
secs = 3600 * (10 * (str[1] - 48) + str[2] - 48);
|
||||
secs += 60 * (10 * (str[3] - 48) + str[4] - 48);
|
||||
|
||||
if (str[0] == L'-')
|
||||
secs = -secs;
|
||||
}
|
||||
else
|
||||
secs = 1;
|
||||
|
||||
return secs;
|
||||
}
|
7
Src/Plugins/Library/ml_wire/RFCDate.h
Normal file
7
Src/Plugins/Library/ml_wire/RFCDate.h
Normal file
@ -0,0 +1,7 @@
|
||||
#ifndef NULLSOFT_RFCDATEH
|
||||
#define NULLSOFT_RFCDATEH
|
||||
|
||||
void MakeRFCDateString(__time64_t convertTime, wchar_t *data_str, size_t len);
|
||||
__time64_t MakeRFCDate(const wchar_t *date);
|
||||
void MakeDateString(__time64_t convertTime, wchar_t *date_str, size_t len);
|
||||
#endif
|
232
Src/Plugins/Library/ml_wire/RSSCOM.cpp
Normal file
232
Src/Plugins/Library/ml_wire/RSSCOM.cpp
Normal file
@ -0,0 +1,232 @@
|
||||
#include "main.h"
|
||||
#include "./rssCOM.h"
|
||||
#include "./util.h"
|
||||
#include "api__ml_wire.h"
|
||||
#include "./cloud.h"
|
||||
#include "./feedUtil.h"
|
||||
#include "./defaults.h"
|
||||
#include "./errors.h"
|
||||
|
||||
#include "../winamp/jsapi.h"
|
||||
|
||||
#include "./rssCOM.h"
|
||||
|
||||
#include <strsafe.h>
|
||||
|
||||
extern Cloud cloud;
|
||||
|
||||
|
||||
#define DISPTABLE_CLASS RssCOM
|
||||
|
||||
DISPTABLE_BEGIN()
|
||||
DISPENTRY_ADD(DISPATCH_SUBSCRIBE, L"subscribe", OnSubscribe)
|
||||
DISPTABLE_END
|
||||
|
||||
#undef DISPTABLE_CLASS
|
||||
|
||||
|
||||
|
||||
RssCOM::RssCOM()
|
||||
{}
|
||||
|
||||
RssCOM::~RssCOM()
|
||||
{}
|
||||
|
||||
HRESULT RssCOM::CreateInstance(RssCOM **instance)
|
||||
{
|
||||
if (NULL == instance) return E_POINTER;
|
||||
|
||||
*instance = new RssCOM();
|
||||
if (NULL == *instance) return E_OUTOFMEMORY;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
STDMETHODIMP_(ULONG) RssCOM::AddRef(void)
|
||||
{
|
||||
return _ref.fetch_add( 1 );
|
||||
}
|
||||
|
||||
STDMETHODIMP_(ULONG) RssCOM::Release(void)
|
||||
{
|
||||
if (0 == _ref.load() )
|
||||
return _ref.load();
|
||||
|
||||
LONG r = _ref.fetch_sub( 1 );
|
||||
if (0 == r)
|
||||
delete(this);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
STDMETHODIMP RssCOM::QueryInterface(REFIID riid, PVOID *ppvObject)
|
||||
{
|
||||
if (NULL == ppvObject) return E_POINTER;
|
||||
|
||||
if (IsEqualIID(riid, IID_IDispatch))
|
||||
*ppvObject = static_cast<IDispatch*>(this);
|
||||
else if (IsEqualIID(riid, IID_IUnknown))
|
||||
*ppvObject = static_cast<IUnknown*>(this);
|
||||
else
|
||||
{
|
||||
*ppvObject = NULL;
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
AddRef();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
HRESULT RssCOM::OnSubscribe(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr)
|
||||
{
|
||||
JSAPI_VERIFY_METHOD(wFlags);
|
||||
JSAPI_VERIFY_PARAMCOUNT(pdispparams, 1);
|
||||
|
||||
BSTR url;
|
||||
|
||||
JSAPI_GETSTRING(url, pdispparams, 1, puArgErr);
|
||||
|
||||
SubscribeUrl(url, pvarResult);
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
struct SubscribeThreadData
|
||||
{
|
||||
LPWSTR url;
|
||||
};
|
||||
static LPCWSTR FormatLangString(LPWSTR pszBuffer, INT cchBufferMax, LPWSTR pszFormat, INT cchFormatMax, INT formatId, ...)
|
||||
{
|
||||
HRESULT hr;
|
||||
va_list argList;
|
||||
va_start(argList, formatId);
|
||||
|
||||
if(NULL != WASABI_API_LNGSTRINGW_BUF(formatId, pszFormat, cchFormatMax))
|
||||
{
|
||||
hr = StringCchVPrintfExW(pszBuffer, cchBufferMax, NULL, NULL, STRSAFE_IGNORE_NULLS, pszFormat, argList);
|
||||
}
|
||||
else
|
||||
{
|
||||
hr = E_FAIL;
|
||||
}
|
||||
|
||||
va_end(argList);
|
||||
|
||||
return (SUCCEEDED(hr)) ? pszBuffer : NULL;
|
||||
}
|
||||
|
||||
static DWORD WINAPI SubscribeThreadProc(void *param)
|
||||
{
|
||||
SubscribeThreadData *data = (SubscribeThreadData *)param;
|
||||
Channel newFeed;
|
||||
newFeed.updateTime = updateTime;
|
||||
newFeed.autoUpdate = autoUpdate;
|
||||
newFeed.autoDownload = autoDownload;
|
||||
newFeed.autoDownloadEpisodes = autoDownloadEpisodes;
|
||||
newFeed.SetURL(data->url);
|
||||
newFeed.needsRefresh = true;
|
||||
|
||||
WCHAR szBuffer1[2048] = {0}, szBuffer2[2048] = {0};
|
||||
LPCWSTR pszMessage = NULL, pszTitle = NULL;
|
||||
|
||||
switch (DownloadFeedInformation(newFeed))
|
||||
{
|
||||
case DOWNLOAD_SUCCESS:
|
||||
{
|
||||
Nullsoft::Utility::AutoLock lock (channels LOCKNAME("AddURL"));
|
||||
newFeed.autoDownload = ::autoDownload;
|
||||
if (channels.AddChannel(newFeed))
|
||||
cloud.Pulse();
|
||||
}
|
||||
break;
|
||||
|
||||
case DOWNLOAD_DUPLICATE:
|
||||
pszMessage = FormatLangString(szBuffer1, ARRAYSIZE(szBuffer1), szBuffer2, ARRAYSIZE(szBuffer2), IDS_ALREADY_SUBSCRIBED, newFeed.title, data->url);
|
||||
break;
|
||||
|
||||
case DOWNLOAD_404:
|
||||
pszMessage = FormatLangString(szBuffer1, ARRAYSIZE(szBuffer1), szBuffer2, ARRAYSIZE(szBuffer2), IDS_FILE_NOT_FOUND, data->url);
|
||||
break;
|
||||
|
||||
case DOWNLOAD_TIMEOUT:
|
||||
pszMessage = FormatLangString(szBuffer1, ARRAYSIZE(szBuffer1), szBuffer2, ARRAYSIZE(szBuffer2), IDS_CONNECTION_TIMED_OUT, data->url);
|
||||
break;
|
||||
|
||||
case DOWNLOAD_ERROR_PARSING_XML:
|
||||
pszMessage = FormatLangString(szBuffer1, ARRAYSIZE(szBuffer1), szBuffer2, ARRAYSIZE(szBuffer2), IDS_ERROR_PARSING_XML, data->url);
|
||||
break;
|
||||
|
||||
case DOWNLOAD_NOTRSS:
|
||||
pszMessage = FormatLangString(szBuffer1, ARRAYSIZE(szBuffer1), szBuffer2, ARRAYSIZE(szBuffer2), IDS_INVALID_RSS_FEED, data->url);
|
||||
break;
|
||||
|
||||
case DOWNLOAD_CONNECTIONRESET:
|
||||
pszMessage = FormatLangString(szBuffer1, ARRAYSIZE(szBuffer1), szBuffer2, ARRAYSIZE(szBuffer2), IDS_CONNECTION_RESET, data->url);
|
||||
break;
|
||||
|
||||
case DOWNLOAD_NOHTTP:
|
||||
pszMessage = WASABI_API_LNGSTRINGW_BUF(IDS_NO_JNETLIB, szBuffer1, ARRAYSIZE(szBuffer1));
|
||||
pszTitle = WASABI_API_LNGSTRINGW_BUF(IDS_JNETLIB_MISSING, szBuffer2, ARRAYSIZE(szBuffer2));
|
||||
break;
|
||||
|
||||
case DOWNLOAD_NOPARSER:
|
||||
pszMessage = WASABI_API_LNGSTRINGW_BUF(IDS_NO_EXPAT, szBuffer1, ARRAYSIZE(szBuffer1));
|
||||
pszTitle = WASABI_API_LNGSTRINGW_BUF(IDS_EXPAT_MISSING, szBuffer2, ARRAYSIZE(szBuffer2));
|
||||
break;
|
||||
|
||||
|
||||
}
|
||||
|
||||
if(NULL != pszMessage)
|
||||
{
|
||||
if (NULL == pszTitle)
|
||||
pszTitle = WASABI_API_LNGSTRINGW_BUF(IDS_ERROR_SUBSCRIBING_TO_PODCAST, szBuffer2, ARRAYSIZE(szBuffer2));
|
||||
|
||||
MessageBox(plugin.hwndLibraryParent, pszMessage, pszTitle, MB_ICONERROR | MB_OK);
|
||||
}
|
||||
|
||||
Plugin_FreeString(data->url);
|
||||
free(data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
LPCWSTR RssCOM::GetName()
|
||||
{
|
||||
return L"Podcast";
|
||||
}
|
||||
|
||||
HRESULT RssCOM::SubscribeUrl(BSTR url, VARIANT FAR *result)
|
||||
{
|
||||
HRESULT hr;
|
||||
SubscribeThreadData *data = (SubscribeThreadData*)malloc(sizeof(SubscribeThreadData));
|
||||
if (NULL != data)
|
||||
{
|
||||
data->url = Plugin_CopyString(url);
|
||||
DWORD threadId;
|
||||
HANDLE hThread = CreateThread(NULL, NULL, SubscribeThreadProc, (void*)data, NULL, &threadId);
|
||||
if (NULL == hThread)
|
||||
{
|
||||
DWORD error = GetLastError();
|
||||
hr = HRESULT_FROM_WIN32(error);
|
||||
Plugin_FreeString(data->url);
|
||||
free(data);
|
||||
}
|
||||
else
|
||||
{
|
||||
CloseHandle(hThread);
|
||||
hr = S_OK;
|
||||
}
|
||||
}
|
||||
else
|
||||
hr = E_OUTOFMEMORY;
|
||||
|
||||
if (NULL != result)
|
||||
{
|
||||
VariantInit(result);
|
||||
V_VT(result) = VT_BOOL;
|
||||
V_BOOL(result) = (SUCCEEDED(hr) ? VARIANT_TRUE : VARIANT_FALSE);
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
42
Src/Plugins/Library/ml_wire/RSSCOM.h
Normal file
42
Src/Plugins/Library/ml_wire/RSSCOM.h
Normal file
@ -0,0 +1,42 @@
|
||||
#ifndef NULLSOFT_PODCAST_PLUGIN_RSS_COM_HEADER
|
||||
#define NULLSOFT_PODCAST_PLUGIN_RSS_COM_HEADER
|
||||
|
||||
#if defined(_MSC_VER) && (_MSC_VER >= 1020)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <wtypes.h>
|
||||
#include <atomic>
|
||||
|
||||
#include "../nu/dispatchTable.h"
|
||||
|
||||
class RssCOM : public IDispatch
|
||||
{
|
||||
public:
|
||||
typedef enum
|
||||
{
|
||||
DISPATCH_SUBSCRIBE = 0,
|
||||
} DispatchCodes;
|
||||
|
||||
protected:
|
||||
RssCOM();
|
||||
~RssCOM();
|
||||
|
||||
public:
|
||||
static HRESULT CreateInstance(RssCOM **instance);
|
||||
static HRESULT SubscribeUrl(BSTR url, VARIANT FAR *result);
|
||||
static LPCWSTR GetName();
|
||||
|
||||
/* IUnknown*/
|
||||
STDMETHOD(QueryInterface)(REFIID riid, PVOID *ppvObject);
|
||||
STDMETHOD_(ULONG, AddRef)(void);
|
||||
STDMETHOD_(ULONG, Release)(void);
|
||||
|
||||
protected:
|
||||
DISPTABLE_INCLUDE();
|
||||
DISPHANDLER_REGISTER(OnSubscribe);
|
||||
|
||||
std::atomic<std::size_t> _ref = 1;
|
||||
};
|
||||
|
||||
#endif //NULLSOFT_PODCAST_PLUGIN_RSS_COM_HEADER
|
181
Src/Plugins/Library/ml_wire/RSSParse.cpp
Normal file
181
Src/Plugins/Library/ml_wire/RSSParse.cpp
Normal file
@ -0,0 +1,181 @@
|
||||
#include "Main.h"
|
||||
#include "RSSParse.h"
|
||||
|
||||
#include "RFCDate.h"
|
||||
#include "../xml/XMLNode.h"
|
||||
#include "Feeds.h"
|
||||
#include "Defaults.h"
|
||||
#include "ChannelSync.h"
|
||||
#include "ParseUtil.h"
|
||||
#include <strsafe.h>
|
||||
|
||||
static void ReadWinampSpecificItem(const XMLNode *item, RSS::Item &newItem)
|
||||
{
|
||||
newItem.listened = PropertyIsTrue(item, L"winamp:listened");
|
||||
newItem.downloaded = PropertyIsTrue(item, L"winamp:downloaded");
|
||||
}
|
||||
|
||||
static void ReadRSSItem(XMLNode *item, Channel &channel, bool doWinampSpecificTags)
|
||||
{
|
||||
RSS::MutableItem newItem;
|
||||
if (doWinampSpecificTags)
|
||||
ReadWinampSpecificItem(item, newItem);
|
||||
|
||||
const wchar_t *pubdate = GetContent(item, L"pubDate");
|
||||
if (pubdate && pubdate[0])
|
||||
{
|
||||
newItem.publishDate = MakeRFCDate(pubdate);
|
||||
if (newItem.publishDate <= 0)
|
||||
{
|
||||
newItem.publishDate = _time64(0);
|
||||
newItem.generatedDate = true;
|
||||
}
|
||||
else
|
||||
newItem.generatedDate = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
newItem.publishDate = _time64(0);
|
||||
newItem.generatedDate = true;
|
||||
}
|
||||
|
||||
const wchar_t *itemName = GetContent(item, L"title");
|
||||
if (itemName && itemName[0])
|
||||
newItem.SetItemName(itemName);
|
||||
else
|
||||
{
|
||||
wchar_t date_str[128] = {0};
|
||||
MakeRFCDateString(newItem.publishDate, date_str, 128);
|
||||
newItem.SetItemName(date_str);
|
||||
}
|
||||
|
||||
newItem.SetLink(GetContent(item, L"link"));
|
||||
newItem.SetURL(GetProperty(item, L"enclosure", L"url"));
|
||||
const wchar_t* src = GetProperty(item, L"source", L"src");
|
||||
if (!src || !src[0])
|
||||
{
|
||||
newItem.SetSourceURL(GetProperty(item, L"source", L"url"));
|
||||
}
|
||||
else
|
||||
{
|
||||
newItem.SetSourceURL(src/*GetProperty(item, L"source", L"src")*/);
|
||||
}
|
||||
newItem.SetSize(GetProperty(item, L"enclosure", L"length"));
|
||||
|
||||
const wchar_t *guid = GetContent(item, L"guid");
|
||||
if (!guid || !guid[0])
|
||||
guid = GetProperty(item, L"enclosure", L"url");
|
||||
|
||||
if (guid && guid[0])
|
||||
{
|
||||
newItem.SetGUID(guid);
|
||||
}
|
||||
else
|
||||
{
|
||||
wchar_t generated_guid[160] = {0};
|
||||
StringCbPrintf(generated_guid, sizeof(generated_guid), L"%s%s", channel.title, newItem.itemName);
|
||||
newItem.SetGUID(generated_guid);
|
||||
}
|
||||
|
||||
const wchar_t *description = GetContent(item, L"description");
|
||||
if (!description || !description[0])
|
||||
description = GetContent(item, L"content:encoded");
|
||||
newItem.SetDescription(description);
|
||||
|
||||
const wchar_t *duration = GetContent(item, L"itunes:duration");
|
||||
if (duration && duration[0])
|
||||
newItem.SetDuration(duration);
|
||||
|
||||
if (newItem.itemName && newItem.itemName[0])
|
||||
{
|
||||
channel.items.push_back(newItem);
|
||||
}
|
||||
}
|
||||
|
||||
void ReadWinampSpecificChannel(const XMLNode *node, Channel &newChannel)
|
||||
{
|
||||
const XMLNode *curNode = 0;
|
||||
const wchar_t *lastupdate = node->GetProperty(L"winamp:lastupdate");
|
||||
if (lastupdate && lastupdate[0])
|
||||
newChannel.lastUpdate = MakeRFCDate(lastupdate);
|
||||
|
||||
const wchar_t *winamp_url = GetContent(node, L"winamp:url");
|
||||
newChannel.SetURL(winamp_url);
|
||||
|
||||
// set to preference value first
|
||||
newChannel.updateTime = updateTime;
|
||||
newChannel.autoUpdate = autoUpdate;
|
||||
newChannel.autoDownload = autoDownload;
|
||||
newChannel.autoDownloadEpisodes = autoDownloadEpisodes;
|
||||
|
||||
curNode = node->Get(L"winamp:update");
|
||||
if (curNode)
|
||||
{
|
||||
newChannel.useDefaultUpdate = PropertyIsTrue(curNode, L"usedefaultupdate");
|
||||
newChannel.needsRefresh = PropertyIsTrue(curNode, L"needsrefresh");
|
||||
if (!newChannel.useDefaultUpdate)
|
||||
{
|
||||
newChannel.updateTime = _wtoi64(curNode->GetProperty(L"updatetime"));
|
||||
newChannel.autoUpdate = PropertyIsTrue(curNode, L"autoupdate");
|
||||
}
|
||||
}
|
||||
|
||||
curNode = node->Get(L"winamp:download");
|
||||
if (curNode)
|
||||
{
|
||||
newChannel.autoDownload = PropertyIsTrue(curNode, L"autodownload");
|
||||
if (newChannel.autoDownload)
|
||||
{
|
||||
const wchar_t *prop = curNode->GetProperty(L"autoDownloadEpisodes");
|
||||
if (prop)
|
||||
newChannel.autoDownloadEpisodes = _wtoi(prop);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void ReadRSSChannel(const XMLNode *node, Channel &newChannel, bool doWinampSpecificTags)
|
||||
{
|
||||
XMLNode::NodeList::const_iterator itemItr;
|
||||
if (doWinampSpecificTags)
|
||||
ReadWinampSpecificChannel(node, newChannel);
|
||||
|
||||
const wchar_t *title = GetContent(node, L"title");
|
||||
newChannel.SetTitle(title);
|
||||
|
||||
const wchar_t *link = GetContent(node, L"link");
|
||||
newChannel.SetLink(link);
|
||||
|
||||
const wchar_t *description = GetContent(node, L"description");
|
||||
newChannel.SetDescription(description);
|
||||
|
||||
const wchar_t *ttl = GetContent(node, L"ttl");
|
||||
if (ttl)
|
||||
newChannel.ttl = _wtoi(ttl);
|
||||
|
||||
const XMLNode::NodeList *items = node->GetList(L"item");
|
||||
if (items)
|
||||
{
|
||||
for (itemItr = items->begin(); itemItr != items->end(); itemItr++)
|
||||
ReadRSSItem(*itemItr, newChannel, doWinampSpecificTags);
|
||||
}
|
||||
}
|
||||
|
||||
void ReadRSS(const XMLNode *rss, ChannelSync *sync, bool doWinampSpecificTags, const wchar_t *url)
|
||||
{
|
||||
XMLNode::NodeList::const_iterator itr;
|
||||
|
||||
sync->BeginChannelSync();
|
||||
const XMLNode::NodeList *channelList = rss->GetList(L"channel");
|
||||
if (channelList)
|
||||
{
|
||||
for (itr = channelList->begin(); itr != channelList->end(); itr ++)
|
||||
{
|
||||
Channel newChannel;
|
||||
ReadRSSChannel(*itr, newChannel, doWinampSpecificTags);
|
||||
if (!newChannel.url || !newChannel.url[0])
|
||||
newChannel.SetURL(url);
|
||||
sync->NewChannel(newChannel);
|
||||
}
|
||||
}
|
||||
sync->EndChannelSync();
|
||||
}
|
9
Src/Plugins/Library/ml_wire/RSSParse.h
Normal file
9
Src/Plugins/Library/ml_wire/RSSParse.h
Normal file
@ -0,0 +1,9 @@
|
||||
#ifndef NULLSOFT_RSSPARSEH
|
||||
#define NULLSOFT_RSSPARSEH
|
||||
|
||||
#include "../xml/XMLNode.h"
|
||||
#include "ChannelSync.h"
|
||||
|
||||
void ReadRSS(const XMLNode *rss, ChannelSync *sync, bool doWinampSpecificTags, const wchar_t *url);
|
||||
|
||||
#endif
|
51
Src/Plugins/Library/ml_wire/TODO.txt
Normal file
51
Src/Plugins/Library/ml_wire/TODO.txt
Normal file
@ -0,0 +1,51 @@
|
||||
to fix
|
||||
----
|
||||
crash on shutdown
|
||||
|
||||
|
||||
/////------------ 1.1 below --------------
|
||||
automatically switch to 'custom' if you click on dropdown in "add" or "edit" url dialog
|
||||
|
||||
need icon for listened media
|
||||
maybe one for read text?
|
||||
|
||||
strip whitespace from beginning of titles
|
||||
|
||||
multiple-select
|
||||
|
||||
Allow for customizing the download location in add/edit url
|
||||
|
||||
deletable items (needs to move to a separate 'deleted items' list so we don't re-add them next rss refresh)
|
||||
|
||||
drag-n-drop from webpages
|
||||
|
||||
once we get an HTTP 200, we should put the downloaded on the 'downloads' list, and be able to update the download percentage status as necessary
|
||||
|
||||
BACKGROUND DOWNLOADER
|
||||
<<<
|
||||
avoid multiple downloads of the same thing
|
||||
avoid downlaoding things that have already been downloaded.
|
||||
range / if-range to handle download resuming
|
||||
save the last modified dates from "Last-Modified" header
|
||||
save unfinished downloads to an XML file and read on load
|
||||
>>>
|
||||
|
||||
UNIFIED DOWNLOAD MANAGER CONCEPT !!!!!
|
||||
|
||||
who needs updates
|
||||
downloaded file list
|
||||
downloads page (to refresh view)
|
||||
item object
|
||||
podcast page (to refresh view)
|
||||
|
||||
|
||||
new way of listing items
|
||||
---
|
||||
create a common "items" data structure that select channels add their items to.
|
||||
When a channel is select, it adds its items.
|
||||
When a channel is deselected, it removes its items.
|
||||
When a channel is refreshed, it re-adds its items (assuming the item-adder function protects against dupes)
|
||||
only potential issue is if a channel somehow "loses" items (or an item's GUID is changes)
|
||||
could be fixed by either 1) keeps track of "parent channel" in the items list
|
||||
2) rebuilding the entire items list on every channel refresh
|
||||
or 3) preventing GUID changes and item deletions (or forcing an item list rebuild if it does occur)
|
57
Src/Plugins/Library/ml_wire/UpdateAutoDownload.cpp
Normal file
57
Src/Plugins/Library/ml_wire/UpdateAutoDownload.cpp
Normal file
@ -0,0 +1,57 @@
|
||||
#include "main.h"
|
||||
#include "api__ml_wire.h"
|
||||
#include "UpdateAutoDownload.h"
|
||||
|
||||
int UpdateAutoDownload::episodes[] = {0, // AUTODOWNLOAD_NEVER
|
||||
1, // AUTODOWNLOAD_LAST_ONE
|
||||
2, // AUTODOWNLOAD_LAST_TWO
|
||||
3, // AUTODOWNLOAD_LAST_THREE
|
||||
5, // AUTODOWNLOAD_LAST_FIVE
|
||||
};
|
||||
|
||||
const wchar_t *UpdateAutoDownload::GetTitle(int position, wchar_t *buffer, int bufferMax)
|
||||
{
|
||||
if (NULL == buffer)
|
||||
return NULL;
|
||||
|
||||
INT stringId = IDS_ERROR_FYEO;
|
||||
switch (position)
|
||||
{
|
||||
case AUTODOWNLOAD_NEVER: stringId = IDS_ATD_NEVER; break;
|
||||
case AUTODOWNLOAD_LAST_ONE: stringId = IDS_ATD_LASTONE; break;
|
||||
case AUTODOWNLOAD_LAST_TWO: stringId = IDS_ATD_LASTTWO; break;
|
||||
case AUTODOWNLOAD_LAST_THREE: stringId = IDS_ATD_LASTTHREE; break;
|
||||
case AUTODOWNLOAD_LAST_FIVE: stringId = IDS_ATD_LASTFIVE; break;
|
||||
}
|
||||
return WASABI_API_LNGSTRINGW_BUF(stringId, buffer, bufferMax);
|
||||
}
|
||||
|
||||
|
||||
bool UpdateAutoDownload::GetAutoDownload(int selection)
|
||||
{
|
||||
if (selection == AUTODOWNLOAD_NEVER)
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
int UpdateAutoDownload::GetAutoDownloadEpisodes(int selection)
|
||||
{
|
||||
if (selection >= 0 && selection < AUTODOWNLOAD_NUMENTRIES)
|
||||
return episodes[selection];
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
int UpdateAutoDownload::GetSelection(int selEpisodes, bool autoDownload)
|
||||
{
|
||||
if (!autoDownload)
|
||||
return AUTODOWNLOAD_NEVER;
|
||||
|
||||
for (int i = AUTODOWNLOAD_LAST_ONE;i < AUTODOWNLOAD_NUMENTRIES;i++)
|
||||
if (selEpisodes == episodes[i])
|
||||
return i;
|
||||
|
||||
return AUTODOWNLOAD_LAST_ONE;
|
||||
|
||||
}
|
28
Src/Plugins/Library/ml_wire/UpdateAutoDownload.h
Normal file
28
Src/Plugins/Library/ml_wire/UpdateAutoDownload.h
Normal file
@ -0,0 +1,28 @@
|
||||
#ifndef NULLSOFT_UPDATEAUTODOWNLOADH
|
||||
#define NULLSOFT_UPDATEAUTODOWNLOADH
|
||||
|
||||
/* This header file is used by FeedsDialog.h
|
||||
It provides a set of helper functions to deal with the combo box for auto download
|
||||
|
||||
basically - converts between combo box choice and int
|
||||
*/
|
||||
namespace UpdateAutoDownload
|
||||
{
|
||||
enum
|
||||
{
|
||||
AUTODOWNLOAD_NEVER = 0,
|
||||
AUTODOWNLOAD_LAST_ONE,
|
||||
AUTODOWNLOAD_LAST_TWO,
|
||||
AUTODOWNLOAD_LAST_THREE,
|
||||
AUTODOWNLOAD_LAST_FIVE,
|
||||
AUTODOWNLOAD_NUMENTRIES
|
||||
};
|
||||
|
||||
extern int episodes[];
|
||||
|
||||
const wchar_t *GetTitle(int position, wchar_t *buffer, int bufferMax);
|
||||
bool GetAutoDownload(int selection);
|
||||
int GetAutoDownloadEpisodes(int selection);
|
||||
int GetSelection(int selEpisodes, bool autoDownload);
|
||||
}
|
||||
#endif
|
62
Src/Plugins/Library/ml_wire/UpdateTime.cpp
Normal file
62
Src/Plugins/Library/ml_wire/UpdateTime.cpp
Normal file
@ -0,0 +1,62 @@
|
||||
#include "main.h"
|
||||
#include "api__ml_wire.h"
|
||||
#include "UpdateTime.h"
|
||||
|
||||
__time64_t Update::times[] = {0, // TIME_MANUALLY
|
||||
60 /* 1 minute */ * 60 /* 1 hour */ * 24 /* 1 day */ * 7 /* 1 week */, // TIME_WEEKLY
|
||||
60 /* 1 minute */ * 60 /* 1 hour */ * 24 /* 1 day */, // TIME_DAILY
|
||||
60 /* 1 minute */ * 60 /* 1 hour */, // TIME_HOURLY
|
||||
};
|
||||
|
||||
const wchar_t *Update::GetTitle( int position, wchar_t *buffer, int bufferMax )
|
||||
{
|
||||
if ( NULL == buffer )
|
||||
return NULL;
|
||||
|
||||
INT stringId = IDS_ERROR_FYEO;
|
||||
switch ( position )
|
||||
{
|
||||
case TIME_MANUALLY:
|
||||
stringId = IDS_UPD_MANUALLY;
|
||||
break;
|
||||
case TIME_WEEKLY:
|
||||
stringId = IDS_UPD_WEEK;
|
||||
break;
|
||||
case TIME_DAILY:
|
||||
stringId = IDS_UPD_DAY;
|
||||
break;
|
||||
case TIME_HOURLY:
|
||||
stringId = IDS_UPD_HOUR;
|
||||
break;
|
||||
}
|
||||
return WASABI_API_LNGSTRINGW_BUF( stringId, buffer, bufferMax );
|
||||
}
|
||||
|
||||
bool Update::GetAutoUpdate(int selection)
|
||||
{
|
||||
if (selection == TIME_MANUALLY)
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
__time64_t Update::GetTime(int selection)
|
||||
{
|
||||
if (selection >= 0 && selection < TIME_NUMENTRIES)
|
||||
return times[selection];
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Update::GetSelection(__time64_t selTime, bool autoUpdate)
|
||||
{
|
||||
if (!autoUpdate)
|
||||
return TIME_MANUALLY;
|
||||
|
||||
for (int i = TIME_WEEKLY;i < TIME_NUMENTRIES;i++)
|
||||
if (selTime >= times[i])
|
||||
return i;
|
||||
|
||||
return TIME_DAILY;
|
||||
|
||||
}
|
29
Src/Plugins/Library/ml_wire/UpdateTime.h
Normal file
29
Src/Plugins/Library/ml_wire/UpdateTime.h
Normal file
@ -0,0 +1,29 @@
|
||||
#ifndef NULLSOFT_UPDATETIMEH
|
||||
#define NULLSOFT_UPDATETIMEH
|
||||
|
||||
#include <time.h>
|
||||
|
||||
/* This header file is used by FeedsDialog.h
|
||||
It provides a set of helper functions to deal with the combo box for update time
|
||||
|
||||
basically - converts between combo box choice and __time64_t
|
||||
*/
|
||||
namespace Update
|
||||
{
|
||||
enum
|
||||
{
|
||||
TIME_MANUALLY = 0,
|
||||
TIME_WEEKLY,
|
||||
TIME_DAILY,
|
||||
TIME_HOURLY,
|
||||
TIME_NUMENTRIES
|
||||
};
|
||||
|
||||
extern __time64_t times[];
|
||||
|
||||
const wchar_t *GetTitle(int position, wchar_t *buffer, int bufferMax);
|
||||
bool GetAutoUpdate(int selection);
|
||||
__time64_t GetTime(int selection);
|
||||
int GetSelection(__time64_t selTime, bool autoUpdate);
|
||||
}
|
||||
#endif
|
69
Src/Plugins/Library/ml_wire/Util.h
Normal file
69
Src/Plugins/Library/ml_wire/Util.h
Normal file
@ -0,0 +1,69 @@
|
||||
#ifndef NULLSOFT_PODCAST_PLUGIN_UTIL_HEADER
|
||||
#define NULLSOFT_PODCAST_PLUGIN_UTIL_HEADER
|
||||
|
||||
#if defined(_MSC_VER) && (_MSC_VER >= 1020)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <wtypes.h>
|
||||
#include "../nu/trace.h"
|
||||
|
||||
#define CSTR_INVARIANT MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT)
|
||||
|
||||
#ifndef ARRAYSIZE
|
||||
#define ARRAYSIZE(blah) (sizeof(blah)/sizeof(*blah))
|
||||
#endif
|
||||
|
||||
#ifndef LONGX86
|
||||
#ifdef _WIN64
|
||||
#define LONGX86 LONG_PTR
|
||||
#else /*_WIN64*/
|
||||
#define LONGX86 LONG
|
||||
#endif /*_WIN64*/
|
||||
#endif // LONGX86
|
||||
|
||||
#ifdef __cplusplus
|
||||
#define SENDMSG(__hwnd, __msgId, __wParam, __lParam) ::SendMessageW((__hwnd), (__msgId), (__wParam), (__lParam))
|
||||
#else
|
||||
#define SENDMSG(__hwnd, __msgId, __wParam, __lParam) SendMessageW((__hwnd), (__msgId), (__wParam), (__lParam))
|
||||
#endif // __cplusplus
|
||||
|
||||
#define SENDMLIPC(__hwndML, __ipcMsgId, __param) SENDMSG((__hwndML), WM_ML_IPC, (WPARAM)(__param), (LPARAM)(__ipcMsgId))
|
||||
#define SENDWAIPC(__hwndWA, __ipcMsgId, __param) SENDMSG((__hwndWA), WM_WA_IPC, (WPARAM)(__param), (LPARAM)(__ipcMsgId))
|
||||
|
||||
|
||||
#if defined (_WIN64)
|
||||
#define MSGRESULT(__hwnd, __result) { SetWindowLongPtrW((__hwnd), DWLP_MSGRESULT, ((LONGX86)(LONG_PTR)(__result))); return TRUE; }
|
||||
#else
|
||||
#define MSGRESULT(__hwnd, __result) { SetWindowLongPtrW((__hwnd), DWL_MSGRESULT, ((LONGX86)(LONG_PTR)(__result))); return TRUE; }
|
||||
#endif
|
||||
|
||||
#define SENDCMD(__hwnd, __ctrlId, __eventId, __hctrl) (SENDMSG((__hwnd), WM_COMMAND, MAKEWPARAM(__ctrlId, __eventId), (LPARAM)(__hctrl)))
|
||||
|
||||
|
||||
LPWSTR Plugin_MallocString(size_t cchLen);
|
||||
LPWSTR Plugin_ReAllocString(LPWSTR pszString, size_t cchLen);
|
||||
void Plugin_FreeString(LPWSTR pszString);
|
||||
LPWSTR Plugin_CopyString(LPCWSTR pszSource);
|
||||
|
||||
LPSTR Plugin_MallocAnsiString(size_t cchLen);
|
||||
LPSTR Plugin_CopyAnsiString(LPCSTR pszSource);
|
||||
void Plugin_FreeAnsiString(LPSTR pszString);
|
||||
|
||||
LPWSTR Plugin_DuplicateResString(LPCWSTR pszResource);
|
||||
void Plugin_FreeResString(LPWSTR pszResource);
|
||||
HRESULT Plugin_CopyResString(LPWSTR pszBuffer, INT cchBufferMax, LPCWSTR pszString);
|
||||
|
||||
LPSTR Plugin_WideCharToMultiByte(UINT codePage, DWORD dwFlags, LPCWSTR lpWideCharStr, INT cchWideChar, LPCSTR lpDefaultChar, LPBOOL lpUsedDefaultChar);
|
||||
LPWSTR Plugin_MultiByteToWideChar(UINT codePage, DWORD dwFlags, LPCSTR lpMultiByteStr, INT cbMultiByte);
|
||||
|
||||
void Plugin_SafeRelease(IUnknown *pUnk);
|
||||
|
||||
|
||||
HRESULT Plugin_FileExtensionFromUrl(LPWSTR pszBuffer, INT cchBufferMax, LPCWSTR pszUrl, LPCWSTR defaultExtension);
|
||||
void Plugin_ReplaceBadPathChars(LPWSTR pszPath);
|
||||
INT Plugin_CleanDirectory(LPWSTR pszPath);
|
||||
|
||||
HRESULT Plugin_EnsurePathExist(LPCWSTR pszDirectory);
|
||||
|
||||
#endif // NULLSOFT_PODCAST_PLUGIN_UTIL_HEADER
|
14
Src/Plugins/Library/ml_wire/WantsDownloadStatus.h
Normal file
14
Src/Plugins/Library/ml_wire/WantsDownloadStatus.h
Normal file
@ -0,0 +1,14 @@
|
||||
#ifndef NULLSOFT_WANTSDOWNLOADSTATUSH
|
||||
#define NULLSOFT_WANTSDOWNLOADSTATUSH
|
||||
|
||||
class WantsDownloadStatus
|
||||
{
|
||||
public:
|
||||
virtual void DownloadStarted() {}
|
||||
virtual void UpdateDownloadStatus(size_t downloaded, size_t totalBytes) {}
|
||||
virtual void DownloadDone() {}
|
||||
virtual void DownloadFailed() {}
|
||||
|
||||
};
|
||||
|
||||
#endif
|
99
Src/Plugins/Library/ml_wire/Wire.cpp
Normal file
99
Src/Plugins/Library/ml_wire/Wire.cpp
Normal file
@ -0,0 +1,99 @@
|
||||
#include "Main.h"
|
||||
|
||||
#include "./subscriptionView.h"
|
||||
#include "FeedsDialog.h"
|
||||
#include "Feeds.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
|
||||
ChannelList channels;
|
||||
|
||||
//CategoryIndex sourceByCategory;
|
||||
using namespace Nullsoft::Utility;
|
||||
//LockGuard /*feedGuard, */channelGuard, categoryGuard;
|
||||
|
||||
void WireManager::BeginChannelSync()
|
||||
{
|
||||
// TODO something better than this =)
|
||||
// like making 'touched' flags and delete untouched ones
|
||||
//sources.clear();
|
||||
//sourceByCategory.clear();
|
||||
}
|
||||
|
||||
void WireManager::NewChannel(const Channel &newChannel)
|
||||
{
|
||||
AutoLock lock (channels LOCKNAME("NewChannel"));
|
||||
for (ChannelList::iterator itr=channels.begin();itr!=channels.end(); itr++)
|
||||
{
|
||||
if (*itr == newChannel)
|
||||
{
|
||||
itr->UpdateFrom(newChannel);
|
||||
return;
|
||||
}
|
||||
}
|
||||
channels.push_back(newChannel);
|
||||
|
||||
}
|
||||
|
||||
void WireManager::EndChannelSync()
|
||||
{
|
||||
//SubscriptionView_RefreshChannels(NULL, TRUE);
|
||||
}
|
||||
|
||||
bool ChannelTitleSort(Channel &channel1, Channel &channel2)
|
||||
{
|
||||
return (CSTR_LESS_THAN == CompareStringW(LOCALE_USER_DEFAULT, NORM_IGNORECASE, channel1.title, -1, channel2.title, -1));
|
||||
}
|
||||
|
||||
void ChannelList::SortByTitle()
|
||||
{
|
||||
AutoLock lock (channelGuard LOCKNAME("SortByTitle"));
|
||||
std::sort(channelList.begin(), channelList.end(), ChannelTitleSort);
|
||||
}
|
||||
|
||||
void ChannelList::push_back(const Channel &channel)
|
||||
{
|
||||
channelList.push_back(channel);
|
||||
}
|
||||
|
||||
bool ChannelList::AddChannel(Channel &channel)
|
||||
{
|
||||
ChannelList::iterator found;
|
||||
for (found=channels.begin(); found!=channels.end(); found++)
|
||||
{
|
||||
if (!wcscmp(found->url, channel.url))
|
||||
break;
|
||||
}
|
||||
|
||||
if (found == channels.end()){
|
||||
channel.needsRefresh=true;
|
||||
push_back(channel);
|
||||
SaveChannels(*this);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t ChannelList::GetNumPodcasts()
|
||||
{
|
||||
return channels.size();
|
||||
}
|
||||
|
||||
ifc_podcast *ChannelList::EnumPodcast(size_t i)
|
||||
{
|
||||
if (i < channels.size())
|
||||
return &channels[i];
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
#undef CBCLASS
|
||||
#define CBCLASS ChannelList
|
||||
START_DISPATCH;
|
||||
CB(API_PODCASTS_GETNUMPODCASTS, GetNumPodcasts)
|
||||
CB(API_PODCASTS_ENUMPODCAST, EnumPodcast)
|
||||
END_DISPATCH;
|
||||
#undef CBCLASS
|
||||
|
62
Src/Plugins/Library/ml_wire/Wire.h
Normal file
62
Src/Plugins/Library/ml_wire/Wire.h
Normal file
@ -0,0 +1,62 @@
|
||||
#ifndef NULLSOFT_WIREH
|
||||
#define NULLSOFT_WIREH
|
||||
|
||||
#include "Feeds.h"
|
||||
#include "../nu/AutoLock.h"
|
||||
#include "api_podcasts.h"
|
||||
#include <vector>
|
||||
|
||||
class ChannelList : public api_podcasts
|
||||
{
|
||||
public:
|
||||
|
||||
ChannelList() : channelGuard( "Feed Guard" ) {}
|
||||
|
||||
typedef std::vector<Channel> ChannelContainer;
|
||||
typedef ChannelContainer::iterator iterator;
|
||||
|
||||
size_t size() { return channelList.size(); }
|
||||
bool empty() { return channelList.empty(); }
|
||||
|
||||
void push_back( const Channel &channel );
|
||||
bool AddChannel( Channel &channel );
|
||||
|
||||
iterator begin() { return channelList.begin(); }
|
||||
|
||||
iterator end() { return channelList.end(); }
|
||||
|
||||
void RemoveChannel( int index ) { channelList.erase( channelList.begin() + index ); }
|
||||
|
||||
Channel &operator[]( size_t index ) { return channelList[ index ]; }
|
||||
|
||||
ChannelContainer channelList;
|
||||
|
||||
operator Nullsoft::Utility::LockGuard &( ) { return channelGuard; }
|
||||
|
||||
void SortByTitle();
|
||||
|
||||
Nullsoft::Utility::LockGuard channelGuard;
|
||||
|
||||
public: // api_podcasts interface
|
||||
size_t GetNumPodcasts();
|
||||
ifc_podcast *EnumPodcast( size_t i );
|
||||
|
||||
protected:
|
||||
RECVS_DISPATCH;
|
||||
};
|
||||
|
||||
extern ChannelList channels;
|
||||
//extern CategoryIndex sourceByCategory;
|
||||
#include "ChannelSync.h"
|
||||
|
||||
class WireManager : public ChannelSync
|
||||
{
|
||||
public:
|
||||
void BeginChannelSync();
|
||||
void NewChannel( const Channel &newChannel );
|
||||
void EndChannelSync();
|
||||
};
|
||||
|
||||
extern WireManager channelMgr;
|
||||
|
||||
#endif
|
272
Src/Plugins/Library/ml_wire/XMLWriter.cpp
Normal file
272
Src/Plugins/Library/ml_wire/XMLWriter.cpp
Normal file
@ -0,0 +1,272 @@
|
||||
#include "Main.h"
|
||||
#include "Feeds.h"
|
||||
#include "RFCDate.h"
|
||||
#include "Downloaded.h"
|
||||
#include "../nu/AutoLock.h"
|
||||
#include "Defaults.h"
|
||||
#include "../Agave/Language/api_language.h"
|
||||
|
||||
using namespace Nullsoft::Utility;
|
||||
|
||||
static void XMLWriteString(FILE *fp, const wchar_t *str)
|
||||
{
|
||||
for (const wchar_t *itr = str; *itr; itr=CharNextW(itr))
|
||||
{
|
||||
switch (*itr)
|
||||
{
|
||||
case '<': fputws(L"<", fp); break;
|
||||
case '>': fputws(L">", fp); break;
|
||||
case '&': fputws(L"&", fp); break;
|
||||
case '\"': fputws(L""", fp); break;
|
||||
case '\'': fputws(L"'", fp); break;
|
||||
default: fputwc(*itr, fp); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void InstaProp(FILE *fp, const wchar_t *property, const wchar_t *value)
|
||||
{
|
||||
fwprintf(fp, L" %s=\"", property);
|
||||
XMLWriteString(fp, value);
|
||||
fputws(L"\"", fp);
|
||||
}
|
||||
|
||||
static void InstaProp(FILE *fp, const wchar_t *property, int value)
|
||||
{
|
||||
fwprintf(fp, L" %s=\"%i\"", property, value);
|
||||
}
|
||||
|
||||
static void InstaPropI64(FILE *fp, const wchar_t *property, int64_t value)
|
||||
{
|
||||
fwprintf(fp, L" %s=\"%I64d\"", property, value);
|
||||
}
|
||||
|
||||
static void InstaPropTime(FILE *fp, const wchar_t *property, __time64_t value)
|
||||
{
|
||||
fwprintf(fp, L" %s=\"%I64u\"", property, value);
|
||||
}
|
||||
|
||||
static void InstaProp(FILE *fp, const wchar_t *property, float value)
|
||||
{
|
||||
_fwprintf_l(fp, L" %s=\"%3.3f\"", WASABI_API_LNG->Get_C_NumericLocale(), property, value);
|
||||
}
|
||||
|
||||
static void InstaProp(FILE *fp, const wchar_t *property, bool value)
|
||||
{
|
||||
fwprintf(fp, L" %s=\"", property);
|
||||
if (value)
|
||||
fputws(L"true\"", fp);
|
||||
else
|
||||
fputws(L"false\"", fp);
|
||||
}
|
||||
|
||||
static void InstaTag(FILE *fp, const wchar_t *tag, const wchar_t *content)
|
||||
{
|
||||
if (content && !((INT_PTR)content < 65536) && *content)
|
||||
{
|
||||
fwprintf(fp, L"<%s>", tag);
|
||||
XMLWriteString(fp, content);
|
||||
fwprintf(fp, L"</%s>\r\n", tag);
|
||||
}
|
||||
}
|
||||
|
||||
static void InstaTag(FILE *fp, const wchar_t *tag, unsigned int uint)
|
||||
{
|
||||
fwprintf(fp, L"<%s>%u</%s>", tag, uint, tag);
|
||||
}
|
||||
|
||||
static void InstaTag(FILE *fp, const wchar_t *tag, __time64_t uint)
|
||||
{
|
||||
fwprintf(fp, L"<%s>%I64u</%s>", tag, uint, tag);
|
||||
}
|
||||
|
||||
static void BuildXMLString(FILE *fp, const RSS::Item &item)
|
||||
{
|
||||
fputws(L"<item", fp);
|
||||
InstaProp(fp, L"winamp:listened", item.listened);
|
||||
InstaProp(fp, L"winamp:downloaded", item.downloaded);
|
||||
fputws(L">\r\n", fp);
|
||||
|
||||
InstaTag(fp, L"title", item.itemName);
|
||||
|
||||
if (item.url && item.url[0])
|
||||
{
|
||||
fputws(L"<enclosure", fp);
|
||||
InstaProp(fp, L"url", item.url);
|
||||
InstaPropI64(fp, L"length", item.size);
|
||||
fputws(L"/>\r\n", fp);
|
||||
}
|
||||
|
||||
InstaTag(fp, L"guid", item.guid);
|
||||
InstaTag(fp, L"description", item.description);
|
||||
InstaTag(fp, L"link", item.link);
|
||||
|
||||
if (item.duration && item.duration[0])
|
||||
{
|
||||
InstaTag(fp, L"itunes:duration", item.duration);
|
||||
}
|
||||
|
||||
if (item.publishDate)
|
||||
{
|
||||
wchar_t date_str[128] = {0};
|
||||
MakeRFCDateString(item.publishDate, date_str, 128);
|
||||
InstaTag(fp, L"pubDate", date_str);
|
||||
}
|
||||
|
||||
if (item.sourceUrl && item.sourceUrl[0])
|
||||
{
|
||||
fputws(L"<source",fp);
|
||||
InstaProp(fp, L"src", item.sourceUrl);
|
||||
fputws(L"/>\r\n", fp);
|
||||
}
|
||||
|
||||
fputws(L"</item>\r\n", fp);
|
||||
}
|
||||
|
||||
static void BuildXMLString(FILE *fp, Channel &channel)
|
||||
{
|
||||
fputws(L"<channel", fp);
|
||||
|
||||
wchar_t date_str[128] = {0};
|
||||
MakeRFCDateString(channel.lastUpdate, date_str, 128);
|
||||
|
||||
InstaProp(fp, L"winamp:lastupdate", date_str);
|
||||
fputws(L">\r\n", fp);
|
||||
|
||||
// write update settings for this channel
|
||||
fputws(L"<winamp:update", fp);
|
||||
InstaProp(fp, L"usedefaultupdate", channel.useDefaultUpdate);
|
||||
InstaProp(fp, L"needsrefresh", channel.needsRefresh);
|
||||
|
||||
|
||||
if (!channel.useDefaultUpdate)
|
||||
{
|
||||
InstaProp(fp, L"autoupdate", channel.autoUpdate);
|
||||
InstaPropTime(fp, L"updatetime", channel.updateTime);
|
||||
}
|
||||
fputws(L"/>\r\n", fp);
|
||||
|
||||
if (!channel.useDefaultUpdate)
|
||||
{
|
||||
fputws(L"<winamp:download", fp);
|
||||
InstaProp(fp, L"autodownload", channel.autoDownload);
|
||||
|
||||
if (channel.autoDownload)
|
||||
{
|
||||
InstaProp(fp, L"autoDownloadEpisodes", channel.autoDownloadEpisodes);
|
||||
}
|
||||
fputws(L"/>\r\n", fp);
|
||||
}
|
||||
|
||||
InstaTag(fp, L"winamp:url", channel.url);
|
||||
InstaTag(fp, L"title", channel.title);
|
||||
InstaTag(fp, L"link", channel.link);
|
||||
InstaTag(fp, L"description", channel.description);
|
||||
|
||||
if (channel.ttl)
|
||||
InstaTag(fp, L"ttl", channel.ttl);
|
||||
fputws(L"\r\n", fp);
|
||||
|
||||
Channel::ItemList::iterator itemItr;
|
||||
for (itemItr = channel.items.begin();itemItr != channel.items.end(); itemItr++)
|
||||
BuildXMLString(fp, *itemItr);
|
||||
|
||||
fputws(L"</channel>\r\n", fp);
|
||||
}
|
||||
|
||||
void SaveChannels(const wchar_t *fileName, ChannelList &channels)
|
||||
{
|
||||
FILE *fp = _wfopen(fileName, L"wb");
|
||||
if (fp)
|
||||
{
|
||||
ChannelList::iterator itr;
|
||||
wchar_t BOM = 0xFEFF;
|
||||
fwrite(&BOM, sizeof(BOM), 1, fp);
|
||||
fputws(L"<?xml version=\"1.0\" encoding=\"UTF-16\"?>\r\n", fp);
|
||||
fputws(L"<rss version=\"2.0\" xmlns:winamp=\"http://www.winamp.com\">\r\n", fp);
|
||||
|
||||
for (itr = channels.begin();itr != channels.end();itr++)
|
||||
BuildXMLString(fp, *itr);
|
||||
|
||||
fputws(L"</rss>", fp);
|
||||
fclose(fp);
|
||||
}
|
||||
}
|
||||
|
||||
static void BuildXMLPreferences(FILE *fp)
|
||||
{
|
||||
fputws(L"<download", fp);
|
||||
InstaProp(fp, L"downloadpath", defaultDownloadPath);
|
||||
InstaProp(fp, L"autodownload", autoDownload);
|
||||
InstaProp(fp, L"autoDownloadEpisodes", autoDownloadEpisodes);
|
||||
InstaProp(fp, L"needToMakePodcastsView", needToMakePodcastsView);
|
||||
fputws(L"/>\r\n", fp);
|
||||
|
||||
fputws(L"<update", fp);
|
||||
InstaPropTime(fp, L"updatetime", updateTime);
|
||||
InstaProp(fp, L"autoupdate", autoUpdate);
|
||||
InstaProp(fp, L"updateonlaunch", updateOnLaunch);
|
||||
fputws(L"/>\r\n", fp);
|
||||
|
||||
fputws(L"<subscriptions", fp);
|
||||
InstaProp(fp, L"htmldivider", htmlDividerPercent);
|
||||
InstaProp(fp, L"channeldivider", channelDividerPercent);
|
||||
InstaProp(fp, L"itemtitlewidth", itemTitleWidth);
|
||||
InstaProp(fp, L"itemdatewidth", itemDateWidth);
|
||||
InstaProp(fp, L"itemmediawidth", itemMediaWidth);
|
||||
InstaProp(fp, L"itemsizewidth", itemSizeWidth);
|
||||
InstaProp(fp, L"currentitemsort", currentItemSort);
|
||||
InstaProp(fp, L"itemsortascending", itemSortAscending);
|
||||
InstaProp(fp, L"channelsortascending", channelSortAscending);
|
||||
InstaProp(fp, L"channelLastSelection", channelLastSelection);
|
||||
fputws(L"/>\r\n", fp);
|
||||
|
||||
fputws(L"<downloadsView", fp);
|
||||
InstaProp(fp, L"downloadsChannelWidth", downloadsChannelWidth);
|
||||
InstaProp(fp, L"downloadsItemWidth", downloadsItemWidth);
|
||||
InstaProp(fp, L"downloadsProgressWidth", downloadsProgressWidth);
|
||||
InstaProp(fp, L"downloadsPathWidth", downloadsPathWidth);
|
||||
|
||||
InstaProp(fp, L"downloadsItemSort", downloadsItemSort);
|
||||
InstaProp(fp, L"downloadsSortAscending", downloadsSortAscending);
|
||||
fputws(L"/>\r\n", fp);
|
||||
|
||||
fputws(L"<service", fp);
|
||||
InstaProp(fp, L"url", serviceUrl);
|
||||
fputws(L"/>\r\n", fp);
|
||||
}
|
||||
|
||||
static void BuildXMLDownloads(FILE *fp, DownloadList &downloads)
|
||||
{
|
||||
fputws(L"<downloads>", fp);
|
||||
AutoLock lock (downloads);
|
||||
DownloadList::const_iterator itr;
|
||||
for ( itr = downloads.begin(); itr != downloads.end(); itr++ )
|
||||
{
|
||||
fputws(L"<download>", fp);
|
||||
InstaTag(fp, L"channel", itr->channel);
|
||||
InstaTag(fp, L"item", itr->item);
|
||||
InstaTag(fp, L"url", itr->url);
|
||||
InstaTag(fp, L"path", itr->path);
|
||||
InstaTag(fp, L"publishDate", itr->publishDate);
|
||||
fputws(L"</download>\r\n", fp);
|
||||
}
|
||||
|
||||
fputws(L"</downloads>", fp);
|
||||
}
|
||||
|
||||
void SaveSettings(const wchar_t *fileName, DownloadList &downloads)
|
||||
{
|
||||
FILE *fp = _wfopen(fileName, L"wb");
|
||||
if (fp)
|
||||
{
|
||||
wchar_t BOM = 0xFEFF;
|
||||
fwrite(&BOM, sizeof(BOM), 1, fp);
|
||||
fputws(L"<?xml version=\"1.0\" encoding=\"UTF-16\"?>\r\n", fp);
|
||||
fputws(L"<winamp:preferences xmlns:winamp=\"http://www.winamp.com\" version=\"2\">\r\n", fp);
|
||||
BuildXMLPreferences(fp);
|
||||
BuildXMLDownloads(fp, downloads);
|
||||
fputws(L"</winamp:preferences>", fp);
|
||||
fclose(fp);
|
||||
}
|
||||
}
|
8
Src/Plugins/Library/ml_wire/XMLWriter.h
Normal file
8
Src/Plugins/Library/ml_wire/XMLWriter.h
Normal file
@ -0,0 +1,8 @@
|
||||
#ifndef NULLSOFT_XMLWRITERH
|
||||
#define NULLSOFT_XMLWRITERH
|
||||
#include "Wire.h"
|
||||
#include "Downloaded.h"
|
||||
void SaveChannels(const wchar_t *fileName, ChannelList &channels);
|
||||
|
||||
void SaveSettings(const wchar_t *fileName, DownloadList &downloads);
|
||||
#endif
|
27
Src/Plugins/Library/ml_wire/api__ml_wire.h
Normal file
27
Src/Plugins/Library/ml_wire/api__ml_wire.h
Normal file
@ -0,0 +1,27 @@
|
||||
#ifndef NULLSOFT_ML_WIRE_API_H
|
||||
#define NULLSOFT_ML_WIRE_API_H
|
||||
|
||||
#include "../Winamp/JSAPI2_api_security.h"
|
||||
extern JSAPI2::api_security *jsapi2_security;
|
||||
#define AGAVE_API_JSAPI2_SECURITY jsapi2_security
|
||||
|
||||
#include "../Agave/Language/api_language.h"
|
||||
|
||||
#include <api/application/api_application.h>
|
||||
#define WASABI_API_APP applicationApi
|
||||
|
||||
#include "../omBrowser/obj_ombrowser.h"
|
||||
extern obj_ombrowser *browserManager;
|
||||
#define OMBROWSERMNGR browserManager
|
||||
|
||||
#include "../Winamp/api_stats.h"
|
||||
extern api_stats *statsApi;
|
||||
#define AGAVE_API_STATS statsApi
|
||||
|
||||
#include "../nu/threadpool/api_threadpool.h"
|
||||
extern api_threadpool *threadPoolApi;
|
||||
#define WASABI_API_THREADPOOL threadPoolApi
|
||||
|
||||
#include "../Agave/ExplorerFindFile/api_explorerfindfile.h"
|
||||
|
||||
#endif // !NULLSOFT_ML_WIRE_API_H
|
46
Src/Plugins/Library/ml_wire/api_podcasts.h
Normal file
46
Src/Plugins/Library/ml_wire/api_podcasts.h
Normal file
@ -0,0 +1,46 @@
|
||||
#ifndef NULLSOFT_API_ML_WIRE_PODCASTS_H
|
||||
#define NULLSOFT_API_ML_WIRE_PODCASTS_H
|
||||
|
||||
#include <bfc/dispatch.h>
|
||||
|
||||
class ifc_podcastsubscribecallback;
|
||||
class ifc_podcast;
|
||||
|
||||
class api_podcasts : public Dispatchable
|
||||
{
|
||||
protected:
|
||||
api_podcasts() {}
|
||||
~api_podcasts() {}
|
||||
|
||||
public:
|
||||
size_t GetNumPodcasts();
|
||||
ifc_podcast *EnumPodcast( size_t i );
|
||||
|
||||
// TODO: locking mechanism like api_playlists
|
||||
// TODO: Remove playlists
|
||||
// TODO: int Subscribe(const wchar_t *url, ifc_podcastsubscribecallback *callback);
|
||||
/* TODO: method to download/parse a podcast channel w/o adding it to the list
|
||||
maybe as part of a separate class? */
|
||||
|
||||
enum
|
||||
{
|
||||
API_PODCASTS_GETNUMPODCASTS = 0,
|
||||
API_PODCASTS_ENUMPODCAST = 1,
|
||||
};
|
||||
};
|
||||
|
||||
inline size_t api_podcasts::GetNumPodcasts()
|
||||
{
|
||||
return _call( API_PODCASTS_GETNUMPODCASTS, (size_t)0 );
|
||||
}
|
||||
|
||||
inline ifc_podcast *api_podcasts::EnumPodcast( size_t i )
|
||||
{
|
||||
return _call( API_PODCASTS_ENUMPODCAST, (ifc_podcast *)0, i );
|
||||
}
|
||||
|
||||
// {4D2E9987-D955-45f0-A06F-371405E8B961}
|
||||
static const GUID api_podcastsGUID =
|
||||
{ 0x4d2e9987, 0xd955, 0x45f0, { 0xa0, 0x6f, 0x37, 0x14, 0x5, 0xe8, 0xb9, 0x61 } };
|
||||
|
||||
#endif // !NULLSOFT_API_ML_WIRE_PODCASTS_H
|
687
Src/Plugins/Library/ml_wire/channelEditor.cpp
Normal file
687
Src/Plugins/Library/ml_wire/channelEditor.cpp
Normal file
@ -0,0 +1,687 @@
|
||||
#include "main.h"
|
||||
#include "./util.h"
|
||||
#include "./channelEditor.h"
|
||||
#include "api__ml_wire.h"
|
||||
#include "./defaults.h"
|
||||
#include "./updateTime.h"
|
||||
#include "./UpdateAutoDownload.h"
|
||||
#include "./errors.h"
|
||||
#include "./feeds.h"
|
||||
#include "./feedUtil.h"
|
||||
#include "./cloud.h"
|
||||
#include "./subscriptionView.h"
|
||||
|
||||
|
||||
#include <strsafe.h>
|
||||
|
||||
using namespace Nullsoft::Utility;
|
||||
extern Cloud cloud;
|
||||
|
||||
typedef struct __CHANNELEDITOR
|
||||
{
|
||||
HWND hOwner;
|
||||
size_t iChannel;
|
||||
UINT flags;
|
||||
BOOL enableAutoDownload;
|
||||
BOOL enableAutoUpdate;
|
||||
__time64_t updateTime;
|
||||
INT numOfAutoDownloadEpisodes;
|
||||
} CHANNELEDITOR;
|
||||
|
||||
|
||||
#define GetEditor(__hwnd) ((CHANNELEDITOR*)GetPropW((__hwnd), MAKEINTATOM(VIEWPROP)))
|
||||
|
||||
static INT_PTR CALLBACK ChannelEditor_DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
||||
|
||||
INT_PTR ChannelEditor_Show(HWND hOwner, size_t channelIndex, UINT flags)
|
||||
{
|
||||
if (0 == VIEWPROP)
|
||||
return 0;
|
||||
|
||||
if (NULL == hOwner)
|
||||
hOwner = plugin.hwndLibraryParent;
|
||||
|
||||
if (0 == (CEF_CREATENEW & flags) && BAD_CHANNEL == channelIndex)
|
||||
return 0;
|
||||
|
||||
CHANNELEDITOR editor;
|
||||
ZeroMemory(&editor, sizeof(editor));
|
||||
|
||||
editor.hOwner = hOwner;
|
||||
editor.iChannel = channelIndex;
|
||||
editor.flags = flags;
|
||||
|
||||
INT_PTR result = WASABI_API_DIALOGBOXPARAMW(IDD_ADDURL, hOwner, ChannelEditor_DialogProc, (LPARAM)&editor);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
static BOOL ChannelEditor_SetUpdateTime(HWND hwnd, __time64_t updateTime, BOOL enableAutoUpdate)
|
||||
{
|
||||
HWND hCombo = GetDlgItem(hwnd, IDC_UPDATELIST);
|
||||
if (NULL == hCombo) return FALSE;
|
||||
|
||||
INT selectedVal = Update::GetSelection(updateTime, (FALSE != enableAutoUpdate));
|
||||
INT iCount = (INT)SNDMSG(hCombo, CB_GETCOUNT, 0, 0L);
|
||||
INT iSelect = CB_ERR;
|
||||
for (INT i = 0; i < iCount && CB_ERR == iSelect; i++)
|
||||
{
|
||||
if (selectedVal == (INT)SNDMSG(hCombo, CB_GETITEMDATA, i, 0L))
|
||||
iSelect = i;
|
||||
}
|
||||
|
||||
if (CB_ERR == iSelect)
|
||||
return FALSE;
|
||||
|
||||
if (iSelect != (INT)SNDMSG(hCombo, CB_GETCURSEL, 0, 0L) &&
|
||||
CB_ERR == SNDMSG(hCombo, CB_SETCURSEL, iSelect, 0))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL ChannelEditor_SetAutoDownload(HWND hwnd, INT numOfEpisodes, BOOL enableAutoDownload)
|
||||
{
|
||||
HWND hCombo = GetDlgItem(hwnd, IDC_AUTODOWNLOADLIST);
|
||||
if (NULL == hCombo) return FALSE;
|
||||
|
||||
INT selectedVal = UpdateAutoDownload::GetSelection(numOfEpisodes, (FALSE != enableAutoDownload));
|
||||
INT iCount = (INT)SNDMSG(hCombo, CB_GETCOUNT, 0, 0L);
|
||||
INT iSelect = CB_ERR;
|
||||
for (INT i = 0; i < iCount && CB_ERR == iSelect; i++)
|
||||
{
|
||||
if (selectedVal == (INT)SNDMSG(hCombo, CB_GETITEMDATA, i, 0L))
|
||||
iSelect = i;
|
||||
}
|
||||
|
||||
if (CB_ERR == iSelect)
|
||||
return FALSE;
|
||||
|
||||
if (iSelect != (INT)SNDMSG(hCombo, CB_GETCURSEL, 0, 0L) &&
|
||||
CB_ERR == SNDMSG(hCombo, CB_SETCURSEL, iSelect, 0))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL ChannelEditor_InitCombobox(HWND hwnd)
|
||||
{
|
||||
HWND hCombo = GetDlgItem(hwnd, IDC_UPDATELIST);
|
||||
HWND hAutoDownloadCombo = GetDlgItem(hwnd, IDC_AUTODOWNLOADLIST);
|
||||
if ( NULL == hCombo || NULL == hAutoDownloadCombo ) return FALSE;
|
||||
|
||||
WCHAR szBuffer[256] = {0};
|
||||
INT iPos = 0;
|
||||
|
||||
SNDMSG(hCombo, WM_SETREDRAW, FALSE, 0L);
|
||||
|
||||
for (INT i = 0; i < Update::TIME_NUMENTRIES; i++)
|
||||
{
|
||||
if (NULL != Update::GetTitle(i, szBuffer, ARRAYSIZE(szBuffer)))
|
||||
{
|
||||
iPos = (INT)SNDMSG(hCombo, CB_ADDSTRING, 0, (LPARAM)szBuffer);
|
||||
if (CB_ERR != iPos)
|
||||
{
|
||||
SNDMSG(hCombo, CB_SETITEMDATA, (WPARAM)iPos, (LPARAM)i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SNDMSG(hCombo, WM_SETREDRAW, TRUE, 0L);
|
||||
|
||||
SNDMSG(hAutoDownloadCombo, WM_SETREDRAW, FALSE, 0L);
|
||||
|
||||
for (INT i = 0; i < UpdateAutoDownload::AUTODOWNLOAD_NUMENTRIES; i++)
|
||||
{
|
||||
if (NULL != UpdateAutoDownload::GetTitle(i, szBuffer, ARRAYSIZE(szBuffer)))
|
||||
{
|
||||
iPos = (INT)SNDMSG(hAutoDownloadCombo, CB_ADDSTRING, 0, (LPARAM)szBuffer);
|
||||
if (CB_ERR != iPos)
|
||||
{
|
||||
SNDMSG(hAutoDownloadCombo, CB_SETITEMDATA, (WPARAM)iPos, (LPARAM)i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SNDMSG(hAutoDownloadCombo, WM_SETREDRAW, TRUE, 0L);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL ChannelEditor_EnableUserSettings(HWND hwnd, BOOL fEnable)
|
||||
{
|
||||
BOOL result;
|
||||
UINT activeButton = (FALSE == fEnable) ? IDC_USEDEFAULTS : IDC_USECUSTOM;
|
||||
|
||||
result = CheckRadioButton(hwnd, IDC_USEDEFAULTS, IDC_USECUSTOM, activeButton);
|
||||
|
||||
if (FALSE != result)
|
||||
{
|
||||
SendDlgItemMessage(hwnd, activeButton, BM_CLICK, 0, 0L);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
#if 0
|
||||
static BOOL ChannelEditor_EnableAutoDownload(HWND hwnd, BOOL fEnable)
|
||||
{
|
||||
BOOL result;
|
||||
result = CheckDlgButton(hwnd, IDC_AUTODOWNLOAD, (FALSE != fEnable) ? BST_CHECKED : BST_UNCHECKED);
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
static BOOL ChannelEditor_SetUrl(HWND hwnd, LPCWSTR pszUrl)
|
||||
{
|
||||
HWND hEdit = GetDlgItem(hwnd, IDC_EDITURL);
|
||||
if (NULL == hEdit) return FALSE;
|
||||
|
||||
return SNDMSG(hEdit, WM_SETTEXT, 0, (LPARAM)pszUrl);
|
||||
}
|
||||
static void ChannelEditor_UpdateTitle(HWND hwnd, BOOL fModified)
|
||||
{
|
||||
CHANNELEDITOR *editor = GetEditor(hwnd);
|
||||
if (NULL == editor) return;
|
||||
|
||||
if (0 != (CEF_CREATENEW & editor->flags))
|
||||
return;
|
||||
|
||||
|
||||
|
||||
WCHAR szBuffer[256] = {0};
|
||||
size_t remaining = ARRAYSIZE(szBuffer);
|
||||
LPWSTR cursor = szBuffer;
|
||||
|
||||
if (FALSE != fModified)
|
||||
{
|
||||
StringCchCopyEx(cursor, remaining, L"*", &cursor, &remaining, 0);
|
||||
}
|
||||
|
||||
WASABI_API_LNGSTRINGW_BUF(IDS_EDIT_CHANNEL, cursor, remaining);
|
||||
INT cchLen = lstrlen(cursor);
|
||||
cursor += cchLen;
|
||||
remaining -= cchLen;
|
||||
|
||||
AutoLock lock (channels);
|
||||
LPCWSTR title = NULL;
|
||||
if (editor->iChannel < channels.size())
|
||||
{
|
||||
Channel *channel = &channels[editor->iChannel];
|
||||
title = channel->title;
|
||||
if (NULL != title && L'\0' != title)
|
||||
{
|
||||
StringCchPrintf(cursor, remaining, L": %s", title);
|
||||
}
|
||||
}
|
||||
|
||||
SendMessage(hwnd, WM_SETTEXT, 0, (LPARAM)szBuffer);
|
||||
}
|
||||
|
||||
static void ChannelEditor_UpdateModifiedState(HWND hwnd)
|
||||
{
|
||||
CHANNELEDITOR *editor = GetEditor(hwnd);
|
||||
if (NULL == editor) return;
|
||||
|
||||
if (0 != (CEF_CREATENEW & editor->flags))
|
||||
return;
|
||||
|
||||
AutoLock lock (channels);
|
||||
|
||||
if (editor->iChannel >= channels.size())
|
||||
return;
|
||||
|
||||
BOOL fModified = FALSE;
|
||||
|
||||
Channel *channel = &channels[editor->iChannel];
|
||||
|
||||
HWND hControl;
|
||||
|
||||
if (FALSE == fModified && (NULL != (hControl = GetDlgItem(hwnd, IDC_USECUSTOM))) &&
|
||||
(BST_CHECKED == SNDMSG(hControl, BM_GETCHECK, 0, 0L)) != (false == channel->useDefaultUpdate))
|
||||
{
|
||||
fModified = TRUE;
|
||||
}
|
||||
|
||||
if (false == channel->useDefaultUpdate)
|
||||
{
|
||||
if (editor->enableAutoDownload != (BOOL)channel->autoDownload ||
|
||||
editor->enableAutoUpdate != (BOOL)channel->autoUpdate ||
|
||||
editor->updateTime != channel->updateTime ||
|
||||
editor->numOfAutoDownloadEpisodes != channel->autoDownloadEpisodes)
|
||||
{
|
||||
fModified = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
hControl = GetDlgItem(hwnd, IDOK);
|
||||
if (NULL != hControl) EnableWindow(hControl, fModified);
|
||||
|
||||
ChannelEditor_UpdateTitle(hwnd, fModified);
|
||||
}
|
||||
|
||||
static BOOL ChannelEditor_Reposition(HWND hwnd)
|
||||
{
|
||||
CHANNELEDITOR *editor = GetEditor(hwnd);
|
||||
if (NULL == editor) return FALSE;
|
||||
|
||||
RECT rectEditor, rectOwner;
|
||||
|
||||
if (0 != (CEF_CENTEROWNER & editor->flags))
|
||||
{
|
||||
if (FALSE == GetWindowRect(editor->hOwner, &rectOwner) ||
|
||||
FALSE == GetWindowRect(hwnd, &rectEditor))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
LONG x = rectOwner.left + ((rectOwner.right - rectOwner.left) - (rectEditor.right - rectEditor.left))/2;
|
||||
LONG y = rectOwner.top + ((rectOwner.bottom - rectOwner.top) - (rectEditor.bottom - rectEditor.top))/2;
|
||||
SetWindowPos(hwnd, NULL, x, y, 0, 0, SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSIZE);
|
||||
SendMessage(hwnd, DM_REPOSITION, 0, 0L);
|
||||
}
|
||||
|
||||
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static INT_PTR ChannelEditor_OnInitDialog(HWND hwnd, HWND hFocus, LPARAM lParam)
|
||||
{
|
||||
|
||||
CHANNELEDITOR *editor = (CHANNELEDITOR*)lParam;
|
||||
if (NULL == editor || FALSE == SetProp(hwnd, MAKEINTATOM(VIEWPROP), editor))
|
||||
{
|
||||
EndDialog(hwnd, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ChannelEditor_InitCombobox(hwnd);
|
||||
|
||||
editor->enableAutoDownload = autoDownload;
|
||||
editor->enableAutoUpdate = autoUpdate;
|
||||
editor->updateTime = updateTime;
|
||||
editor->numOfAutoDownloadEpisodes = autoDownloadEpisodes;
|
||||
|
||||
if (0 != (CEF_CREATENEW & editor->flags))
|
||||
{
|
||||
ChannelEditor_SetUrl(hwnd, L"");
|
||||
ChannelEditor_EnableUserSettings(hwnd, FALSE);
|
||||
}
|
||||
else
|
||||
{
|
||||
AutoLock lock (channels);
|
||||
if (editor->iChannel >= channels.size())
|
||||
{
|
||||
EndDialog(hwnd, 0);
|
||||
return 0;
|
||||
}
|
||||
Channel *channel = &channels[editor->iChannel];
|
||||
|
||||
HWND hControl;
|
||||
|
||||
hControl = GetDlgItem(hwnd, IDC_EDITURL);
|
||||
if (NULL != hControl) SNDMSG(hControl, EM_SETREADONLY, TRUE, 0L);
|
||||
|
||||
hControl = GetDlgItem(hwnd, IDOK);
|
||||
if (NULL != hControl)
|
||||
{
|
||||
WCHAR szBuffer[128] = {0};
|
||||
WASABI_API_LNGSTRINGW_BUF(IDS_SAVE, szBuffer, ARRAYSIZE(szBuffer));
|
||||
SNDMSG(hControl, WM_SETTEXT, 0, (LPARAM)szBuffer);
|
||||
}
|
||||
|
||||
if (false == channel->useDefaultUpdate)
|
||||
{
|
||||
editor->enableAutoDownload = channel->autoDownload;
|
||||
editor->enableAutoUpdate = channel->autoUpdate;
|
||||
editor->updateTime = channel->updateTime;
|
||||
editor->numOfAutoDownloadEpisodes = channel->autoDownloadEpisodes;
|
||||
}
|
||||
|
||||
ChannelEditor_SetUrl(hwnd, channel->url);
|
||||
ChannelEditor_EnableUserSettings(hwnd, !channel->useDefaultUpdate);
|
||||
}
|
||||
|
||||
ChannelEditor_Reposition(hwnd);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void ChannelEditor_OnDestroy(HWND hwnd)
|
||||
{
|
||||
CHANNELEDITOR *editor = GetEditor(hwnd);
|
||||
RemoveProp(hwnd, MAKEINTATOM(VIEWPROP));
|
||||
}
|
||||
|
||||
static void ChannelEditor_UpdateUserSettings(HWND hwnd)
|
||||
{
|
||||
CHANNELEDITOR *editor = GetEditor(hwnd);
|
||||
if (NULL == editor) return;
|
||||
|
||||
HWND hControl;
|
||||
FALSE;
|
||||
|
||||
hControl = GetDlgItem(hwnd, IDC_USECUSTOM);
|
||||
BOOL enableUser = (NULL != hControl && BST_CHECKED == (INT)SNDMSG(hControl, BM_GETCHECK, 0, 0L));
|
||||
|
||||
if (FALSE == enableUser)
|
||||
{
|
||||
ChannelEditor_SetUpdateTime(hwnd, updateTime, autoUpdate);
|
||||
ChannelEditor_SetAutoDownload(hwnd, autoDownloadEpisodes, autoDownload);
|
||||
}
|
||||
else
|
||||
{
|
||||
ChannelEditor_SetUpdateTime(hwnd, editor->updateTime, editor->enableAutoUpdate);
|
||||
ChannelEditor_SetAutoDownload(hwnd, editor->numOfAutoDownloadEpisodes, editor->enableAutoDownload);
|
||||
}
|
||||
|
||||
const INT szControl[] = { IDC_UPDATELIST, IDC_AUTODOWNLOADLIST, IDC_STATIC_UPDATEEVERY, IDC_STATIC_AUTODOWNLOAD, };
|
||||
for (INT i = 0; i < ARRAYSIZE(szControl); i++)
|
||||
{
|
||||
hControl = GetDlgItem(hwnd, szControl[i]);
|
||||
if (NULL != hControl) EnableWindow(hControl, enableUser);
|
||||
}
|
||||
|
||||
ChannelEditor_UpdateModifiedState(hwnd);
|
||||
|
||||
}
|
||||
|
||||
static INT_PTR ChannelEditor_SaveChannel(HWND hwnd)
|
||||
{
|
||||
CHANNELEDITOR *editor = GetEditor(hwnd);
|
||||
if (NULL == editor) return 0;
|
||||
|
||||
AutoLock lock (channels);
|
||||
if (editor->iChannel >= channels.size())
|
||||
return 0;
|
||||
|
||||
HWND hControl = GetDlgItem(hwnd, IDC_USECUSTOM);
|
||||
if (NULL == hControl) return 0;
|
||||
|
||||
Channel *channel = &channels[editor->iChannel];
|
||||
|
||||
if (BST_CHECKED == SNDMSG(hControl, BM_GETCHECK, 0, 0L))
|
||||
{
|
||||
channel->useDefaultUpdate = false;
|
||||
channel->autoDownload = (FALSE != editor->enableAutoDownload);
|
||||
channel->updateTime = editor->updateTime;
|
||||
channel->autoUpdate = (FALSE != editor->enableAutoUpdate);
|
||||
channel->autoDownloadEpisodes = editor->numOfAutoDownloadEpisodes;
|
||||
}
|
||||
else
|
||||
{
|
||||
channel->useDefaultUpdate = true;
|
||||
channel->autoDownload = autoDownload;
|
||||
channel->updateTime = updateTime;
|
||||
channel->autoUpdate = autoUpdate;
|
||||
channel->autoDownloadEpisodes = autoDownloadEpisodes;
|
||||
}
|
||||
|
||||
if (channel->autoUpdate)
|
||||
cloud.Pulse();
|
||||
return
|
||||
IDOK;
|
||||
}
|
||||
|
||||
static DWORD AddUrlThread(void *vBuffer, HWND hwndDlg)
|
||||
{
|
||||
Channel newFeed;
|
||||
newFeed.autoUpdate = false; // TODO check defaults
|
||||
newFeed.autoDownload = false; // leave this as false
|
||||
newFeed.SetURL((const wchar_t *)vBuffer);
|
||||
delete vBuffer;
|
||||
|
||||
int downloadError = DownloadFeedInformation(newFeed);
|
||||
if (downloadError != DOWNLOAD_SUCCESS)
|
||||
return downloadError;
|
||||
|
||||
// TODO check defaults;
|
||||
if (IsDlgButtonChecked(hwndDlg, IDC_USECUSTOM) == BST_CHECKED)
|
||||
{
|
||||
LRESULT timeSelection;
|
||||
timeSelection = SendMessage(GetDlgItem(hwndDlg, IDC_UPDATELIST), CB_GETCURSEL, 0, 0);
|
||||
if (timeSelection != CB_ERR)
|
||||
{
|
||||
newFeed.autoUpdate = Update::GetAutoUpdate(timeSelection);
|
||||
newFeed.updateTime = Update::GetTime(timeSelection);
|
||||
}
|
||||
LRESULT episodesSelection;
|
||||
episodesSelection = SendMessage(GetDlgItem(hwndDlg, IDC_AUTODOWNLOADLIST), CB_GETCURSEL, 0, 0);
|
||||
if (episodesSelection != CB_ERR)
|
||||
{
|
||||
newFeed.autoDownload = UpdateAutoDownload::GetAutoDownload(episodesSelection);
|
||||
newFeed.autoDownloadEpisodes = UpdateAutoDownload::GetAutoDownloadEpisodes(episodesSelection);
|
||||
}
|
||||
newFeed.useDefaultUpdate = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
newFeed.useDefaultUpdate = true;
|
||||
newFeed.autoUpdate = autoUpdate;
|
||||
newFeed.updateTime = updateTime;
|
||||
newFeed.autoDownloadEpisodes = autoDownloadEpisodes;
|
||||
newFeed.autoDownload = autoDownload;
|
||||
}
|
||||
|
||||
//newFeed.title += L" ";
|
||||
AutoLock lock (channels LOCKNAME("AddURL"));
|
||||
if (!channels.AddChannel(newFeed))
|
||||
{
|
||||
wchar_t error_msg[1024] = {0}, titleStr[64] = {0};
|
||||
StringCchPrintf( error_msg, 1024, WASABI_API_LNGSTRINGW( IDS_CHANNEL_ALREADY_PRESENT ), newFeed.title, newFeed.url );
|
||||
MessageBox( hwndDlg, error_msg, WASABI_API_LNGSTRINGW_BUF( IDS_DUPLICATE_CHANNEL, titleStr, 64 ), MB_OK );
|
||||
|
||||
return DOWNLOAD_DUPLICATE;
|
||||
}
|
||||
else
|
||||
{
|
||||
cloud.Pulse(); // TODO why?
|
||||
HWND hView = SubscriptionView_FindWindow();
|
||||
if (NULL != hView)
|
||||
{
|
||||
SubscriptionView_RefreshChannels(hView, TRUE);
|
||||
}
|
||||
|
||||
}
|
||||
return DOWNLOAD_SUCCESS; // success
|
||||
}
|
||||
|
||||
static INT ChannelEditor_AddUrl(HWND hwnd)
|
||||
{
|
||||
size_t length = GetWindowTextLength(GetDlgItem(hwnd, IDC_EDITURL)) + 1;
|
||||
wchar_t *buffer = new wchar_t[length];
|
||||
ZeroMemory(buffer,sizeof(wchar_t)*length);
|
||||
GetDlgItemText(hwnd, IDC_EDITURL, buffer, (int)length);
|
||||
return AddUrlThread((void *)buffer, hwnd);
|
||||
}
|
||||
|
||||
static INT_PTR ChannelEditor_CreateChannel(HWND hwnd)
|
||||
{
|
||||
INT result = ChannelEditor_AddUrl(hwnd);
|
||||
if (DOWNLOAD_SUCCESS == result)
|
||||
return IDOK;
|
||||
|
||||
INT messageId = IDS_ERROR_ADDING_URL;
|
||||
INT titleId = IDS_ERROR_ADDING_URL;
|
||||
|
||||
switch (result)
|
||||
{
|
||||
case DOWNLOAD_ERROR_PARSING_XML: messageId = IDS_ERROR_PARSING_XML_FROM_SERVER; break;
|
||||
case DOWNLOAD_NOTRSS: messageId = IDS_LINK_HAS_NO_RSS_INFO; break;
|
||||
case DOWNLOAD_404: messageId = IDS_INVALID_LINK; break;
|
||||
case DOWNLOAD_NOHTTP: messageId = IDS_NO_JNETLIB; titleId = IDS_JNETLIB_MISSING; break;
|
||||
case DOWNLOAD_NOPARSER: messageId = IDS_NO_EXPAT; titleId = IDS_EXPAT_MISSING; break;
|
||||
case DOWNLOAD_CONNECTIONRESET: messageId = IDS_CONNECTION_RESET_BY_PEER; break;
|
||||
}
|
||||
|
||||
if(result != DOWNLOAD_DUPLICATE)
|
||||
{
|
||||
WCHAR szMessage[512] = {0}, szTitle[128] = {0};
|
||||
|
||||
WASABI_API_LNGSTRINGW_BUF(messageId, szMessage, ARRAYSIZE(szMessage));
|
||||
WASABI_API_LNGSTRINGW_BUF(titleId, szTitle, ARRAYSIZE(szTitle));
|
||||
MessageBox(hwnd, szMessage, szTitle, MB_OK | MB_ICONERROR);
|
||||
}
|
||||
|
||||
return IDIGNORE;
|
||||
}
|
||||
|
||||
static void ChannelEditor_OnCancel(HWND hwnd)
|
||||
{
|
||||
EndDialog(hwnd, IDCANCEL);
|
||||
}
|
||||
|
||||
static void ChannelEditor_OnOk(HWND hwnd)
|
||||
{
|
||||
INT_PTR result = 0;
|
||||
|
||||
CHANNELEDITOR *editor = GetEditor(hwnd);
|
||||
if (NULL != editor)
|
||||
{
|
||||
if (0 == (CEF_CREATENEW & editor->flags))
|
||||
{
|
||||
result = ChannelEditor_SaveChannel(hwnd);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = ChannelEditor_CreateChannel(hwnd);
|
||||
}
|
||||
}
|
||||
|
||||
if (IDIGNORE != result)
|
||||
{
|
||||
EndDialog(hwnd, result);
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
static void ChannelEditor_OnAutoDownloadChanged(HWND hwnd)
|
||||
{
|
||||
CHANNELEDITOR *editor = GetEditor(hwnd);
|
||||
if (NULL == editor) return;
|
||||
|
||||
HWND hControl = GetDlgItem(hwnd, IDC_USECUSTOM);
|
||||
if (NULL == hControl || BST_CHECKED != SNDMSG(hControl, BM_GETCHECK, 0, 0L)) return;
|
||||
|
||||
hControl = GetDlgItem(hwnd, IDC_AUTODOWNLOAD);
|
||||
if (NULL == hControl) return;
|
||||
|
||||
editor->enableAutoDownload = (BST_CHECKED == SNDMSG(hControl, BM_GETCHECK, 0, 0L));
|
||||
|
||||
ChannelEditor_UpdateModifiedState(hwnd);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void ChannelEditor_OnUrlChange(HWND hwnd)
|
||||
{
|
||||
WCHAR szBuffer[4096] = {0};
|
||||
|
||||
HWND hControl = GetDlgItem(hwnd, IDC_EDITURL);
|
||||
if (NULL == hControl || 0 == (INT)SNDMSG(hControl, WM_GETTEXT, (WPARAM)ARRAYSIZE(szBuffer), (LPARAM)szBuffer))
|
||||
szBuffer[0] = L'\0';
|
||||
|
||||
LPCWSTR p = szBuffer;
|
||||
while (L' ' == *p && L'\0' != *p) p++;
|
||||
BOOL enableButton = (L'\0' != *p);
|
||||
|
||||
hControl = GetDlgItem(hwnd, IDOK);
|
||||
if (NULL != hControl)
|
||||
{
|
||||
EnableWindow(hControl, enableButton);
|
||||
}
|
||||
}
|
||||
|
||||
static void ChannelEditor_OnUpdateTimeChange(HWND hwnd)
|
||||
{
|
||||
CHANNELEDITOR *editor = GetEditor(hwnd);
|
||||
if (NULL == editor) return;
|
||||
|
||||
HWND hControl = GetDlgItem(hwnd, IDC_USECUSTOM);
|
||||
if (NULL == hControl || BST_CHECKED != SNDMSG(hControl, BM_GETCHECK, 0, 0L)) return;
|
||||
|
||||
hControl = GetDlgItem(hwnd, IDC_UPDATELIST);
|
||||
if (NULL == hControl) return;
|
||||
|
||||
INT iSelected = (INT)SNDMSG(hControl, CB_GETCURSEL, 0, 0L);
|
||||
if (CB_ERR == iSelected) return;
|
||||
|
||||
INT selectedVal = (INT)SNDMSG(hControl, CB_GETITEMDATA, iSelected, 0L);
|
||||
if (selectedVal < 0 || selectedVal >= Update::TIME_NUMENTRIES) return;
|
||||
|
||||
editor->updateTime = Update::GetTime(selectedVal);
|
||||
editor->enableAutoUpdate = Update::GetAutoUpdate(selectedVal);
|
||||
|
||||
ChannelEditor_UpdateModifiedState(hwnd);
|
||||
}
|
||||
|
||||
static void ChannelEditor_OnUpdateAutoDownloadChange(HWND hwnd)
|
||||
{
|
||||
CHANNELEDITOR *editor = GetEditor(hwnd);
|
||||
if (NULL == editor) return;
|
||||
|
||||
HWND hControl = GetDlgItem(hwnd, IDC_USECUSTOM);
|
||||
if (NULL == hControl || BST_CHECKED != SNDMSG(hControl, BM_GETCHECK, 0, 0L)) return;
|
||||
|
||||
hControl = GetDlgItem(hwnd, IDC_AUTODOWNLOADLIST);
|
||||
if (NULL == hControl) return;
|
||||
|
||||
INT iSelected = (INT)SNDMSG(hControl, CB_GETCURSEL, 0, 0L);
|
||||
if (CB_ERR == iSelected) return;
|
||||
|
||||
INT selectedVal = (INT)SNDMSG(hControl, CB_GETITEMDATA, iSelected, 0L);
|
||||
if (selectedVal < 0 || selectedVal >= UpdateAutoDownload::AUTODOWNLOAD_NUMENTRIES) return;
|
||||
|
||||
editor->numOfAutoDownloadEpisodes = UpdateAutoDownload::GetAutoDownloadEpisodes(selectedVal);
|
||||
editor->enableAutoDownload = UpdateAutoDownload::GetAutoDownload(selectedVal);
|
||||
|
||||
ChannelEditor_UpdateModifiedState(hwnd);
|
||||
}
|
||||
|
||||
static void ChannelEditor_OnCommand(HWND hwnd, UINT commandId, UINT eventId, HWND hControl)
|
||||
{
|
||||
switch(commandId)
|
||||
{
|
||||
case IDCANCEL: ChannelEditor_OnCancel(hwnd); break;
|
||||
case IDOK: ChannelEditor_OnOk(hwnd); break;
|
||||
case IDC_USEDEFAULTS:
|
||||
case IDC_USECUSTOM:
|
||||
switch(eventId)
|
||||
{
|
||||
case BN_CLICKED: ChannelEditor_UpdateUserSettings(hwnd); break;
|
||||
}
|
||||
break;
|
||||
case IDC_EDITURL:
|
||||
switch(eventId)
|
||||
{
|
||||
case EN_CHANGE: ChannelEditor_OnUrlChange(hwnd); break;
|
||||
}
|
||||
break;
|
||||
case IDC_UPDATELIST:
|
||||
switch(eventId)
|
||||
{
|
||||
case CBN_SELCHANGE: ChannelEditor_OnUpdateTimeChange(hwnd); break;
|
||||
}
|
||||
break;
|
||||
case IDC_AUTODOWNLOADLIST:
|
||||
switch(eventId)
|
||||
{
|
||||
case CBN_SELCHANGE: ChannelEditor_OnUpdateAutoDownloadChange(hwnd); break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static INT_PTR CALLBACK ChannelEditor_DialogProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
switch(uMsg)
|
||||
{
|
||||
case WM_INITDIALOG: return ChannelEditor_OnInitDialog(hwnd, (HWND)wParam, lParam);
|
||||
case WM_DESTROY: ChannelEditor_OnDestroy(hwnd); return TRUE;
|
||||
case WM_COMMAND: ChannelEditor_OnCommand(hwnd, LOWORD(wParam), HIWORD(wParam), (HWND)lParam); return TRUE;
|
||||
}
|
||||
return 0;
|
||||
}
|
15
Src/Plugins/Library/ml_wire/channelEditor.h
Normal file
15
Src/Plugins/Library/ml_wire/channelEditor.h
Normal file
@ -0,0 +1,15 @@
|
||||
#ifndef NULLSOFT_PODCAST_PLUGIN_CHANNEL_EDITOR_HEADER
|
||||
#define NULLSOFT_PODCAST_PLUGIN_CHANNEL_EDITOR_HEADER
|
||||
|
||||
#if defined(_MSC_VER) && (_MSC_VER >= 1020)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <wtypes.h>
|
||||
|
||||
#define CEF_CREATENEW 0x00000001
|
||||
#define CEF_CENTEROWNER 0x00000002
|
||||
|
||||
INT_PTR ChannelEditor_Show(HWND hOwner, size_t channelIndex, UINT flags);
|
||||
|
||||
#endif //NULLSOFT_PODCAST_PLUGIN_CHANNEL_EDITOR_HEADER
|
1
Src/Plugins/Library/ml_wire/date.c
Normal file
1
Src/Plugins/Library/ml_wire/date.c
Normal file
@ -0,0 +1 @@
|
||||
#include "time.h"
|
20
Src/Plugins/Library/ml_wire/date.h
Normal file
20
Src/Plugins/Library/ml_wire/date.h
Normal file
@ -0,0 +1,20 @@
|
||||
#ifndef _OD_DATE_
|
||||
#define _OD_DATE_
|
||||
|
||||
#include <time.h>
|
||||
|
||||
|
||||
|
||||
/* These functions all work with "Internet"(RFC 822) format Date/Time strings only */
|
||||
/* An example of an RFC 822 format Date/Time string is "Thu, 28 Aug 2003 21:30:47 EDT" */
|
||||
|
||||
/* converts the RFC 822 format date string into UTC Calendar time */
|
||||
time_t getDateSecs(char *date);
|
||||
|
||||
/* returns a string that represents the given UTC Calendar time value as an
|
||||
RFC 822 format string. The buffer is user-supplied and must be at least
|
||||
30 bytes in size. */
|
||||
char *getDateStr(time_t tmval, char *buffer, int gmt);
|
||||
|
||||
#endif /*_OD_DATE_*/
|
||||
|
171
Src/Plugins/Library/ml_wire/db.cpp
Normal file
171
Src/Plugins/Library/ml_wire/db.cpp
Normal file
@ -0,0 +1,171 @@
|
||||
#include <shlwapi.h>
|
||||
|
||||
#include "api__ml_wire.h"
|
||||
#include "Downloaded.h"
|
||||
#include "../nde/nde_c.h"
|
||||
#include "../nu/AutoLock.h"
|
||||
|
||||
/* DB Schema
|
||||
ChannelTitle
|
||||
ItemUrl
|
||||
ItemTitle
|
||||
PublishDate
|
||||
Length
|
||||
Filename
|
||||
*/
|
||||
|
||||
static Nullsoft::Utility::LockGuard dbcs;
|
||||
static nde_table_t table = 0;
|
||||
static nde_database_t db = 0;
|
||||
using namespace Nullsoft::Utility;
|
||||
|
||||
enum
|
||||
{
|
||||
DB_ID_CHANNELTITLE = 0,
|
||||
DB_ID_ITEMURL = 1,
|
||||
DB_ID_ITEMTITLE = 2,
|
||||
DB_ID_PUBLISHDATE = 3,
|
||||
DB_ID_LENGTH = 4,
|
||||
DB_ID_FILENAME = 5
|
||||
};
|
||||
|
||||
static bool OpenDatabase()
|
||||
{
|
||||
AutoLock lock(dbcs);
|
||||
if (!db)
|
||||
db = NDE_CreateDatabase();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CloseDatabase()
|
||||
{
|
||||
AutoLock lock( dbcs );
|
||||
if ( db )
|
||||
{
|
||||
if ( table )
|
||||
NDE_Database_CloseTable( db, table );
|
||||
|
||||
NDE_DestroyDatabase( db );
|
||||
}
|
||||
|
||||
db = 0;
|
||||
}
|
||||
|
||||
static void CreateFields(nde_table_t table)
|
||||
{
|
||||
// create defaults
|
||||
NDE_Table_NewColumnW(table, DB_ID_CHANNELTITLE, L"channeltitle", FIELD_STRING);
|
||||
NDE_Table_NewColumnW(table, DB_ID_ITEMURL, L"itemurl", FIELD_STRING);
|
||||
NDE_Table_NewColumnW(table, DB_ID_ITEMTITLE, L"itemtitle", FIELD_STRING);
|
||||
NDE_Table_NewColumnW(table, DB_ID_PUBLISHDATE, L"publishdate", FIELD_DATETIME);
|
||||
NDE_Table_NewColumnW(table, DB_ID_LENGTH, L"length", FIELD_INTEGER);
|
||||
NDE_Table_NewColumnW(table, DB_ID_FILENAME, L"filename", FIELD_FILENAME);
|
||||
NDE_Table_PostColumns(table);
|
||||
NDE_Table_AddIndexByIDW(table, DB_ID_ITEMURL, L"itemurl");
|
||||
}
|
||||
|
||||
static bool OpenTable()
|
||||
{
|
||||
AutoLock lock( dbcs );
|
||||
if ( !OpenDatabase() )
|
||||
return false;
|
||||
|
||||
if ( !table )
|
||||
{
|
||||
const wchar_t *inidir = WASABI_API_APP->path_getUserSettingsPath();
|
||||
wchar_t tablePath[ MAX_PATH ] = { 0 }, indexPath[ MAX_PATH ] = { 0 };
|
||||
|
||||
PathCombineW( tablePath, inidir, L"plugins" );
|
||||
PathAppendW( tablePath, L"podcasts.dat" );
|
||||
PathCombineW( indexPath, inidir, L"plugins" );
|
||||
PathAppendW( indexPath, L"podcasts.idx" );
|
||||
|
||||
table = NDE_Database_OpenTable( db, tablePath, indexPath, NDE_OPEN_ALWAYS, NDE_CACHE );
|
||||
if ( table )
|
||||
CreateFields( table );
|
||||
}
|
||||
|
||||
return !!table;
|
||||
}
|
||||
|
||||
static void db_add( nde_scanner_t s, unsigned char id, wchar_t *data )
|
||||
{
|
||||
if ( data )
|
||||
{
|
||||
nde_field_t f = NDE_Scanner_NewFieldByID( s, id );
|
||||
NDE_StringField_SetString( f, data );
|
||||
}
|
||||
}
|
||||
|
||||
static void db_add_int( nde_scanner_t s, unsigned char id, int data )
|
||||
{
|
||||
if ( data )
|
||||
{
|
||||
nde_field_t f = NDE_Scanner_NewFieldByID( s, id );
|
||||
NDE_IntegerField_SetValue( f, data );
|
||||
}
|
||||
}
|
||||
|
||||
static void db_add_time( nde_scanner_t s, unsigned char id, time_t data )
|
||||
{
|
||||
if ( data )
|
||||
{
|
||||
nde_field_t f = NDE_Scanner_NewFieldByID( s, id );
|
||||
NDE_IntegerField_SetValue( f, static_cast<int>( data ) );
|
||||
}
|
||||
}
|
||||
|
||||
bool AddPodcastData( const DownloadedFile &data )
|
||||
{
|
||||
AutoLock lock( dbcs );
|
||||
if ( !OpenTable() )
|
||||
return false;
|
||||
|
||||
nde_scanner_t s = NDE_Table_CreateScanner( table );
|
||||
if ( s )
|
||||
{
|
||||
NDE_Scanner_New( s );
|
||||
db_add( s, DB_ID_CHANNELTITLE, data.channel );
|
||||
db_add( s, DB_ID_ITEMURL, data.url );
|
||||
db_add( s, DB_ID_ITEMTITLE, data.item );
|
||||
db_add_time( s, DB_ID_PUBLISHDATE, data.publishDate );
|
||||
db_add_int( s, DB_ID_LENGTH, (int)data.totalSize );
|
||||
db_add( s, DB_ID_FILENAME, data.path );
|
||||
NDE_Scanner_Post( s );
|
||||
NDE_Table_DestroyScanner( table, s );
|
||||
NDE_Table_Sync( table );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IsPodcastDownloaded( const wchar_t *url )
|
||||
{
|
||||
AutoLock lock( dbcs );
|
||||
if ( !OpenTable() )
|
||||
return false;
|
||||
|
||||
nde_scanner_t s = NDE_Table_CreateScanner( table );
|
||||
if ( s )
|
||||
{
|
||||
if ( NDE_Scanner_LocateString( s, DB_ID_ITEMURL, FIRST_RECORD, url ) )
|
||||
{
|
||||
NDE_Table_DestroyScanner( table, s );
|
||||
return true;
|
||||
}
|
||||
|
||||
NDE_Table_DestroyScanner( table, s );
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void CompactDatabase()
|
||||
{
|
||||
AutoLock lock( dbcs );
|
||||
if ( OpenTable() )
|
||||
NDE_Table_Compact( table );
|
||||
}
|
17
Src/Plugins/Library/ml_wire/errors.h
Normal file
17
Src/Plugins/Library/ml_wire/errors.h
Normal file
@ -0,0 +1,17 @@
|
||||
#ifndef NULLSOFT_ML_WIRE_ERRORS_H
|
||||
#define NULLSOFT_ML_WIRE_ERRORS_H
|
||||
|
||||
enum
|
||||
{
|
||||
DOWNLOAD_SUCCESS = 0,
|
||||
DOWNLOAD_404,
|
||||
DOWNLOAD_TIMEOUT,
|
||||
DOWNLOAD_NOTRSS,
|
||||
DOWNLOAD_DUPLICATE,
|
||||
DOWNLOAD_NOHTTP,
|
||||
DOWNLOAD_NOPARSER,
|
||||
DOWNLOAD_CONNECTIONRESET,
|
||||
DOWNLOAD_ERROR_PARSING_XML,
|
||||
};
|
||||
|
||||
#endif
|
15
Src/Plugins/Library/ml_wire/ifc_article.h
Normal file
15
Src/Plugins/Library/ml_wire/ifc_article.h
Normal file
@ -0,0 +1,15 @@
|
||||
#ifndef NULLSOFT_ML_WIRE_IFC_ARTICLE_H
|
||||
#define NULLSOFT_ML_WIRE_IFC_ARTICLE_H
|
||||
|
||||
#include <bfc/dispatch.h>
|
||||
|
||||
class ifc_article
|
||||
{
|
||||
protected:
|
||||
ifc_article() {}
|
||||
~ifc_article() {}
|
||||
public:
|
||||
|
||||
};
|
||||
|
||||
#endif
|
39
Src/Plugins/Library/ml_wire/ifc_podcast.h
Normal file
39
Src/Plugins/Library/ml_wire/ifc_podcast.h
Normal file
@ -0,0 +1,39 @@
|
||||
#ifndef NULLSOFT_ML_WIRE_IFC_PODCAST_H
|
||||
#define NULLSOFT_ML_WIRE_IFC_PODCAST_H
|
||||
|
||||
#include <bfc/dispatch.h>
|
||||
class ifc_podcast : public Dispatchable
|
||||
{
|
||||
protected:
|
||||
ifc_podcast() {}
|
||||
~ifc_podcast() {}
|
||||
public:
|
||||
//int GetUrl(wchar_t *str, size_t len);
|
||||
int GetTitle(wchar_t *str, size_t len);
|
||||
//int GetLink(wchar_t *str, size_t len);
|
||||
//int GetDescription(wchar_t *str, size_t len);
|
||||
size_t GetNumArticles();
|
||||
// TODO: ifc_article *EnumArticle(size_t i);
|
||||
|
||||
enum
|
||||
{
|
||||
IFC_PODCAST_GETURL = 0,
|
||||
IFC_PODCAST_GETTITLE = 1,
|
||||
IFC_PODCAST_GETLINK = 2,
|
||||
IFC_PODCAST_GETDESCRIPTION = 3,
|
||||
IFC_PODCAST_GETNUMARTICLES = 4,
|
||||
};
|
||||
};
|
||||
|
||||
inline int ifc_podcast::GetTitle(wchar_t *str, size_t len)
|
||||
{
|
||||
return _call(IFC_PODCAST_GETTITLE, (int)1, str, len);
|
||||
}
|
||||
|
||||
|
||||
inline size_t ifc_podcast::GetNumArticles()
|
||||
{
|
||||
return _call(IFC_PODCAST_GETNUMARTICLES, (size_t)0);
|
||||
}
|
||||
|
||||
#endif
|
215
Src/Plugins/Library/ml_wire/layout.cpp
Normal file
215
Src/Plugins/Library/ml_wire/layout.cpp
Normal file
@ -0,0 +1,215 @@
|
||||
#include "./layout.h"
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
BOOL Layout_Initialize( HWND hwnd, const INT *itemList, INT itemCount, LAYOUTITEM *layout )
|
||||
{
|
||||
if ( NULL == itemList || NULL == layout )
|
||||
return FALSE;
|
||||
|
||||
LAYOUTITEM *item;
|
||||
|
||||
for ( INT i = 0; i < itemCount; i++ )
|
||||
{
|
||||
item = &layout[ i ];
|
||||
item->hwnd = GetDlgItem( hwnd, itemList[ i ] );
|
||||
if ( item->hwnd == NULL )
|
||||
continue;
|
||||
|
||||
if ( FALSE == GetWindowRect( item->hwnd, &item->rect ) )
|
||||
SetRectEmpty( &item->rect );
|
||||
else
|
||||
MapWindowPoints( HWND_DESKTOP, hwnd, (POINT *)&item->rect, 2 );
|
||||
|
||||
item->cx = item->rect.right - item->rect.left;
|
||||
item->cy = item->rect.bottom - item->rect.top;
|
||||
item->x = item->rect.left;
|
||||
item->y = item->rect.top;
|
||||
item->flags = 0;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL Layout_Perform( HWND hwnd, LAYOUTITEM *layout, INT layoutCount, BOOL fRedraw )
|
||||
{
|
||||
HDWP hdwp, hdwpTemp;
|
||||
hdwp = BeginDeferWindowPos( layoutCount );
|
||||
if ( hdwp == NULL )
|
||||
return FALSE;
|
||||
|
||||
UINT baseFlags = SWP_NOACTIVATE | SWP_NOZORDER;
|
||||
if ( fRedraw == FALSE )
|
||||
baseFlags |= ( SWP_NOREDRAW | SWP_NOCOPYBITS );
|
||||
|
||||
LAYOUTITEM *item;
|
||||
for ( INT i = 0; i < layoutCount; i++ )
|
||||
{
|
||||
item = &layout[ i ];
|
||||
if ( item->hwnd == NULL )
|
||||
continue;
|
||||
|
||||
UINT flags = baseFlags | ( item->flags & ~( SWP_HIDEWINDOW | SWP_SHOWWINDOW ) );
|
||||
if ( item->x == item->rect.left && item->y == item->rect.top )
|
||||
flags |= SWP_NOMOVE;
|
||||
|
||||
if ( item->cx == ( item->rect.right - item->rect.left ) && item->cy == ( item->rect.bottom - item->rect.top ) )
|
||||
flags |= SWP_NOSIZE;
|
||||
|
||||
if ( ( SWP_HIDEWINDOW & item->flags ) != 0 )
|
||||
{
|
||||
UINT windowStyle = GetWindowLongPtr( item->hwnd, GWL_STYLE );
|
||||
if ( ( WS_VISIBLE & windowStyle ) != 0 )
|
||||
{
|
||||
SetWindowLongPtr( item->hwnd, GWL_STYLE, windowStyle & ~WS_VISIBLE );
|
||||
if ( FALSE != fRedraw )
|
||||
{
|
||||
RedrawWindow( hwnd, &item->rect, NULL, RDW_INVALIDATE | RDW_ERASE );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( ( SWP_NOSIZE | SWP_NOMOVE ) != ( ( SWP_NOSIZE | SWP_NOMOVE | SWP_FRAMECHANGED ) & flags ) )
|
||||
{
|
||||
hdwpTemp = DeferWindowPos( hdwp, item->hwnd, NULL, item->x, item->y, item->cx, item->cy, flags );
|
||||
if ( hdwpTemp == NULL )
|
||||
break;
|
||||
|
||||
hdwp = hdwpTemp;
|
||||
}
|
||||
}
|
||||
|
||||
BOOL result = ( hdwp != NULL ) ? EndDeferWindowPos( hdwp ) : FALSE;
|
||||
|
||||
for ( INT i = 0; i < layoutCount; i++ )
|
||||
{
|
||||
item = &layout[ i ];
|
||||
if ( NULL != item->hwnd && 0 != ( SWP_SHOWWINDOW & item->flags ) )
|
||||
{
|
||||
UINT windowStyle = GetWindowLongPtr( item->hwnd, GWL_STYLE );
|
||||
if ( 0 == ( WS_VISIBLE & windowStyle ) )
|
||||
{
|
||||
SetWindowLongPtr( item->hwnd, GWL_STYLE, windowStyle | WS_VISIBLE );
|
||||
if ( FALSE != fRedraw )
|
||||
RedrawWindow( item->hwnd, NULL, NULL, RDW_INVALIDATE | RDW_ERASE | RDW_FRAME | RDW_ALLCHILDREN );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void Layout_SetItemVisibility( const RECT *rect, LAYOUTITEM *item )
|
||||
{
|
||||
if ( NULL == item || NULL == item->hwnd )
|
||||
return;
|
||||
|
||||
BOOL outsider = ( item->cx <= 0 || item->cy <= 0 ||
|
||||
item->x >= rect->right || item->y >= rect->bottom ||
|
||||
( item->x + item->cx ) < rect->left || ( item->y + item->cy ) < rect->top );
|
||||
|
||||
UINT windowStyle = GetWindowLongPtr( item->hwnd, GWL_STYLE );
|
||||
if ( 0 == ( WS_VISIBLE & windowStyle ) )
|
||||
{
|
||||
if ( !outsider )
|
||||
{
|
||||
item->flags |= SWP_SHOWWINDOW;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( outsider )
|
||||
{
|
||||
item->flags |= SWP_HIDEWINDOW;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BOOL Layout_SetVisibility( const RECT *rect, LAYOUTITEM *layout, INT layoutCount )
|
||||
{
|
||||
if ( NULL == rect || NULL == layout )
|
||||
return FALSE;
|
||||
|
||||
for ( INT i = 0; i < layoutCount; i++ )
|
||||
{
|
||||
Layout_SetItemVisibility( rect, &layout[ i ] );
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL Layout_SetVisibilityEx( const RECT *rect, const INT *indexList, INT indexCount, LAYOUTITEM *layout )
|
||||
{
|
||||
if ( NULL == rect || NULL == indexList || NULL == layout )
|
||||
return FALSE;
|
||||
|
||||
for ( INT i = 0; i < indexCount; i++ )
|
||||
{
|
||||
Layout_SetItemVisibility( rect, &layout[ indexList[ i ] ] );
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
BOOL Layout_GetValidRgn( HRGN validRgn, POINTS parrentOffset, const RECT *validRect, LAYOUTITEM *layout, INT layoutCount )
|
||||
{
|
||||
if ( NULL == validRgn )
|
||||
return FALSE;
|
||||
|
||||
SetRectRgn( validRgn, 0, 0, 0, 0 );
|
||||
|
||||
if ( NULL == layout )
|
||||
return FALSE;
|
||||
|
||||
HRGN rgn = CreateRectRgn( 0, 0, 0, 0 );
|
||||
if ( NULL == rgn )
|
||||
return FALSE;
|
||||
|
||||
LAYOUTITEM *item;
|
||||
LONG l, t, r, b;
|
||||
|
||||
for ( INT i = 0; i < layoutCount; i++ )
|
||||
{
|
||||
item = &layout[ i ];
|
||||
if ( NULL != item->hwnd && 0 == ( ( SWP_HIDEWINDOW | SWP_SHOWWINDOW ) & item->flags ) )
|
||||
{
|
||||
l = item->x + parrentOffset.x;
|
||||
t = item->y + parrentOffset.y;
|
||||
r = l + item->cx;
|
||||
b = t + item->cy;
|
||||
if ( 0 != ( SWP_NOREDRAW & item->flags ) || ( l == item->rect.left && t == item->rect.top && r == item->rect.right && b == item->rect.bottom ) )
|
||||
{
|
||||
if ( NULL != validRect )
|
||||
{
|
||||
if ( l < validRect->left )
|
||||
l = validRect->left;
|
||||
|
||||
if ( t < validRect->top )
|
||||
t = validRect->top;
|
||||
|
||||
if ( r > validRect->right )
|
||||
r = validRect->right;
|
||||
|
||||
if ( b > validRect->bottom )
|
||||
b = validRect->bottom;
|
||||
}
|
||||
|
||||
if ( l < r && t < b )
|
||||
{
|
||||
SetRectRgn( rgn, l, t, r, b );
|
||||
CombineRgn( validRgn, validRgn, rgn, RGN_OR );
|
||||
|
||||
if ( NULLREGION != GetUpdateRgn( item->hwnd, rgn, FALSE ) )
|
||||
{
|
||||
OffsetRgn( rgn, parrentOffset.x, parrentOffset.y );
|
||||
CombineRgn( validRgn, validRgn, rgn, RGN_DIFF );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DeleteObject( rgn );
|
||||
|
||||
return TRUE;
|
||||
}
|
43
Src/Plugins/Library/ml_wire/layout.h
Normal file
43
Src/Plugins/Library/ml_wire/layout.h
Normal file
@ -0,0 +1,43 @@
|
||||
#ifndef NULLSOFT_PODCAST_PLUGIN_LAYOUT_HEADER
|
||||
#define NULLSOFT_PODCAST_PLUGIN_LAYOUT_HEADER
|
||||
|
||||
#if defined(_MSC_VER) && (_MSC_VER >= 1020)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <wtypes.h>
|
||||
|
||||
typedef struct __LAYOUTITEM
|
||||
{
|
||||
HWND hwnd;
|
||||
LONG x;
|
||||
LONG y;
|
||||
LONG cx;
|
||||
LONG cy;
|
||||
UINT flags;
|
||||
RECT rect;
|
||||
} LAYOUTITEM;
|
||||
|
||||
|
||||
#define LI_GET_R(__li) ((__li).x + (__li).cx)
|
||||
#define LI_GET_B(__li) ((__li).y + (__li).cy)
|
||||
#define LI_EXPAND_W(__li, __delta) { (__li).cx += (__delta); }
|
||||
#define LI_EXPAND_H(__li, __delta) { (__li).cy += (__delta); }
|
||||
#define LI_SHIFT_L(__li, __delta) { (__li).x += (__delta); }
|
||||
#define LI_SHIFT_T(__li, __delta) { { (__li).y += (__delta); }
|
||||
#define LI_SET_L(__li, __val) { (__li).x = (__val); }
|
||||
#define LI_SET_T(__li, __val) { (__li).y = (__val); }
|
||||
#define LI_SET_W(__li, __val) { (__li).cx = (__val); }
|
||||
#define LI_SET_H(__li, __val) { (__li).cy = (__val); }
|
||||
#define LI_SET_R(__li, __val) { (__li).cx = ((__val) - (__li).x); }
|
||||
#define LI_SET_B(__li, __val) { (__li).cy = ((__val) - (__li).y); }
|
||||
|
||||
BOOL Layout_Initialize(HWND hwnd, const INT *itemList, INT itemCount, LAYOUTITEM *layout);
|
||||
BOOL Layout_SetVisibilityEx(const RECT *rect, const INT *indexList, INT indexCount, LAYOUTITEM *layout);
|
||||
BOOL Layout_SetVisibility(const RECT *rect, LAYOUTITEM *layout, INT layoutCount);
|
||||
BOOL Layout_Perform(HWND hwnd, LAYOUTITEM *layout, INT layoutCount, BOOL fRedraw);
|
||||
|
||||
BOOL Layout_GetValidRgn(HRGN validRgn, POINTS parrentOffset, const RECT *validRect, LAYOUTITEM *layout, INT layoutCount);
|
||||
|
||||
|
||||
#endif //NULLSOFT_PODCAST_PLUGIN_LAYOUT_HEADER
|
396
Src/Plugins/Library/ml_wire/ml_podcast.rc
Normal file
396
Src/Plugins/Library/ml_wire/ml_podcast.rc
Normal file
@ -0,0 +1,396 @@
|
||||
// Microsoft Visual C++ generated resource script.
|
||||
//
|
||||
#include "resource.h"
|
||||
|
||||
#define APSTUDIO_READONLY_SYMBOLS
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Generated from the TEXTINCLUDE 2 resource.
|
||||
//
|
||||
#include "afxres.h"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
#undef APSTUDIO_READONLY_SYMBOLS
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// English (U.S.) resources
|
||||
|
||||
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
|
||||
#ifdef _WIN32
|
||||
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
|
||||
#pragma code_page(1252)
|
||||
#endif //_WIN32
|
||||
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// TEXTINCLUDE
|
||||
//
|
||||
|
||||
1 TEXTINCLUDE
|
||||
BEGIN
|
||||
"resource.h\0"
|
||||
END
|
||||
|
||||
2 TEXTINCLUDE
|
||||
BEGIN
|
||||
"#include ""afxres.h""\r\0"
|
||||
END
|
||||
|
||||
3 TEXTINCLUDE
|
||||
BEGIN
|
||||
"#include ""version.rc2""\r\n"
|
||||
"\0"
|
||||
END
|
||||
|
||||
#endif // APSTUDIO_INVOKED
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Dialog
|
||||
//
|
||||
|
||||
IDD_PODCAST DIALOGEX 0, 0, 285, 277
|
||||
STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN
|
||||
EXSTYLE WS_EX_CONTROLPARENT
|
||||
FONT 8, "MS Shell Dlg", 400, 0, 0x1
|
||||
BEGIN
|
||||
CONTROL "",IDC_CHANNELLIST,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | LVS_OWNERDATA | WS_TABSTOP,0,0,122,181,WS_EX_CLIENTEDGE
|
||||
CONTROL "",IDC_VDIV,"Static",SS_BLACKFRAME,122,0,5,182
|
||||
CONTROL "",IDC_ITEMLIST,"SysListView32",LVS_REPORT | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | LVS_OWNERDATA | WS_TABSTOP,127,0,156,181,WS_EX_CLIENTEDGE
|
||||
PUSHBUTTON "Directory",IDC_FINDNEW,2,183,41,11
|
||||
PUSHBUTTON "Add",IDC_ADD,45,183,35,11
|
||||
PUSHBUTTON "Edit",IDC_EDIT,83,183,35,11
|
||||
PUSHBUTTON "Delete",IDC_DELETE,121,183,35,11
|
||||
PUSHBUTTON "Update",IDC_REFRESH,159,183,35,11
|
||||
CONTROL "",IDC_HDIV,"Static",SS_BLACKFRAME,0,194,285,5
|
||||
CONTROL "",IDC_EPISODE_INFO,"SysListView32",LVS_REPORT | LVS_SINGLESEL | LVS_SHOWSELALWAYS | LVS_ALIGNLEFT | LVS_OWNERDATA | WS_TABSTOP,0,198,285,10,WS_EX_CLIENTEDGE
|
||||
CONTROL "",IDC_DESCRIPTION,"Static",SS_BLACKRECT,0,208,283,55
|
||||
PUSHBUTTON "Play",IDC_PLAY,0,266,37,11
|
||||
PUSHBUTTON "Enqueue",IDC_ENQUEUE,39,266,37,11
|
||||
PUSHBUTTON "Download",IDC_DOWNLOAD,78,266,40,11
|
||||
PUSHBUTTON "Visit site",IDC_VISIT,120,266,40,11
|
||||
CONTROL "",IDC_STATUS,"Static",SS_LEFTNOWORDWRAP | SS_CENTERIMAGE | SS_WORDELLIPSIS | WS_GROUP,164,266,120,11
|
||||
END
|
||||
|
||||
IDD_ADDURL DIALOGEX 0, 0, 270, 90
|
||||
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
|
||||
EXSTYLE WS_EX_CONTROLPARENT
|
||||
CAPTION "Add RSS Subscription"
|
||||
FONT 8, "MS Shell Dlg", 400, 0, 0x1
|
||||
BEGIN
|
||||
EDITTEXT IDC_EDITURL,4,7,262,14,ES_AUTOHSCROLL
|
||||
CONTROL "Use default settings",IDC_USEDEFAULTS,"Button",BS_AUTORADIOBUTTON,8,25,88,10
|
||||
CONTROL "Use custom settings",IDC_USECUSTOM,"Button",BS_AUTORADIOBUTTON,114,25,93,10
|
||||
LTEXT "Update Every:",IDC_STATIC_UPDATEEVERY,8,42,48,8,WS_DISABLED
|
||||
COMBOBOX IDC_UPDATELIST,59,40,70,95,CBS_DROPDOWNLIST | WS_DISABLED | WS_VSCROLL | WS_TABSTOP
|
||||
LTEXT "Download New Episodes:",IDC_STATIC_AUTODOWNLOAD,8,58,81,8,WS_DISABLED
|
||||
COMBOBOX IDC_AUTODOWNLOADLIST,93,56,122,30,CBS_DROPDOWNLIST | WS_DISABLED | WS_VSCROLL | WS_TABSTOP
|
||||
PUSHBUTTON "Add",IDOK,162,73,50,13
|
||||
PUSHBUTTON "Cancel",IDCANCEL,216,73,50,13
|
||||
END
|
||||
|
||||
IDD_DOWNLOADS DIALOGEX 0, 0, 266, 92
|
||||
STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN
|
||||
EXSTYLE WS_EX_CONTROLPARENT
|
||||
FONT 8, "MS Shell Dlg", 400, 0, 0x1
|
||||
BEGIN
|
||||
CONTROL "",IDC_DOWNLOADLIST,"SysListView32",LVS_REPORT | LVS_ALIGNLEFT | LVS_OWNERDATA | WS_TABSTOP,0,0,264,79
|
||||
CONTROL "Play",IDC_PLAY,"Button",BS_OWNERDRAW | WS_TABSTOP,0,81,37,11
|
||||
CONTROL "Enqueue",IDC_ENQUEUE,"Button",BS_OWNERDRAW | WS_TABSTOP,40,81,37,11
|
||||
CONTROL "Remove",IDC_REMOVE,"Button",BS_OWNERDRAW | WS_TABSTOP,80,81,37,11
|
||||
CONTROL "Clean up",IDC_CLEANUP,"Button",BS_OWNERDRAW | WS_TABSTOP,120,81,37,11
|
||||
CONTROL "",IDC_STATUS,"Static",SS_LEFTNOWORDWRAP | SS_CENTERIMAGE | SS_ENDELLIPSIS | WS_GROUP,163,81,102,11
|
||||
END
|
||||
|
||||
IDD_PREFERENCES DIALOGEX 0, 0, 272, 247
|
||||
STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_SYSMENU
|
||||
EXSTYLE WS_EX_CONTROLPARENT
|
||||
FONT 8, "MS Shell Dlg", 400, 0, 0x1
|
||||
BEGIN
|
||||
GROUPBOX "Podcasts",IDC_STATIC,0,0,272,246
|
||||
GROUPBOX "Subscription Updates",IDC_STATIC,5,11,260,53
|
||||
LTEXT "Update every:",IDC_STATICUPDATEEVERY,11,28,50,9,SS_CENTERIMAGE
|
||||
COMBOBOX IDC_UPDATELIST,65,27,94,131,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
|
||||
CONTROL "Update on launch",IDC_UPDATEONLAUNCH,"Button",BS_AUTOCHECKBOX | BS_LEFT | WS_TABSTOP,181,28,72,10
|
||||
LTEXT "Download New Episodes:",IDC_STATICAUTODOWNLOAD,11,47,84,9
|
||||
COMBOBOX IDC_AUTODOWNLOADLIST,99,45,112,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
|
||||
GROUPBOX "Podcast Download Location",IDC_STATIC,5,67,260,34
|
||||
EDITTEXT IDC_DOWNLOADLOCATION,11,81,198,13,ES_AUTOHSCROLL
|
||||
PUSHBUTTON "Browse...",IDC_BROWSE,209,81,50,13
|
||||
GROUPBOX "'Podcast Directory' Service",IDC_STATIC,5,105,260,72
|
||||
LTEXT "This allows you to specify an alternative Podcast Directory service to display in the 'Podcast Directory' node. Leave blank to reset to the default service.",IDC_STATIC,11,116,248,18
|
||||
EDITTEXT IDC_DIRECTORYURL,11,138,248,13,ES_AUTOHSCROLL
|
||||
LTEXT "Note: To subscribe to feeds when using an alternative Podcast Directory service, the service will need to use the available Winamp Javascript API.",IDC_STATIC,11,155,248,18,WS_DISABLED
|
||||
END
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// DESIGNINFO
|
||||
//
|
||||
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
GUIDELINES DESIGNINFO
|
||||
BEGIN
|
||||
IDD_ADDURL, DIALOG
|
||||
BEGIN
|
||||
LEFTMARGIN, 4
|
||||
RIGHTMARGIN, 266
|
||||
TOPMARGIN, 7
|
||||
BOTTOMMARGIN, 86
|
||||
END
|
||||
|
||||
IDD_PREFERENCES, DIALOG
|
||||
BEGIN
|
||||
BOTTOMMARGIN, 246
|
||||
END
|
||||
END
|
||||
#endif // APSTUDIO_INVOKED
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Menu
|
||||
//
|
||||
|
||||
IDR_MENU1 MENU
|
||||
BEGIN
|
||||
POPUP "Podcast"
|
||||
BEGIN
|
||||
MENUITEM "Update podcast\tF5", IDC_REFRESH
|
||||
MENUITEM "Edit podcast...\tF2", IDC_EDIT
|
||||
MENUITEM "Delete podcast\tDel", IDC_DELETE
|
||||
MENUITEM SEPARATOR
|
||||
MENUITEM "Visit site\tF7", IDC_VISIT
|
||||
MENUITEM SEPARATOR
|
||||
MENUITEM "Add podcast...\tInsert", IDC_ADD
|
||||
MENUITEM "Update all\tShift+F5", IDC_REFRESHALL
|
||||
END
|
||||
POPUP "Episode"
|
||||
BEGIN
|
||||
MENUITEM "Play media", IDC_PLAY
|
||||
MENUITEM "Enqueue media", IDC_ENQUEUE
|
||||
POPUP "Send to:"
|
||||
BEGIN
|
||||
MENUITEM "", ID_Menu
|
||||
END
|
||||
MENUITEM SEPARATOR
|
||||
MENUITEM "Download media", IDC_DOWNLOAD
|
||||
MENUITEM SEPARATOR
|
||||
MENUITEM "Select all\tCtrl+A", IDC_SELECTALL
|
||||
MENUITEM "Explore media folder\tCtrl+F", ID_DOWNLOADS_EXPLORERITEMFOLDER
|
||||
MENUITEM "Visit site\tF7", IDC_VISIT
|
||||
MENUITEM SEPARATOR
|
||||
MENUITEM "Update podcast\tF5", IDC_REFRESH
|
||||
END
|
||||
POPUP "Downloads"
|
||||
BEGIN
|
||||
MENUITEM "Play file\tEnter", IDC_PLAY
|
||||
MENUITEM "Enqueue file\tShift+Enter", IDC_ENQUEUE
|
||||
POPUP "Send to:"
|
||||
BEGIN
|
||||
MENUITEM "", ID_Menu
|
||||
END
|
||||
MENUITEM SEPARATOR
|
||||
MENUITEM "Select all\tCtrl+A", IDC_SELECTALL
|
||||
MENUITEM "View file info...\tAlt+3", IDC_INFOBOX
|
||||
MENUITEM "Explore item folder\tCtrl+F", ID_DOWNLOADS_EXPLORERITEMFOLDER
|
||||
MENUITEM SEPARATOR
|
||||
MENUITEM "Remove from list\tDel", IDC_REMOVE
|
||||
MENUITEM "Delete file\tShift+Del", IDC_DELETE
|
||||
END
|
||||
POPUP "Navigation"
|
||||
BEGIN
|
||||
MENUITEM "&Preferences", ID_NAVIGATION_PREFERENCES
|
||||
MENUITEM SEPARATOR
|
||||
MENUITEM "Help", ID_NAVIGATION_HELP
|
||||
END
|
||||
POPUP "SubscriptionNavigation"
|
||||
BEGIN
|
||||
MENUITEM "Directory", ID_NAVIGATION_DIRECTORY
|
||||
MENUITEM "&Preferences", ID_NAVIGATION_PREFERENCES
|
||||
MENUITEM SEPARATOR
|
||||
MENUITEM "Update all", ID_NAVIGATION_REFRESHALL
|
||||
MENUITEM SEPARATOR
|
||||
MENUITEM "Help", ID_NAVIGATION_HELP
|
||||
END
|
||||
END
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Accelerator
|
||||
//
|
||||
|
||||
IDR_VIEW_DOWNLOAD_ACCELERATORS ACCELERATORS
|
||||
BEGIN
|
||||
"F", ID_DOWNLOADS_EXPLORERITEMFOLDER, VIRTKEY, CONTROL, NOINVERT
|
||||
VK_RETURN, IDC_CUSTOM, VIRTKEY, SHIFT, CONTROL, NOINVERT
|
||||
VK_DELETE, IDC_DELETE, VIRTKEY, SHIFT, NOINVERT
|
||||
VK_RETURN, IDC_ENQUEUE, VIRTKEY, SHIFT, NOINVERT
|
||||
"3", IDC_INFOBOX, VIRTKEY, ALT, NOINVERT
|
||||
VK_RETURN, IDC_PLAY, VIRTKEY, NOINVERT
|
||||
VK_DELETE, IDC_REMOVE, VIRTKEY, NOINVERT
|
||||
"A", IDC_SELECTALL, VIRTKEY, CONTROL, NOINVERT
|
||||
VK_F7, IDC_VISIT, VIRTKEY, NOINVERT
|
||||
VK_F5, IDC_REFRESH, VIRTKEY, NOINVERT
|
||||
"D", IDC_DOWNLOAD, VIRTKEY, CONTROL, NOINVERT
|
||||
END
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// String Table
|
||||
//
|
||||
|
||||
STRINGTABLE
|
||||
BEGIN
|
||||
IDS_PLUGIN_NAME "Nullsoft Podcasts v%d.%02d"
|
||||
65535 "{1FF327B2-A41D-4c67-A58A-EB09BA1470D3}"
|
||||
END
|
||||
|
||||
STRINGTABLE
|
||||
BEGIN
|
||||
IDS_PODCASTS "Podcasts"
|
||||
IDS_DOWNLOADING_KB_COMPLETE "Downloading %u files, %ukb complete."
|
||||
IDS_DOWNLOADING_KB_PROGRESS
|
||||
"Downloading %u files, %ukb of %ukb complete (%d%%)."
|
||||
IDS_SUBSCRIPTIONS "Subscriptions"
|
||||
IDS_DOWNLOADS "Downloads"
|
||||
IDS_DOWNLOADING "Downloading..."
|
||||
IDS_CHOOSE_FOLDER "Choose folder to store downloaded media."
|
||||
IDS_ALREADY_SUBSCRIBED "You are already subscribed to %s.\n%s"
|
||||
IDS_FILE_NOT_FOUND "Cannot connect to %s\nFile not Found."
|
||||
IDS_CONNECTION_TIMED_OUT "Cannot connect to %s\nConnection timed out."
|
||||
IDS_ERROR_PARSING_XML "Subscription to %s failed.\nError parsing XML data from server."
|
||||
IDS_INVALID_RSS_FEED "Subscription to %s failed.\nDoes not appear to be a valid RSS feed."
|
||||
IDS_NO_JNETLIB "HTTP Downloader library is missing.\nPlease reinstall Winamp."
|
||||
IDS_JNETLIB_MISSING "JNetLib missing"
|
||||
IDS_NO_EXPAT "XML Parsing library is missing.\nPlease reinstall Winamp."
|
||||
END
|
||||
|
||||
STRINGTABLE
|
||||
BEGIN
|
||||
IDS_EXPAT_MISSING "Expat missing"
|
||||
IDS_CONNECTION_RESET "Subscription to %s failed.\nConnection reset by peer."
|
||||
IDS_ERROR_SUBSCRIBING_TO_PODCAST "Error Subscribing to Podcast"
|
||||
IDS_UPD_MANUALLY "Manually"
|
||||
IDS_UPD_WEEK "Week"
|
||||
IDS_UPD_DAY "Day"
|
||||
IDS_UPD_12HRS "12 hours"
|
||||
IDS_UPD_6HRS "6 hours"
|
||||
IDS_UPD_3HRS "3 hours"
|
||||
IDS_UPD_HOUR "Hour"
|
||||
IDS_UPD_30MINS "30 minutes"
|
||||
IDS_ERROR_FYEO "ERROR ! ! YOU SHOULDN'T SEE THIS"
|
||||
IDS_WDAY_SUN "Sun"
|
||||
IDS_WDAY_MON "Mon"
|
||||
IDS_WDAY_TUE "Tue"
|
||||
IDS_WDAY_WED "Wed"
|
||||
END
|
||||
|
||||
STRINGTABLE
|
||||
BEGIN
|
||||
IDS_WDAY_THU "Thu"
|
||||
IDS_WDAY_FRI "Fri"
|
||||
IDS_WDAY_SAT "Sat"
|
||||
IDS_MONTH_JAN "Jan"
|
||||
IDS_MONTH_FEB "Feb"
|
||||
IDS_MONTH_MAR "Mar"
|
||||
IDS_MONTH_APR "Apr"
|
||||
IDS_MONTH_MAY "May"
|
||||
IDS_MONTH_JUN "Jun"
|
||||
IDS_MONTH_JUL "Jul"
|
||||
IDS_MONTH_AUG "Aug"
|
||||
IDS_MONTH_SEP "Sep"
|
||||
IDS_MONTH_OCT "Oct"
|
||||
IDS_MONTH_NOV "Nov"
|
||||
IDS_MONTH_DEC "Dec"
|
||||
IDS_RECEIVING_UPDATES_FOR "Retrieving updates for "
|
||||
END
|
||||
|
||||
STRINGTABLE
|
||||
BEGIN
|
||||
IDS_GOT_NEW_ITEMS_FOR "Got new items for "
|
||||
IDS_CHANNEL_ALREADY_PRESENT "Podcast Already Present:\n%s\n%s"
|
||||
IDS_DUPLICATE_CHANNEL "Duplicate Podcast"
|
||||
IDS_ERROR_ADDING_URL "Error adding URL"
|
||||
IDS_ERROR_PARSING_XML_FROM_SERVER "Error parsing XML data from server"
|
||||
IDS_LINK_HAS_NO_RSS_INFO "Link does not contain valid RSS information"
|
||||
IDS_INVALID_LINK "Invalid link (404 or timeout)"
|
||||
IDS_CONNECTION_RESET_BY_PEER "Connection reset by peer."
|
||||
IDS_DOWNLOADING_PERCENT "Downloading %d%%"
|
||||
IDS_CHANNEL "Podcast"
|
||||
IDS_ITEM "Episode"
|
||||
IDS_PROGRESS "Progress"
|
||||
IDS_PATH "Path"
|
||||
IDS_PERM_DELETE_ARE_YOU_SURE
|
||||
"This will permanently delete this file, are you sure?"
|
||||
IDS_PERM_DELETE_THESE_ARE_YOU_SURE
|
||||
"This will permanently delete these %d files, are you sure?"
|
||||
IDS_DELETION "Deletion"
|
||||
END
|
||||
|
||||
STRINGTABLE
|
||||
BEGIN
|
||||
IDS_CLEAR_ALL_FINISHED_DOWNLOADS
|
||||
"This will clear all finished downloads, are you sure?\n\nTip: You can view all your downloaded podcasts in Local Media/Podcasts"
|
||||
IDS_CLEAN_UP_LIST "Clean Up List"
|
||||
IDS_DONE "Done"
|
||||
IDS_SAVE "Save"
|
||||
IDS_REQUIRES_INTERNET_CONNECTION_ENSURE_CONNECTION
|
||||
"The media library feature you are attempting to use requires an internet connection. Please make sure you are connected to the internet and try again."
|
||||
IDS_ADD_TO_DOWNLOADS "Added to downloads."
|
||||
IDS_NO_MEDIA_TO_DOWNLOAD "No media to download."
|
||||
IDS_TEXT_ARTICLE "Text article"
|
||||
IDS_DATE_ADDED "Date Added"
|
||||
IDS_MEDIA_PRESENT "Media Present"
|
||||
IDS_SURE_YOU_WANT_TO_REMOVE_THIS
|
||||
"Are you sure you want to remove %s\n(%s)"
|
||||
IDS_CONFIRM "Confirm"
|
||||
IDS_CANCEL_DOWNLOADS_AND_QUIT
|
||||
"You are currently downloading podcasts\nAre you sure you want to cancel these downloads and quit?"
|
||||
IDS_CONFIRM_QUIT "Confirm Quit"
|
||||
IDS_ARTICLE_WITH_MEDIA "Article with media"
|
||||
IDS_PODCAST_DIRECTORY "Podcast Directory"
|
||||
END
|
||||
|
||||
STRINGTABLE
|
||||
BEGIN
|
||||
IDS_DELETEFAILED "Delete Failed"
|
||||
IDS_SORRY "Sorry"
|
||||
IDS_EDIT_CHANNEL "Edit Podcast"
|
||||
IDS_ATD_NEVER "Never"
|
||||
IDS_ATD_LASTONE "Most recent episode"
|
||||
IDS_ATD_LASTTWO "Last 2 episodes"
|
||||
IDS_ATD_LASTTHREE "Last 3 episodes"
|
||||
IDS_ATD_LASTFIVE "Last 5 episodes"
|
||||
END
|
||||
|
||||
STRINGTABLE
|
||||
BEGIN
|
||||
IDS_PODCAST_SUBSCRIPTION_HEADER "Winamp Podcast Subscription"
|
||||
IDS_PODCAST_SUBSCRIPTION_PROMP
|
||||
"Are you sure that you want to subscribe to this podcast?\n\n%s"
|
||||
IDS_MEDIA_TIME "Time"
|
||||
IDS_EPISODE_INFO "Episode Info"
|
||||
IDS_MEDIA_SIZE "Size"
|
||||
END
|
||||
|
||||
#endif // English (U.S.) resources
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
#ifndef APSTUDIO_INVOKED
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Generated from the TEXTINCLUDE 3 resource.
|
||||
//
|
||||
#include "version.rc2"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
#endif // not APSTUDIO_INVOKED
|
||||
|
87
Src/Plugins/Library/ml_wire/ml_wire.sln
Normal file
87
Src/Plugins/Library/ml_wire/ml_wire.sln
Normal file
@ -0,0 +1,87 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 16
|
||||
VisualStudioVersion = 16.0.29509.3
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ml_wire", "ml_wire.vcxproj", "{2BF2E8A5-18E0-47B4-822C-FF17077926FD}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "nde", "..\nde\nde.vcxproj", "{4D25C321-7F8B-424E-9899-D80A364BAF1A}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "nx", "..\replicant\nx\nx.vcxproj", "{57C90706-B25D-4ACA-9B33-95CDB2427C27}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{44AEBB50-1331-4F2E-8AEC-56C82DE16C11} = {44AEBB50-1331-4F2E-8AEC-56C82DE16C11}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "nu", "..\replicant\nu\nu.vcxproj", "{F1F5CD60-0D5B-4CEA-9EEB-2F87FF9AA915}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "jnetlib", "..\replicant\jnetlib\jnetlib.vcxproj", "{E105A0A2-7391-47C5-86AC-718003524C3D}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{44AEBB50-1331-4F2E-8AEC-56C82DE16C11} = {44AEBB50-1331-4F2E-8AEC-56C82DE16C11}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zlib", "..\replicant\zlib\zlib.vcxproj", "{44AEBB50-1331-4F2E-8AEC-56C82DE16C11}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Win32 = Debug|Win32
|
||||
Debug|x64 = Debug|x64
|
||||
Release|Win32 = Release|Win32
|
||||
Release|x64 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{2BF2E8A5-18E0-47B4-822C-FF17077926FD}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{2BF2E8A5-18E0-47B4-822C-FF17077926FD}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{2BF2E8A5-18E0-47B4-822C-FF17077926FD}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{2BF2E8A5-18E0-47B4-822C-FF17077926FD}.Debug|x64.Build.0 = Debug|x64
|
||||
{2BF2E8A5-18E0-47B4-822C-FF17077926FD}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{2BF2E8A5-18E0-47B4-822C-FF17077926FD}.Release|Win32.Build.0 = Release|Win32
|
||||
{2BF2E8A5-18E0-47B4-822C-FF17077926FD}.Release|x64.ActiveCfg = Release|x64
|
||||
{2BF2E8A5-18E0-47B4-822C-FF17077926FD}.Release|x64.Build.0 = Release|x64
|
||||
{4D25C321-7F8B-424E-9899-D80A364BAF1A}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{4D25C321-7F8B-424E-9899-D80A364BAF1A}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{4D25C321-7F8B-424E-9899-D80A364BAF1A}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{4D25C321-7F8B-424E-9899-D80A364BAF1A}.Debug|x64.Build.0 = Debug|x64
|
||||
{4D25C321-7F8B-424E-9899-D80A364BAF1A}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{4D25C321-7F8B-424E-9899-D80A364BAF1A}.Release|Win32.Build.0 = Release|Win32
|
||||
{4D25C321-7F8B-424E-9899-D80A364BAF1A}.Release|x64.ActiveCfg = Release|x64
|
||||
{4D25C321-7F8B-424E-9899-D80A364BAF1A}.Release|x64.Build.0 = Release|x64
|
||||
{57C90706-B25D-4ACA-9B33-95CDB2427C27}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{57C90706-B25D-4ACA-9B33-95CDB2427C27}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{57C90706-B25D-4ACA-9B33-95CDB2427C27}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{57C90706-B25D-4ACA-9B33-95CDB2427C27}.Debug|x64.Build.0 = Debug|x64
|
||||
{57C90706-B25D-4ACA-9B33-95CDB2427C27}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{57C90706-B25D-4ACA-9B33-95CDB2427C27}.Release|Win32.Build.0 = Release|Win32
|
||||
{57C90706-B25D-4ACA-9B33-95CDB2427C27}.Release|x64.ActiveCfg = Release|x64
|
||||
{57C90706-B25D-4ACA-9B33-95CDB2427C27}.Release|x64.Build.0 = Release|x64
|
||||
{F1F5CD60-0D5B-4CEA-9EEB-2F87FF9AA915}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{F1F5CD60-0D5B-4CEA-9EEB-2F87FF9AA915}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{F1F5CD60-0D5B-4CEA-9EEB-2F87FF9AA915}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{F1F5CD60-0D5B-4CEA-9EEB-2F87FF9AA915}.Debug|x64.Build.0 = Debug|x64
|
||||
{F1F5CD60-0D5B-4CEA-9EEB-2F87FF9AA915}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{F1F5CD60-0D5B-4CEA-9EEB-2F87FF9AA915}.Release|Win32.Build.0 = Release|Win32
|
||||
{F1F5CD60-0D5B-4CEA-9EEB-2F87FF9AA915}.Release|x64.ActiveCfg = Release|x64
|
||||
{F1F5CD60-0D5B-4CEA-9EEB-2F87FF9AA915}.Release|x64.Build.0 = Release|x64
|
||||
{E105A0A2-7391-47C5-86AC-718003524C3D}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{E105A0A2-7391-47C5-86AC-718003524C3D}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{E105A0A2-7391-47C5-86AC-718003524C3D}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{E105A0A2-7391-47C5-86AC-718003524C3D}.Debug|x64.Build.0 = Debug|x64
|
||||
{E105A0A2-7391-47C5-86AC-718003524C3D}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{E105A0A2-7391-47C5-86AC-718003524C3D}.Release|Win32.Build.0 = Release|Win32
|
||||
{E105A0A2-7391-47C5-86AC-718003524C3D}.Release|x64.ActiveCfg = Release|x64
|
||||
{E105A0A2-7391-47C5-86AC-718003524C3D}.Release|x64.Build.0 = Release|x64
|
||||
{44AEBB50-1331-4F2E-8AEC-56C82DE16C11}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{44AEBB50-1331-4F2E-8AEC-56C82DE16C11}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{44AEBB50-1331-4F2E-8AEC-56C82DE16C11}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{44AEBB50-1331-4F2E-8AEC-56C82DE16C11}.Debug|x64.Build.0 = Debug|x64
|
||||
{44AEBB50-1331-4F2E-8AEC-56C82DE16C11}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{44AEBB50-1331-4F2E-8AEC-56C82DE16C11}.Release|Win32.Build.0 = Release|Win32
|
||||
{44AEBB50-1331-4F2E-8AEC-56C82DE16C11}.Release|x64.ActiveCfg = Release|x64
|
||||
{44AEBB50-1331-4F2E-8AEC-56C82DE16C11}.Release|x64.Build.0 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {C4E799C1-027B-487B-8E1A-31F2D26A1AFE}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
423
Src/Plugins/Library/ml_wire/ml_wire.vcxproj
Normal file
423
Src/Plugins/Library/ml_wire/ml_wire.vcxproj
Normal file
@ -0,0 +1,423 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{2BF2E8A5-18E0-47B4-822C-FF17077926FD}</ProjectGuid>
|
||||
<RootNamespace>ml_wire</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>10.0.19041.0</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<OutDir>$(PlatformShortName)_$(Configuration)\</OutDir>
|
||||
<IntDir>$(PlatformShortName)_$(Configuration)\</IntDir>
|
||||
<IncludePath>$(IncludePath)</IncludePath>
|
||||
<LibraryPath>$(LibraryPath)</LibraryPath>
|
||||
<EmbedManifest>true</EmbedManifest>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<OutDir>$(PlatformShortName)_$(Configuration)\</OutDir>
|
||||
<IntDir>$(PlatformShortName)_$(Configuration)\</IntDir>
|
||||
<EmbedManifest>true</EmbedManifest>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<OutDir>$(PlatformShortName)_$(Configuration)\</OutDir>
|
||||
<IntDir>$(PlatformShortName)_$(Configuration)\</IntDir>
|
||||
<IncludePath>$(IncludePath)</IncludePath>
|
||||
<LibraryPath>$(LibraryPath)</LibraryPath>
|
||||
<EmbedManifest>true</EmbedManifest>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<OutDir>$(PlatformShortName)_$(Configuration)\</OutDir>
|
||||
<IntDir>$(PlatformShortName)_$(Configuration)\</IntDir>
|
||||
<EmbedManifest>true</EmbedManifest>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Label="Vcpkg">
|
||||
<VcpkgEnableManifest>false</VcpkgEnableManifest>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<VcpkgInstalledDir>
|
||||
</VcpkgInstalledDir>
|
||||
<VcpkgUseStatic>false</VcpkgUseStatic>
|
||||
<VcpkgConfiguration>Debug</VcpkgConfiguration>
|
||||
<VcpkgTriplet>x86-windows-static-md</VcpkgTriplet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<VcpkgInstalledDir>
|
||||
</VcpkgInstalledDir>
|
||||
<VcpkgUseStatic>false</VcpkgUseStatic>
|
||||
<VcpkgTriplet>x86-windows-static-md</VcpkgTriplet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<VcpkgInstalledDir>
|
||||
</VcpkgInstalledDir>
|
||||
<VcpkgUseStatic>false</VcpkgUseStatic>
|
||||
<VcpkgTriplet>x86-windows-static-md</VcpkgTriplet>
|
||||
<VcpkgConfiguration>Debug</VcpkgConfiguration>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<VcpkgInstalledDir>
|
||||
</VcpkgInstalledDir>
|
||||
<VcpkgUseStatic>false</VcpkgUseStatic>
|
||||
<VcpkgTriplet>x86-windows-static-md</VcpkgTriplet>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<AdditionalIncludeDirectories>.;..\..\..\Wasabi;..\..\..\replicant;..;..\..\..\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>_WIN32_WINNT=0x0601;WINVER=0x0601;_WIN32_IE=0x0A00;_DEBUG;WIN32;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<MinimalRebuild>false</MinimalRebuild>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
|
||||
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
|
||||
<BufferSecurityCheck>true</BufferSecurityCheck>
|
||||
<TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
|
||||
<ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
<DisableSpecificWarnings>4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
|
||||
<ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>comctl32.lib;shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<RandomizedBaseAddress>false</RandomizedBaseAddress>
|
||||
<ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
|
||||
<TargetMachine>MachineX86</TargetMachine>
|
||||
<ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
|
||||
<AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<MapFileName>$(IntDir)$(TargetName).map</MapFileName>
|
||||
</Link>
|
||||
<PostBuildEvent>
|
||||
<Command>xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\
|
||||
|
||||
xcopy /Y /D $(IntDir)$(TargetName).pdb ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\ </Command>
|
||||
<Message>Post build event: 'xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\'</Message>
|
||||
</PostBuildEvent>
|
||||
<ResourceCompile>
|
||||
<PreprocessorDefinitions>_WIN32_WINNT=0x0601;WINVER=0x0601;_UNICODE;UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ResourceCompile>
|
||||
<Manifest>
|
||||
<OutputManifestFile>$(IntDir)$(TargetName)$(TargetExt).intermediate.manifest</OutputManifestFile>
|
||||
</Manifest>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<AdditionalIncludeDirectories>.;..\..\..\Wasabi;..\..\..\replicant;..;..\..\..\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>_WIN32_WINNT=0x0601;WINVER=0x0601;_WIN32_IE=0x0A00;_DEBUG;WIN64;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<MinimalRebuild>false</MinimalRebuild>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
|
||||
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
|
||||
<BufferSecurityCheck>true</BufferSecurityCheck>
|
||||
<TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
|
||||
<ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
<DisableSpecificWarnings>4244;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
|
||||
<ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>comctl32.lib;shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<RandomizedBaseAddress>false</RandomizedBaseAddress>
|
||||
<ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
|
||||
<ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
|
||||
<AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<MapFileName>$(IntDir)$(TargetName).map</MapFileName>
|
||||
</Link>
|
||||
<PostBuildEvent>
|
||||
<Command>xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\
|
||||
|
||||
xcopy /Y /D $(IntDir)$(TargetName).pdb ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\ </Command>
|
||||
<Message>Post build event: 'xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\'</Message>
|
||||
</PostBuildEvent>
|
||||
<ResourceCompile>
|
||||
<PreprocessorDefinitions>_WIN32_WINNT=0x0601;WINVER=0x0601;_UNICODE;UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ResourceCompile>
|
||||
<Manifest>
|
||||
<OutputManifestFile>$(IntDir)$(TargetName)$(TargetExt).intermediate.manifest</OutputManifestFile>
|
||||
</Manifest>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<Optimization>MinSpace</Optimization>
|
||||
<FavorSizeOrSpeed>Size</FavorSizeOrSpeed>
|
||||
<AdditionalIncludeDirectories>.;..\..\..\Wasabi;..\..\..\replicant;..;..\..\..\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>_WIN32_WINNT=0x0601;WINVER=0x0601;_WIN32_IE=0x0A00;IGNORE_API_GRACENOTE;NDEBUG;WIN32;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<StringPooling>true</StringPooling>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
|
||||
<BufferSecurityCheck>true</BufferSecurityCheck>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<DebugInformationFormat>None</DebugInformationFormat>
|
||||
<DisableSpecificWarnings>4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
|
||||
<ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>comctl32.lib;shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
|
||||
<GenerateDebugInformation>false</GenerateDebugInformation>
|
||||
<ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile>
|
||||
<MapFileName>$(IntDir)$(TargetName).map</MapFileName>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<RandomizedBaseAddress>false</RandomizedBaseAddress>
|
||||
<ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
|
||||
<TargetMachine>MachineX86</TargetMachine>
|
||||
<AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
|
||||
</Link>
|
||||
<PostBuildEvent>
|
||||
<Command>xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\ </Command>
|
||||
<Message>Post build event: 'xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\'</Message>
|
||||
</PostBuildEvent>
|
||||
<ResourceCompile>
|
||||
<PreprocessorDefinitions>_WIN32_WINNT=0x0601;WINVER=0x0601;_UNICODE;UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ResourceCompile>
|
||||
<Manifest>
|
||||
<OutputManifestFile>$(IntDir)$(TargetName)$(TargetExt).intermediate.manifest</OutputManifestFile>
|
||||
</Manifest>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<Optimization>MinSpace</Optimization>
|
||||
<FavorSizeOrSpeed>Size</FavorSizeOrSpeed>
|
||||
<AdditionalIncludeDirectories>.;..\..\..\Wasabi;..\..\..\replicant;..;..\..\..\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>_WIN32_WINNT=0x0601;WINVER=0x0601;_WIN32_IE=0x0A00;IGNORE_API_GRACENOTE;NDEBUG;WIN64;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<StringPooling>true</StringPooling>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
|
||||
<BufferSecurityCheck>true</BufferSecurityCheck>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<DebugInformationFormat>None</DebugInformationFormat>
|
||||
<DisableSpecificWarnings>4244;4996;%(DisableSpecificWarnings)</DisableSpecificWarnings>
|
||||
<ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>comctl32.lib;shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
|
||||
<GenerateDebugInformation>false</GenerateDebugInformation>
|
||||
<ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile>
|
||||
<MapFileName>$(IntDir)$(TargetName).map</MapFileName>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<RandomizedBaseAddress>false</RandomizedBaseAddress>
|
||||
<ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
|
||||
<AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
|
||||
</Link>
|
||||
<PostBuildEvent>
|
||||
<Command>xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\ </Command>
|
||||
<Message>Post build event: 'xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\'</Message>
|
||||
</PostBuildEvent>
|
||||
<ResourceCompile>
|
||||
<PreprocessorDefinitions>_WIN32_WINNT=0x0601;WINVER=0x0601;_UNICODE;UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ResourceCompile>
|
||||
<Manifest>
|
||||
<OutputManifestFile>$(IntDir)$(TargetName)$(TargetExt).intermediate.manifest</OutputManifestFile>
|
||||
</Manifest>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\nde\nde.vcxproj">
|
||||
<Project>{4d25c321-7f8b-424e-9899-d80a364baf1a}</Project>
|
||||
<CopyLocalSatelliteAssemblies>true</CopyLocalSatelliteAssemblies>
|
||||
<ReferenceOutputAssembly>true</ReferenceOutputAssembly>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\..\Wasabi\Wasabi.vcxproj">
|
||||
<Project>{3e0bfa8a-b86a-42e9-a33f-ec294f823f7f}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\..\WAT\WAT.vcxproj">
|
||||
<Project>{c5714908-a71f-4644-bd95-aad8ee7914da}</Project>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\..\General\gen_ml\menu.h" />
|
||||
<ClInclude Include="..\..\..\nu\Alias.h" />
|
||||
<ClInclude Include="..\..\..\nu\ChildSizer.h" />
|
||||
<ClInclude Include="..\..\..\nu\DialogSkinner.h" />
|
||||
<ClInclude Include="..\..\..\nu\MediaLibraryInterface.h" />
|
||||
<ClInclude Include="..\..\..\nu\menushortcuts.h" />
|
||||
<ClInclude Include="..\..\..\xml\XMLDOM.h" />
|
||||
<ClInclude Include="..\..\..\xml\XMLNode.h" />
|
||||
<ClInclude Include="api__ml_wire.h" />
|
||||
<ClInclude Include="api_podcasts.h" />
|
||||
<ClInclude Include="BackgroundDownloader.h" />
|
||||
<ClInclude Include="ChannelCheck.h" />
|
||||
<ClInclude Include="channelEditor.h" />
|
||||
<ClInclude Include="ChannelRefresher.h" />
|
||||
<ClInclude Include="ChannelSync.h" />
|
||||
<ClInclude Include="Cloud.h" />
|
||||
<ClInclude Include="Defaults.h" />
|
||||
<ClInclude Include="Downloaded.h" />
|
||||
<ClInclude Include="DownloadsDialog.h" />
|
||||
<ClInclude Include="DownloadsParse.h" />
|
||||
<ClInclude Include="DownloadStatus.h" />
|
||||
<ClInclude Include="DownloadThread.h" />
|
||||
<ClInclude Include="errors.h" />
|
||||
<ClInclude Include="ExternalCOM.h" />
|
||||
<ClInclude Include="Factory.h" />
|
||||
<ClInclude Include="FeedParse.h" />
|
||||
<ClInclude Include="Feeds.h" />
|
||||
<ClInclude Include="FeedUtil.h" />
|
||||
<ClInclude Include="ifc_article.h" />
|
||||
<ClInclude Include="ifc_podcast.h" />
|
||||
<ClInclude Include="Item.h" />
|
||||
<ClInclude Include="JSAPI2_Creator.h" />
|
||||
<ClInclude Include="JSAPI2_PodcastsAPI.h" />
|
||||
<ClInclude Include="layout.h" />
|
||||
<ClInclude Include="Main.h" />
|
||||
<ClInclude Include="navigation.h" />
|
||||
<ClInclude Include="OPMLParse.h" />
|
||||
<ClInclude Include="ParseUtil.h" />
|
||||
<ClInclude Include="PCastFactory.h" />
|
||||
<ClInclude Include="PCastURIHandler.h" />
|
||||
<ClInclude Include="Preferences.h" />
|
||||
<ClInclude Include="resource.h" />
|
||||
<ClInclude Include="RFCDate.h" />
|
||||
<ClInclude Include="RSSCOM.h" />
|
||||
<ClInclude Include="RSSParse.h" />
|
||||
<ClInclude Include="service.h" />
|
||||
<ClInclude Include="subscriptionView.h" />
|
||||
<ClInclude Include="UpdateAutoDownload.h" />
|
||||
<ClInclude Include="UpdateTime.h" />
|
||||
<ClInclude Include="Util.h" />
|
||||
<ClInclude Include="WantsDownloadStatus.h" />
|
||||
<ClInclude Include="Wire.h" />
|
||||
<ClInclude Include="XMLWriter.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\..\General\gen_ml\menu.cpp" />
|
||||
<ClCompile Include="..\..\General\gen_ml\ml_lib.cpp" />
|
||||
<ClCompile Include="..\..\..\nu\ChildSizer.cpp" />
|
||||
<ClCompile Include="..\..\..\nu\DialogSkinner.cpp" />
|
||||
<ClCompile Include="..\..\..\nu\listview.cpp">
|
||||
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(IntDir)%(Filename)1.obj</ObjectFileName>
|
||||
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(IntDir)%(Filename)1.obj</ObjectFileName>
|
||||
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(IntDir)%(Filename)1.obj</ObjectFileName>
|
||||
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(IntDir)%(Filename)1.obj</ObjectFileName>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\nu\MediaLibraryInterface.cpp" />
|
||||
<ClCompile Include="..\..\..\nu\menushortcuts.cpp" />
|
||||
<ClCompile Include="..\..\..\xml\XMLDOM.cpp" />
|
||||
<ClCompile Include="..\..\..\xml\XMLNode.cpp" />
|
||||
<ClCompile Include="BackgroundDownloader.cpp" />
|
||||
<ClCompile Include="channelEditor.cpp" />
|
||||
<ClCompile Include="ChannelRefresher.cpp" />
|
||||
<ClCompile Include="Cloud.cpp" />
|
||||
<ClCompile Include="db.cpp" />
|
||||
<ClCompile Include="Defaults.cpp" />
|
||||
<ClCompile Include="Downloaded.cpp" />
|
||||
<ClCompile Include="DownloadsDialog.cpp" />
|
||||
<ClCompile Include="DownloadsParse.cpp" />
|
||||
<ClCompile Include="DownloadStatus.cpp" />
|
||||
<ClCompile Include="DownloadThread.cpp" />
|
||||
<ClCompile Include="ExternalCOM.cpp" />
|
||||
<ClCompile Include="Factory.cpp" />
|
||||
<ClCompile Include="FeedParse.cpp" />
|
||||
<ClCompile Include="Feeds.cpp" />
|
||||
<ClCompile Include="FeedUtil.cpp" />
|
||||
<ClCompile Include="item.cpp" />
|
||||
<ClCompile Include="JSAPI2_Creator.cpp" />
|
||||
<ClCompile Include="JSAPI2_PodcastsAPI.cpp" />
|
||||
<ClCompile Include="layout.cpp" />
|
||||
<ClCompile Include="Main.cpp" />
|
||||
<ClCompile Include="navigation.cpp" />
|
||||
<ClCompile Include="OPMLParse.cpp" />
|
||||
<ClCompile Include="ParseUtil.cpp" />
|
||||
<ClCompile Include="PCastFactory.cpp" />
|
||||
<ClCompile Include="PCastURIHandler.cpp" />
|
||||
<ClCompile Include="Preferences.cpp" />
|
||||
<ClCompile Include="RFCDate.cpp" />
|
||||
<ClCompile Include="RSSCOM.cpp" />
|
||||
<ClCompile Include="RSSParse.cpp" />
|
||||
<ClCompile Include="service.cpp" />
|
||||
<ClCompile Include="subscriptionView.cpp" />
|
||||
<ClCompile Include="UpdateAutoDownload.cpp" />
|
||||
<ClCompile Include="UpdateTime.cpp" />
|
||||
<ClCompile Include="util.cpp">
|
||||
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(IntDir)%(Filename)2.obj</ObjectFileName>
|
||||
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(IntDir)%(Filename)2.obj</ObjectFileName>
|
||||
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(IntDir)%(Filename)2.obj</ObjectFileName>
|
||||
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(IntDir)%(Filename)2.obj</ObjectFileName>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Wire.cpp" />
|
||||
<ClCompile Include="XMLWriter.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="ml_podcast.rc" />
|
||||
<ResourceCompile Include="png.rc" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Text Include="DESIGN.txt" />
|
||||
<Text Include="TODO.txt" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
345
Src/Plugins/Library/ml_wire/ml_wire.vcxproj.filters
Normal file
345
Src/Plugins/Library/ml_wire/ml_wire.vcxproj.filters
Normal file
@ -0,0 +1,345 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<ClCompile Include="BackgroundDownloader.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="channelEditor.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ChannelRefresher.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Cloud.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="db.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Defaults.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Downloaded.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="DownloadsDialog.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="DownloadsParse.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="DownloadStatus.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="DownloadThread.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ExternalCOM.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Factory.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="FeedParse.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Feeds.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="FeedUtil.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="item.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="JSAPI2_Creator.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="JSAPI2_PodcastsAPI.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="layout.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Main.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="navigation.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="OPMLParse.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ParseUtil.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="PCastFactory.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="PCastURIHandler.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="XMLWriter.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Preferences.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="RFCDate.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="RSSCOM.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="RSSParse.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="service.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="subscriptionView.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="UpdateAutoDownload.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="UpdateTime.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="util.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Wire.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\nu\ChildSizer.cpp">
|
||||
<Filter>Source Files\nu</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\nu\DialogSkinner.cpp">
|
||||
<Filter>Source Files\nu</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\nu\listview.cpp">
|
||||
<Filter>Source Files\nu</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\nu\MediaLibraryInterface.cpp">
|
||||
<Filter>Source Files\nu</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\General\gen_ml\menu.cpp">
|
||||
<Filter>Source Files\gen_ml</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\nu\menushortcuts.cpp">
|
||||
<Filter>Source Files\nu</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\General\gen_ml\ml_lib.cpp">
|
||||
<Filter>Source Files\gen_ml</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\xml\XMLNode.cpp">
|
||||
<Filter>Source Files\XML</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\xml\XMLDOM.cpp">
|
||||
<Filter>Source Files\XML</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="api__ml_wire.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="api_podcasts.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="BackgroundDownloader.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="ChannelCheck.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="channelEditor.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="ChannelRefresher.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="ChannelSync.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Cloud.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Defaults.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Downloaded.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="DownloadsDialog.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="DownloadsParse.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="DownloadStatus.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="DownloadThread.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="errors.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="ExternalCOM.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Factory.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="FeedParse.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Feeds.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="FeedUtil.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="ifc_article.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="ifc_podcast.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Item.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="JSAPI2_Creator.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="JSAPI2_PodcastsAPI.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="layout.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Main.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="navigation.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="OPMLParse.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="ParseUtil.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="PCastFactory.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="PCastURIHandler.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Preferences.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="resource.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="RFCDate.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="RSSCOM.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="RSSParse.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="service.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="subscriptionView.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="UpdateAutoDownload.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="UpdateTime.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Util.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="WantsDownloadStatus.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Wire.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="XMLWriter.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\..\nu\Alias.h">
|
||||
<Filter>Header Files\nu</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\..\nu\ChildSizer.h">
|
||||
<Filter>Header Files\nu</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\..\nu\DialogSkinner.h">
|
||||
<Filter>Header Files\nu</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\..\nu\MediaLibraryInterface.h">
|
||||
<Filter>Header Files\nu</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\General\gen_ml\menu.h">
|
||||
<Filter>Header Files\gen_ml</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\..\nu\menushortcuts.h">
|
||||
<Filter>Header Files\nu</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\..\xml\XMLNode.h">
|
||||
<Filter>Header Files\xml</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\..\xml\XMLDOM.h">
|
||||
<Filter>Header Files\xml</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="ml_podcast.rc">
|
||||
<Filter>Ressource Files</Filter>
|
||||
</ResourceCompile>
|
||||
<ResourceCompile Include="png.rc">
|
||||
<Filter>Ressource Files</Filter>
|
||||
</ResourceCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Text Include="DESIGN.txt" />
|
||||
<Text Include="TODO.txt" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{04424438-0f00-45d3-957e-f60ad4e3addc}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Ressource Files">
|
||||
<UniqueIdentifier>{ab23d144-c22c-4693-98c5-bc8255a28f57}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{8ca72875-5c2c-4336-984e-9aa6e1b15b2f}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Source Files\nu">
|
||||
<UniqueIdentifier>{d8fe42ef-d543-46b2-9045-646ded85494d}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Source Files\gen_ml">
|
||||
<UniqueIdentifier>{e6bd8d09-5297-423e-943c-22b3f0982d40}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Source Files\XML">
|
||||
<UniqueIdentifier>{59f272b6-8c65-4db5-95b5-bca0712a07a8}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Header Files\nu">
|
||||
<UniqueIdentifier>{d47a4f2b-363d-4281-aa4f-d76fdb3a22f6}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Header Files\gen_ml">
|
||||
<UniqueIdentifier>{df263acf-3409-47f8-9bee-6090095c081c}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Header Files\xml">
|
||||
<UniqueIdentifier>{b38287f4-c45a-41f8-9787-fe36ed08cb08}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
</Project>
|
420
Src/Plugins/Library/ml_wire/navigation.cpp
Normal file
420
Src/Plugins/Library/ml_wire/navigation.cpp
Normal file
@ -0,0 +1,420 @@
|
||||
#include <strsafe.h>
|
||||
|
||||
#include "main.h"
|
||||
#include "./navigation.h"
|
||||
#include "./util.h"
|
||||
#include "./resource.h"
|
||||
#include "api__ml_wire.h"
|
||||
#include "./service.h"
|
||||
#include "./subscriptionView.h"
|
||||
#include "./downloadsDialog.h"
|
||||
#include "../omBrowser/browserView.h"
|
||||
#include "../winamp/wa_ipc.h"
|
||||
#include "..\..\General\gen_ml/ml_ipc_0313.h"
|
||||
#include "./Defaults.h"
|
||||
|
||||
|
||||
#define NAVITEM_PREFIX L"podcast_svc_"
|
||||
|
||||
#define E_NAVITEM_UNKNOWN E_NOINTERFACE
|
||||
|
||||
static Nullsoft::Utility::LockGuard navigationLock;
|
||||
|
||||
static INT Navigation_RegisterIcon( HWND hLibrary, INT iconIndex, LPCWSTR pszImage )
|
||||
{
|
||||
HMLIMGLST hmlilNavigation = MLNavCtrl_GetImageList( hLibrary );
|
||||
if ( hmlilNavigation == NULL )
|
||||
return -1;
|
||||
|
||||
MLIMAGESOURCE mlis;
|
||||
ZeroMemory( &mlis, sizeof( MLIMAGESOURCE ) );
|
||||
|
||||
mlis.cbSize = sizeof( MLIMAGESOURCE );
|
||||
mlis.hInst = NULL;
|
||||
mlis.bpp = 24;
|
||||
mlis.lpszName = pszImage;
|
||||
mlis.type = SRC_TYPE_PNG;
|
||||
mlis.flags = ISF_FORCE_BPP | ISF_PREMULTIPLY | ISF_LOADFROMFILE;
|
||||
|
||||
MLIMAGELISTITEM item;
|
||||
ZeroMemory( &item, sizeof( MLIMAGELISTITEM ) );
|
||||
item.cbSize = sizeof( MLIMAGELISTITEM );
|
||||
item.hmlil = hmlilNavigation;
|
||||
item.filterUID = MLIF_FILTER3_UID;
|
||||
item.pmlImgSource = &mlis;
|
||||
|
||||
if (iconIndex >= 0)
|
||||
{
|
||||
INT count = MLImageList_GetImageCount( hLibrary, item.hmlil );
|
||||
if (iconIndex < count)
|
||||
{
|
||||
item.mlilIndex = iconIndex;
|
||||
|
||||
return (FALSE != MLImageList_Replace(hLibrary, &item)) ? iconIndex : -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return MLImageList_Add( hLibrary, &item );
|
||||
}
|
||||
|
||||
static HNAVITEM Navigation_CreateItem( HWND hLibrary, HNAVITEM hParent, OmService *service )
|
||||
{
|
||||
if ( hLibrary == NULL || service == NULL )
|
||||
return NULL;
|
||||
|
||||
WCHAR szName[ 256 ] = { 0 }, szInvariant[ 64 ] = { 0 };
|
||||
if ( FAILED( service->GetName( szName, ARRAYSIZE( szName ) ) ) )
|
||||
return NULL;
|
||||
|
||||
if ( FAILED( StringCchPrintf( szInvariant, ARRAYSIZE( szInvariant ), NAVITEM_PREFIX L"%u", service->GetId() ) ) )
|
||||
return NULL;
|
||||
|
||||
NAVINSERTSTRUCT nis = { 0 };
|
||||
nis.hInsertAfter = NULL;
|
||||
nis.hParent = hParent;
|
||||
|
||||
WCHAR szIcon[ 512 ] = { 0 };
|
||||
INT iIcon = ( SUCCEEDED( service->GetIcon( szIcon, ARRAYSIZE( szIcon ) ) ) ) ? Navigation_RegisterIcon( hLibrary, -1, szIcon ) : -1;
|
||||
|
||||
nis.item.cbSize = sizeof( NAVITEM );
|
||||
nis.item.mask = NIMF_TEXT | NIMF_STYLE | NIMF_TEXTINVARIANT | NIMF_PARAM | NIMF_IMAGE | NIMF_IMAGESEL;
|
||||
|
||||
nis.item.id = 0;
|
||||
nis.item.pszText = szName;
|
||||
nis.item.pszInvariant = szInvariant;
|
||||
nis.item.lParam = (LPARAM)service;
|
||||
|
||||
nis.item.style = 0;
|
||||
|
||||
UINT serviceFlags = service->GetFlags();
|
||||
|
||||
if ( ( OmService::flagRoot & serviceFlags ) != 0 )
|
||||
nis.item.style |= ( NIS_HASCHILDREN | NIS_DEFAULTIMAGE );
|
||||
|
||||
nis.item.styleMask = nis.item.style;
|
||||
|
||||
nis.item.iImage = iIcon;
|
||||
nis.item.iSelectedImage = iIcon;
|
||||
|
||||
HNAVITEM hItem = MLNavCtrl_InsertItem( hLibrary, &nis );
|
||||
if ( hItem != NULL )
|
||||
service->AddRef();
|
||||
|
||||
return hItem;
|
||||
}
|
||||
|
||||
static HNAVITEM Navigation_GetMessageItem( INT msg, INT_PTR param1 )
|
||||
{
|
||||
HWND hLibrary = plugin.hwndLibraryParent;
|
||||
HNAVITEM hItem = ( msg < ML_MSG_NAVIGATION_FIRST ) ? MLNavCtrl_FindItemById( hLibrary, param1 ) : (HNAVITEM)param1;
|
||||
|
||||
return hItem;
|
||||
}
|
||||
|
||||
static BOOL Navigation_CheckInvariantName( LPCWSTR pszInvarian )
|
||||
{
|
||||
INT cchInvariant = ( NULL != pszInvarian ) ? lstrlen( pszInvarian ) : 0;
|
||||
INT cchPrefix = ARRAYSIZE( NAVITEM_PREFIX ) - 1;
|
||||
|
||||
return ( cchInvariant > cchPrefix &&
|
||||
CompareString( CSTR_INVARIANT, 0, NAVITEM_PREFIX, cchPrefix, pszInvarian, cchPrefix ) == CSTR_EQUAL );
|
||||
}
|
||||
|
||||
static HRESULT Navigation_GetServiceInt( HWND hLibrary, HNAVITEM hItem, OmService **service )
|
||||
{
|
||||
WCHAR szBuffer[ 64 ] = { 0 };
|
||||
|
||||
if ( service == NULL )
|
||||
return E_POINTER;
|
||||
|
||||
*service = NULL;
|
||||
|
||||
if ( NULL == hLibrary || NULL == hItem )
|
||||
return E_INVALIDARG;
|
||||
|
||||
NAVITEM itemInfo = {0};
|
||||
itemInfo.cbSize = sizeof( NAVITEM );
|
||||
itemInfo.hItem = hItem;
|
||||
itemInfo.pszInvariant = szBuffer;
|
||||
itemInfo.cchInvariantMax = ARRAYSIZE( szBuffer );
|
||||
itemInfo.mask = NIMF_PARAM | NIMF_TEXTINVARIANT;
|
||||
|
||||
if ( FALSE == MLNavItem_GetInfo( hLibrary, &itemInfo ) )
|
||||
return E_FAIL;
|
||||
|
||||
if ( FALSE == Navigation_CheckInvariantName( szBuffer ) )
|
||||
return E_NAVITEM_UNKNOWN;
|
||||
|
||||
*service = (OmService *)itemInfo.lParam;
|
||||
(*service)->AddRef();
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT Navigation_GetService( HNAVITEM hItem, OmService **service )
|
||||
{
|
||||
return Navigation_GetServiceInt( plugin.hwndLibraryParent, hItem, service );
|
||||
}
|
||||
|
||||
static HRESULT Navigation_CreateView( HNAVITEM hItem, HWND hParent, HWND *hView )
|
||||
{
|
||||
if ( NULL == hView )
|
||||
return E_POINTER;
|
||||
|
||||
*hView = NULL;
|
||||
|
||||
if ( hItem == NULL || hParent == NULL )
|
||||
return E_INVALIDARG;
|
||||
|
||||
HRESULT hr;
|
||||
|
||||
OmService *service;
|
||||
hr = Navigation_GetServiceInt( plugin.hwndLibraryParent, hItem, &service );
|
||||
if ( SUCCEEDED( hr ) )
|
||||
{
|
||||
if ( service->GetId() == SERVICE_PODCAST )
|
||||
service->SetUrl( serviceUrl[ 0 ] ? serviceUrl : L"https://client.winamp.com/podcasts" );
|
||||
|
||||
hr = service->CreateView( hParent, hView );
|
||||
service->Release();
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
static void Navigation_OnDestroy()
|
||||
{
|
||||
if ( OMBROWSERMNGR != NULL )
|
||||
OMBROWSERMNGR->Finish();
|
||||
}
|
||||
|
||||
HNAVITEM Navigation_FindService( UINT serviceId, HNAVITEM hStart, OmService **serviceOut )
|
||||
{
|
||||
HWND hLibrary = plugin.hwndLibraryParent;
|
||||
|
||||
INT cchPrefix = ARRAYSIZE( NAVITEM_PREFIX ) - 1;
|
||||
|
||||
WCHAR szBuffer[256] = {0};
|
||||
NAVITEM itemInfo = {0};
|
||||
|
||||
itemInfo.cbSize = sizeof( itemInfo );
|
||||
itemInfo.mask = NIMF_TEXTINVARIANT | NIMF_PARAM;
|
||||
itemInfo.cchInvariantMax = ARRAYSIZE( szBuffer );
|
||||
itemInfo.pszInvariant = szBuffer;
|
||||
|
||||
if ( hStart == NULL )
|
||||
hStart = MLNavCtrl_GetFirst( hLibrary );
|
||||
|
||||
itemInfo.hItem = hStart;
|
||||
while ( itemInfo.hItem != NULL )
|
||||
{
|
||||
if ( FALSE != MLNavItem_GetInfo( hLibrary, &itemInfo ) &&
|
||||
CSTR_EQUAL == CompareString( CSTR_INVARIANT, NORM_IGNORECASE, itemInfo.pszInvariant, cchPrefix,
|
||||
NAVITEM_PREFIX, cchPrefix ) )
|
||||
{
|
||||
OmService *service = (OmService *)itemInfo.lParam;
|
||||
if ( service != NULL && service->GetId() == serviceId )
|
||||
{
|
||||
if ( serviceOut != NULL )
|
||||
{
|
||||
*serviceOut = service;
|
||||
service->AddRef();
|
||||
}
|
||||
|
||||
return itemInfo.hItem;
|
||||
}
|
||||
}
|
||||
|
||||
itemInfo.hItem = MLNavItem_GetNext( hLibrary, itemInfo.hItem );
|
||||
}
|
||||
|
||||
if ( serviceOut != NULL )
|
||||
*serviceOut = NULL;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int downloadsViewLoaded = -1;
|
||||
|
||||
static int Navigation_CheckDownloadsView()
|
||||
{
|
||||
if ( downloadsViewLoaded == -1 )
|
||||
{
|
||||
pluginMessage p = { ML_MSG_DOWNLOADS_VIEW_LOADED, 0, 0, 0 };
|
||||
downloadsViewLoaded = SENDMLIPC( plugin.hwndLibraryParent, ML_IPC_SEND_PLUGIN_MESSAGE, (WPARAM)&p );
|
||||
}
|
||||
|
||||
return downloadsViewLoaded;
|
||||
}
|
||||
|
||||
HRESULT Navigation_ShowService( UINT serviceId, INT showMode )
|
||||
{
|
||||
if ( serviceId == SERVICE_DOWNLOADS && Navigation_CheckDownloadsView() )
|
||||
return S_OK;
|
||||
|
||||
Nullsoft::Utility::AutoLock lock3( navigationLock );
|
||||
|
||||
HNAVITEM hRoot = Navigation_FindService( SERVICE_PODCAST, NULL, NULL );
|
||||
if( hRoot == NULL )
|
||||
return E_UNEXPECTED;
|
||||
|
||||
switch ( serviceId )
|
||||
{
|
||||
case SERVICE_SUBSCRIPTION:
|
||||
if ( SHOWMODE_AUTO == showMode )
|
||||
return E_INVALIDARG;
|
||||
break;
|
||||
|
||||
case SERVICE_DOWNLOADS:
|
||||
if ( SHOWMODE_AUTO == showMode )
|
||||
{
|
||||
Nullsoft::Utility::AutoLock lock1( downloadedFiles.downloadedLock );
|
||||
Nullsoft::Utility::AutoLock lock2( downloadStatus.statusLock );
|
||||
showMode = ( 0 != downloadedFiles.downloadList.size() || 0 != downloadStatus.downloads.size() ) ? SHOWMODE_SHOW : SHOWMODE_HIDE;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return E_INVALIDARG;
|
||||
}
|
||||
|
||||
if ( showMode != SHOWMODE_HIDE && showMode != SHOWMODE_SHOW )
|
||||
return E_INVALIDARG;
|
||||
|
||||
HWND hLibrary = plugin.hwndLibraryParent;
|
||||
|
||||
MLNavCtrl_BeginUpdate( hLibrary, NUF_LOCK_TOP );
|
||||
|
||||
OmService *service;
|
||||
HNAVITEM hItem = MLNavItem_GetChild( hLibrary, hRoot );
|
||||
hItem = Navigation_FindService( serviceId, hItem, &service );
|
||||
|
||||
HRESULT hr = S_OK;
|
||||
|
||||
if ( showMode == SHOWMODE_HIDE )
|
||||
{
|
||||
if ( hItem == NULL )
|
||||
hr = S_FALSE;
|
||||
else if ( MLNavCtrl_DeleteItem( hLibrary, hItem ) == FALSE )
|
||||
hr = E_FAIL;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( hItem != NULL )
|
||||
hr = S_FALSE;
|
||||
else
|
||||
{
|
||||
switch ( serviceId )
|
||||
{
|
||||
case SERVICE_SUBSCRIPTION:
|
||||
hr = OmService::CreateLocal( SERVICE_SUBSCRIPTION, MAKEINTRESOURCE( IDS_SUBSCRIPTIONS ), MAKEINTRESOURCE( IDR_SUBSCRIPTION_ICON ), SubscriptionView_Create, &service );
|
||||
break;
|
||||
case SERVICE_DOWNLOADS:
|
||||
hr = OmService::CreateLocal( SERVICE_DOWNLOADS, MAKEINTRESOURCE( IDS_DOWNLOADS ), MAKEINTRESOURCE( IDR_DOWNLOAD_ICON ), DownloadDialog_Create, &service );
|
||||
break;
|
||||
default:
|
||||
hr = E_UNEXPECTED;
|
||||
break;
|
||||
}
|
||||
|
||||
if ( SUCCEEDED( hr ) )
|
||||
{
|
||||
if ( Navigation_CreateItem( hLibrary, hRoot, service ) == NULL )
|
||||
hr = E_FAIL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( service != NULL )
|
||||
service->Release();
|
||||
|
||||
MLNavCtrl_EndUpdate( hLibrary );
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
BOOL Navigation_Initialize( void )
|
||||
{
|
||||
HNAVITEM hParent = NULL;
|
||||
OmService *service = NULL;
|
||||
HWND hLibrary = plugin.hwndLibraryParent;
|
||||
|
||||
MLNavCtrl_BeginUpdate( hLibrary, NUF_LOCK_TOP );
|
||||
|
||||
if ( SUCCEEDED( OmService::CreateRemote( SERVICE_PODCAST, MAKEINTRESOURCE( IDS_PODCAST_DIRECTORY ),
|
||||
MAKEINTRESOURCE( IDR_DISCOVER_ICON ),
|
||||
( serviceUrl[ 0 ] ? serviceUrl : L"https://client.winamp.com/podcasts" ), &service ) ) )
|
||||
{
|
||||
service->SetFlags( OmService::flagRoot, OmService::flagRoot );
|
||||
hParent = Navigation_CreateItem( hLibrary, hParent, service );
|
||||
service->Release();
|
||||
}
|
||||
|
||||
if ( hParent != NULL )
|
||||
{
|
||||
Navigation_ShowService( SERVICE_SUBSCRIPTION, SHOWMODE_SHOW );
|
||||
//Navigation_ShowService(SERVICE_DOWNLOADS, SHOWMODE_AUTO);
|
||||
}
|
||||
|
||||
MLNavCtrl_EndUpdate( hLibrary );
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void Navigation_OnDeleteItem( HNAVITEM hItem )
|
||||
{
|
||||
if ( hItem == NULL )
|
||||
return;
|
||||
|
||||
HWND hLibrary = plugin.hwndLibraryParent;
|
||||
if ( hLibrary == NULL )
|
||||
return;
|
||||
|
||||
WCHAR szBuffer[64] = {0};
|
||||
NAVITEM itemInfo = {0};
|
||||
|
||||
itemInfo.cbSize = sizeof( itemInfo );
|
||||
itemInfo.hItem = hItem;
|
||||
itemInfo.pszInvariant = szBuffer;
|
||||
itemInfo.cchInvariantMax = ARRAYSIZE( szBuffer );
|
||||
itemInfo.mask = NIMF_PARAM | NIMF_TEXTINVARIANT | NIMF_IMAGE;
|
||||
|
||||
if ( MLNavItem_GetInfo( hLibrary, &itemInfo ) != FALSE && Navigation_CheckInvariantName( szBuffer ) != FALSE )
|
||||
{
|
||||
OmService *service = (OmService *)itemInfo.lParam;
|
||||
|
||||
itemInfo.mask = NIMF_PARAM;
|
||||
itemInfo.lParam = 0L;
|
||||
|
||||
MLNavItem_SetInfo( hLibrary, &itemInfo );
|
||||
|
||||
service->Release();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
BOOL Navigation_ProcessMessage( INT msg, INT_PTR param1, INT_PTR param2, INT_PTR param3, INT_PTR *result )
|
||||
{
|
||||
if (msg < ML_MSG_TREE_BEGIN || msg > ML_MSG_TREE_END)
|
||||
return FALSE;
|
||||
|
||||
switch ( msg )
|
||||
{
|
||||
case ML_MSG_TREE_ONCREATEVIEW:
|
||||
{
|
||||
HWND hView = NULL;
|
||||
HRESULT hr = Navigation_CreateView( Navigation_GetMessageItem( msg, param1 ), (HWND)param2, &hView );
|
||||
*result = ( SUCCEEDED( hr ) ) ? (INT_PTR)hView : NULL;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
case ML_MSG_NAVIGATION_ONDESTROY:
|
||||
Navigation_OnDestroy();
|
||||
return TRUE;
|
||||
case ML_MSG_NAVIGATION_ONDELETE:
|
||||
Navigation_OnDeleteItem( Navigation_GetMessageItem( msg, param1 ) );
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
24
Src/Plugins/Library/ml_wire/navigation.h
Normal file
24
Src/Plugins/Library/ml_wire/navigation.h
Normal file
@ -0,0 +1,24 @@
|
||||
#ifndef NULLSOFT_PODCAST_PLUGIN_NAVIGATION_HEADER
|
||||
#define NULLSOFT_PODCAST_PLUGIN_NAVIGATION_HEADER
|
||||
|
||||
#if defined(_MSC_VER) && (_MSC_VER >= 1020)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <wtypes.h>
|
||||
|
||||
typedef LPVOID HNAVITEM;
|
||||
class OmService;
|
||||
|
||||
|
||||
BOOL Navigation_Initialize(void);
|
||||
BOOL Navigation_ProcessMessage(INT msg, INT_PTR param1, INT_PTR param2, INT_PTR param3, INT_PTR *result);
|
||||
|
||||
#define SHOWMODE_HIDE ((INT)0)
|
||||
#define SHOWMODE_SHOW ((INT)1)
|
||||
#define SHOWMODE_AUTO ((INT)-1)
|
||||
|
||||
HRESULT Navigation_ShowService(UINT serviceId, INT showMode);
|
||||
HNAVITEM Navigation_FindService(UINT serviceId, HNAVITEM hStart, OmService **serviceOut);
|
||||
|
||||
#endif //NULLSOFT_PODCAST_PLUGIN_NAVIGATION_HEADER
|
15
Src/Plugins/Library/ml_wire/png.rc
Normal file
15
Src/Plugins/Library/ml_wire/png.rc
Normal file
@ -0,0 +1,15 @@
|
||||
#include "resource.h"
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Data
|
||||
//
|
||||
IDR_DISCOVER_ICON RCDATA
|
||||
".\\resources\\discoverIcon.png"
|
||||
IDR_DOWNLOAD_ICON RCDATA
|
||||
".\\resources\\downloadIcon.png"
|
||||
IDR_SUBSCRIPTION_ICON RCDATA
|
||||
".\\resources\\subscriptionIcon.png"
|
||||
IDR_MEDIA_ICON RCDATA
|
||||
".\\resources\\mediaIcon.png"
|
||||
IDR_TEXT_ICON RCDATA
|
||||
".\\resources\\textIcon.png"
|
220
Src/Plugins/Library/ml_wire/resource.h
Normal file
220
Src/Plugins/Library/ml_wire/resource.h
Normal file
@ -0,0 +1,220 @@
|
||||
//{{NO_DEPENDENCIES}}
|
||||
// Microsoft Visual C++ generated include file.
|
||||
// Used by ml_podcast.rc
|
||||
//
|
||||
#define IDS_NULLSOFT_PODCAST 0
|
||||
#define IDS_PODCASTS 1
|
||||
#define IDS_DOWNLOADING_KB_COMPLETE 2
|
||||
#define IDS_DOWNLOADING_KB_PROGRESS 3
|
||||
#define IDS_SUBSCRIPTIONS 4
|
||||
#define IDS_DOWNLOADS 5
|
||||
#define IDS_DOWNLOADING 6
|
||||
#define IDS_CHOOSE_FOLDER 7
|
||||
#define IDS_ALREADY_SUBSCRIBED 8
|
||||
#define IDD_PODCAST 9
|
||||
#define IDS_FILE_NOT_FOUND 9
|
||||
#define IDS_CONNECTION_TIMED_OUT 10
|
||||
#define IDS_ERROR_PARSING_XML 11
|
||||
#define IDS_INVALID_RSS_FEED 12
|
||||
#define IDS_NO_JNETLIB 13
|
||||
#define IDS_JNETLIB_MISSING 14
|
||||
#define IDS_NO_EXPAT 15
|
||||
#define IDS_EXPAT_MISSING 16
|
||||
#define IDS_CONNECTION_RESET 17
|
||||
#define IDS_ERROR_SUBSCRIBING_TO_PODCAST 18
|
||||
#define IDS_UPD_MANUALLY 19
|
||||
#define IDS_UPD_WEEK 20
|
||||
#define IDS_UPD_DAY 21
|
||||
#define IDS_UPD_12HRS 22
|
||||
#define IDS_UPD_6HRS 23
|
||||
#define IDS_UPD_3HRS 24
|
||||
#define IDS_UPD_HOUR 25
|
||||
#define IDS_UPD_30MINS 26
|
||||
#define IDS_ERROR_FYEO 27
|
||||
#define IDS_WDAY_SUN 28
|
||||
#define IDS_WDAY_MON 29
|
||||
#define IDS_WDAY_TUE 30
|
||||
#define IDS_WDAY_WED 31
|
||||
#define IDS_WDAY_THU 32
|
||||
#define IDS_WDAY_FRI 33
|
||||
#define IDS_WDAY_SAT 34
|
||||
#define IDS_MONTH_JAN 35
|
||||
#define IDS_MONTH_FEB 36
|
||||
#define IDS_MONTH_MAR 37
|
||||
#define IDS_MONTH_APR 38
|
||||
#define IDS_MONTH_MAY 39
|
||||
#define IDS_MONTH_JUN 40
|
||||
#define IDS_MONTH_JUL 41
|
||||
#define IDS_MONTH_AUG 42
|
||||
#define IDS_MONTH_SEP 43
|
||||
#define IDS_MONTH_OCT 44
|
||||
#define IDS_MONTH_NOV 45
|
||||
#define IDS_MONTH_DEC 46
|
||||
#define IDS_RECEIVING_UPDATES_FOR 47
|
||||
#define IDS_GOT_NEW_ITEMS_FOR 48
|
||||
#define IDS_CHANNEL_ALREADY_PRESENT 49
|
||||
#define IDS_DUPLICATE_CHANNEL 50
|
||||
#define IDS_ERROR_ADDING_URL 51
|
||||
#define IDS_ERROR_PARSING_XML_FROM_SERVER 52
|
||||
#define IDS_LINK_HAS_NO_RSS_INFO 53
|
||||
#define IDS_INVALID_LINK 54
|
||||
#define IDS_CONNECTION_RESET_BY_PEER 55
|
||||
#define IDS_DOWNLOADING_PERCENT 56
|
||||
#define IDS_CHANNEL 57
|
||||
#define IDS_ITEM 58
|
||||
#define IDS_PROGRESS 59
|
||||
#define IDS_PATH 60
|
||||
#define IDS_PERM_DELETE_ARE_YOU_SURE 61
|
||||
#define IDS_PERM_DELETE_THESE_ARE_YOU_SURE 62
|
||||
#define IDS_DELETION 63
|
||||
#define IDS_CLEAR_ALL_FINISHED_DOWNLOADS 64
|
||||
#define IDS_CLEAN_UP_LIST 65
|
||||
#define IDS_DONE 66
|
||||
#define IDS_SAVE 67
|
||||
#define IDS_REQUIRES_INTERNET_CONNECTION_ENSURE_CONNECTION 68
|
||||
#define IDS_ADD_TO_DOWNLOADS 69
|
||||
#define IDS_NO_MEDIA_TO_DOWNLOAD 70
|
||||
#define IDS_TEXT_ARTICLE 71
|
||||
#define IDS_DATE_ADDED 72
|
||||
#define IDS_MEDIA_PRESENT 73
|
||||
#define IDS_SURE_YOU_WANT_TO_REMOVE_THIS 74
|
||||
#define IDS_CONFIRM 75
|
||||
#define IDS_CANCEL_DOWNLOADS_AND_QUIT 76
|
||||
#define IDS_CONFIRM_QUIT 77
|
||||
#define IDS_ARTICLE_WITH_MEDIA 78
|
||||
#define IDS_PODCASTS_DIRECTORY 79
|
||||
#define IDS_PODCAST_DIRECTORY 79
|
||||
#define IDS_DELETEFAILED 80
|
||||
#define IDS_STRING81 81
|
||||
#define IDS_SORRY 81
|
||||
#define IDS_EDIT_CHANNEL 82
|
||||
#define IDS_ATD_NEVER 83
|
||||
#define IDS_ATD_LASTONE 84
|
||||
#define IDS_ATD_LASTTWO 85
|
||||
#define IDS_ATD_LASTTHREE 86
|
||||
#define IDS_ATD_LASTFIVE 87
|
||||
#define IDD_PREFERENCES 104
|
||||
#define IDD_ADDURL 105
|
||||
#define IDD_DOWNLOADS 107
|
||||
#define IDB_ICON_TEXT 110
|
||||
#define IDB_BITMAP1 111
|
||||
#define IDB_ICON_MEDIA 111
|
||||
#define IDR_MENU1 112
|
||||
#define IDB_BITMAP2 114
|
||||
#define IDB_TREEIMAGE_DOWNLOAD 114
|
||||
#define IDB_BITMAP3 115
|
||||
#define IDB_TREEIMAGE_SUBSCRIPTION 115
|
||||
#define IDB_BITMAP4 116
|
||||
#define IDB_TREEIMAGE_DISCOVER 116
|
||||
#define IDS_PODCAST_SUBSCRIPTION_HEADER 120
|
||||
#define IDS_PODCAST_SUBSCRIPTION_PROMP 121
|
||||
#define IDR_VIEW_DOWNLOAD_ACCELERATORS 122
|
||||
#define IDS_MEDIA_TIME 125
|
||||
#define IDS_EPISODE_INFO 126
|
||||
#define IDS_MEDIA_SIZE 127
|
||||
#define IDS_BYTES 128
|
||||
#define IDS_KIB 129
|
||||
#define IDS_MIB 130
|
||||
#define IDS_GIB 131
|
||||
#define IDC_CUSTOM 1000
|
||||
#define IDC_CHANNELLIST 1002
|
||||
#define IDC_CHANNELLIST2 1003
|
||||
#define IDC_EPISODE_INFO 1003
|
||||
#define IDC_ITEMLIST 1006
|
||||
#define IDC_DESCRIPTION 1008
|
||||
#define IDC_FEEDLIST 1009
|
||||
#define IDC_NEW 1010
|
||||
#define IDC_DELETE 1011
|
||||
#define IDC_REFRESH 1012
|
||||
#define IDC_EDITDESCRIPTION 1013
|
||||
#define IDC_EDITURL 1014
|
||||
#define IDC_UPDATETIME 1017
|
||||
#define IDC_AUTODOWNLOAD 1018
|
||||
#define IDC_DEFAULTUPDATETIME 1019
|
||||
#define IDC_DEFAULTAUTODOWNLOAD 1020
|
||||
#define IDC_APPLYDEFAULTS 1021
|
||||
#define IDC_LOCATION 1022
|
||||
#define IDC_LOCATIONBROWSE 1024
|
||||
#define IDC_ADDURLEDIT 1027
|
||||
#define IDC_ADDURLBUTTON 1028
|
||||
#define IDC_LIST1 1029
|
||||
#define IDC_DOWNLOADLIST 1029
|
||||
#define IDC_STATICDESCRIPTION 1030
|
||||
#define IDC_STATICURL 1031
|
||||
#define IDC_STATICUPDATE 1032
|
||||
#define IDC_DOWNLOADGROUP 1033
|
||||
#define IDC_STATICAUTODOWNLOAD 1035
|
||||
#define IDC_FEEDSGROUP 1036
|
||||
#define IDC_DEFAULTSGROUP 1037
|
||||
#define IDC_STATICUPDATEEVERY 1038
|
||||
#define IDC_STATICDEFAULTAUTODOWNLOAD 1039
|
||||
#define IDC_ADD 1044
|
||||
#define IDC_EDIT 1045
|
||||
#define IDC_PLAY 1047
|
||||
#define IDC_ADDURL 1047
|
||||
#define IDC_ENQUEUE 1048
|
||||
#define IDC_USEDEFAULTS 1048
|
||||
#define IDC_VISIT 1049
|
||||
#define IDC_USECUSTOM 1049
|
||||
#define IDC_DOWNLOAD 1050
|
||||
#define IDC_CUSTOMGROUP 1050
|
||||
#define IDC_BUTTON1 1051
|
||||
#define IDC_CANCEL 1051
|
||||
#define IDC_BROWSE 1051
|
||||
#define IDC_ENQUEUE2 1051
|
||||
#define IDC_FINDNEW 1051
|
||||
#define IDC_UPDATELIST 1052
|
||||
#define IDC_VDIV 1054
|
||||
#define IDC_HDIV1 1055
|
||||
#define IDC_HDIV 1055
|
||||
#define IDC_BROWSER 1057
|
||||
#define IDC_STATUS 1058
|
||||
#define IDC_EDIT1 1059
|
||||
#define IDC_DOWNLOADLOCATION 1059
|
||||
#define IDC_SETTINGSBOX 1060
|
||||
#define IDC_CLEANUP 1060
|
||||
#define IDC_CHECK1 1062
|
||||
#define IDC_UPDATEONLAUNCH 1062
|
||||
#define IDC_STATIC_UPDATEEVERY 1064
|
||||
#define IDC_PLAYACTION 1065
|
||||
#define IDC_ENQUEUEACTION 1066
|
||||
#define IDC_AUTODOWNLOADLIST 1067
|
||||
#define IDC_STATIC_AUTODOWNLOAD 1068
|
||||
#define IDC_DIRECTORYURL 1069
|
||||
#define IDR_DISCOVER_ICON 20000
|
||||
#define IDR_DOWNLOAD_ICON 20001
|
||||
#define IDR_SUBSCRIPTION_ICON 20002
|
||||
#define IDR_MEDIA_ICON 20003
|
||||
#define IDR_TEXT_ICON 20004
|
||||
#define IDM_CHANNELS 40006
|
||||
#define IDC_REFRESHALL 40008
|
||||
#define ID_PLAYMEDIA_IDC 40018
|
||||
#define IDC_REMOVE 40024
|
||||
#define ID_DOWNLOADS_SENDTO 40025
|
||||
#define ID_Menu 40026
|
||||
#define IDC_INFOBOX 40028
|
||||
#define IDC_SELECTALL 40030
|
||||
#define ID_DOWNLOADS_SENDTO40031 40031
|
||||
#define ID_NAVIGATION_PREFERENCES 40032
|
||||
#define ID_NAVIGATION_HELP 40033
|
||||
#define ID_DOWNLOADS_EXPLORERITEMFOLDER 40034
|
||||
#define IDC_EXPLORERITEMFOLDER 40034
|
||||
#define ID_ENQUEUE 40036
|
||||
#define ID_SUBSCRIPTIONNAVIGATION_PREFERENCE 40043
|
||||
#define ID_SUBSCRIPTIONNAVIGATION_DIRECTORY 40044
|
||||
#define ID_NAVIGATION_DIRECTORY 40045
|
||||
#define ID_SUBSCRIPTIONNAVIGATION_HELP 40046
|
||||
#define ID_NAVIGATION_REFRESHALL 40047
|
||||
#define ID_EPISODE_SELECTALL 40048
|
||||
#define IDS_PLUGIN_NAME 65534
|
||||
|
||||
// Next default values for new objects
|
||||
//
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
#ifndef APSTUDIO_READONLY_SYMBOLS
|
||||
#define _APS_NEXT_RESOURCE_VALUE 133
|
||||
#define _APS_NEXT_COMMAND_VALUE 40052
|
||||
#define _APS_NEXT_CONTROL_VALUE 1068
|
||||
#define _APS_NEXT_SYMED_VALUE 101
|
||||
#endif
|
||||
#endif
|
BIN
Src/Plugins/Library/ml_wire/resources/discoverIcon.png
Normal file
BIN
Src/Plugins/Library/ml_wire/resources/discoverIcon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 223 B |
BIN
Src/Plugins/Library/ml_wire/resources/downloadIcon.png
Normal file
BIN
Src/Plugins/Library/ml_wire/resources/downloadIcon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 220 B |
BIN
Src/Plugins/Library/ml_wire/resources/mediaIcon.png
Normal file
BIN
Src/Plugins/Library/ml_wire/resources/mediaIcon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 168 B |
BIN
Src/Plugins/Library/ml_wire/resources/subscriptionIcon.png
Normal file
BIN
Src/Plugins/Library/ml_wire/resources/subscriptionIcon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 244 B |
BIN
Src/Plugins/Library/ml_wire/resources/textIcon.png
Normal file
BIN
Src/Plugins/Library/ml_wire/resources/textIcon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 152 B |
273
Src/Plugins/Library/ml_wire/service.cpp
Normal file
273
Src/Plugins/Library/ml_wire/service.cpp
Normal file
@ -0,0 +1,273 @@
|
||||
#include "main.h"
|
||||
#include "./service.h"
|
||||
#include "api__ml_wire.h"
|
||||
#include "./util.h"
|
||||
#include "./resource.h"
|
||||
#include "./externalCOM.h"
|
||||
|
||||
#include "../winamp/wa_ipc.h"
|
||||
#include <strsafe.h>
|
||||
|
||||
#define IS_INVALIDISPATCH(__disp) (((IDispatch *)1) == (__disp) || NULL == (__disp))
|
||||
|
||||
OmService::OmService( UINT nId ) : id( nId )
|
||||
{}
|
||||
|
||||
OmService::~OmService()
|
||||
{
|
||||
Plugin_FreeResString( name );
|
||||
Plugin_FreeResString( url );
|
||||
Plugin_FreeResString( icon );
|
||||
}
|
||||
|
||||
|
||||
HRESULT OmService::CreateRemote( UINT nId, LPCWSTR pszName, LPCWSTR pszIcon, LPCWSTR pszUrl, OmService **instance )
|
||||
{
|
||||
if ( instance == NULL )
|
||||
return E_POINTER;
|
||||
|
||||
*instance = NULL;
|
||||
|
||||
if ( nId == 0 || pszName == NULL )
|
||||
return E_INVALIDARG;
|
||||
|
||||
OmService *service = new OmService( nId );
|
||||
if ( service == NULL )
|
||||
return E_OUTOFMEMORY;
|
||||
|
||||
service->SetName( pszName );
|
||||
service->SetIcon( pszIcon );
|
||||
service->SetUrl( pszUrl );
|
||||
|
||||
*instance = service;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT OmService::CreateLocal( UINT nId, LPCWSTR pszName, LPCWSTR pszIcon, SVCWNDCREATEPROC windowCreator, OmService **instance )
|
||||
{
|
||||
if ( instance == NULL )
|
||||
return E_POINTER;
|
||||
|
||||
*instance = NULL;
|
||||
|
||||
if ( nId == 0 || pszName == NULL )
|
||||
return E_INVALIDARG;
|
||||
|
||||
OmService *service = new OmService( nId );
|
||||
if ( service == NULL )
|
||||
return E_OUTOFMEMORY;
|
||||
|
||||
service->SetFlags( flagLocal, flagLocal );
|
||||
service->SetName( pszName );
|
||||
service->SetIcon( pszIcon );
|
||||
service->SetWindowCreator( windowCreator );
|
||||
|
||||
*instance = service;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
size_t OmService::AddRef()
|
||||
{
|
||||
return _ref.fetch_add( 1 );
|
||||
}
|
||||
|
||||
size_t OmService::Release()
|
||||
{
|
||||
if ( _ref.load() == 0 )
|
||||
return _ref.load();
|
||||
|
||||
LONG r = _ref.fetch_sub( 1 );
|
||||
if ( r == 0 )
|
||||
delete( this );
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
int OmService::QueryInterface( GUID interface_guid, void **object )
|
||||
{
|
||||
if ( object == NULL )
|
||||
return E_POINTER;
|
||||
|
||||
if ( IsEqualIID( interface_guid, IFC_OmService ) )
|
||||
*object = static_cast<ifc_omservice *>( this );
|
||||
else
|
||||
{
|
||||
*object = NULL;
|
||||
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
if ( *object == NULL )
|
||||
return E_UNEXPECTED;
|
||||
|
||||
AddRef();
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
unsigned int OmService::GetId()
|
||||
{
|
||||
return id;
|
||||
}
|
||||
|
||||
HRESULT OmService::GetName( wchar_t *pszBuffer, int cchBufferMax )
|
||||
{
|
||||
return Plugin_CopyResString( pszBuffer, cchBufferMax, name );
|
||||
}
|
||||
|
||||
HRESULT OmService::GetUrl( wchar_t *pszBuffer, int cchBufferMax )
|
||||
{
|
||||
return Plugin_CopyResString( pszBuffer, cchBufferMax, url );
|
||||
}
|
||||
|
||||
HRESULT OmService::GetIcon( wchar_t *pszBuffer, int cchBufferMax )
|
||||
{
|
||||
if ( icon != NULL && IS_INTRESOURCE( icon ) )
|
||||
{
|
||||
WCHAR szPath[ 2 * MAX_PATH ] = { 0 };
|
||||
if ( GetModuleFileName( plugin.hDllInstance, szPath, ARRAYSIZE( szPath ) ) == 0 )
|
||||
return E_FAIL;
|
||||
|
||||
return StringCchPrintf( pszBuffer, cchBufferMax, L"res://%s/#%d/#%d", szPath, RT_RCDATA, icon );
|
||||
}
|
||||
|
||||
return StringCchCopyEx( pszBuffer, cchBufferMax, icon, NULL, NULL, STRSAFE_IGNORE_NULLS );
|
||||
}
|
||||
|
||||
HRESULT OmService::GetExternal( IDispatch **ppDispatch )
|
||||
{
|
||||
if ( ppDispatch == NULL )
|
||||
return E_POINTER;
|
||||
|
||||
*ppDispatch = NULL;
|
||||
|
||||
HWND hWinamp = plugin.hwndWinampParent;
|
||||
if ( hWinamp == NULL )
|
||||
return E_UNEXPECTED;
|
||||
|
||||
//////*ppDispatch = (IDispatch*)SENDWAIPC(hWinamp, IPC_GET_DISPATCH_OBJECT, 0);
|
||||
|
||||
WCHAR szBuffer[ 64 ] = { 0 };
|
||||
if ( SUCCEEDED( StringCchPrintfW( szBuffer, ARRAYSIZE( szBuffer ), L"%u", id ) ) )
|
||||
*ppDispatch = (IDispatch *) SENDWAIPC( hWinamp, IPC_JSAPI2_GET_DISPATCH_OBJECT, (WPARAM) szBuffer );
|
||||
|
||||
|
||||
if (IS_INVALIDISPATCH(*ppDispatch) && FAILED(ExternalCOM::CreateInstance((ExternalCOM**)ppDispatch)))
|
||||
{
|
||||
*ppDispatch = NULL;
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
HRESULT OmService::SetName( LPCWSTR pszName )
|
||||
{
|
||||
Plugin_FreeResString( name );
|
||||
name = Plugin_DuplicateResString( pszName );
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT OmService::SetUrl( LPCWSTR pszUrl )
|
||||
{
|
||||
Plugin_FreeResString( url );
|
||||
url = Plugin_DuplicateResString( pszUrl );
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT OmService::SetIcon( LPCWSTR pszIcon )
|
||||
{
|
||||
Plugin_FreeResString( icon );
|
||||
icon = Plugin_DuplicateResString( pszIcon );
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
void OmService::SetFlags( UINT mask, UINT newFlags )
|
||||
{
|
||||
flags = ( flags & ~mask ) | ( mask & newFlags );
|
||||
}
|
||||
|
||||
UINT OmService::GetFlags( void )
|
||||
{
|
||||
return flags;
|
||||
}
|
||||
|
||||
|
||||
HRESULT OmService::SetWindowCreator( SVCWNDCREATEPROC proc )
|
||||
{
|
||||
windowCreator = proc;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT OmService::GetWindowCreator( SVCWNDCREATEPROC *proc )
|
||||
{
|
||||
if ( proc == NULL )
|
||||
return E_INVALIDARG;
|
||||
|
||||
*proc = windowCreator;
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
HRESULT OmService::CreateView( HWND hParent, HWND *hView )
|
||||
{
|
||||
if ( hView == NULL )
|
||||
return E_POINTER;
|
||||
|
||||
*hView = NULL;
|
||||
HRESULT hr = S_OK;
|
||||
|
||||
if ( ( flagLocal & flags ) != 0 )
|
||||
{
|
||||
if ( windowCreator != NULL )
|
||||
{
|
||||
*hView = windowCreator( hParent, this );
|
||||
if ( *hView == NULL )
|
||||
hr = E_FAIL;
|
||||
}
|
||||
else
|
||||
hr = E_INVALIDARG;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( OMBROWSERMNGR != NULL )
|
||||
{
|
||||
hr = OMBROWSERMNGR->Initialize( NULL, plugin.hwndWinampParent );
|
||||
if ( SUCCEEDED( hr ) )
|
||||
hr = OMBROWSERMNGR->CreateView( this, hParent, NULL, 0, hView );
|
||||
}
|
||||
else
|
||||
hr = E_UNEXPECTED;
|
||||
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
|
||||
#define CBCLASS OmService
|
||||
START_DISPATCH;
|
||||
CB( ADDREF, AddRef )
|
||||
CB( RELEASE, Release )
|
||||
CB( QUERYINTERFACE, QueryInterface )
|
||||
CB( API_GETID, GetId )
|
||||
CB( API_GETNAME, GetName )
|
||||
CB( API_GETURL, GetUrl )
|
||||
CB( API_GETICON, GetIcon )
|
||||
CB( API_GETEXTERNAL, GetExternal )
|
||||
END_DISPATCH;
|
||||
#undef CBCLASS
|
||||
|
||||
|
69
Src/Plugins/Library/ml_wire/service.h
Normal file
69
Src/Plugins/Library/ml_wire/service.h
Normal file
@ -0,0 +1,69 @@
|
||||
#ifndef NULLSOFT_PODCAST_PLUGIN_SERVICE_HEADER
|
||||
#define NULLSOFT_PODCAST_PLUGIN_SERVICE_HEADER
|
||||
|
||||
#if defined(_MSC_VER) && (_MSC_VER >= 1020)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <wtypes.h>
|
||||
#include <atomic>
|
||||
|
||||
#include "../omBrowser/ifc_omservice.h"
|
||||
|
||||
class OmService;
|
||||
typedef HWND (CALLBACK *SVCWNDCREATEPROC)(HWND /*hParent*/, OmService* /*service*/);
|
||||
|
||||
class OmService : public ifc_omservice
|
||||
{
|
||||
public:
|
||||
typedef enum
|
||||
{
|
||||
flagRoot = 0x00000001,
|
||||
flagLocal = 0x00000002,
|
||||
} Flags;
|
||||
|
||||
protected:
|
||||
OmService( UINT nId );
|
||||
~OmService();
|
||||
|
||||
public:
|
||||
static HRESULT CreateRemote( UINT nId, LPCWSTR pszName, LPCWSTR pszIcon, LPCWSTR pszUrl, OmService **instance );
|
||||
static HRESULT CreateLocal( UINT nId, LPCWSTR pszName, LPCWSTR pszIcon, SVCWNDCREATEPROC windowCreator, OmService **instance );
|
||||
|
||||
/* Dispatchable */
|
||||
size_t AddRef();
|
||||
size_t Release();
|
||||
int QueryInterface( GUID interface_guid, void **object );
|
||||
|
||||
/* ifc_omservice */
|
||||
unsigned int GetId();
|
||||
HRESULT GetName( wchar_t *pszBuffer, int cchBufferMax );
|
||||
HRESULT GetUrl( wchar_t *pszBuffer, int cchBufferMax );
|
||||
HRESULT GetExternal( IDispatch **ppDispatch );
|
||||
HRESULT GetIcon( wchar_t *pszBuffer, int cchBufferMax );
|
||||
|
||||
HRESULT SetName( LPCWSTR pszName );
|
||||
HRESULT SetUrl( LPCWSTR pszUrl );
|
||||
HRESULT SetIcon( LPCWSTR pszIcon );
|
||||
|
||||
void SetFlags( UINT mask, UINT newFlags );
|
||||
UINT GetFlags( void );
|
||||
|
||||
HRESULT SetWindowCreator( SVCWNDCREATEPROC proc );
|
||||
HRESULT GetWindowCreator( SVCWNDCREATEPROC *proc );
|
||||
|
||||
HRESULT CreateView( HWND hParent, HWND *hView );
|
||||
|
||||
protected:
|
||||
RECVS_DISPATCH;
|
||||
|
||||
std::atomic<std::size_t> _ref = 1;
|
||||
UINT id = 0;
|
||||
LPWSTR name = NULL;
|
||||
LPWSTR url = NULL;
|
||||
SVCWNDCREATEPROC windowCreator = NULL;
|
||||
LPWSTR icon = NULL;
|
||||
UINT flags = 0;
|
||||
};
|
||||
|
||||
#endif //NULLSOFT_PODCAST_PLUGIN_SERVICE_HEADER
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user