mirror of
https://github.com/WinampDesktop/winamp.git
synced 2025-06-17 16:55:46 -04:00
Initial community commit
This commit is contained in:
253
Src/playlist/B4SLoader.cpp
Normal file
253
Src/playlist/B4SLoader.cpp
Normal file
@ -0,0 +1,253 @@
|
||||
#include "main.h"
|
||||
#include "B4SLoader.h"
|
||||
#include "../nu/AutoChar.h"
|
||||
#include "..\Components\wac_network\wac_network_http_receiver_api.h"
|
||||
#include <strsafe.h>
|
||||
|
||||
B4SLoader::B4SLoader() : parser(0), parserFactory(0)
|
||||
{
|
||||
parserFactory = WASABI_API_SVC->service_getServiceByGuid(obj_xmlGUID);
|
||||
if (parserFactory)
|
||||
parser = (obj_xml *)parserFactory->getInterface();
|
||||
|
||||
if (parser)
|
||||
{
|
||||
parser->xmlreader_registerCallback(L"WasabiXML\fplaylist\fentry\fname", &b4sXml.title);
|
||||
parser->xmlreader_registerCallback(L"WinampXML\fplaylist\fentry\fname", &b4sXml.title);
|
||||
|
||||
parser->xmlreader_registerCallback(L"WasabiXML\fplaylist\fentry\flength", &b4sXml.length);
|
||||
parser->xmlreader_registerCallback(L"WinampXML\fplaylist\fentry\flength", &b4sXml.length);
|
||||
|
||||
//parser->xmlreader_registerCallback(L"WasabiXML\fplaylist", this);
|
||||
//parser->xmlreader_registerCallback(L"WinampXML\fplaylist", this);
|
||||
parser->xmlreader_registerCallback(L"WasabiXML\fplaylist\fentry", &b4sXml);
|
||||
parser->xmlreader_registerCallback(L"WinampXML\fplaylist\fentry", &b4sXml);
|
||||
parser->xmlreader_open();
|
||||
//parser->xmlreader_setEncoding(L"UTF-8");
|
||||
}
|
||||
}
|
||||
|
||||
B4SXML::B4SXML()
|
||||
{
|
||||
filename[0]=0;
|
||||
playlist = 0;
|
||||
}
|
||||
|
||||
B4SLoader::~B4SLoader()
|
||||
{
|
||||
if (parser)
|
||||
{
|
||||
parser->xmlreader_unregisterCallback(&b4sXml);
|
||||
parser->xmlreader_unregisterCallback(&b4sXml.length);
|
||||
parser->xmlreader_unregisterCallback(&b4sXml.title);
|
||||
parser->xmlreader_close();
|
||||
}
|
||||
|
||||
if (parserFactory && parser)
|
||||
parserFactory->releaseInterface(parser);
|
||||
|
||||
parserFactory = 0;
|
||||
parser = 0;
|
||||
}
|
||||
|
||||
#define HTTP_BUFFER_SIZE 1024
|
||||
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;
|
||||
}
|
||||
|
||||
static void 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 ;
|
||||
}
|
||||
while (ret == HTTPRECEIVER_RUN_OK);
|
||||
|
||||
// finish off the data
|
||||
do
|
||||
{
|
||||
if (FeedXMLHTTP(http, parser, &noData) != API_XML_SUCCESS)
|
||||
return ;
|
||||
} while (!noData);
|
||||
|
||||
parser->xmlreader_feed(0, 0);
|
||||
}
|
||||
|
||||
void B4SXML::StartTag(const wchar_t *xmlpath, const wchar_t *xmltag, ifc_xmlreaderparams *params)
|
||||
{
|
||||
if (!_wcsicmp(xmltag, L"entry"))
|
||||
{
|
||||
const wchar_t *track = params->getItemValue(L"playstring");
|
||||
if (!_wcsnicmp(track, L"file://", 7))
|
||||
track+=7;
|
||||
else if (!_wcsnicmp(track, L"file:", 5))
|
||||
track+=5;
|
||||
StringCchCopyW(filename, FILENAME_SIZE, track);
|
||||
}
|
||||
}
|
||||
|
||||
void B4SXML::EndTag(const wchar_t *xmlpath, const wchar_t *xmltag)
|
||||
{
|
||||
if (!_wcsicmp(xmltag, L"entry") && filename[0])
|
||||
{
|
||||
int lengthSeconds=-1;
|
||||
const wchar_t *trackLength = length.GetString();
|
||||
if (trackLength && *trackLength)
|
||||
lengthSeconds = _wtoi(trackLength) / 1000;
|
||||
|
||||
const wchar_t *trackTitle = title.GetString();
|
||||
// TODO: deal with relative pathnames
|
||||
if (trackTitle && *trackTitle)
|
||||
playlist->OnFile(filename, trackTitle, lengthSeconds, 0); // TODO: extended info
|
||||
else
|
||||
playlist->OnFile(filename, 0, lengthSeconds, 0);// TODO: extended info
|
||||
|
||||
filename[0]=0;
|
||||
length.Reset();
|
||||
title.Reset();
|
||||
}
|
||||
}
|
||||
#if 0 // TOOD: reimplement
|
||||
void B4SLoader::LoadURL(const char *url)
|
||||
{
|
||||
if (!parser)
|
||||
return ; // no sense in continuing if there's no parser available
|
||||
|
||||
api_httpreceiver *http = 0;
|
||||
waServiceFactory *sf = WASABI_API_SVC->service_getServiceByGuid(httpreceiverGUID);
|
||||
if (sf)
|
||||
http = (api_httpreceiver *)sf->getInterface();
|
||||
|
||||
if (!http)
|
||||
return ;
|
||||
http->AllowCompression();
|
||||
http->open(API_DNS_AUTODNS, HTTP_BUFFER_SIZE, GetProxy());
|
||||
SetUserAgent(http);
|
||||
http->connect(url);
|
||||
int ret;
|
||||
bool first = true;
|
||||
|
||||
do
|
||||
{
|
||||
Sleep(50);
|
||||
ret = http->run();
|
||||
if (ret == -1) // connection failed
|
||||
break;
|
||||
|
||||
// ---- check our reply code ----
|
||||
int replycode = http->GetReplyCode();
|
||||
switch (replycode)
|
||||
{
|
||||
case 0:
|
||||
case 100:
|
||||
break;
|
||||
case 200:
|
||||
{
|
||||
RunXMLDownload(http, parser);
|
||||
sf->releaseInterface(http);
|
||||
return ;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
sf->releaseInterface(http);
|
||||
return ;
|
||||
}
|
||||
}
|
||||
while (ret == HTTPRECEIVER_RUN_OK);
|
||||
const char *er = http->geterrorstr();
|
||||
sf->releaseInterface(http);
|
||||
return ;
|
||||
}
|
||||
|
||||
void B4SLoader::LoadFile(const char *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, NULL, NULL);
|
||||
|
||||
if (file == INVALID_HANDLE_VALUE)
|
||||
return ;
|
||||
|
||||
char data[1024] = {0};
|
||||
|
||||
while (true)
|
||||
{
|
||||
DWORD bytesRead = 0;
|
||||
if (ReadFile(file, data, 1024, &bytesRead, NULL) && bytesRead)
|
||||
{
|
||||
parser->xmlreader_feed(data, bytesRead);
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
CloseHandle(file);
|
||||
parser->xmlreader_feed(0, 0);
|
||||
}
|
||||
#endif
|
||||
int B4SLoader::Load(const wchar_t *filename, ifc_playlistloadercallback *playlist)
|
||||
{
|
||||
if (!parser)
|
||||
return IFC_PLAYLISTLOADER_FAILED; // no sense in continuing if there's no parser available
|
||||
|
||||
b4sXml.playlist=playlist;
|
||||
|
||||
HANDLE file = CreateFileW(filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, NULL, NULL);
|
||||
|
||||
if (file == INVALID_HANDLE_VALUE)
|
||||
return IFC_PLAYLISTLOADER_FAILED;
|
||||
|
||||
while (true)
|
||||
{
|
||||
char data[1024] = {0};
|
||||
DWORD bytesRead = 0;
|
||||
if (ReadFile(file, data, 1024, &bytesRead, NULL) && bytesRead)
|
||||
{
|
||||
parser->xmlreader_feed(data, bytesRead);
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
CloseHandle(file);
|
||||
parser->xmlreader_feed(0, 0);
|
||||
return IFC_PLAYLISTLOADER_SUCCESS;
|
||||
}
|
||||
|
||||
#ifdef CBCLASS
|
||||
#undef CBCLASS
|
||||
#endif
|
||||
|
||||
#define CBCLASS B4SXML
|
||||
START_DISPATCH;
|
||||
VCB(ONSTARTELEMENT, StartTag)
|
||||
VCB(ONENDELEMENT, EndTag)
|
||||
END_DISPATCH;
|
||||
|
||||
#ifdef CBCLASS
|
||||
#undef CBCLASS
|
||||
#endif
|
||||
|
||||
#define CBCLASS B4SLoader
|
||||
START_DISPATCH;
|
||||
CB(IFC_PLAYLISTLOADER_LOAD, Load)
|
||||
|
||||
END_DISPATCH;
|
46
Src/playlist/B4SLoader.h
Normal file
46
Src/playlist/B4SLoader.h
Normal file
@ -0,0 +1,46 @@
|
||||
#ifndef NULLSOFT_WINAMP_B4S_H
|
||||
#define NULLSOFT_WINAMP_B4S_H
|
||||
|
||||
#include "../xml/obj_xml.h"
|
||||
#include "../xml/ifc_xmlreadercallback.h"
|
||||
#include "api__playlist.h"
|
||||
#include <api/service/waServiceFactory.h>
|
||||
#include "XMLString.h"
|
||||
#include "main.h"
|
||||
#include "ifc_playlistloader.h"
|
||||
|
||||
class B4SXML : public ifc_xmlreadercallback
|
||||
{
|
||||
public:
|
||||
B4SXML();
|
||||
ifc_playlistloadercallback *playlist;
|
||||
//private:
|
||||
|
||||
/* XML callbacks */
|
||||
void StartTag(const wchar_t *xmlpath, const wchar_t *xmltag, ifc_xmlreaderparams *params);
|
||||
void EndTag(const wchar_t *xmlpath, const wchar_t *xmltag);
|
||||
|
||||
XMLString /*name, artist, */title/*, album*/, length; // wa2 only supports title and length in the playlist anyway
|
||||
RECVS_DISPATCH;
|
||||
wchar_t filename[FILENAME_SIZE];
|
||||
};
|
||||
|
||||
class B4SLoader : public ifc_playlistloader
|
||||
{
|
||||
public:
|
||||
B4SLoader();
|
||||
~B4SLoader();
|
||||
|
||||
void LoadFile(const char *filename);
|
||||
void LoadURL(const char *url);
|
||||
|
||||
int Load(const wchar_t *filename, ifc_playlistloadercallback *playlist);
|
||||
|
||||
RECVS_DISPATCH;
|
||||
|
||||
obj_xml *parser;
|
||||
waServiceFactory *parserFactory;
|
||||
B4SXML b4sXml;
|
||||
};
|
||||
|
||||
#endif
|
40
Src/playlist/B4SWriter.cpp
Normal file
40
Src/playlist/B4SWriter.cpp
Normal file
@ -0,0 +1,40 @@
|
||||
#include "B4SWriter.h"
|
||||
|
||||
/*
|
||||
TODO: escape XML shit
|
||||
*/
|
||||
|
||||
B4SWriter::B4SWriter() : fp(0)
|
||||
{
|
||||
}
|
||||
|
||||
int B4SWriter::Open(const wchar_t *filename)
|
||||
{
|
||||
fp = _wfopen(filename, L"wt");
|
||||
if (!fp)
|
||||
return 0;
|
||||
|
||||
fwprintf(fp, L"<playlist>\n");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void B4SWriter::Write(const wchar_t *filename)
|
||||
{
|
||||
fwprintf(fp, L"<entry playstring=\"%s\"/>\n", filename);
|
||||
}
|
||||
|
||||
void B4SWriter::Write(const wchar_t *filename, const wchar_t *title, int length)
|
||||
{
|
||||
fwprintf(fp, L"<entry playstring=\"%s\">\n", filename);
|
||||
fwprintf(fp, L"<name>%s</name>\n", title);
|
||||
fwprintf(fp, L"<length>%d</length>\n", length);
|
||||
fwprintf(fp, L"</entry>\n");
|
||||
}
|
||||
|
||||
void B4SWriter::Close()
|
||||
{
|
||||
fputs("</playlist>", fp);
|
||||
fclose(fp);
|
||||
|
||||
}
|
24
Src/playlist/B4SWriter.h
Normal file
24
Src/playlist/B4SWriter.h
Normal file
@ -0,0 +1,24 @@
|
||||
#ifndef NULLSOFT_PLAYLIST_B4SWRITER_H
|
||||
#define NULLSOFT_PLAYLIST_B4SWRITER_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include "PlaylistWriter.h"
|
||||
|
||||
class B4SWriter : public PlaylistWriter
|
||||
{
|
||||
public:
|
||||
B4SWriter();
|
||||
|
||||
int Open( const wchar_t *filename ) override;
|
||||
void Write( const wchar_t *filename ) override;
|
||||
void Write( const wchar_t *filename, const wchar_t *title, int length ) override;
|
||||
void Write( const wchar_t *p_filename, const wchar_t *p_title, const wchar_t *p_extended_infos, int p_length ) override
|
||||
{};
|
||||
|
||||
void Close() override;
|
||||
|
||||
private:
|
||||
FILE *fp;
|
||||
};
|
||||
|
||||
#endif
|
210
Src/playlist/Handler.cpp
Normal file
210
Src/playlist/Handler.cpp
Normal file
@ -0,0 +1,210 @@
|
||||
#include "Handler.h"
|
||||
#include "resource.h"
|
||||
#include "M3ULoader.h"
|
||||
#include "PLSLoader.h"
|
||||
#include "B4SLoader.h"
|
||||
#include <shlwapi.h>
|
||||
|
||||
void GetExtension(const wchar_t *filename, wchar_t *ext, size_t extCch)
|
||||
{
|
||||
const wchar_t *s = PathFindExtensionW(filename);
|
||||
if (!PathIsURLW(filename)
|
||||
|| (!wcsstr(s, L"?") && !wcsstr(s, L"&") && !wcsstr(s, L"=") && *s))
|
||||
{
|
||||
lstrcpynW(ext, s, (int)extCch);
|
||||
return ;
|
||||
}
|
||||
// s is not a terribly good extension, let's try again
|
||||
{
|
||||
wchar_t *copy = _wcsdup(filename);
|
||||
s = L"";
|
||||
again:
|
||||
{
|
||||
wchar_t *p = StrRChrW(copy,NULL, L'?');
|
||||
if (p)
|
||||
{
|
||||
*p = 0;
|
||||
s = PathFindExtensionW(copy);
|
||||
if (!*s) goto again;
|
||||
}
|
||||
lstrcpynW(ext, s, (int)extCch);
|
||||
}
|
||||
free(copy);
|
||||
}
|
||||
}
|
||||
|
||||
const wchar_t *M3UHandler::enumExtensions(size_t n)
|
||||
{
|
||||
switch(n)
|
||||
{
|
||||
case 0:
|
||||
return L"M3U";
|
||||
case 1:
|
||||
return L"M3U8";
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int M3UHandler::SupportedFilename(const wchar_t *filename)
|
||||
{
|
||||
wchar_t ext[16] = {0};
|
||||
GetExtension(filename, ext, 16);
|
||||
|
||||
if (!lstrcmpiW(ext, L".M3U"))
|
||||
return SVC_PLAYLISTHANDLER_SUCCESS;
|
||||
if (!lstrcmpiW(ext, L".M3U8"))
|
||||
return SVC_PLAYLISTHANDLER_SUCCESS;
|
||||
|
||||
return SVC_PLAYLISTHANDLER_FAILED;
|
||||
}
|
||||
|
||||
ifc_playlistloader *M3UHandler::CreateLoader(const wchar_t *filename)
|
||||
{
|
||||
return new M3ULoader;
|
||||
}
|
||||
|
||||
void M3UHandler::ReleaseLoader(ifc_playlistloader *loader)
|
||||
{
|
||||
M3ULoader *m3u;
|
||||
|
||||
m3u = static_cast<M3ULoader *>(loader);
|
||||
delete m3u;
|
||||
}
|
||||
|
||||
const wchar_t *M3UHandler::GetName()
|
||||
{
|
||||
static wchar_t m3upl[64];
|
||||
// no point re-loading this all of the time since it won't change once we've been loaded
|
||||
return (!m3upl[0]?WASABI_API_LNGSTRINGW_BUF(IDS_M3U_PLAYLIST,m3upl,64):m3upl);
|
||||
}
|
||||
/* ----------------------------------------------------- */
|
||||
|
||||
const wchar_t *PLSHandler::enumExtensions(size_t n)
|
||||
{
|
||||
switch(n)
|
||||
{
|
||||
case 0:
|
||||
return L"PLS";
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int PLSHandler::SupportedFilename(const wchar_t *filename)
|
||||
{
|
||||
wchar_t ext[16] = {0};
|
||||
GetExtension(filename, ext, 16);
|
||||
|
||||
if (!lstrcmpiW(ext, L".PLS"))
|
||||
return SVC_PLAYLISTHANDLER_SUCCESS;
|
||||
|
||||
// TODO: open file and sniff it for file signature
|
||||
return SVC_PLAYLISTHANDLER_FAILED;
|
||||
}
|
||||
|
||||
ifc_playlistloader *PLSHandler::CreateLoader(const wchar_t *filename)
|
||||
{
|
||||
return new PLSLoader;
|
||||
}
|
||||
|
||||
void PLSHandler::ReleaseLoader(ifc_playlistloader *loader)
|
||||
{
|
||||
PLSLoader *pls;
|
||||
|
||||
pls = static_cast<PLSLoader *>(loader);
|
||||
delete pls;
|
||||
}
|
||||
|
||||
|
||||
const wchar_t *PLSHandler::GetName()
|
||||
{
|
||||
static wchar_t plspl[64];
|
||||
// no point re-loading this all of the time since it won't change once we've been loaded
|
||||
return (!plspl[0]?WASABI_API_LNGSTRINGW_BUF(IDS_PLS_PLAYLIST,plspl,64):plspl);
|
||||
}
|
||||
|
||||
/* --- B4S --- */
|
||||
const wchar_t *B4SHandler::enumExtensions(size_t n)
|
||||
{
|
||||
switch(n)
|
||||
{
|
||||
case 0:
|
||||
return L"B4S";
|
||||
//case 1:
|
||||
//return L"BPL";
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int B4SHandler::SupportedFilename(const wchar_t *filename)
|
||||
{
|
||||
wchar_t ext[16] = {0};
|
||||
GetExtension(filename, ext, 16);
|
||||
|
||||
if (!lstrcmpiW(ext, L".B4S"))
|
||||
return SVC_PLAYLISTHANDLER_SUCCESS;
|
||||
if (!lstrcmpiW(ext, L".BPL"))
|
||||
return SVC_PLAYLISTHANDLER_SUCCESS;
|
||||
|
||||
// TODO: open file and sniff it for file signature
|
||||
return SVC_PLAYLISTHANDLER_FAILED;
|
||||
}
|
||||
|
||||
ifc_playlistloader *B4SHandler::CreateLoader(const wchar_t *filename)
|
||||
{
|
||||
return new B4SLoader;
|
||||
}
|
||||
|
||||
void B4SHandler::ReleaseLoader(ifc_playlistloader *loader)
|
||||
{
|
||||
B4SLoader *pls;
|
||||
|
||||
pls = static_cast<B4SLoader *>(loader);
|
||||
delete pls;
|
||||
}
|
||||
|
||||
const wchar_t *B4SHandler::GetName()
|
||||
{
|
||||
static wchar_t wa3pl[64];
|
||||
// no point re-loading this all of the time since it won't change once we've been loaded
|
||||
return (!wa3pl[0]?WASABI_API_LNGSTRINGW_BUF(IDS_WINAMP3_PLAYLIST,wa3pl,64):wa3pl);
|
||||
}
|
||||
|
||||
|
||||
#ifdef CBCLASS
|
||||
#undef CBCLASS
|
||||
#endif
|
||||
|
||||
#define CBCLASS M3UHandler
|
||||
START_DISPATCH;
|
||||
CB(SVC_PLAYLISTHANDLER_ENUMEXTENSIONS, enumExtensions)
|
||||
CB(SVC_PLAYLISTHANDLER_SUPPORTFILENAME, SupportedFilename)
|
||||
CB(SVC_PLAYLISTHANDLER_CREATELOADER, CreateLoader)
|
||||
VCB(SVC_PLAYLISTHANDLER_RELEASELOADER, ReleaseLoader)
|
||||
CB(SVC_PLAYLISTHANDLER_GETNAME, GetName)
|
||||
CB(SVC_PLAYLISTHANDLER_HASWRITER, HasWriter)
|
||||
END_DISPATCH;
|
||||
#undef CBCLASS
|
||||
|
||||
#define CBCLASS PLSHandler
|
||||
START_DISPATCH;
|
||||
CB(SVC_PLAYLISTHANDLER_ENUMEXTENSIONS, enumExtensions)
|
||||
CB(SVC_PLAYLISTHANDLER_SUPPORTFILENAME, SupportedFilename)
|
||||
CB(SVC_PLAYLISTHANDLER_CREATELOADER, CreateLoader)
|
||||
VCB(SVC_PLAYLISTHANDLER_RELEASELOADER, ReleaseLoader)
|
||||
CB(SVC_PLAYLISTHANDLER_GETNAME, GetName)
|
||||
CB(SVC_PLAYLISTHANDLER_HASWRITER, HasWriter)
|
||||
END_DISPATCH;
|
||||
#undef CBCLASS
|
||||
|
||||
#define CBCLASS B4SHandler
|
||||
START_DISPATCH;
|
||||
CB(SVC_PLAYLISTHANDLER_ENUMEXTENSIONS, enumExtensions)
|
||||
CB(SVC_PLAYLISTHANDLER_SUPPORTFILENAME, SupportedFilename)
|
||||
CB(SVC_PLAYLISTHANDLER_CREATELOADER, CreateLoader)
|
||||
VCB(SVC_PLAYLISTHANDLER_RELEASELOADER, ReleaseLoader)
|
||||
CB(SVC_PLAYLISTHANDLER_GETNAME, GetName)
|
||||
CB(SVC_PLAYLISTHANDLER_HASWRITER, HasWriter)
|
||||
END_DISPATCH;
|
32
Src/playlist/Handler.h
Normal file
32
Src/playlist/Handler.h
Normal file
@ -0,0 +1,32 @@
|
||||
#ifndef NULLSOFT_PLAYLISTS_HANDLER_H
|
||||
#define NULLSOFT_PLAYLISTS_HANDLER_H
|
||||
|
||||
#include "svc_playlisthandler.h"
|
||||
#include <bfc/platform/types.h>
|
||||
|
||||
#define DECLARE_HANDLER(className, IS_WRITER) class className ## Handler : public svc_playlisthandler {\
|
||||
public:\
|
||||
const wchar_t *enumExtensions(size_t n); \
|
||||
int SupportedFilename(const wchar_t *filename); \
|
||||
ifc_playlistloader *CreateLoader(const wchar_t *filename);\
|
||||
void ReleaseLoader(ifc_playlistloader *loader);\
|
||||
const wchar_t *GetName(); \
|
||||
int HasWriter() { return IS_WRITER; }\
|
||||
protected: RECVS_DISPATCH;}
|
||||
|
||||
DECLARE_HANDLER(M3U, 1);
|
||||
DECLARE_HANDLER(PLS, 1);
|
||||
DECLARE_HANDLER(B4S, 0);
|
||||
|
||||
// {8D031378-4209-4bfe-AC94-03C57C896214}
|
||||
static const GUID m3uHandlerGUID =
|
||||
{ 0x8d031378, 0x4209, 0x4bfe, { 0xac, 0x94, 0x3, 0xc5, 0x7c, 0x89, 0x62, 0x14 } };
|
||||
|
||||
// {4FF33CC0-F82C-4550-8E4A-DDF90036BE85}
|
||||
static const GUID plsHandlerGUID =
|
||||
{ 0x4ff33cc0, 0xf82c, 0x4550, { 0x8e, 0x4a, 0xdd, 0xf9, 0x0, 0x36, 0xbe, 0x85 } };
|
||||
|
||||
static const GUID b4sHandlerGUID =
|
||||
{ 0x6f62cbb8, 0x7e1f, 0x43eb, { 0xb3, 0xf6, 0x1, 0xc2, 0x60, 0x10, 0x29, 0xa3 } };
|
||||
|
||||
#endif
|
102
Src/playlist/JSAPI2_Creator.cpp
Normal file
102
Src/playlist/JSAPI2_Creator.cpp
Normal file
@ -0,0 +1,102 @@
|
||||
#include "JSAPI2_Creator.h"
|
||||
#include "JSAPI2_Playlists.h"
|
||||
#include "api__playlist.h"
|
||||
#include "main.h"
|
||||
#include "resource.h"
|
||||
|
||||
IDispatch *JSAPI2_Creator::CreateAPI(const wchar_t *name, const wchar_t *key, JSAPI::ifc_info *info)
|
||||
{
|
||||
if (!wcscmp(name, L"Playlists"))
|
||||
return new JSAPI2::PlaylistsAPI(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 && !wcscmp(group, L"playlists"))
|
||||
{
|
||||
const wchar_t *title_str = AGAVE_API_JSAPI2_SECURITY->GetAssociatedName(authorization_key);
|
||||
if (action && !wcscmp(action, L"read"))
|
||||
{
|
||||
return AGAVE_API_JSAPI2_SECURITY->SecurityPrompt(parent, title_str, L"This service is requesting access to the playlists in your Library.", 0);
|
||||
}
|
||||
else if (action && !wcscmp(action, L"write"))
|
||||
{
|
||||
return AGAVE_API_JSAPI2_SECURITY->SecurityPrompt(parent, title_str, L"This service is trying modify one of the playlists in your Library.", 0);
|
||||
}
|
||||
}
|
||||
|
||||
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[] = "Playlist Javascript Objects";
|
||||
|
||||
// {CF057176-A819-4bc5-8723-6C072BB28BAA}
|
||||
static const GUID jsapi2_factory_guid =
|
||||
{ 0xcf057176, 0xa819, 0x4bc5, { 0x87, 0x23, 0x6c, 0x7, 0x2b, 0xb2, 0x8b, 0xaa } };
|
||||
|
||||
|
||||
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)
|
||||
// WASABI_API_SVC->service_lock(this, (void *)ifc);
|
||||
return &jsapi2_svc;
|
||||
}
|
||||
|
||||
int JSAPI2Factory::SupportNonLockingInterface()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
int JSAPI2Factory::ReleaseInterface(void *ifc)
|
||||
{
|
||||
//WASABI_API_SVC->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/playlist/JSAPI2_Creator.h
Normal file
31
Src/playlist/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;
|
||||
};
|
328
Src/playlist/JSAPI2_Playlist.cpp
Normal file
328
Src/playlist/JSAPI2_Playlist.cpp
Normal file
@ -0,0 +1,328 @@
|
||||
#include "JSAPI2_Playlist.h"
|
||||
#include "../Winamp/JSAPI.h"
|
||||
#include "api__playlist.h"
|
||||
#include "PlaylistManager.h"
|
||||
|
||||
JSAPI2::PlaylistObject::PlaylistObject(const wchar_t *_key)
|
||||
{
|
||||
key = _key;
|
||||
}
|
||||
|
||||
#define DISP_TABLE \
|
||||
CHECK_ID(Clear)\
|
||||
CHECK_ID(AppendURL)\
|
||||
CHECK_ID(GetItemFilename)\
|
||||
CHECK_ID(GetItemTitle)\
|
||||
CHECK_ID(GetItemLength)\
|
||||
CHECK_ID(GetItemExtendedInfo)\
|
||||
CHECK_ID(Reverse)\
|
||||
CHECK_ID(SwapItems)\
|
||||
CHECK_ID(Randomize)\
|
||||
CHECK_ID(RemoveItem)\
|
||||
CHECK_ID(SortByTitle)\
|
||||
CHECK_ID(SortByFilename)\
|
||||
CHECK_ID(SetItemFilename)\
|
||||
CHECK_ID(SetItemTitle)\
|
||||
CHECK_ID(SetItemLength)\
|
||||
CHECK_ID(InsertURL)\
|
||||
CHECK_ID(numitems)\
|
||||
|
||||
|
||||
#define CHECK_ID(str) JSAPI_DISP_ENUMIFY(str),
|
||||
enum {
|
||||
DISP_TABLE
|
||||
};
|
||||
|
||||
#undef CHECK_ID
|
||||
#define CHECK_ID(str) if (wcscmp(rgszNames[i], L## #str) == 0) { rgdispid[i] = JSAPI_DISP_ENUMIFY(str); continue; }
|
||||
HRESULT JSAPI2::PlaylistObject::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::PlaylistObject::GetTypeInfo(unsigned int itinfo, LCID lcid, ITypeInfo FAR* FAR* pptinfo)
|
||||
{
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
HRESULT JSAPI2::PlaylistObject::GetTypeInfoCount(unsigned int FAR * pctinfo)
|
||||
{
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
HRESULT JSAPI2::PlaylistObject::Clear(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr)
|
||||
{
|
||||
JSAPI_VERIFY_METHOD(wFlags);
|
||||
JSAPI_VERIFY_PARAMCOUNT(pdispparams, 0);
|
||||
|
||||
JSAPI_INIT_RESULT(pvarResult, VT_BOOL);
|
||||
JSAPI_SET_RESULT(pvarResult, boolVal, VARIANT_TRUE);
|
||||
playlist.Clear();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT JSAPI2::PlaylistObject::AppendURL(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr)
|
||||
{
|
||||
JSAPI_VERIFY_METHOD(wFlags);
|
||||
JSAPI_VERIFY_PARAMCOUNT_OPTIONAL(pdispparams, 1, 3);
|
||||
JSAPI_VERIFY_PARAMTYPE(pdispparams, 1, VT_BSTR, puArgErr);
|
||||
JSAPI_VERIFY_PARAMTYPE_OPTIONAL(pdispparams, 2, VT_BSTR, puArgErr);
|
||||
JSAPI_VERIFY_PARAMTYPE_OPTIONAL(pdispparams, 3, VT_I4, puArgErr);
|
||||
|
||||
JSAPI_INIT_RESULT(pvarResult, VT_BOOL);
|
||||
JSAPI_SET_RESULT(pvarResult, boolVal, VARIANT_TRUE);
|
||||
const wchar_t *filename = JSAPI_PARAM(pdispparams, 1).bstrVal;
|
||||
const wchar_t *title = JSAPI_PARAM_OPTIONAL(pdispparams, 2, bstrVal, 0);
|
||||
int length = JSAPI_PARAM_OPTIONAL(pdispparams, 3, lVal, -1);
|
||||
playlist.AppendWithInfo(filename, title, length);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT JSAPI2::PlaylistObject::InsertURL(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr)
|
||||
{
|
||||
JSAPI_VERIFY_METHOD(wFlags);
|
||||
JSAPI_VERIFY_PARAMCOUNT_OPTIONAL(pdispparams, 2, 4);
|
||||
JSAPI_VERIFY_PARAMTYPE(pdispparams, 1, VT_I4, puArgErr);
|
||||
JSAPI_VERIFY_PARAMTYPE(pdispparams, 2, VT_BSTR, puArgErr);
|
||||
JSAPI_VERIFY_PARAMTYPE_OPTIONAL(pdispparams, 3, VT_BSTR, puArgErr);
|
||||
JSAPI_VERIFY_PARAMTYPE_OPTIONAL(pdispparams, 4, VT_I4, puArgErr);
|
||||
|
||||
JSAPI_INIT_RESULT(pvarResult, VT_BOOL);
|
||||
JSAPI_SET_RESULT(pvarResult, boolVal, VARIANT_TRUE);
|
||||
const wchar_t *filename = JSAPI_PARAM(pdispparams, 2).bstrVal;
|
||||
const wchar_t *title = JSAPI_PARAM_OPTIONAL(pdispparams, 3, bstrVal, 0);
|
||||
int length = JSAPI_PARAM_OPTIONAL(pdispparams, 4, lVal, -1);
|
||||
playlist.Insert(JSAPI_PARAM(pdispparams, 1).lVal, filename, title, length);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
HRESULT JSAPI2::PlaylistObject::GetItemFilename(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr)
|
||||
{
|
||||
JSAPI_VERIFY_METHOD(wFlags);
|
||||
JSAPI_VERIFY_PARAMCOUNT(pdispparams, 1);
|
||||
JSAPI_VERIFY_PARAMTYPE(pdispparams, 1, VT_I4, puArgErr);
|
||||
|
||||
JSAPI_INIT_RESULT(pvarResult, VT_BSTR);
|
||||
JSAPI_SET_RESULT(pvarResult, bstrVal, SysAllocString(playlist.ItemName(JSAPI_PARAM(pdispparams, 1).lVal)));
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT JSAPI2::PlaylistObject::GetItemTitle(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr)
|
||||
{
|
||||
JSAPI_VERIFY_METHOD(wFlags);
|
||||
JSAPI_VERIFY_PARAMCOUNT(pdispparams, 1);
|
||||
JSAPI_VERIFY_PARAMTYPE(pdispparams, 1, VT_I4, puArgErr);
|
||||
|
||||
JSAPI_INIT_RESULT(pvarResult, VT_BSTR);
|
||||
JSAPI_SET_RESULT(pvarResult, bstrVal, SysAllocString(playlist.ItemTitle(JSAPI_PARAM(pdispparams, 1).lVal)));
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT JSAPI2::PlaylistObject::GetItemLength(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr)
|
||||
{
|
||||
JSAPI_VERIFY_METHOD(wFlags);
|
||||
JSAPI_VERIFY_PARAMCOUNT(pdispparams, 1);
|
||||
JSAPI_VERIFY_PARAMTYPE(pdispparams, 1, VT_I4, puArgErr);
|
||||
|
||||
JSAPI_INIT_RESULT(pvarResult, VT_I4);
|
||||
JSAPI_SET_RESULT(pvarResult, lVal, playlist.GetItemLengthMilliseconds(JSAPI_PARAM(pdispparams, 1).lVal));
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT JSAPI2::PlaylistObject::GetItemExtendedInfo(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr)
|
||||
{
|
||||
JSAPI_VERIFY_METHOD(wFlags);
|
||||
JSAPI_VERIFY_PARAMCOUNT(pdispparams, 2);
|
||||
JSAPI_VERIFY_PARAMTYPE(pdispparams, 1, VT_I4, puArgErr);
|
||||
JSAPI_VERIFY_PARAMTYPE(pdispparams, 2, VT_BSTR, puArgErr);
|
||||
|
||||
JSAPI_INIT_RESULT(pvarResult, VT_BSTR);
|
||||
wchar_t metadata[1024]=L"";
|
||||
playlist.GetItemExtendedInfo(JSAPI_PARAM(pdispparams, 1).lVal, JSAPI_PARAM(pdispparams, 2).bstrVal, metadata, sizeof(metadata)/sizeof(*metadata));
|
||||
JSAPI_SET_RESULT(pvarResult, bstrVal, SysAllocString(metadata));
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT JSAPI2::PlaylistObject::Reverse(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr)
|
||||
{
|
||||
JSAPI_VERIFY_METHOD(wFlags);
|
||||
JSAPI_VERIFY_PARAMCOUNT(pdispparams, 0);
|
||||
|
||||
JSAPI_INIT_RESULT(pvarResult, VT_BOOL);
|
||||
JSAPI_SET_RESULT(pvarResult, boolVal, VARIANT_TRUE);
|
||||
playlist.Reverse();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
||||
HRESULT JSAPI2::PlaylistObject::SwapItems(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr)
|
||||
{
|
||||
JSAPI_VERIFY_METHOD(wFlags);
|
||||
JSAPI_VERIFY_PARAMCOUNT(pdispparams, 2);
|
||||
JSAPI_VERIFY_PARAMTYPE(pdispparams, 1, VT_I4, puArgErr);
|
||||
JSAPI_VERIFY_PARAMTYPE(pdispparams, 2, VT_I4, puArgErr);
|
||||
|
||||
JSAPI_INIT_RESULT(pvarResult, VT_BOOL);
|
||||
JSAPI_SET_RESULT(pvarResult, boolVal, VARIANT_TRUE);
|
||||
playlist.Swap(JSAPI_PARAM(pdispparams, 1).lVal, JSAPI_PARAM(pdispparams, 2).lVal);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT JSAPI2::PlaylistObject::Randomize(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr)
|
||||
{
|
||||
JSAPI_VERIFY_METHOD(wFlags);
|
||||
JSAPI_VERIFY_PARAMCOUNT(pdispparams, 0);
|
||||
|
||||
JSAPI_INIT_RESULT(pvarResult, VT_BOOL);
|
||||
JSAPI_SET_RESULT(pvarResult, boolVal, VARIANT_TRUE);
|
||||
playlistManager.Randomize(&playlist);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT JSAPI2::PlaylistObject::RemoveItem(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr)
|
||||
{
|
||||
JSAPI_VERIFY_METHOD(wFlags);
|
||||
JSAPI_VERIFY_PARAMCOUNT(pdispparams, 1);
|
||||
JSAPI_VERIFY_PARAMTYPE(pdispparams, 1, VT_I4, puArgErr);
|
||||
|
||||
JSAPI_INIT_RESULT(pvarResult, VT_BOOL);
|
||||
JSAPI_SET_RESULT(pvarResult, boolVal, VARIANT_TRUE);
|
||||
playlist.Remove(JSAPI_PARAM(pdispparams, 1).lVal);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT JSAPI2::PlaylistObject::SortByTitle(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr)
|
||||
{
|
||||
JSAPI_VERIFY_METHOD(wFlags);
|
||||
JSAPI_VERIFY_PARAMCOUNT(pdispparams, 0);
|
||||
|
||||
JSAPI_INIT_RESULT(pvarResult, VT_BOOL);
|
||||
JSAPI_SET_RESULT(pvarResult, boolVal, VARIANT_TRUE);
|
||||
playlist.SortByTitle();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT JSAPI2::PlaylistObject::SortByFilename(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr)
|
||||
{
|
||||
JSAPI_VERIFY_METHOD(wFlags);
|
||||
JSAPI_VERIFY_PARAMCOUNT(pdispparams, 0);
|
||||
|
||||
JSAPI_INIT_RESULT(pvarResult, VT_BOOL);
|
||||
JSAPI_SET_RESULT(pvarResult, boolVal, VARIANT_TRUE);
|
||||
playlist.SortByFilename();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT JSAPI2::PlaylistObject::SetItemFilename(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr)
|
||||
{
|
||||
JSAPI_VERIFY_METHOD(wFlags);
|
||||
JSAPI_VERIFY_PARAMCOUNT(pdispparams, 2);
|
||||
JSAPI_VERIFY_PARAMTYPE(pdispparams, 1, VT_I4, puArgErr);
|
||||
JSAPI_VERIFY_PARAMTYPE(pdispparams, 2, VT_BSTR, puArgErr);
|
||||
|
||||
JSAPI_INIT_RESULT(pvarResult, VT_BOOL);
|
||||
JSAPI_SET_RESULT(pvarResult, boolVal, VARIANT_TRUE);
|
||||
playlist.SetItemFilename(JSAPI_PARAM(pdispparams, 1).lVal, JSAPI_PARAM(pdispparams, 2).bstrVal);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT JSAPI2::PlaylistObject::SetItemTitle(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr)
|
||||
{
|
||||
JSAPI_VERIFY_METHOD(wFlags);
|
||||
JSAPI_VERIFY_PARAMCOUNT(pdispparams, 2);
|
||||
JSAPI_VERIFY_PARAMTYPE(pdispparams, 1, VT_I4, puArgErr);
|
||||
JSAPI_VERIFY_PARAMTYPE(pdispparams, 2, VT_BSTR, puArgErr);
|
||||
|
||||
JSAPI_INIT_RESULT(pvarResult, VT_BOOL);
|
||||
JSAPI_SET_RESULT(pvarResult, boolVal, VARIANT_TRUE);
|
||||
playlist.SetItemTitle(JSAPI_PARAM(pdispparams, 1).lVal, JSAPI_PARAM(pdispparams, 2).bstrVal);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT JSAPI2::PlaylistObject::SetItemLength(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr)
|
||||
{
|
||||
JSAPI_VERIFY_METHOD(wFlags);
|
||||
JSAPI_VERIFY_PARAMCOUNT(pdispparams, 2);
|
||||
JSAPI_VERIFY_PARAMTYPE(pdispparams, 1, VT_I4, puArgErr);
|
||||
JSAPI_VERIFY_PARAMTYPE(pdispparams, 2, VT_I4, puArgErr);
|
||||
|
||||
JSAPI_INIT_RESULT(pvarResult, VT_BOOL);
|
||||
JSAPI_SET_RESULT(pvarResult, boolVal, VARIANT_TRUE);
|
||||
playlist.SetItemLengthMilliseconds(JSAPI_PARAM(pdispparams, 1).lVal, JSAPI_PARAM(pdispparams, 2).lVal);
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT JSAPI2::PlaylistObject::numitems(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr)
|
||||
{
|
||||
// JSAPI_VERIFY_METHOD(wFlags);
|
||||
// JSAPI_VERIFY_PARAMCOUNT(pdispparams, 0);
|
||||
if (wFlags & DISPATCH_PROPERTYGET)
|
||||
{
|
||||
JSAPI_INIT_RESULT(pvarResult, VT_I4);
|
||||
JSAPI_SET_RESULT(pvarResult, lVal, (LONG)playlist.GetNumItems());
|
||||
return S_OK;
|
||||
}
|
||||
else
|
||||
return DISP_E_MEMBERNOTFOUND;
|
||||
}
|
||||
|
||||
|
||||
#undef CHECK_ID
|
||||
#define CHECK_ID(str) case JSAPI_DISP_ENUMIFY(str): return str(wFlags, pdispparams, pvarResult, puArgErr);
|
||||
HRESULT JSAPI2::PlaylistObject::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::PlaylistObject::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 if (IsEqualIID(riid, IID_PlaylistObject))
|
||||
*ppvObject = (PlaylistObject *)this;
|
||||
else
|
||||
{
|
||||
*ppvObject = NULL;
|
||||
return E_NOINTERFACE;
|
||||
}
|
||||
|
||||
AddRef();
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
ULONG JSAPI2::PlaylistObject::AddRef(void)
|
||||
{
|
||||
return this->_refCount.fetch_add( 1 );
|
||||
}
|
||||
|
||||
|
||||
ULONG JSAPI2::PlaylistObject::Release( void )
|
||||
{
|
||||
std::size_t l_Ref = this->_refCount.fetch_sub( 1 );
|
||||
if ( l_Ref == 0 )
|
||||
delete this;
|
||||
|
||||
return l_Ref;
|
||||
}
|
51
Src/playlist/JSAPI2_Playlist.h
Normal file
51
Src/playlist/JSAPI2_Playlist.h
Normal file
@ -0,0 +1,51 @@
|
||||
#pragma once
|
||||
|
||||
#include <ocidl.h>
|
||||
#include <atomic>
|
||||
|
||||
#include "Playlist.h"
|
||||
|
||||
namespace JSAPI2
|
||||
{
|
||||
// {8535DB01-7630-45df-9429-2640A29B9468}
|
||||
static const GUID IID_PlaylistObject =
|
||||
{ 0x8535db01, 0x7630, 0x45df, { 0x94, 0x29, 0x26, 0x40, 0xa2, 0x9b, 0x94, 0x68 } };
|
||||
|
||||
|
||||
class PlaylistObject : public IDispatch
|
||||
{
|
||||
public:
|
||||
PlaylistObject( const wchar_t *_key );
|
||||
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 );
|
||||
|
||||
Playlist playlist;
|
||||
private:
|
||||
const wchar_t *key;
|
||||
volatile std::atomic<std::size_t> _refCount = 1;
|
||||
|
||||
STDMETHOD( Clear )( WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr );
|
||||
STDMETHOD( AppendURL )( WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr );
|
||||
STDMETHOD( GetItemFilename )( WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr );
|
||||
STDMETHOD( GetItemTitle )( WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr );
|
||||
STDMETHOD( GetItemLength )( WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr );
|
||||
STDMETHOD( GetItemExtendedInfo )( WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr );
|
||||
STDMETHOD( Reverse )( WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr );
|
||||
STDMETHOD( SwapItems )( WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr );
|
||||
STDMETHOD( Randomize )( WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr );
|
||||
STDMETHOD( RemoveItem )( WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr );
|
||||
STDMETHOD( SortByTitle )( WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr );
|
||||
STDMETHOD( SortByFilename )( WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr );
|
||||
STDMETHOD( SetItemFilename )( WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr );
|
||||
STDMETHOD( SetItemTitle )( WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr );
|
||||
STDMETHOD( SetItemLength )( WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr );
|
||||
STDMETHOD( InsertURL )( WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr );
|
||||
STDMETHOD( numitems )( WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr );
|
||||
};
|
||||
}
|
221
Src/playlist/JSAPI2_Playlists.cpp
Normal file
221
Src/playlist/JSAPI2_Playlists.cpp
Normal file
@ -0,0 +1,221 @@
|
||||
#include "JSAPI2_Playlists.h"
|
||||
#include "../Winamp/JSAPI.h"
|
||||
#include "api__playlist.h"
|
||||
#include "../Winamp/JSAPI_ObjectArray.h"
|
||||
#include "Playlists.h"
|
||||
#include "JSAPI2_Playlist.h"
|
||||
#include "PlaylistManager.h"
|
||||
#include "../Winamp/JSAPI_CallbackParameters.h"
|
||||
|
||||
extern Playlists playlists;
|
||||
|
||||
JSAPI2::PlaylistsAPI::PlaylistsAPI(const wchar_t *_key, JSAPI::ifc_info *_info)
|
||||
{
|
||||
info = _info;
|
||||
key = _key;
|
||||
}
|
||||
|
||||
#define DISP_TABLE \
|
||||
CHECK_ID(GetPlaylists)\
|
||||
CHECK_ID(OpenPlaylist)\
|
||||
CHECK_ID(SavePlaylist)\
|
||||
|
||||
#define CHECK_ID(str) JSAPI_DISP_ENUMIFY(str),
|
||||
enum {
|
||||
DISP_TABLE
|
||||
};
|
||||
|
||||
#undef CHECK_ID
|
||||
#define CHECK_ID(str) if (wcscmp(rgszNames[i], L## #str) == 0) { rgdispid[i] = JSAPI_DISP_ENUMIFY(str); continue; }
|
||||
HRESULT JSAPI2::PlaylistsAPI::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::PlaylistsAPI::GetTypeInfo(unsigned int itinfo, LCID lcid, ITypeInfo FAR* FAR* pptinfo)
|
||||
{
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
HRESULT JSAPI2::PlaylistsAPI::GetTypeInfoCount(unsigned int FAR * pctinfo)
|
||||
{
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
HRESULT JSAPI2::PlaylistsAPI::GetPlaylists(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr)
|
||||
{
|
||||
JSAPI_VERIFY_METHOD(wFlags);
|
||||
JSAPI_VERIFY_PARAMCOUNT(pdispparams, 0);
|
||||
|
||||
VariantInit(pvarResult);
|
||||
V_VT(pvarResult) = VT_DISPATCH;
|
||||
if (AGAVE_API_JSAPI2_SECURITY->GetActionAuthorization(L"playlists", L"read", key, info, JSAPI2::api_security::ACTION_PROMPT) == JSAPI2::api_security::ACTION_ALLOWED)
|
||||
{
|
||||
JSAPI::ObjectArray *objectArray = new JSAPI::ObjectArray;
|
||||
playlists.Lock();
|
||||
|
||||
size_t count = playlists.GetCount();
|
||||
|
||||
for (size_t i=0;i!=count;i++)
|
||||
{
|
||||
const PlaylistInfo &info = playlists.GetPlaylistInfo(i);
|
||||
JSAPI::CallbackParameters *playlistParams = new JSAPI::CallbackParameters;
|
||||
playlistParams->AddString(L"filename", info.filename);
|
||||
playlistParams->AddString(L"title", info.title);
|
||||
wchar_t guid_str[40];
|
||||
nsGUID::toCharW(info.guid, guid_str);
|
||||
playlistParams->AddString(L"playlistId", guid_str);
|
||||
playlistParams->AddLong(L"length", info.length);
|
||||
playlistParams->AddLong(L"numitems", info.numItems);
|
||||
objectArray->AddObject(playlistParams);
|
||||
playlistParams->Release();
|
||||
}
|
||||
playlists.Unlock();
|
||||
V_DISPATCH(pvarResult) = objectArray;
|
||||
return S_OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
V_DISPATCH(pvarResult) = 0;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
HRESULT JSAPI2::PlaylistsAPI::OpenPlaylist(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr)
|
||||
{
|
||||
JSAPI_VERIFY_METHOD(wFlags);
|
||||
JSAPI_VERIFY_PARAMCOUNT(pdispparams, 1);
|
||||
JSAPI_VERIFY_PARAMTYPE(pdispparams, 1, VT_BSTR, puArgErr);
|
||||
|
||||
VariantInit(pvarResult);
|
||||
V_VT(pvarResult) = VT_DISPATCH;
|
||||
V_DISPATCH(pvarResult) = 0;
|
||||
if (AGAVE_API_JSAPI2_SECURITY->GetActionAuthorization(L"playlists", L"read", key, info, JSAPI2::api_security::ACTION_PROMPT) == JSAPI2::api_security::ACTION_ALLOWED)
|
||||
{
|
||||
GUID playlist_guid = nsGUID::fromCharW(JSAPI_PARAM(pdispparams, 1).bstrVal);
|
||||
playlists.Lock();
|
||||
size_t index;
|
||||
if (playlists.GetPosition(playlist_guid, &index) == API_PLAYLISTS_SUCCESS)
|
||||
{
|
||||
const wchar_t *filename = playlists.GetFilename(index);
|
||||
if (filename)
|
||||
{
|
||||
PlaylistObject *playlist = new PlaylistObject(key);
|
||||
if (playlistManager.Load(filename, &playlist->playlist) == PLAYLISTMANAGER_SUCCESS)
|
||||
{
|
||||
V_DISPATCH(pvarResult) = playlist;
|
||||
}
|
||||
else
|
||||
{
|
||||
delete playlist;
|
||||
}
|
||||
}
|
||||
}
|
||||
playlists.Unlock();
|
||||
return S_OK;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
HRESULT JSAPI2::PlaylistsAPI::SavePlaylist(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr)
|
||||
{
|
||||
JSAPI_VERIFY_METHOD(wFlags);
|
||||
JSAPI_VERIFY_PARAMCOUNT(pdispparams, 2);
|
||||
JSAPI_VERIFY_PARAMTYPE(pdispparams, 1, VT_BSTR, puArgErr);
|
||||
JSAPI_VERIFY_PARAMTYPE(pdispparams, 2, VT_DISPATCH, puArgErr);
|
||||
|
||||
VariantInit(pvarResult);
|
||||
V_VT(pvarResult) = VT_BOOL;
|
||||
V_BOOL(pvarResult) = FALSE;
|
||||
if (AGAVE_API_JSAPI2_SECURITY->GetActionAuthorization(L"playlists", L"write", key, info, JSAPI2::api_security::ACTION_PROMPT) == JSAPI2::api_security::ACTION_ALLOWED)
|
||||
{
|
||||
GUID playlist_guid = nsGUID::fromCharW(JSAPI_PARAM(pdispparams, 1).bstrVal);
|
||||
playlists.Lock();
|
||||
size_t index;
|
||||
if (playlists.GetPosition(playlist_guid, &index) == API_PLAYLISTS_SUCCESS)
|
||||
{
|
||||
const wchar_t *filename = playlists.GetFilename(index);
|
||||
if (filename)
|
||||
{
|
||||
IDispatch *dispPlaylist = JSAPI_PARAM(pdispparams, 2).pdispVal;
|
||||
PlaylistObject *playlist = 0;
|
||||
dispPlaylist->QueryInterface(JSAPI2::IID_PlaylistObject, (void **)&playlist);
|
||||
if (playlistManager.Save(filename, &(playlist->playlist)) == PLAYLISTMANAGER_SUCCESS)
|
||||
V_BOOL(pvarResult) = TRUE;
|
||||
}
|
||||
}
|
||||
playlists.Unlock();
|
||||
return S_OK;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
#undef CHECK_ID
|
||||
#define CHECK_ID(str) case JSAPI_DISP_ENUMIFY(str): return str(wFlags, pdispparams, pvarResult, puArgErr);
|
||||
HRESULT JSAPI2::PlaylistsAPI::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::PlaylistsAPI::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::PlaylistsAPI::AddRef(void)
|
||||
{
|
||||
return this->_refCount.fetch_add( 1 );
|
||||
}
|
||||
|
||||
ULONG JSAPI2::PlaylistsAPI::Release( void )
|
||||
{
|
||||
std::size_t l_Ref = this->_refCount.fetch_sub( 1 );
|
||||
if ( l_Ref == 0 )
|
||||
delete this;
|
||||
|
||||
return l_Ref;
|
||||
}
|
30
Src/playlist/JSAPI2_Playlists.h
Normal file
30
Src/playlist/JSAPI2_Playlists.h
Normal file
@ -0,0 +1,30 @@
|
||||
#pragma once
|
||||
|
||||
#include <ocidl.h>
|
||||
#include <atomic>
|
||||
#include "../Winamp/JSAPI_Info.h"
|
||||
|
||||
namespace JSAPI2
|
||||
{
|
||||
class PlaylistsAPI : public IDispatch
|
||||
{
|
||||
public:
|
||||
PlaylistsAPI(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 (GetPlaylists)(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr);
|
||||
STDMETHOD (OpenPlaylist)(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr);
|
||||
STDMETHOD (SavePlaylist)(WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, unsigned int FAR *puArgErr);
|
||||
};
|
||||
}
|
39
Src/playlist/M3U8Writer.cpp
Normal file
39
Src/playlist/M3U8Writer.cpp
Normal file
@ -0,0 +1,39 @@
|
||||
#include "M3U8Writer.h"
|
||||
#include "../nu/AutoChar.h"
|
||||
#include <bfc/platform/types.h>
|
||||
|
||||
M3U8Writer::M3U8Writer() : fp(0)
|
||||
{
|
||||
}
|
||||
|
||||
int M3U8Writer::Open(const wchar_t *filename)
|
||||
{
|
||||
fp = _wfopen(filename, L"wt");
|
||||
if (!fp)
|
||||
return 0;
|
||||
|
||||
fputs( "\xEF\xBB\xBF", fp );
|
||||
fprintf(fp,"#EXTM3U\n");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void M3U8Writer::Write(const wchar_t *filename)
|
||||
{
|
||||
fwprintf(fp,L"%s\n", filename);
|
||||
}
|
||||
|
||||
void M3U8Writer::Write(const wchar_t *filename, const wchar_t *title, int length)
|
||||
{
|
||||
fprintf( fp, "#EXTINF:%d,%s\n%s\n", length, (char *) AutoChar( title, CP_UTF8 ), (char *) AutoChar( filename, CP_UTF8 ) );
|
||||
}
|
||||
|
||||
void M3U8Writer::Write( const wchar_t *p_filename, const wchar_t *p_title, const wchar_t *p_extended_infos, int p_length )
|
||||
{
|
||||
fprintf( fp, "#EXTINF:%d %s,%s\n%s\n", p_length, (char *)AutoChar( p_extended_infos, CP_UTF8 ), (char *)AutoChar( p_title, CP_UTF8 ), (char *)AutoChar( p_filename, CP_UTF8 ) );
|
||||
}
|
||||
|
||||
void M3U8Writer::Close()
|
||||
{
|
||||
fclose(fp);
|
||||
}
|
21
Src/playlist/M3U8Writer.h
Normal file
21
Src/playlist/M3U8Writer.h
Normal file
@ -0,0 +1,21 @@
|
||||
#ifndef NULLSOFT_M3U8WRITERH
|
||||
#define NULLSOFT_M3U8WRITERH
|
||||
|
||||
#include <stdio.h>
|
||||
#include "PlaylistWriter.h"
|
||||
class M3U8Writer : public PlaylistWriter
|
||||
{
|
||||
public:
|
||||
M3U8Writer();
|
||||
|
||||
int Open( const wchar_t *filename ) override;
|
||||
void Write( const wchar_t *filename ) override;
|
||||
void Write( const wchar_t *filename, const wchar_t *title, int length ) override;
|
||||
void Write( const wchar_t *p_filename, const wchar_t *p_title, const wchar_t* p_extended_infos, int p_length ) override;
|
||||
void Close() override;
|
||||
|
||||
private:
|
||||
FILE *fp;
|
||||
};
|
||||
|
||||
#endif
|
466
Src/playlist/M3ULoader.cpp
Normal file
466
Src/playlist/M3ULoader.cpp
Normal file
@ -0,0 +1,466 @@
|
||||
#include <stdio.h>
|
||||
#include <shlwapi.h>
|
||||
#include <strsafe.h>
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
|
||||
#include "M3ULoader.h"
|
||||
#include "../nu/ns_wc.h"
|
||||
|
||||
#include "../WAT/WAT.h"
|
||||
|
||||
|
||||
M3ULoader::M3ULoader() : _utf8( false )
|
||||
{
|
||||
wideTitle[ 0 ] = wideFilename[ 0 ] = 0;
|
||||
}
|
||||
|
||||
M3ULoader::~M3ULoader( void )
|
||||
{
|
||||
//Close();
|
||||
}
|
||||
|
||||
struct cmpWchar_t {
|
||||
bool operator()(const wchar_t* a, const wchar_t* b) const {
|
||||
return wcscmp(a, b) < 0;
|
||||
}
|
||||
};
|
||||
|
||||
class M3UInfo : public ifc_plentryinfo
|
||||
{
|
||||
public:
|
||||
M3UInfo() {}
|
||||
M3UInfo( wchar_t *_mediahash, wchar_t *_metahash, wchar_t *_cloud_id, wchar_t *_cloud_status, wchar_t *_cloud_devices )
|
||||
{
|
||||
_extended_infos.emplace( _wcsdup( _INFO_NAME_MEDIA_HASH ), _wcsdup( _mediahash) );
|
||||
_extended_infos.emplace( _wcsdup( _INFO_NAME_META_HASH ), _wcsdup( _metahash ) );
|
||||
|
||||
_extended_infos.emplace( _wcsdup( _INFO_NAME_CLOUD_ID ), _wcsdup( _cloud_id ) );
|
||||
_extended_infos.emplace( _wcsdup( _INFO_NAME_CLOUD_STATUS ), _wcsdup( _cloud_status ) );
|
||||
_extended_infos.emplace( _wcsdup( _INFO_NAME_CLOUD_DEVICES ), _wcsdup( _cloud_devices ) );
|
||||
}
|
||||
|
||||
~M3UInfo()
|
||||
{
|
||||
for ( auto l_extended_infos_iterator = _extended_infos.begin(); l_extended_infos_iterator != _extended_infos.end(); ++l_extended_infos_iterator )
|
||||
{
|
||||
free( ( *l_extended_infos_iterator ).first );
|
||||
free( ( *l_extended_infos_iterator ).second );
|
||||
}
|
||||
|
||||
_extended_infos.clear();
|
||||
}
|
||||
|
||||
void SetExtendedInfo( const wchar_t *p_parameter_name, const wchar_t *p_parameter_value )
|
||||
{
|
||||
_extended_infos.emplace( _wcsdup( p_parameter_name ), _wcsdup( p_parameter_value ) );
|
||||
}
|
||||
|
||||
const wchar_t *GetExtendedInfo( wchar_t *parameter )
|
||||
{
|
||||
//for ( auto l_extended_infos_iterator = _extended_infos.begin(); l_extended_infos_iterator != _extended_infos.end(); ++l_extended_infos_iterator )
|
||||
//{
|
||||
// wchar_t *l_key = _wcsdup( ( *l_extended_infos_iterator ).first );
|
||||
// if ( wcscmp( l_key, parameter ) == 0 )
|
||||
// return _wcsdup( ( *l_extended_infos_iterator ).second );
|
||||
//}
|
||||
|
||||
// OLD
|
||||
//std::map<wchar_t *, wchar_t *>::iterator l_extended_infos_iterator = _extended_infos.find( parameter );
|
||||
|
||||
//if ( l_extended_infos_iterator != _extended_infos.end() )
|
||||
// return _wcsdup( ( *l_extended_infos_iterator ).second );
|
||||
|
||||
auto it = _extended_infos.find(parameter);
|
||||
if (_extended_infos.end() != it)
|
||||
{
|
||||
return it->second;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private:
|
||||
RECVS_DISPATCH;
|
||||
|
||||
std::map<wchar_t *, wchar_t *, cmpWchar_t> _extended_infos;
|
||||
};
|
||||
|
||||
#define CBCLASS M3UInfo
|
||||
START_DISPATCH;
|
||||
CB( IFC_PLENTRYINFO_GETEXTENDEDINFO, GetExtendedInfo )
|
||||
END_DISPATCH;
|
||||
#undef CBCLASS
|
||||
|
||||
|
||||
int M3ULoader::OnFileHelper( ifc_playlistloadercallback *playlist, const wchar_t *trackName, const wchar_t *title, int length, const wchar_t *rootPath, ifc_plentryinfo *extraInfo )
|
||||
{
|
||||
if ( length == -1000 )
|
||||
length = -1;
|
||||
|
||||
wcsncpy( wideFilename, trackName, FILENAME_SIZE );
|
||||
|
||||
int ret;
|
||||
|
||||
if ( wcsstr( wideFilename, L"://" ) || PathIsRootW( wideFilename ) )
|
||||
{
|
||||
ret = playlist->OnFile( wideFilename, title, length, extraInfo );
|
||||
}
|
||||
else
|
||||
{
|
||||
wchar_t fullPath[ MAX_PATH ] = { 0 };
|
||||
if ( PathCombineW( fullPath, rootPath, wideFilename ) )
|
||||
{
|
||||
wchar_t canonicalizedPath[ MAX_PATH ] = { 0 };
|
||||
PathCanonicalizeW( canonicalizedPath, fullPath );
|
||||
ret = playlist->OnFile( canonicalizedPath, title, length, extraInfo );
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = ifc_playlistloadercallback::LOAD_CONTINUE;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool StringEnds( const wchar_t *a, const wchar_t *b )
|
||||
{
|
||||
size_t aLen = wcslen( a );
|
||||
size_t bLen = wcslen( b );
|
||||
|
||||
if ( aLen < bLen )
|
||||
return false; // too short
|
||||
|
||||
if ( !_wcsicmp( a + aLen - bLen, b ) )
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int M3ULoader::Load( const wchar_t *p_filename, ifc_playlistloadercallback *playlist )
|
||||
{
|
||||
// TODO: download temp file if it's a URL
|
||||
// TODO - WDP2-198
|
||||
|
||||
FILE *fp = _wfopen( p_filename, L"rt,ccs=UNICODE" );
|
||||
if ( !fp )
|
||||
return IFC_PLAYLISTLOADER_FAILED;
|
||||
|
||||
fseek( fp, 0, SEEK_END );
|
||||
int size = ftell( fp );
|
||||
fseek( fp, 0, SEEK_SET );
|
||||
|
||||
if ( size == -1 )
|
||||
{
|
||||
fclose( fp );
|
||||
fp = 0;
|
||||
|
||||
return IFC_PLAYLISTLOADER_FAILED;
|
||||
}
|
||||
|
||||
if ( StringEnds( p_filename, L".m3u8" ) )
|
||||
_utf8 = true;
|
||||
|
||||
int ext = 0;
|
||||
|
||||
wchar_t *p;
|
||||
|
||||
const int l_linebuf_size = 2048;
|
||||
wchar_t linebuf[ l_linebuf_size ] = { 0 };
|
||||
|
||||
wchar_t ext_title[ MAX_PATH ] = { 0 };
|
||||
|
||||
wchar_t ext_mediahash[ 128 ] = { 0 };
|
||||
wchar_t ext_metahash[ 128 ] = { 0 };
|
||||
|
||||
wchar_t ext_cloud_id[ 128 ] = { 0 };
|
||||
wchar_t ext_cloud_status[ 16 ] = { 0 };
|
||||
wchar_t ext_cloud_devices[ 128 ] = { 0 };
|
||||
|
||||
int ext_len = -1;
|
||||
|
||||
wchar_t rootPath[ MAX_PATH ] = { 0 };
|
||||
const wchar_t *callbackPath = playlist->GetBasePath();
|
||||
if ( callbackPath )
|
||||
StringCchCopyW( rootPath, MAX_PATH, callbackPath );
|
||||
else
|
||||
{
|
||||
StringCchCopyW( rootPath, MAX_PATH, p_filename );
|
||||
PathRemoveFileSpecW( rootPath );
|
||||
}
|
||||
|
||||
unsigned char BOM[ 3 ] = { 0, 0, 0 };
|
||||
if ( fread( BOM, 3, 1, fp ) == 1 && BOM[ 0 ] == 0xEF && BOM[ 1 ] == 0xBB && BOM[ 2 ] == 0xBF )
|
||||
_utf8 = true;
|
||||
else
|
||||
fseek( fp, 0, SEEK_SET );
|
||||
|
||||
|
||||
std::wstring l_separator = L"\" ";
|
||||
std::wstring l_key_separator = L"=";
|
||||
|
||||
|
||||
const wchar_t _ASF[] = L"ASF ";
|
||||
const wchar_t _DIRECTIVE_EXTINF[] = L"#EXTINF:";
|
||||
const wchar_t _DIRECTIVE_EXTM3U[] = L"#EXTM3U";
|
||||
const wchar_t _DIRECTIVE_EXT_X_NS_CLOUD[] = L"#EXT-X-NS-CLOUD:";
|
||||
const wchar_t _DIRECTIVE_UTF8[] = L"#UTF8";
|
||||
const wchar_t _END_LINE[] = L"\r\n";
|
||||
|
||||
const int l_move_size = sizeof( wchar_t );
|
||||
|
||||
|
||||
wa::strings::wa_string l_key_value_pair = "";
|
||||
wa::strings::wa_string l_key = "";
|
||||
wa::strings::wa_string l_value = "";
|
||||
|
||||
std::map<std::wstring, std::wstring> l_extended_infos;
|
||||
|
||||
while ( 1 )
|
||||
{
|
||||
if ( feof( fp ) )
|
||||
break;
|
||||
|
||||
linebuf[ 0 ] = 0;
|
||||
fgetws( linebuf, l_linebuf_size - 1, fp );
|
||||
|
||||
linebuf[ wcscspn( linebuf, _END_LINE ) ] = 0;
|
||||
if ( wcslen( linebuf ) == 0 )
|
||||
continue;
|
||||
|
||||
if ( ext == 0 && wcsstr( linebuf, _DIRECTIVE_EXTM3U ) )
|
||||
{
|
||||
ext = 1;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( !wcsncmp( linebuf, _DIRECTIVE_UTF8, 5 ) )
|
||||
{
|
||||
_utf8 = true;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
p = linebuf;
|
||||
|
||||
while ( p && *p == ' ' || *p == '\t' )
|
||||
p = CharNextW( p );
|
||||
|
||||
if ( *p != '#' && *p != '\n' && *p != '\r' && *p )
|
||||
{
|
||||
wchar_t buf[ 4096 ] = { 0 };
|
||||
|
||||
wchar_t *p2 = CharPrevW( linebuf, linebuf + wcslen( linebuf ) ); //GetLastCharacter(linebuf);
|
||||
if ( p2 && *p2 == '\n' )
|
||||
*p2 = 0;
|
||||
|
||||
if ( !wcsncmp( p, _ASF, 4 ) && wcslen( p ) > 4 )
|
||||
p += 4;
|
||||
|
||||
if ( wcsncmp( p, L"\\\\", 2 ) && wcsncmp( p + 1, L":\\", 2 ) && wcsncmp( p + 1, L":/", 2 ) && !wcsstr( p, L"://" ) )
|
||||
{
|
||||
if ( p[ 0 ] == '\\' )
|
||||
{
|
||||
buf[ 0 ] = rootPath[ 0 ];
|
||||
buf[ 1 ] = rootPath[ 1 ];
|
||||
|
||||
StringCchCopyW( buf + 2, 4093, p );
|
||||
|
||||
//buf[ wcslen( buf ) - 1 ] = 0;
|
||||
buf[ wcscspn( buf, _END_LINE ) ] = 0;
|
||||
p = buf;
|
||||
}
|
||||
}
|
||||
|
||||
int ret;
|
||||
|
||||
// generate extra info from the cloud specific values (if present)
|
||||
M3UInfo info( ext_mediahash, ext_metahash, ext_cloud_id, ext_cloud_status, ext_cloud_devices );
|
||||
|
||||
|
||||
if ( !l_extended_infos.empty() )
|
||||
{
|
||||
for ( auto l_extended_infos_iterator = l_extended_infos.begin(); l_extended_infos_iterator != l_extended_infos.end(); ++l_extended_infos_iterator )
|
||||
{
|
||||
info.SetExtendedInfo( ( *l_extended_infos_iterator ).first.c_str(), ( *l_extended_infos_iterator ).second.c_str() );
|
||||
}
|
||||
}
|
||||
|
||||
l_extended_infos.clear();
|
||||
|
||||
if ( ext_title[ 0 ] )
|
||||
{
|
||||
wcsncpy( wideTitle, ext_title, FILETITLE_SIZE );
|
||||
ret = OnFileHelper( playlist, p, wideTitle, ext_len * 1000, rootPath, &info );
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = OnFileHelper( playlist, p, 0, -1, rootPath, &info );
|
||||
}
|
||||
|
||||
if ( ret != ifc_playlistloadercallback::LOAD_CONTINUE )
|
||||
break;
|
||||
|
||||
ext_len = -1;
|
||||
ext_title[ 0 ] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( ext && !wcsncmp( p, _DIRECTIVE_EXTINF, 8 ) )
|
||||
{
|
||||
p += 8;
|
||||
ext_len = _wtoi( p );
|
||||
|
||||
int l_track_length = ext_len;
|
||||
int l_digits = ( l_track_length < 0 ? 1 : 0 );
|
||||
while ( l_track_length )
|
||||
{
|
||||
l_track_length /= 10;
|
||||
++l_digits;
|
||||
}
|
||||
|
||||
p += l_digits;
|
||||
|
||||
|
||||
if ( p && *p )
|
||||
{
|
||||
wchar_t *p2 = CharPrevW( p, p + wcslen( p ) ); // GetLastCharacter(p);
|
||||
if ( p2 && *p2 == '\n' )
|
||||
*p2 = 0;
|
||||
|
||||
while ( p && *p == ' ' )
|
||||
p = CharNextW( p );
|
||||
|
||||
std::wstring l_string( p );
|
||||
|
||||
int l_pos = l_string.find_first_of( L"," );
|
||||
|
||||
if ( l_pos > 0 )
|
||||
{
|
||||
int l_key_separator_pos = 0;
|
||||
|
||||
wa::strings::wa_string l_line_trail( l_string.substr( 0, l_pos ) );
|
||||
|
||||
while ( !l_line_trail.empty() )
|
||||
{
|
||||
int l_separator_pos = l_line_trail.find( l_separator );
|
||||
|
||||
if ( l_separator_pos > 0 )
|
||||
l_key_value_pair = l_line_trail.mid( 0, l_separator_pos + 1 );
|
||||
else
|
||||
l_key_value_pair = l_line_trail;
|
||||
|
||||
|
||||
l_key_separator_pos = l_key_value_pair.find( l_key_separator );
|
||||
|
||||
l_key = l_key_value_pair.mid( 0, l_key_separator_pos );
|
||||
l_value = l_key_value_pair.mid( l_key_separator_pos + 1, l_key_value_pair.lengthS() - l_key_separator_pos + 1 );
|
||||
|
||||
l_value.replaceAll( "\"", "" );
|
||||
|
||||
l_extended_infos.emplace( l_key.GetW(), l_value.GetW() );
|
||||
|
||||
if ( l_separator_pos > 0 )
|
||||
l_line_trail = l_line_trail.mid( l_separator_pos + l_move_size, l_line_trail.lengthS() - l_separator_pos + 1 );
|
||||
else
|
||||
l_line_trail.clear();
|
||||
}
|
||||
|
||||
|
||||
l_string = l_string.substr( l_pos + 1, l_string.size() - l_pos );
|
||||
|
||||
StringCchCopyW( ext_title, MAX_PATH, l_string.c_str() );
|
||||
}
|
||||
else
|
||||
StringCchCopyW( ext_title, MAX_PATH, CharNextW( p ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
ext_len = -1;
|
||||
ext_title[ 0 ] = 0;
|
||||
}
|
||||
}
|
||||
// cloud specific playlist line for holding information about the entry
|
||||
else if ( ext && !wcsncmp( p, _DIRECTIVE_EXT_X_NS_CLOUD, 16 ) )
|
||||
{
|
||||
p += 16;
|
||||
wchar_t *pt = wcstok( p, L"," );
|
||||
while ( pt != NULL )
|
||||
{
|
||||
int end = (int)wcscspn( pt, L"=" );
|
||||
|
||||
if ( !wcsncmp( pt, _INFO_NAME_MEDIA_HASH, end ) )
|
||||
{
|
||||
if ( ( lstrcpynW( ext_mediahash, pt + end + 1, 128 ) ) == NULL )
|
||||
return IFC_PLAYLISTLOADER_FAILED;
|
||||
}
|
||||
else if ( !wcsncmp( pt, _INFO_NAME_META_HASH, end ) )
|
||||
{
|
||||
if ( ( lstrcpynW( ext_metahash, pt + end + 1, 128 ) ) == NULL )
|
||||
return IFC_PLAYLISTLOADER_FAILED;
|
||||
}
|
||||
else if ( !wcsncmp( pt, _INFO_NAME_CLOUD_ID, end ) )
|
||||
{
|
||||
if ( ( lstrcpynW( ext_cloud_id, pt + end + 1, 128 ) ) == NULL )
|
||||
return IFC_PLAYLISTLOADER_FAILED;
|
||||
}
|
||||
else if ( !wcsncmp( pt, _INFO_NAME_CLOUD_STATUS, end ) )
|
||||
{
|
||||
if ( ( lstrcpynW( ext_cloud_status, pt + end + 1, 16 ) ) == NULL )
|
||||
return IFC_PLAYLISTLOADER_FAILED;
|
||||
}
|
||||
else if ( !wcsncmp( pt, _INFO_NAME_CLOUD_DEVICES, end ) )
|
||||
{
|
||||
wchar_t *p2 = pt + end + 1;
|
||||
while ( p2 && *p2 != '\n' )
|
||||
p2 = CharNextW( p2 );
|
||||
|
||||
if ( p2 && *p2 == '\n' )
|
||||
*p2 = 0;
|
||||
|
||||
if ( ( lstrcpynW( ext_cloud_devices, pt + end + 1, 128 ) ) == NULL )
|
||||
return IFC_PLAYLISTLOADER_FAILED;
|
||||
}
|
||||
|
||||
pt = wcstok( NULL, L"," );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ext_len = -1;
|
||||
ext_title[ 0 ] = 0;
|
||||
ext_mediahash[ 0 ] = 0;
|
||||
ext_metahash[ 0 ] = 0;
|
||||
ext_cloud_id[ 0 ] = 0;
|
||||
ext_cloud_status[ 0 ] = 0;
|
||||
ext_cloud_devices[ 0 ] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( fp )
|
||||
fclose( fp );
|
||||
|
||||
return IFC_PLAYLISTLOADER_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
#ifdef CBCLASS
|
||||
#undef CBCLASS
|
||||
#endif
|
||||
|
||||
#define CBCLASS M3ULoader
|
||||
|
||||
START_DISPATCH;
|
||||
CB( IFC_PLAYLISTLOADER_LOAD, Load )
|
||||
#if 0
|
||||
VCB( IFC_PLAYLISTLOADER_CLOSE, Close )
|
||||
CB( IFC_PLAYLISTLOADER_GETITEM, GetItem )
|
||||
CB( IFC_PLAYLISTLOADER_GETITEMTITLE, GetItemTitle )
|
||||
CB( IFC_PLAYLISTLOADER_GETITEMLENGTHMILLISECONDS, GetItemLengthMilliseconds )
|
||||
CB( IFC_PLAYLISTLOADER_GETITEMEXTENDEDINFO, GetItemExtendedInfo )
|
||||
CB( IFC_PLAYLISTLOADER_NEXTITEM, NextItem )
|
||||
#endif
|
||||
END_DISPATCH;
|
31
Src/playlist/M3ULoader.h
Normal file
31
Src/playlist/M3ULoader.h
Normal file
@ -0,0 +1,31 @@
|
||||
#ifndef NULLSOFT_PLAYLIST_M3U_LOADER_H
|
||||
#define NULLSOFT_PLAYLIST_M3U_LOADER_H
|
||||
|
||||
#include "ifc_playlistloader.h"
|
||||
#include "ifc_playlistloadercallback.h"
|
||||
#include <stdio.h>
|
||||
|
||||
static wchar_t *_INFO_NAME_MEDIA_HASH = L"mediahash";
|
||||
static wchar_t *_INFO_NAME_META_HASH = L"metahash";
|
||||
static wchar_t *_INFO_NAME_CLOUD_ID = L"cloud_id";
|
||||
static wchar_t *_INFO_NAME_CLOUD_STATUS = L"cloud_status";
|
||||
static wchar_t *_INFO_NAME_CLOUD_DEVICES = L"cloud_devices";
|
||||
|
||||
class M3ULoader : public ifc_playlistloader
|
||||
{
|
||||
public:
|
||||
M3ULoader();
|
||||
virtual ~M3ULoader( void );
|
||||
|
||||
int Load( const wchar_t *filename, ifc_playlistloadercallback *playlist );
|
||||
int OnFileHelper( ifc_playlistloadercallback *playlist, const wchar_t *trackName, const wchar_t *title, int length, const wchar_t *rootPath, ifc_plentryinfo *extraInfo );
|
||||
|
||||
|
||||
protected:
|
||||
RECVS_DISPATCH;
|
||||
|
||||
bool _utf8;
|
||||
wchar_t wideFilename[ FILENAME_SIZE ];
|
||||
wchar_t wideTitle[ FILETITLE_SIZE ];
|
||||
};
|
||||
#endif
|
42
Src/playlist/M3UWriter.cpp
Normal file
42
Src/playlist/M3UWriter.cpp
Normal file
@ -0,0 +1,42 @@
|
||||
#include "M3UWriter.h"
|
||||
#include "../nu/AutoChar.h"
|
||||
|
||||
M3UWriter::~M3UWriter()
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
int M3UWriter::Open( const wchar_t *filename )
|
||||
{
|
||||
if ( fp != NULL )
|
||||
return 0;
|
||||
|
||||
fp = _wfopen( filename, L"wt" );
|
||||
if ( !fp )
|
||||
return 0;
|
||||
|
||||
fprintf( fp, "#EXTM3U\n" );
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void M3UWriter::Write( const wchar_t *filename )
|
||||
{
|
||||
if ( fp != NULL )
|
||||
fprintf( fp, "%s\n", (char *)AutoChar( filename ) );
|
||||
}
|
||||
|
||||
void M3UWriter::Write( const wchar_t *filename, const wchar_t *title, int length )
|
||||
{
|
||||
if ( fp != NULL )
|
||||
fprintf( fp, "#EXTINF:%d,%s\n%s\n", length, (char *)AutoChar( title ), (char *)AutoChar( filename ) );
|
||||
}
|
||||
|
||||
void M3UWriter::Close()
|
||||
{
|
||||
if ( fp != NULL )
|
||||
{
|
||||
fclose( fp );
|
||||
fp = NULL;
|
||||
}
|
||||
}
|
23
Src/playlist/M3UWriter.h
Normal file
23
Src/playlist/M3UWriter.h
Normal file
@ -0,0 +1,23 @@
|
||||
#ifndef NULLSOFT_M3UWRITERH
|
||||
#define NULLSOFT_M3UWRITERH
|
||||
|
||||
#include <stdio.h>
|
||||
#include "PlaylistWriter.h"
|
||||
class M3UWriter : public PlaylistWriter
|
||||
{
|
||||
public:
|
||||
M3UWriter() {}
|
||||
virtual ~M3UWriter();
|
||||
|
||||
int Open( const wchar_t *filename ) override;
|
||||
void Write( const wchar_t *filename ) override;
|
||||
void Write( const wchar_t *filename, const wchar_t *title, int length ) override;
|
||||
void Write( const wchar_t *p_filename, const wchar_t *p_title, const wchar_t *p_extended_infos, int p_length ) override
|
||||
{};
|
||||
void Close() override;
|
||||
|
||||
private:
|
||||
FILE *fp = NULL;
|
||||
};
|
||||
|
||||
#endif
|
159
Src/playlist/PLSLoader.cpp
Normal file
159
Src/playlist/PLSLoader.cpp
Normal file
@ -0,0 +1,159 @@
|
||||
#include "PLSLoader.h"
|
||||
|
||||
#include "../nu/AutoChar.h"
|
||||
#include "../nu/AutoWide.h"
|
||||
#include <shlwapi.h>
|
||||
#include <strsafe.h>
|
||||
|
||||
|
||||
class PLSInfo : public ifc_plentryinfo
|
||||
{
|
||||
public:
|
||||
PLSInfo( const wchar_t *_filename, int _entryNum ) : filename( _filename ), entryNum( _entryNum )
|
||||
{}
|
||||
|
||||
const wchar_t *GetExtendedInfo( const wchar_t *parameter )
|
||||
{
|
||||
static wchar_t data[ 1024 ];
|
||||
wchar_t fieldbuf[ 100 ] = { 0 };
|
||||
|
||||
StringCchPrintfW( fieldbuf, 100, L"%s%d", parameter, entryNum );
|
||||
|
||||
GetPrivateProfileStringW( L"playlist", fieldbuf, L"", data, 1024, filename );
|
||||
|
||||
if ( data[ 0 ] )
|
||||
return data;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
private:
|
||||
RECVS_DISPATCH;
|
||||
|
||||
const wchar_t *filename;
|
||||
int entryNum;
|
||||
};
|
||||
|
||||
#define CBCLASS PLSInfo
|
||||
START_DISPATCH;
|
||||
CB( IFC_PLENTRYINFO_GETEXTENDEDINFO, GetExtendedInfo )
|
||||
END_DISPATCH;
|
||||
#undef CBCLASS
|
||||
|
||||
int PLSLoader::OnFileHelper( ifc_playlistloadercallback *playlist, const wchar_t *trackName, const wchar_t *title, int length, const wchar_t *rootPath, ifc_plentryinfo *extraInfo )
|
||||
{
|
||||
if ( length == -1000 )
|
||||
length = -1;
|
||||
|
||||
int ret;
|
||||
if ( wcsstr( trackName, L"://" ) || PathIsRootW( trackName ) )
|
||||
{
|
||||
ret = playlist->OnFile( trackName, title, length, extraInfo );
|
||||
}
|
||||
else
|
||||
{
|
||||
wchar_t fullPath[ MAX_PATH ] = { 0 };
|
||||
if ( PathCombineW( fullPath, rootPath, trackName ) )
|
||||
{
|
||||
wchar_t canonicalizedPath[ MAX_PATH ] = { 0 };
|
||||
PathCanonicalizeW( canonicalizedPath, fullPath );
|
||||
ret = playlist->OnFile( canonicalizedPath, title, length, extraInfo );
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = ifc_playlistloadercallback::LOAD_CONTINUE;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int PLSLoader::Load( const wchar_t *filename, ifc_playlistloadercallback *playlist )
|
||||
{
|
||||
int x, numfiles;
|
||||
int ext = 0;
|
||||
char fieldbuf[ 100 ] = { 0 };
|
||||
char fnbuf[ FILENAME_SIZE ] = { 0 };
|
||||
char tmp[ MAX_PATH ] = { 0 };
|
||||
|
||||
wchar_t rootPath[ MAX_PATH ] = { 0 };
|
||||
const wchar_t *callbackPath = playlist->GetBasePath();
|
||||
if ( callbackPath )
|
||||
lstrcpynW( rootPath, callbackPath, MAX_PATH );
|
||||
else
|
||||
{
|
||||
lstrcpynW( rootPath, filename, MAX_PATH );
|
||||
PathRemoveFileSpecW( rootPath );
|
||||
}
|
||||
|
||||
tmp[ 0 ] = (char)rootPath[ 0 ];
|
||||
tmp[ 1 ] = (char)rootPath[ 1 ];
|
||||
tmp[ 2 ] = (char)rootPath[ 2 ];
|
||||
|
||||
AutoChar fn( filename );
|
||||
|
||||
numfiles = GetPrivateProfileIntA( "playlist", "NumberOfEntries", 0, fn );
|
||||
ext = GetPrivateProfileIntA( "playlist", "Version", 1, fn );
|
||||
if ( numfiles == 0 )
|
||||
return IFC_PLAYLISTLOADER_FAILED;
|
||||
|
||||
for ( x = 1; x <= numfiles; x++ )
|
||||
{
|
||||
int flen = -1;
|
||||
char ftitle[ FILETITLE_SIZE ] = "";
|
||||
StringCchPrintfA( fieldbuf, 100, "File%d", x );
|
||||
GetPrivateProfileStringA( "playlist", fieldbuf, "", fnbuf, FILENAME_SIZE, fn );
|
||||
if ( ext )
|
||||
{
|
||||
StringCchPrintfA( fieldbuf, 100, "Title%d", x );
|
||||
GetPrivateProfileStringA( "playlist", fieldbuf, "", ftitle, FILETITLE_SIZE, fn );
|
||||
StringCchPrintfA( fieldbuf, 100, "Length%d", x );
|
||||
flen = GetPrivateProfileIntA( "playlist", fieldbuf, -1, fn );
|
||||
}
|
||||
|
||||
if ( *fnbuf )
|
||||
{
|
||||
char *p;
|
||||
char buf[ 512 ] = { 0 };
|
||||
|
||||
p = fnbuf;
|
||||
|
||||
if ( strncmp( p, "\\\\", 2 ) && strncmp( p + 1, ":\\", 2 ) && !strstr( p, ":/" ) )
|
||||
{
|
||||
if ( p[ 0 ] == '\\' )
|
||||
{
|
||||
buf[ 0 ] = tmp[ 0 ];
|
||||
buf[ 1 ] = tmp[ 1 ];
|
||||
lstrcpynA( buf + 2, p, 510 );
|
||||
buf[ 511 ] = 0;
|
||||
p = buf;
|
||||
}
|
||||
}
|
||||
|
||||
PLSInfo info( filename, x );
|
||||
|
||||
int ret;
|
||||
if ( ftitle[ 0 ] )
|
||||
{
|
||||
ret = OnFileHelper( playlist, AutoWide( p ), AutoWide( ftitle ), flen * 1000, rootPath, &info );
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = OnFileHelper( playlist, AutoWide( p ), 0, -1, rootPath, &info );
|
||||
}
|
||||
|
||||
if ( ret != ifc_playlistloadercallback::LOAD_CONTINUE )
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return IFC_PLAYLISTLOADER_SUCCESS;
|
||||
}
|
||||
|
||||
#define CBCLASS PLSLoader
|
||||
START_DISPATCH;
|
||||
CB( IFC_PLAYLISTLOADER_LOAD, Load )
|
||||
END_DISPATCH;
|
||||
#undef CBCLASS
|
22
Src/playlist/PLSLoader.h
Normal file
22
Src/playlist/PLSLoader.h
Normal file
@ -0,0 +1,22 @@
|
||||
#ifndef NULLSOFT_PLAYLIST_PLSLOADER_H
|
||||
#define NULLSOFT_PLAYLIST_PLSLOADER_H
|
||||
|
||||
#include "ifc_playlistloader.h"
|
||||
#include <windows.h>
|
||||
|
||||
class PLSLoader : public ifc_playlistloader
|
||||
{
|
||||
public:
|
||||
PLSLoader() {}
|
||||
virtual ~PLSLoader() {}
|
||||
|
||||
int Load( const wchar_t *filename, ifc_playlistloadercallback *playlist );
|
||||
|
||||
protected:
|
||||
RECVS_DISPATCH;
|
||||
|
||||
private:
|
||||
int OnFileHelper( ifc_playlistloadercallback *playlist, const wchar_t *trackName, const wchar_t *title, int length, const wchar_t *rootPath, ifc_plentryinfo *extraInfo );
|
||||
};
|
||||
|
||||
#endif
|
36
Src/playlist/PLSWriter.cpp
Normal file
36
Src/playlist/PLSWriter.cpp
Normal file
@ -0,0 +1,36 @@
|
||||
#include "PLSWriter.h"
|
||||
#include "../nu/AutoChar.h"
|
||||
|
||||
PLSWriter::PLSWriter() : fp(0), numEntries(0)
|
||||
{
|
||||
}
|
||||
|
||||
int PLSWriter::Open(const wchar_t *filename)
|
||||
{
|
||||
fp = _wfopen(filename, L"wt");
|
||||
if (!fp)
|
||||
return 0;
|
||||
|
||||
fprintf(fp, "[playlist]\r\n");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void PLSWriter::Write(const wchar_t *filename)
|
||||
{
|
||||
fwprintf(fp, L"File%d=%s\r\n", (int)++numEntries, filename);
|
||||
}
|
||||
|
||||
void PLSWriter::Write(const wchar_t *filename, const wchar_t *title, int length)
|
||||
{
|
||||
Write(filename);
|
||||
fwprintf(fp, L"Title%d=%s\r\n", (int)numEntries, title);
|
||||
fprintf(fp, "Length%d=%d\r\n", (int)numEntries, length);
|
||||
}
|
||||
|
||||
void PLSWriter::Close()
|
||||
{
|
||||
fprintf(fp, "NumberOfEntries=%d\r\n", (int)numEntries);
|
||||
fprintf(fp, "Version=2\r\n");
|
||||
fclose(fp);
|
||||
}
|
21
Src/playlist/PLSWriter.h
Normal file
21
Src/playlist/PLSWriter.h
Normal file
@ -0,0 +1,21 @@
|
||||
#ifndef NULLSOFT_PLSWRITERH
|
||||
#define NULLSOFT_PLSWRITERH
|
||||
|
||||
#include <stdio.h>
|
||||
#include "PlaylistWriter.h"
|
||||
class PLSWriter : public PlaylistWriter
|
||||
{
|
||||
public:
|
||||
PLSWriter();
|
||||
int Open(const wchar_t *filename);
|
||||
void Write(const wchar_t *filename);
|
||||
void Write(const wchar_t *filename, const wchar_t *title, int length);
|
||||
void Write( const wchar_t *p_filename, const wchar_t *p_title, const wchar_t *p_extended_infos, int p_length ) override
|
||||
{};
|
||||
void Close();
|
||||
private:
|
||||
size_t numEntries;
|
||||
FILE *fp;
|
||||
};
|
||||
|
||||
#endif
|
230
Src/playlist/Playlist.cpp
Normal file
230
Src/playlist/Playlist.cpp
Normal file
@ -0,0 +1,230 @@
|
||||
#include "main.h"
|
||||
#include "Playlist.h"
|
||||
#include <algorithm>
|
||||
#include "../nu/AutoChar.h"
|
||||
#include "../Winamp/strutil.h"
|
||||
|
||||
void Playlist::Clear()
|
||||
{
|
||||
for ( pl_entry *entry : entries )
|
||||
delete entry;
|
||||
|
||||
entries.clear();
|
||||
}
|
||||
|
||||
int Playlist::OnFile( const wchar_t *p_filename, const wchar_t *p_title, int p_lengthInMS, ifc_plentryinfo *p_info )
|
||||
{
|
||||
entries.push_back( new pl_entry( p_filename, p_title, p_lengthInMS, p_info ) );
|
||||
|
||||
return ifc_playlistloadercallback::LOAD_CONTINUE;
|
||||
}
|
||||
|
||||
void Playlist::AppendWithInfo( const wchar_t *p_filename, const wchar_t *p_title, int p_lengthInMS )
|
||||
{
|
||||
entries.push_back( new pl_entry( p_filename, p_title, p_lengthInMS ) );
|
||||
}
|
||||
|
||||
void Playlist::Insert( size_t p_index, const wchar_t *p_filename, const wchar_t *p_title, int p_lengthInMS )
|
||||
{
|
||||
entries.insert( entries.begin() + p_index, new pl_entry( p_filename, p_title, p_lengthInMS ) );
|
||||
}
|
||||
|
||||
Playlist::~Playlist()
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
|
||||
|
||||
size_t Playlist::GetNumItems()
|
||||
{
|
||||
return entries.size();
|
||||
}
|
||||
|
||||
size_t Playlist::GetItem( size_t item, wchar_t *filename, size_t filenameCch )
|
||||
{
|
||||
if ( item >= entries.size() )
|
||||
return 0;
|
||||
|
||||
return entries[ item ]->GetFilename( filename, filenameCch );
|
||||
}
|
||||
|
||||
size_t Playlist::GetItemTitle( size_t item, wchar_t *title, size_t titleCch )
|
||||
{
|
||||
if ( item >= entries.size() )
|
||||
return 0;
|
||||
|
||||
return entries[ item ]->GetTitle( title, titleCch );
|
||||
}
|
||||
|
||||
const wchar_t *Playlist::ItemTitle( size_t item )
|
||||
{
|
||||
if ( item >= entries.size() )
|
||||
return 0;
|
||||
|
||||
return entries[ item ]->filetitle;
|
||||
}
|
||||
|
||||
const wchar_t *Playlist::ItemName( size_t item )
|
||||
{
|
||||
if ( item >= entries.size() )
|
||||
return 0;
|
||||
|
||||
return entries[ item ]->filename;
|
||||
}
|
||||
|
||||
int Playlist::GetItemLengthMilliseconds( size_t item )
|
||||
{
|
||||
if ( item >= entries.size() )
|
||||
return -1;
|
||||
|
||||
return entries[ item ]->GetLengthInMilliseconds();
|
||||
}
|
||||
|
||||
size_t Playlist::GetItemExtendedInfo( size_t item, const wchar_t *metadata, wchar_t *info, size_t infoCch )
|
||||
{
|
||||
if ( item >= entries.size() )
|
||||
return 0;
|
||||
|
||||
return entries[ item ]->GetExtendedInfo( metadata, info, infoCch );
|
||||
}
|
||||
|
||||
int Playlist::Reverse()
|
||||
{
|
||||
// TODO: keep a bool flag and just do size-item-1 every time a GetItem* function is called
|
||||
std::reverse( entries.begin(), entries.end() );
|
||||
|
||||
return PLAYLIST_SUCCESS;
|
||||
}
|
||||
|
||||
int Playlist::Swap( size_t item1, size_t item2 )
|
||||
{
|
||||
std::swap( entries[ item1 ], entries[ item2 ] );
|
||||
|
||||
return PLAYLIST_SUCCESS;
|
||||
}
|
||||
|
||||
class RandMod
|
||||
{
|
||||
public:
|
||||
RandMod( int ( *_generator )( ) ) : generator( _generator ) {}
|
||||
int operator ()( int n ) { return generator() % n; }
|
||||
int ( *generator )( );
|
||||
};
|
||||
|
||||
int Playlist::Randomize( int ( *generator )( ) )
|
||||
{
|
||||
RandMod randMod( generator );
|
||||
std::random_shuffle( entries.begin(), entries.end(), randMod );
|
||||
|
||||
return PLAYLIST_SUCCESS;
|
||||
}
|
||||
|
||||
void Playlist::Remove( size_t item )
|
||||
{
|
||||
if ( entries.size() > item )
|
||||
entries.erase( entries.begin() + item );
|
||||
}
|
||||
|
||||
void Playlist::SetItemFilename( size_t item, const wchar_t *filename )
|
||||
{
|
||||
if ( item < entries.size() )
|
||||
entries[ item ]->SetFilename( filename );
|
||||
}
|
||||
|
||||
void Playlist::SetItemTitle( size_t item, const wchar_t *title )
|
||||
{
|
||||
if ( item < entries.size() )
|
||||
entries[ item ]->SetTitle( title );
|
||||
}
|
||||
|
||||
void Playlist::SetItemLengthMilliseconds( size_t item, int length )
|
||||
{
|
||||
if ( item < entries.size() )
|
||||
entries[ item ]->SetLengthMilliseconds( length );
|
||||
}
|
||||
|
||||
static bool PlayList_sortByTitle( pl_entry *&a, pl_entry *&b )
|
||||
{
|
||||
int comp = CompareStringW( LOCALE_USER_DEFAULT, NORM_IGNORECASE /*|NORM_IGNOREKANATYPE*/ | NORM_IGNOREWIDTH, a->filetitle, -1, b->filetitle, -1 );
|
||||
|
||||
return comp == CSTR_LESS_THAN;
|
||||
// TODO: grab this function from winamp - return CompareStringLogical(a.strTitle, b.strTitle)<0;
|
||||
}
|
||||
|
||||
static bool PlayList_sortByFile( pl_entry *&a, pl_entry *&b ) //const void *a, const void *b)
|
||||
{
|
||||
const wchar_t *file1 = PathFindFileNameW( a->filename );
|
||||
const wchar_t *file2 = PathFindFileNameW( b->filename );
|
||||
|
||||
int comp = CompareStringW( LOCALE_USER_DEFAULT, NORM_IGNORECASE | /*NORM_IGNOREKANATYPE |*/ NORM_IGNOREWIDTH, file1, -1, file2, -1 );
|
||||
|
||||
return comp == CSTR_LESS_THAN;
|
||||
// TODO: grab this function from winamp - return FileCompareLogical(file1, file2)<0;
|
||||
}
|
||||
|
||||
static bool PlayList_sortByDirectory( pl_entry *&a, pl_entry *&b ) // by dir, then by p_title
|
||||
{
|
||||
const wchar_t *directory1 = a->filename;
|
||||
const wchar_t *directory2 = b->filename;
|
||||
|
||||
const wchar_t *directoryEnd1 = scanstr_backcW( directory1, L"\\", 0 );
|
||||
const wchar_t *directoryEnd2 = scanstr_backcW( directory2, L"\\", 0 );
|
||||
|
||||
int dirLen1 = (int)( directoryEnd1 - directory1 );
|
||||
int dirLen2 = (int)( directoryEnd2 - directory2 );
|
||||
|
||||
if ( !dirLen1 && !dirLen2 ) // both in the current directory?
|
||||
return PlayList_sortByFile( a, b ); // not optimized, because the function does another scanstr_back, but easy for now :)
|
||||
|
||||
if ( !dirLen1 ) // only the first dir is empty?
|
||||
return true; // sort it first
|
||||
|
||||
if ( !dirLen2 ) // only the second dir empty?
|
||||
return false; // empty dirs go first
|
||||
|
||||
#if 0 // TODO: grab this function from winamp
|
||||
int comp = FileCompareLogicalN( directory1, dirLen1, directory2, dirLen2 );
|
||||
if ( comp == 0 )
|
||||
return PlayList_sortByFile( a, b );
|
||||
else
|
||||
return comp < 0;
|
||||
#endif
|
||||
|
||||
int comp = CompareStringW( LOCALE_USER_DEFAULT, NORM_IGNORECASE | /*NORM_IGNOREKANATYPE | */NORM_IGNOREWIDTH, directory1, dirLen1, directory2, dirLen2 );
|
||||
if ( comp == CSTR_EQUAL ) // same dir
|
||||
return PlayList_sortByFile( a, b ); // do second sort
|
||||
else // different dirs
|
||||
return comp == CSTR_LESS_THAN;
|
||||
}
|
||||
|
||||
int Playlist::SortByTitle()
|
||||
{
|
||||
std::sort( entries.begin(), entries.end(), PlayList_sortByTitle );
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int Playlist::SortByFilename()
|
||||
{
|
||||
std::sort( entries.begin(), entries.end(), PlayList_sortByFile );
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int Playlist::SortByDirectory()
|
||||
{
|
||||
std::sort( entries.begin(), entries.end(), PlayList_sortByDirectory );
|
||||
|
||||
return 1;
|
||||
}
|
||||
/*
|
||||
int Playlist::Move(size_t itemSrc, size_t itemDest)
|
||||
{
|
||||
if (itemSrc < itemDest)
|
||||
std::rotate(&entries[itemSrc], &entries[itemSrc], &entries[itemDest]);
|
||||
else
|
||||
if (itemSrc > itemDest)
|
||||
std::rotate(&entries[itemDest], &entries[itemSrc], &entries[itemSrc]);
|
||||
return 1;
|
||||
}*/
|
||||
|
48
Src/playlist/Playlist.h
Normal file
48
Src/playlist/Playlist.h
Normal file
@ -0,0 +1,48 @@
|
||||
#ifndef NULLSOFT_ML_PLAYLISTS_PLAYLIST_H
|
||||
#define NULLSOFT_ML_PLAYLISTS_PLAYLIST_H
|
||||
|
||||
#include "ifc_playlist.h"
|
||||
|
||||
#include <windows.h> // for MAX_PATH
|
||||
#include "pl_entry.h"
|
||||
#include "ifc_playlistT.h"
|
||||
#include "ifc_playlistloadercallbackT.h"
|
||||
#include <vector>
|
||||
|
||||
|
||||
class Playlist : public ifc_playlistloadercallbackT<Playlist>, public ifc_playlistT<Playlist>
|
||||
{
|
||||
public:
|
||||
virtual ~Playlist();
|
||||
|
||||
void Clear();
|
||||
int OnFile( const wchar_t *p_filename, const wchar_t *p_title, int p_lengthInMS, ifc_plentryinfo *p_info );
|
||||
void AppendWithInfo( const wchar_t *p_filename, const wchar_t *p_title, int p_lengthInMS );
|
||||
void Insert( size_t p_index, const wchar_t *p_filename, const wchar_t *p_title, int p_lengthInMS );
|
||||
|
||||
size_t GetNumItems();
|
||||
|
||||
size_t GetItem( size_t item, wchar_t *filename, size_t filenameCch );
|
||||
size_t GetItemTitle( size_t item, wchar_t *title, size_t titleCch );
|
||||
const wchar_t *ItemTitle( size_t item );
|
||||
const wchar_t *ItemName( size_t item );
|
||||
int GetItemLengthMilliseconds( size_t item ); // TODO: maybe microsecond for better resolution?
|
||||
size_t GetItemExtendedInfo( size_t item, const wchar_t *metadata, wchar_t *info, size_t infoCch );
|
||||
|
||||
void SetItemFilename( size_t item, const wchar_t *filename );
|
||||
void SetItemTitle( size_t item, const wchar_t *title );
|
||||
void SetItemLengthMilliseconds( size_t item, int length );
|
||||
|
||||
int Reverse();
|
||||
int Swap( size_t item1, size_t item2 );
|
||||
int Randomize( int ( *generator )( ) );
|
||||
void Remove( size_t item );
|
||||
int SortByTitle();
|
||||
int SortByFilename();
|
||||
int SortByDirectory(); //sorts by directory and then by filename
|
||||
|
||||
private:
|
||||
typedef std::vector<pl_entry*> PlaylistEntries;
|
||||
PlaylistEntries entries;
|
||||
};
|
||||
#endif
|
18
Src/playlist/PlaylistCounter.cpp
Normal file
18
Src/playlist/PlaylistCounter.cpp
Normal file
@ -0,0 +1,18 @@
|
||||
#include "PlaylistCounter.h"
|
||||
|
||||
int PlaylistCounter::OnFile( const wchar_t *filename, const wchar_t *title, int lengthInMS, ifc_plentryinfo *info )
|
||||
{
|
||||
// TODO: recursive load?
|
||||
++count;
|
||||
if ( lengthInMS > 0 )
|
||||
length += lengthInMS;
|
||||
|
||||
return LOAD_CONTINUE;
|
||||
}
|
||||
|
||||
|
||||
#define CBCLASS PlaylistCounter
|
||||
START_DISPATCH;
|
||||
CB( IFC_PLAYLISTLOADERCALLBACK_ONFILE_RET, OnFile )
|
||||
END_DISPATCH;
|
||||
#undef CBCLASS
|
21
Src/playlist/PlaylistCounter.h
Normal file
21
Src/playlist/PlaylistCounter.h
Normal file
@ -0,0 +1,21 @@
|
||||
#ifndef NULLSOFT_PLAYLIST_PLAYLISTCOUNTER_H
|
||||
#define NULLSOFT_PLAYLIST_PLAYLISTCOUNTER_H
|
||||
|
||||
#include "ifc_playlistloadercallback.h"
|
||||
|
||||
class PlaylistCounter : public ifc_playlistloadercallback
|
||||
{
|
||||
public:
|
||||
PlaylistCounter() {}
|
||||
|
||||
int OnFile( const wchar_t *filename, const wchar_t *title, int lengthInMS, ifc_plentryinfo *info );
|
||||
|
||||
size_t count = 0;
|
||||
uint64_t length = 0;
|
||||
|
||||
protected:
|
||||
RECVS_DISPATCH;
|
||||
|
||||
};
|
||||
|
||||
#endif
|
630
Src/playlist/PlaylistManager.cpp
Normal file
630
Src/playlist/PlaylistManager.cpp
Normal file
@ -0,0 +1,630 @@
|
||||
#include <strsafe.h>
|
||||
#include <shlwapi.h>
|
||||
#include <algorithm>
|
||||
|
||||
|
||||
#include "main.h"
|
||||
#include "resource.h"
|
||||
#include "PlaylistManager.h"
|
||||
#include "ifc_playlistloader.h"
|
||||
#include "M3ULoader.h"
|
||||
#include "M3UWriter.h"
|
||||
#include "PLSWriter.h"
|
||||
#include "M3U8Writer.h"
|
||||
#include "B4SWriter.h"
|
||||
#include "../nu/AutoChar.h"
|
||||
#include "Playlist.h"
|
||||
#include "../playlist/svc_playlisthandler.h"
|
||||
#include "../playlist/Handler.h"
|
||||
#include "../nu/AutoWide.h"
|
||||
#include "Playlist.h"
|
||||
#include "api/service/services.h"
|
||||
#include "api__playlist.h"
|
||||
#include "api/service/waservicefactory.h"
|
||||
#include "PlaylistCounter.h"
|
||||
#include "ifc_playlistloadercallback.h"
|
||||
#include "ifc_playlistdirectorycallback.h"
|
||||
|
||||
#include "..\WAT\WAT.h"
|
||||
|
||||
class NoRecurseCallback : public ifc_playlistdirectorycallback
|
||||
{
|
||||
public:
|
||||
NoRecurseCallback( ifc_playlistdirectorycallback *_callback ) : callback( _callback ) {}
|
||||
bool ShouldRecurse( const wchar_t *path ) { return false; }
|
||||
bool ShouldLoad( const wchar_t *filename ) { return callback->ShouldLoad( filename ); }
|
||||
|
||||
ifc_playlistdirectorycallback *callback;
|
||||
|
||||
protected:
|
||||
RECVS_DISPATCH;
|
||||
};
|
||||
|
||||
#define CBCLASS NoRecurseCallback
|
||||
START_DISPATCH;
|
||||
CB( IFC_PLAYLISTDIRECTORYCALLBACK_SHOULDRECURSE, ShouldRecurse )
|
||||
CB( IFC_PLAYLISTDIRECTORYCALLBACK_SHOULDLOAD, ShouldLoad )
|
||||
END_DISPATCH;
|
||||
#undef CBCLASS
|
||||
|
||||
|
||||
static void MakeRelativePathName( const wchar_t *filename, wchar_t *outFile, size_t cch, const wchar_t *path )
|
||||
{
|
||||
wchar_t outPath[ MAX_PATH ] = { 0 };
|
||||
|
||||
int common = PathCommonPrefixW( path, filename, outPath );
|
||||
if ( common && common == wcslen( path ) )
|
||||
{
|
||||
PathAddBackslashW( outPath );
|
||||
const wchar_t *p = filename + wcslen( outPath );
|
||||
lstrcpynW( outFile, p, (int)cch );
|
||||
}
|
||||
else if ( !PathIsUNCW( filename ) && PathIsSameRootW( filename, path ) )
|
||||
{
|
||||
if ( outFile[ 1 ] == ':' )
|
||||
lstrcpynW( outFile, filename + 2, (int)cch );
|
||||
}
|
||||
}
|
||||
|
||||
static void PlayList_makerelative( const wchar_t *base, wchar_t *filename, size_t cch )
|
||||
{
|
||||
MakeRelativePathName( filename, filename, cch, base );
|
||||
}
|
||||
|
||||
|
||||
PlaylistManager playlistManager;
|
||||
|
||||
struct LoaderPair
|
||||
{
|
||||
ifc_playlistloader *loader;
|
||||
svc_playlisthandler *handler;
|
||||
};
|
||||
|
||||
static LoaderPair CreateLoader( const wchar_t *filename )
|
||||
{
|
||||
LoaderPair ret = { 0, 0 };
|
||||
int n = 0;
|
||||
waServiceFactory *sf = 0;
|
||||
|
||||
while ( sf = WASABI_API_SVC->service_enumService( WaSvc::PLAYLISTHANDLER, n++ ) )
|
||||
{
|
||||
svc_playlisthandler *handler = static_cast<svc_playlisthandler *>( sf->getInterface() );
|
||||
if ( handler )
|
||||
{
|
||||
if ( handler->SupportedFilename( filename ) == SVC_PLAYLISTHANDLER_SUCCESS )
|
||||
{
|
||||
ret.loader = handler->CreateLoader( filename );
|
||||
ret.handler = handler;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
sf->releaseInterface( handler );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: sniff file if no one claims it
|
||||
return ret;
|
||||
}
|
||||
|
||||
void DestroyLoader( LoaderPair &loader )
|
||||
{
|
||||
loader.handler->ReleaseLoader( loader.loader );
|
||||
}
|
||||
|
||||
// a simple loader...
|
||||
int PlaylistManager::Load( const wchar_t *filename, ifc_playlistloadercallback *playlist )
|
||||
{
|
||||
LoaderPair loaderPair = CreateLoader( filename );
|
||||
ifc_playlistloader *loader = loaderPair.loader;
|
||||
|
||||
if ( !loader )
|
||||
return PLAYLISTMANAGER_LOAD_NO_LOADER; // failed to find a loader
|
||||
|
||||
// TODO: make our own ifc_playlistloadercallback, so we can handle nested playlists
|
||||
int res = loader->Load( filename, playlist );
|
||||
DestroyLoader( loaderPair );
|
||||
|
||||
if ( res != IFC_PLAYLISTLOADER_SUCCESS ) // TODO: switch on the error code and return a more specific error
|
||||
return PLAYLISTMANAGER_LOAD_LOADER_OPEN_FAILED;
|
||||
|
||||
return PLAYLISTMANAGER_SUCCESS;
|
||||
}
|
||||
|
||||
int PlaylistManager::LoadAs( const wchar_t *filename, const wchar_t *ext, ifc_playlistloadercallback *playlist )
|
||||
{
|
||||
LoaderPair loaderPair = CreateLoader( ext );
|
||||
ifc_playlistloader *loader = loaderPair.loader;
|
||||
|
||||
if ( !loader )
|
||||
return PLAYLISTMANAGER_LOAD_NO_LOADER; // failed to find a loader
|
||||
|
||||
// TODO: make our own ifc_playlistloadercallback, so we can handle nested playlists
|
||||
int res = loader->Load( filename, playlist );
|
||||
DestroyLoader( loaderPair );
|
||||
|
||||
if ( res != IFC_PLAYLISTLOADER_SUCCESS ) // TODO: switch on the error code and return a more specific error
|
||||
return PLAYLISTMANAGER_LOAD_LOADER_OPEN_FAILED;
|
||||
|
||||
return PLAYLISTMANAGER_SUCCESS;
|
||||
}
|
||||
|
||||
int PlaylistManager::LoadFromDialog( const wchar_t *fns, ifc_playlistloadercallback *playlist )
|
||||
{
|
||||
wchar_t buf[ MAX_PATH ] = { 0 };
|
||||
const wchar_t *path = fns;
|
||||
fns += wcslen( fns ) + 1;
|
||||
|
||||
while ( fns && *fns )
|
||||
{
|
||||
if ( *path )
|
||||
PathCombineW( buf, path, fns );
|
||||
else
|
||||
StringCchCopyW( buf, MAX_PATH, fns );
|
||||
|
||||
if ( Load( buf, playlist ) != PLAYLISTMANAGER_SUCCESS )
|
||||
{
|
||||
if ( playlist->OnFile( buf, 0, -1, 0 ) != ifc_playlistloadercallback::LOAD_CONTINUE )
|
||||
return PLAYLIST_SUCCESS;
|
||||
}
|
||||
|
||||
fns += wcslen( fns ) + 1;
|
||||
}
|
||||
return PLAYLIST_SUCCESS;
|
||||
}
|
||||
|
||||
int PlaylistManager::LoadFromANSIDialog( const char *fns, ifc_playlistloadercallback *playlist )
|
||||
{
|
||||
char buf[ MAX_PATH ] = { 0 };
|
||||
const char *path = fns;
|
||||
fns += lstrlenA( fns ) + 1;
|
||||
|
||||
while ( fns && *fns )
|
||||
{
|
||||
if ( *path )
|
||||
PathCombineA( buf, path, fns );
|
||||
else
|
||||
lstrcpynA( buf, fns, MAX_PATH );
|
||||
|
||||
AutoWide wideFn( buf );
|
||||
if ( Load( wideFn, playlist ) != PLAYLISTMANAGER_SUCCESS )
|
||||
{
|
||||
if ( playlist->OnFile( wideFn, 0, -1, 0 ) != ifc_playlistloadercallback::LOAD_CONTINUE )
|
||||
return PLAYLIST_SUCCESS;
|
||||
}
|
||||
|
||||
fns += lstrlenA( fns ) + 1;
|
||||
}
|
||||
return PLAYLIST_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
int PlaylistManager::Save( const wchar_t *filename, ifc_playlist *playlist )
|
||||
{
|
||||
const wchar_t *ext = PathFindExtensionW( filename );
|
||||
PlaylistWriter *writer = 0;
|
||||
|
||||
if ( !lstrcmpiW( ext, L".M3U" ) )
|
||||
writer = new M3UWriter;
|
||||
else if ( !lstrcmpiW( ext, L".M3U8" ) )
|
||||
writer = new M3U8Writer;
|
||||
else if ( !lstrcmpiW( ext, L".PLS" ) )
|
||||
writer = new PLSWriter;
|
||||
else if ( !lstrcmpiW( ext, L".B4S" ) )
|
||||
writer = new B4SWriter;
|
||||
else
|
||||
return PLAYLISTMANAGER_FAILED;
|
||||
|
||||
wchar_t base[ MAX_PATH ] = { 0 };
|
||||
StringCchCopyW( base, MAX_PATH, filename );
|
||||
PathRemoveFileSpecW( base );
|
||||
PathRemoveBackslashW( base );
|
||||
|
||||
if ( !writer->Open( filename ) )
|
||||
{
|
||||
delete writer;
|
||||
|
||||
return PLAYLISTMANAGER_FAILED;
|
||||
}
|
||||
|
||||
size_t numItems = playlist->GetNumItems();
|
||||
wchar_t itemname[ FILENAME_SIZE ] = { 0 };
|
||||
wchar_t title[ FILETITLE_SIZE ] = { 0 };
|
||||
wchar_t cloud_info[ 512 ] = { 0 };
|
||||
int length = 0;
|
||||
|
||||
wchar_t l_tvg_id[ 10 ] = { 0 };
|
||||
wchar_t l_tvg_name[ FILETITLE_SIZE ] = { 0 };
|
||||
wchar_t l_tvg_logo[ 512 ] = { 0 };
|
||||
wchar_t l_group_title[ 64 ] = { 0 };
|
||||
|
||||
wchar_t l_ext[ 10 ] = { 0 };
|
||||
|
||||
wa::strings::wa_string l_extented_infos_line( "" );
|
||||
|
||||
for ( size_t i = 0; i != numItems; i++ )
|
||||
{
|
||||
if ( playlist->GetItem( i, itemname, FILENAME_SIZE ) )
|
||||
{
|
||||
//PlayList_makerelative( base, itemname, FILENAME_SIZE );
|
||||
|
||||
// this is used to preserve 'cloud' specific data in playlists
|
||||
// and should only get a response from a cloud-based ml_playlist
|
||||
if ( playlist->GetItemExtendedInfo( i, L"cloud", cloud_info, 512 ) )
|
||||
{
|
||||
writer->Write( cloud_info );
|
||||
}
|
||||
|
||||
|
||||
l_extented_infos_line.clear();
|
||||
|
||||
if ( playlist->GetItemExtendedInfo( i, L"tvg-name", l_tvg_name, FILETITLE_SIZE ) )
|
||||
{
|
||||
playlist->GetItemExtendedInfo( i, L"tvg-id", l_tvg_id, 10 );
|
||||
playlist->GetItemExtendedInfo( i, L"tvg-logo", l_tvg_logo, 512 );
|
||||
playlist->GetItemExtendedInfo( i, L"group-title", l_group_title, 64 );
|
||||
|
||||
l_extented_infos_line = L"tvg-id";
|
||||
l_extented_infos_line.append( L"=\"" );
|
||||
l_extented_infos_line.append( l_tvg_id );
|
||||
l_extented_infos_line.append( L"\" " );
|
||||
|
||||
l_extented_infos_line.append( L"tvg-name" );
|
||||
l_extented_infos_line.append( L"=\"" );
|
||||
l_extented_infos_line.append( l_tvg_name );
|
||||
l_extented_infos_line.append( L"\" " );
|
||||
|
||||
l_extented_infos_line.append( L"tvg-logo" );
|
||||
l_extented_infos_line.append( L"=\"" );
|
||||
l_extented_infos_line.append( l_tvg_logo );
|
||||
l_extented_infos_line.append( L"\" " );
|
||||
|
||||
l_extented_infos_line.append( L"group-title" );
|
||||
l_extented_infos_line.append( L"=\"" );
|
||||
l_extented_infos_line.append( l_group_title );
|
||||
l_extented_infos_line.append( L"\" " );
|
||||
}
|
||||
|
||||
wa::strings::wa_string l_item_name( itemname );
|
||||
|
||||
if ( l_item_name.contains( "://" ) && playlist->GetItemExtendedInfo(i, L"ext", l_ext, 10) )
|
||||
{
|
||||
l_extented_infos_line = L"ext";
|
||||
l_extented_infos_line.append( L"=\"" );
|
||||
l_extented_infos_line.append( l_ext );
|
||||
l_extented_infos_line.append( L"\"" );
|
||||
}
|
||||
|
||||
if ( playlist->GetItemTitle( i, title, FILETITLE_SIZE ) )
|
||||
{
|
||||
length = playlist->GetItemLengthMilliseconds( i );
|
||||
|
||||
if ( l_extented_infos_line.empty() )
|
||||
writer->Write( itemname, title, length / 1000 );
|
||||
else
|
||||
writer->Write( itemname, title, l_extented_infos_line.GetW().c_str(), length / 1000);
|
||||
}
|
||||
else
|
||||
writer->Write( itemname );
|
||||
}
|
||||
}
|
||||
|
||||
writer->Close();
|
||||
delete writer;
|
||||
|
||||
return PLAYLISTMANAGER_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
size_t PlaylistManager::Copy( const wchar_t *destFn, const wchar_t *srcFn )
|
||||
{
|
||||
Playlist copy;
|
||||
|
||||
Load( srcFn, © );
|
||||
Save( destFn, © );
|
||||
|
||||
return copy.GetNumItems();
|
||||
}
|
||||
|
||||
|
||||
size_t PlaylistManager::CountItems( const wchar_t *filename )
|
||||
{
|
||||
LoaderPair loaderPair = CreateLoader( filename );
|
||||
ifc_playlistloader *loader = loaderPair.loader;
|
||||
|
||||
if ( !loader )
|
||||
return 0;
|
||||
|
||||
PlaylistCounter counter;
|
||||
loader->Load( filename, &counter );
|
||||
|
||||
DestroyLoader( loaderPair );
|
||||
return counter.count;
|
||||
}
|
||||
|
||||
|
||||
int PlaylistManager::GetLengthMilliseconds( const wchar_t *filename )
|
||||
{
|
||||
LoaderPair loaderPair = CreateLoader( filename );
|
||||
ifc_playlistloader *loader = loaderPair.loader;
|
||||
|
||||
if ( !loader )
|
||||
return 0;
|
||||
|
||||
PlaylistCounter counter;
|
||||
loader->Load( filename, &counter );
|
||||
DestroyLoader( loaderPair );
|
||||
return (int)counter.length;
|
||||
}
|
||||
|
||||
uint64_t PlaylistManager::GetLongLengthMilliseconds( const wchar_t *filename )
|
||||
{
|
||||
LoaderPair loaderPair = CreateLoader( filename );
|
||||
ifc_playlistloader *loader = loaderPair.loader;
|
||||
|
||||
if ( !loader )
|
||||
return 0;
|
||||
|
||||
PlaylistCounter counter;
|
||||
loader->Load( filename, &counter );
|
||||
DestroyLoader( loaderPair );
|
||||
return counter.length;
|
||||
}
|
||||
|
||||
|
||||
void PlaylistManager::Randomize( ifc_playlist *playlist )
|
||||
{
|
||||
if ( playlist->Randomize( warand ) == PLAYLIST_UNIMPLEMENTED )
|
||||
{
|
||||
// TODO: do it the hard way
|
||||
}
|
||||
}
|
||||
|
||||
void PlaylistManager::Reverse( ifc_playlist *playlist )
|
||||
{
|
||||
if ( playlist->Reverse() == PLAYLIST_UNIMPLEMENTED )
|
||||
{
|
||||
// TODO: do it the hard way
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PlaylistManager::LoadDirectory( const wchar_t *directory, ifc_playlistloadercallback *callback, ifc_playlistdirectorycallback *dirCallback )
|
||||
{
|
||||
WIN32_FIND_DATAW found = { 0 };
|
||||
wchar_t filespec[ MAX_PATH ] = { 0 };
|
||||
PathCombineW( filespec, directory, L"*.*" );
|
||||
|
||||
HANDLE i = FindFirstFileW( filespec, &found );
|
||||
if ( i != INVALID_HANDLE_VALUE )
|
||||
{
|
||||
do
|
||||
{
|
||||
// if it's another folder, then we might want to recurse into it
|
||||
if ( ( found.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) // if it's a directory
|
||||
&& wcscmp( found.cFileName, L"." ) && wcscmp( found.cFileName, L".." ) // but not . or ..
|
||||
&& ( !dirCallback || dirCallback->ShouldRecurse( found.cFileName ) ) ) // and we're allowed to recurse
|
||||
{
|
||||
if ( PathCombineW( filespec, directory, found.cFileName ) )
|
||||
{
|
||||
LoadDirectory( filespec, callback, dirCallback );
|
||||
}
|
||||
}
|
||||
|
||||
if ( !( found.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) )
|
||||
{
|
||||
const wchar_t *ext = PathFindExtensionW( found.cFileName );
|
||||
if ( ext[ 0 ] )
|
||||
{
|
||||
if ( !_wcsicmp( ext, L".lnk" ) )
|
||||
{
|
||||
wchar_t thisf[ MAX_PATH ] = { 0 };
|
||||
wchar_t temp2[ MAX_PATH ] = { 0 };
|
||||
PathCombineW( temp2, directory, found.cFileName );
|
||||
if ( ResolveShortCut( NULL, temp2, thisf ) && GetLongPathNameW( thisf, temp2, MAX_PATH ) && lstrcmpiW( temp2, directory ) )
|
||||
{
|
||||
WIN32_FIND_DATAW d2 = { 0 };
|
||||
if ( IsUrl( temp2 ) && ( !dirCallback || dirCallback->ShouldLoad( temp2 ) ) )
|
||||
{
|
||||
if ( callback->OnFile( temp2, 0, -1, 0 ) != ifc_playlistloadercallback::LOAD_CONTINUE )
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
HANDLE h2 = FindFirstFileW( temp2, &d2 );
|
||||
if ( h2 != INVALID_HANDLE_VALUE )
|
||||
{
|
||||
if ( !( d2.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) )
|
||||
{
|
||||
if ( !dirCallback || dirCallback->ShouldLoad( temp2 ) )
|
||||
{
|
||||
if ( callback->OnFile( temp2, 0, -1, 0 ) != ifc_playlistloadercallback::LOAD_CONTINUE )
|
||||
{
|
||||
FindClose( h2 );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// recursively load a shortcut w/o fear of infinite recursion
|
||||
NoRecurseCallback noRecurse( dirCallback );
|
||||
LoadDirectory( temp2, callback, &noRecurse );
|
||||
}
|
||||
FindClose( h2 );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else // !shortcut
|
||||
{
|
||||
|
||||
if ( PathCombineW( filespec, directory, found.cFileName ) &&
|
||||
( !dirCallback || dirCallback->ShouldLoad( filespec ) ) )
|
||||
{
|
||||
if ( callback->OnFile( filespec, 0, -1, 0 ) != ifc_playlistloadercallback::LOAD_CONTINUE )
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} while ( FindNextFileW( i, &found ) );
|
||||
FindClose( i );
|
||||
}
|
||||
}
|
||||
|
||||
bool PlaylistManager::CanLoad( const wchar_t *filename )
|
||||
{
|
||||
int n = 0;
|
||||
waServiceFactory *sf = 0;
|
||||
while ( sf = WASABI_API_SVC->service_enumService( WaSvc::PLAYLISTHANDLER, n++ ) )
|
||||
{
|
||||
svc_playlisthandler *handler = static_cast<svc_playlisthandler *>( sf->getInterface() );
|
||||
if ( handler )
|
||||
{
|
||||
if ( handler->SupportedFilename( filename ) == SVC_PLAYLISTHANDLER_SUCCESS )
|
||||
{
|
||||
sf->releaseInterface( handler );
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
sf->releaseInterface( handler );
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void PlaylistManager::GetExtensionList( wchar_t *extensionList, size_t extensionListCch )
|
||||
{
|
||||
extensionList[ 0 ] = 0;
|
||||
|
||||
bool first = true;
|
||||
|
||||
int n = 0, extListCch = (int)extensionListCch;
|
||||
wchar_t *extList = extensionList;
|
||||
waServiceFactory *sf = 0;
|
||||
while ( sf = WASABI_API_SVC->service_enumService( WaSvc::PLAYLISTHANDLER, n++ ) )
|
||||
{
|
||||
svc_playlisthandler *handler = static_cast<svc_playlisthandler *>( sf->getInterface() );
|
||||
if ( handler )
|
||||
{
|
||||
const wchar_t *ext = 0;
|
||||
int k = 0;
|
||||
while ( ext = handler->EnumerateExtensions( k++ ) )
|
||||
{
|
||||
if ( first )
|
||||
StringCchCatExW( extensionList, extensionListCch, L"*.", &extensionList, &extensionListCch, 0 );
|
||||
else
|
||||
StringCchCatExW( extensionList, extensionListCch, L";*.", &extensionList, &extensionListCch, 0 );
|
||||
|
||||
first = false;
|
||||
|
||||
StringCchCatExW( extensionList, extensionListCch, ext, &extensionList, &extensionListCch, 0 );
|
||||
}
|
||||
sf->releaseInterface( handler );
|
||||
}
|
||||
}
|
||||
CharUpperBuffW( extList, extListCch );
|
||||
}
|
||||
|
||||
void PlaylistManager::GetFilterList( wchar_t *extensionList, size_t extensionListCch )
|
||||
{
|
||||
extensionListCch--; // this needs to be DOUBLE null terminated, so we'll make sure there's room
|
||||
|
||||
StringCchCopyExW( extensionList, extensionListCch, WASABI_API_LNGSTRINGW( IDS_ALL_PLAYLIST_TYPES ), &extensionList, &extensionListCch, 0 );
|
||||
extensionListCch--;
|
||||
extensionList++;
|
||||
|
||||
GetExtensionList( extensionList, extensionListCch );
|
||||
|
||||
extensionListCch -= ( wcslen( extensionList ) + 1 );
|
||||
extensionList += wcslen( extensionList ) + 1;
|
||||
|
||||
int n = 0;
|
||||
waServiceFactory *sf = 0;
|
||||
while ( sf = WASABI_API_SVC->service_enumService( WaSvc::PLAYLISTHANDLER, n++ ) )
|
||||
{
|
||||
svc_playlisthandler *handler = static_cast<svc_playlisthandler *>( sf->getInterface() );
|
||||
if ( handler )
|
||||
{
|
||||
const wchar_t *name = handler->GetName();
|
||||
if ( !name )
|
||||
name = WASABI_API_LNGSTRINGW( IDS_PLAYLIST );
|
||||
|
||||
StringCchCopyExW( extensionList, extensionListCch, name, &extensionList, &extensionListCch, 0 );
|
||||
extensionList++;
|
||||
extensionListCch--;
|
||||
|
||||
bool first = true;
|
||||
const wchar_t *ext = 0;
|
||||
int k = 0;
|
||||
while ( ext = handler->EnumerateExtensions( k++ ) )
|
||||
{
|
||||
if ( first )
|
||||
StringCchCopyExW( extensionList, extensionListCch, L"*.", &extensionList, &extensionListCch, 0 );
|
||||
else
|
||||
StringCchCatExW( extensionList, extensionListCch, L";*.", &extensionList, &extensionListCch, 0 );
|
||||
|
||||
first = false;
|
||||
|
||||
StringCchCatExW( extensionList, extensionListCch, ext, &extensionList, &extensionListCch, 0 );
|
||||
}
|
||||
extensionList++;
|
||||
extensionListCch--;
|
||||
|
||||
sf->releaseInterface( handler );
|
||||
}
|
||||
}
|
||||
|
||||
extensionList[ 0 ] = 0; // ok because we reserved the room for it above
|
||||
}
|
||||
|
||||
const wchar_t *PlaylistManager::EnumExtensions( size_t num )
|
||||
{
|
||||
int n = 0;
|
||||
int total = 0;
|
||||
waServiceFactory *sf = 0;
|
||||
while ( sf = WASABI_API_SVC->service_enumService( WaSvc::PLAYLISTHANDLER, n++ ) )
|
||||
{
|
||||
svc_playlisthandler *handler = static_cast<svc_playlisthandler *>( sf->getInterface() );
|
||||
if ( handler )
|
||||
{
|
||||
const wchar_t *ext = 0;
|
||||
int k = 0;
|
||||
while ( ext = handler->EnumerateExtensions( k++ ) )
|
||||
{
|
||||
if ( total++ == num )
|
||||
return ext;
|
||||
}
|
||||
|
||||
sf->releaseInterface( handler );
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#define CBCLASS PlaylistManager
|
||||
START_DISPATCH;
|
||||
CB( API_PLAYLISTMANAGER_LOAD, Load )
|
||||
CB( API_PLAYLISTMANAGER_LOADAS, LoadAs )
|
||||
CB( API_PLAYLISTMANAGER_LOADNULLDELIMITED, LoadFromDialog )
|
||||
CB( API_PLAYLISTMANAGER_LOADNULLDELIMITED_ANSI, LoadFromANSIDialog )
|
||||
CB( API_PLAYLISTMANAGER_SAVE, Save )
|
||||
CB( API_PLAYLISTMANAGER_COPY, Copy )
|
||||
CB( API_PLAYLISTMANAGER_COUNT, CountItems )
|
||||
CB( API_PLAYLISTMANAGER_GETLENGTH, GetLengthMilliseconds )
|
||||
CB( API_PLAYLISTMANAGER_GETLONGLENGTH, GetLongLengthMilliseconds )
|
||||
VCB( API_PLAYLISTMANAGER_RANDOMIZE, Randomize )
|
||||
VCB( API_PLAYLISTMANAGER_REVERSE, Reverse )
|
||||
VCB( API_PLAYLISTMANAGER_LOADDIRECTORY, LoadDirectory )
|
||||
CB( API_PLAYLISTMANAGER_CANLOAD, CanLoad )
|
||||
VCB( API_PLAYLISTMANAGER_GETEXTENSIONLIST, GetExtensionList )
|
||||
VCB( API_PLAYLISTMANAGER_GETFILTERLIST, GetFilterList )
|
||||
CB( API_PLAYLISTMANAGER_ENUMEXTENSION, EnumExtensions )
|
||||
END_DISPATCH;
|
||||
#undef CBCLASS
|
42
Src/playlist/PlaylistManager.h
Normal file
42
Src/playlist/PlaylistManager.h
Normal file
@ -0,0 +1,42 @@
|
||||
#ifndef NULLSOFT_ML_PLAYLISTS_PLAYLIST_MANAGER_H
|
||||
#define NULLSOFT_ML_PLAYLISTS_PLAYLIST_MANAGER_H
|
||||
|
||||
#include "api_playlistmanager.h"
|
||||
|
||||
class PlaylistManager : public api_playlistmanager
|
||||
{
|
||||
public:
|
||||
int Load( const wchar_t *filename, ifc_playlistloadercallback *playlist );
|
||||
int LoadAs( const wchar_t *filename, const wchar_t *ext, ifc_playlistloadercallback *playlist );
|
||||
int LoadFromDialog( const wchar_t *fns, ifc_playlistloadercallback *playlist );
|
||||
int LoadFromANSIDialog( const char *fns, ifc_playlistloadercallback *playlist );
|
||||
|
||||
int Save( const wchar_t *filename, ifc_playlist *playlist );
|
||||
|
||||
size_t Copy( const wchar_t *destFn, const wchar_t *srcFn ); // returns number of items copied
|
||||
|
||||
size_t CountItems( const wchar_t *filename );
|
||||
|
||||
int GetLengthMilliseconds( const wchar_t *filename );
|
||||
uint64_t GetLongLengthMilliseconds( const wchar_t *filename );
|
||||
|
||||
void Randomize( ifc_playlist *playlist );
|
||||
void Reverse( ifc_playlist *playlist );
|
||||
|
||||
void LoadDirectory( const wchar_t *directory, ifc_playlistloadercallback *callback, ifc_playlistdirectorycallback *dirCallback );
|
||||
|
||||
bool CanLoad( const wchar_t *filename );
|
||||
|
||||
void GetExtensionList( wchar_t *extensionList, size_t extensionListCch );
|
||||
void GetFilterList( wchar_t *extensionList, size_t extensionListCch );
|
||||
|
||||
const wchar_t *EnumExtensions( size_t num );
|
||||
|
||||
protected:
|
||||
RECVS_DISPATCH;
|
||||
|
||||
};
|
||||
|
||||
extern PlaylistManager playlistManager;
|
||||
|
||||
#endif
|
17
Src/playlist/PlaylistWriter.h
Normal file
17
Src/playlist/PlaylistWriter.h
Normal file
@ -0,0 +1,17 @@
|
||||
#ifndef NULLSOFT_PLAYLIST_PLAYLISTWRITER_H
|
||||
#define NULLSOFT_PLAYLIST_PLAYLISTWRITER_H
|
||||
|
||||
// probably not the final interface, so we won't dispatch it yet
|
||||
|
||||
class PlaylistWriter
|
||||
{
|
||||
public:
|
||||
virtual ~PlaylistWriter() {}
|
||||
virtual int Open( const wchar_t *filename ) = 0;
|
||||
virtual void Write( const wchar_t *filename ) = 0;
|
||||
virtual void Write( const wchar_t *filename, const wchar_t *title, int length ) = 0;
|
||||
virtual void Write( const wchar_t *filename, const wchar_t *title, const wchar_t *p_extended_infos, int length ) = 0;
|
||||
virtual void Close() = 0;
|
||||
};
|
||||
|
||||
#endif
|
746
Src/playlist/Playlists.cpp
Normal file
746
Src/playlist/Playlists.cpp
Normal file
@ -0,0 +1,746 @@
|
||||
#include <algorithm>
|
||||
#include "playlists.h"
|
||||
#include "api__playlist.h"
|
||||
#include "PlaylistsXML.h"
|
||||
#include <shlwapi.h>
|
||||
#include <limits.h>
|
||||
#include <strsafe.h>
|
||||
#pragma comment(lib, "Rpcrt4")
|
||||
using namespace Nullsoft::Utility;
|
||||
|
||||
/*
|
||||
benski> Notes to maintainers
|
||||
be sure to call DelayLoad() before doing anything.
|
||||
This is mainly done because the XML parsing service isn't guaranteed to be registered before this service.
|
||||
It also improves load time.
|
||||
*/
|
||||
|
||||
/* --------------------------------------------- */
|
||||
|
||||
PlaylistInfo::PlaylistInfo()
|
||||
{
|
||||
filename[0] = 0;
|
||||
title[0] = 0;
|
||||
length = 0;
|
||||
numItems = 0;
|
||||
iTunesID = 0;
|
||||
cloud = 0;
|
||||
|
||||
UuidCreate(&guid);
|
||||
}
|
||||
|
||||
PlaylistInfo::PlaylistInfo( const wchar_t *_filename, const wchar_t *_title, GUID playlist_guid )
|
||||
{
|
||||
StringCbCopyW( filename, sizeof( filename ), _filename );
|
||||
if ( _title )
|
||||
StringCbCopyW( title, sizeof( title ), _title );
|
||||
else
|
||||
title[ 0 ] = 0;
|
||||
|
||||
length = 0;
|
||||
numItems = 0;
|
||||
|
||||
if ( playlist_guid == INVALID_GUID )
|
||||
UuidCreate( &guid );
|
||||
else
|
||||
guid = playlist_guid;
|
||||
|
||||
iTunesID = 0;
|
||||
cloud = 0;
|
||||
}
|
||||
|
||||
PlaylistInfo::PlaylistInfo( const PlaylistInfo © )
|
||||
{
|
||||
StringCbCopyW( filename, sizeof( filename ), copy.filename );
|
||||
StringCbCopyW( title, sizeof( title ), copy.title );
|
||||
|
||||
length = copy.length;
|
||||
numItems = copy.numItems;
|
||||
guid = copy.guid;
|
||||
iTunesID = copy.iTunesID;
|
||||
cloud = copy.cloud;
|
||||
}
|
||||
|
||||
/* --------------------------------------------- */
|
||||
Playlists::Playlists()
|
||||
{
|
||||
iterator = 0;
|
||||
triedLoaded = false;
|
||||
loaded = false;
|
||||
dirty = false;
|
||||
}
|
||||
|
||||
bool Playlists::DelayLoad()
|
||||
{
|
||||
if ( triedLoaded )
|
||||
return loaded;
|
||||
|
||||
PlaylistsXML loader( this );
|
||||
|
||||
const wchar_t *g_path = WASABI_API_APP->path_getUserSettingsPath();
|
||||
wchar_t playlistsFilename[ MAX_PATH ] = { 0 };
|
||||
wchar_t oldPlaylistsFilename[ MAX_PATH ] = { 0 };
|
||||
wchar_t newPlaylistsFolder[ MAX_PATH ] = { 0 };
|
||||
|
||||
PathCombineW( playlistsFilename, g_path, L"plugins" );
|
||||
PathAppendW( playlistsFilename, L"ml" );
|
||||
PathAppendW( playlistsFilename, L"playlists" );
|
||||
CreateDirectoryW( playlistsFilename, NULL );
|
||||
lstrcpynW( newPlaylistsFolder, playlistsFilename, MAX_PATH );
|
||||
PathAppendW( playlistsFilename, L"playlists.xml" );
|
||||
|
||||
PathCombineW( oldPlaylistsFilename, g_path, L"plugins" );
|
||||
PathAppendW( oldPlaylistsFilename, L"ml" );
|
||||
PathAppendW( oldPlaylistsFilename, L"playlists.xml" );
|
||||
|
||||
bool migrated = false;
|
||||
if ( PathFileExistsW( oldPlaylistsFilename ) && !PathFileExistsW( playlistsFilename ) )
|
||||
{
|
||||
if ( MoveFileW( oldPlaylistsFilename, playlistsFilename ) )
|
||||
{
|
||||
migrated = true;
|
||||
PathRemoveFileSpecW( oldPlaylistsFilename );
|
||||
}
|
||||
}
|
||||
|
||||
switch ( loader.LoadFile( playlistsFilename ) )
|
||||
{
|
||||
case PLAYLISTSXML_SUCCESS:
|
||||
loaded = true;
|
||||
triedLoaded = true;
|
||||
if ( AGAVE_API_STATS )
|
||||
AGAVE_API_STATS->SetStat( api_stats::PLAYLIST_COUNT, (int)playlists.size() );
|
||||
|
||||
if ( playlists.size() && migrated )
|
||||
{
|
||||
for ( PlaylistInfo l_playlist : playlists )
|
||||
{
|
||||
wchar_t path[ MAX_PATH ] = { 0 }, file[ MAX_PATH ] = { 0 };
|
||||
lstrcpynW( file, l_playlist.filename, MAX_PATH );
|
||||
PathStripPathW( file );
|
||||
PathCombineW( path, oldPlaylistsFilename, file );
|
||||
if ( PathFileExistsW( path ) )
|
||||
{
|
||||
wchar_t new_path[ MAX_PATH ] = { 0 };
|
||||
PathCombineW( new_path, newPlaylistsFolder, file );
|
||||
MoveFileW( path, new_path );
|
||||
}
|
||||
}
|
||||
dirty = true;
|
||||
Flush();
|
||||
}
|
||||
|
||||
break;
|
||||
case PLAYLISTSXML_NO_PARSER:
|
||||
// if there's XML parser, we'll try again on the off-chance it eventually gets loaded (we might still be in the midst of loading the w5s/wac components)
|
||||
break;
|
||||
default:
|
||||
loaded = true;
|
||||
triedLoaded = true;
|
||||
break;
|
||||
}
|
||||
|
||||
return loaded;
|
||||
}
|
||||
|
||||
void Playlists::Lock()
|
||||
{
|
||||
playlistsGuard.Lock();
|
||||
}
|
||||
|
||||
void Playlists::Unlock()
|
||||
{
|
||||
playlistsGuard.Unlock();
|
||||
}
|
||||
|
||||
size_t Playlists::GetIterator()
|
||||
{
|
||||
return iterator;
|
||||
}
|
||||
|
||||
static void WriteEscaped( FILE *fp, const wchar_t *str )
|
||||
{
|
||||
// TODO: for speed optimization,
|
||||
// we should wait until we hit a special character
|
||||
// and write out everything else so before it,
|
||||
// like how ASX loader does it
|
||||
while ( str && *str )
|
||||
{
|
||||
switch ( *str )
|
||||
{
|
||||
case L'&':
|
||||
fputws( L"&", fp );
|
||||
break;
|
||||
case L'>':
|
||||
fputws( L">", fp );
|
||||
break;
|
||||
case L'<':
|
||||
fputws( L"<", fp );
|
||||
break;
|
||||
case L'\'':
|
||||
fputws( L"'", fp );
|
||||
break;
|
||||
case L'\"':
|
||||
fputws( L""", fp );
|
||||
break;
|
||||
default:
|
||||
fputwc( *str, fp );
|
||||
break;
|
||||
}
|
||||
|
||||
// write out the whole UTF-16 character
|
||||
wchar_t *next = CharNextW( str );
|
||||
while ( ++str != next )
|
||||
fputwc( *str, fp );
|
||||
}
|
||||
}
|
||||
|
||||
bool TitleSortAsc( PlaylistInfo &item1, PlaylistInfo &item2 )
|
||||
{
|
||||
int comp = CompareStringW( LOCALE_USER_DEFAULT, NORM_IGNORECASE | NORM_IGNOREWIDTH, item1.title, -1, item2.title, -1 );
|
||||
|
||||
return comp == CSTR_LESS_THAN;
|
||||
}
|
||||
|
||||
bool TitleSortDesc( PlaylistInfo &item1, PlaylistInfo &item2 )
|
||||
{
|
||||
int comp = CompareStringW( LOCALE_USER_DEFAULT, NORM_IGNORECASE | NORM_IGNOREWIDTH, item1.title, -1, item2.title, -1 );
|
||||
|
||||
return comp == CSTR_GREATER_THAN;
|
||||
}
|
||||
|
||||
bool NumberOfEntrySortAsc( PlaylistInfo &item1, PlaylistInfo &item2 )
|
||||
{
|
||||
return !!( item1.numItems < item2.numItems );
|
||||
}
|
||||
|
||||
bool NumberOfEntrySortDesc( PlaylistInfo &item1, PlaylistInfo &item2 )
|
||||
{
|
||||
return !!( item1.numItems > item2.numItems );
|
||||
}
|
||||
|
||||
int Playlists::Sort( size_t sort_type )
|
||||
{
|
||||
if ( !DelayLoad() )
|
||||
return 0;
|
||||
|
||||
int sorted = 1;
|
||||
|
||||
switch ( sort_type )
|
||||
{
|
||||
case SORT_TITLE_ASCENDING:
|
||||
std::sort( playlists.begin(), playlists.end(), TitleSortAsc );
|
||||
break;
|
||||
case SORT_TITLE_DESCENDING:
|
||||
std::sort( playlists.begin(), playlists.end(), TitleSortDesc );
|
||||
break;
|
||||
case SORT_NUMBER_ASCENDING:
|
||||
std::sort( playlists.begin(), playlists.end(), NumberOfEntrySortAsc );
|
||||
break;
|
||||
case SORT_NUMBER_DESCENDING:
|
||||
std::sort( playlists.begin(), playlists.end(), NumberOfEntrySortDesc );
|
||||
break;
|
||||
default:
|
||||
sorted = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
dirty = true;
|
||||
|
||||
if ( sorted )
|
||||
Flush();
|
||||
|
||||
return sorted;
|
||||
}
|
||||
|
||||
void Playlists::Flush()
|
||||
{
|
||||
AutoLockT<Playlists> lock( this );
|
||||
|
||||
if ( !triedLoaded && !loaded ) // if the playlists.xml file was never even attempted to be loaded, don't overwrite
|
||||
return;
|
||||
|
||||
if ( !dirty ) // if we've not seen any changes then no need to re-save
|
||||
return;
|
||||
|
||||
const wchar_t *g_path = WASABI_API_APP->path_getUserSettingsPath();
|
||||
|
||||
wchar_t rootPath[ MAX_PATH ] = { 0 };
|
||||
wchar_t playlistsBackupFilename[ MAX_PATH ] = { 0 };
|
||||
wchar_t playlistsDestination[ MAX_PATH ] = { 0 };
|
||||
|
||||
PathCombineW( rootPath, g_path, L"plugins" );
|
||||
CreateDirectoryW( rootPath, NULL );
|
||||
PathAppendW( rootPath, L"ml" );
|
||||
CreateDirectoryW( rootPath, NULL );
|
||||
PathAppendW( rootPath, L"playlists" );
|
||||
CreateDirectoryW( rootPath, NULL );
|
||||
|
||||
int g_path_size = wcslen( rootPath );
|
||||
PathCombineW( playlistsBackupFilename, rootPath, L"playlists.xml.backup" );
|
||||
PathCombineW( playlistsDestination, rootPath, L"playlists.xml" );
|
||||
|
||||
CopyFileW( playlistsDestination, playlistsBackupFilename, FALSE );
|
||||
|
||||
FILE *fp = _wfopen( playlistsDestination, L"wb" );
|
||||
if ( !fp ) // bah
|
||||
{
|
||||
dirty = false;
|
||||
return;
|
||||
}
|
||||
|
||||
fseek( fp, 0, SEEK_SET );
|
||||
fputwc( L'\xFEFF', fp );
|
||||
fwprintf( fp, L"<?xml version=\"1.0\" encoding=\"UTF-16\"?>" );
|
||||
fwprintf( fp, L"<playlists playlists=\"%u\">", (unsigned int)playlists.size() );
|
||||
|
||||
if ( AGAVE_API_STATS )
|
||||
AGAVE_API_STATS->SetStat( api_stats::PLAYLIST_COUNT, (int)playlists.size() );
|
||||
|
||||
for ( PlaylistInfo &l_play_list_info : playlists )
|
||||
{
|
||||
fputws( L"<playlist filename=\"", fp );
|
||||
const wchar_t *fn = l_play_list_info.filename;
|
||||
|
||||
if ( !_wcsnicmp( rootPath, fn, g_path_size ) )
|
||||
{
|
||||
fn += g_path_size;
|
||||
|
||||
if ( *fn == L'\\' )
|
||||
++fn;
|
||||
}
|
||||
|
||||
WriteEscaped( fp, fn );
|
||||
|
||||
fputws( L"\" title=\"", fp );
|
||||
WriteEscaped( fp, l_play_list_info.title );
|
||||
|
||||
GUID guid = l_play_list_info.guid;
|
||||
|
||||
fwprintf( fp, L"\" id=\"{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}\"",
|
||||
(int)guid.Data1, (int)guid.Data2, (int)guid.Data3,
|
||||
(int)guid.Data4[ 0 ], (int)guid.Data4[ 1 ],
|
||||
(int)guid.Data4[ 2 ], (int)guid.Data4[ 3 ],
|
||||
(int)guid.Data4[ 4 ], (int)guid.Data4[ 5 ],
|
||||
(int)guid.Data4[ 6 ], (int)guid.Data4[ 7 ] );
|
||||
|
||||
fwprintf( fp, L" songs=\"%u\" seconds=\"%u\"", l_play_list_info.numItems, l_play_list_info.length );
|
||||
|
||||
if ( l_play_list_info.iTunesID )
|
||||
fwprintf( fp, L" iTunesID=\"%I64u\"", l_play_list_info.iTunesID );
|
||||
|
||||
if ( l_play_list_info.cloud )
|
||||
fwprintf( fp, L" cloud=\"1\"" );
|
||||
|
||||
fwprintf( fp, L"/>" );
|
||||
}
|
||||
|
||||
fwprintf( fp, L"</playlists>" );
|
||||
fclose( fp );
|
||||
dirty = false;
|
||||
}
|
||||
|
||||
size_t Playlists::GetCount()
|
||||
{
|
||||
DelayLoad();
|
||||
|
||||
return playlists.size();
|
||||
}
|
||||
|
||||
const wchar_t *Playlists::GetFilename( size_t index )
|
||||
{
|
||||
if ( !DelayLoad() || index >= playlists.size() )
|
||||
return 0;
|
||||
|
||||
return playlists[ index ].filename;
|
||||
}
|
||||
|
||||
const wchar_t *Playlists::GetName( size_t index )
|
||||
{
|
||||
if ( !DelayLoad() || index >= playlists.size() )
|
||||
return 0;
|
||||
|
||||
return playlists[ index ].title;
|
||||
}
|
||||
|
||||
GUID Playlists::GetGUID( size_t index )
|
||||
{
|
||||
if ( !DelayLoad() || index >= playlists.size() )
|
||||
return INVALID_GUID;
|
||||
|
||||
return playlists[ index ].guid;
|
||||
}
|
||||
|
||||
int Playlists::GetPosition( GUID playlist_guid, size_t *index )
|
||||
{
|
||||
if ( !DelayLoad() )
|
||||
return API_PLAYLISTS_UNABLE_TO_LOAD_PLAYLISTS;
|
||||
|
||||
size_t indexCount = 0;
|
||||
for ( PlaylistInfo &l_play_list_info : playlists )
|
||||
{
|
||||
if ( l_play_list_info.guid == playlist_guid )
|
||||
{
|
||||
*index = indexCount;
|
||||
return API_PLAYLISTS_SUCCESS;
|
||||
}
|
||||
|
||||
++indexCount;
|
||||
}
|
||||
|
||||
return API_PLAYLISTS_FAILURE;
|
||||
}
|
||||
|
||||
template <class val_t>
|
||||
static int GetWithSize( void *data, size_t dataLen, val_t value )
|
||||
{
|
||||
switch ( dataLen )
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
if ( value > _UI8_MAX ) // check for overflow
|
||||
return API_PLAYLISTS_BAD_SIZE;
|
||||
|
||||
*(uint8_t *)data = (uint8_t)value;
|
||||
|
||||
return API_PLAYLISTS_SUCCESS;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
if ( value > _UI16_MAX ) // check for overflow
|
||||
return API_PLAYLISTS_BAD_SIZE;
|
||||
|
||||
*(uint16_t *)data = (uint16_t)value;
|
||||
|
||||
return API_PLAYLISTS_SUCCESS;
|
||||
}
|
||||
case 4:
|
||||
{
|
||||
if ( value > _UI32_MAX )
|
||||
return API_PLAYLISTS_BAD_SIZE;
|
||||
|
||||
*(uint32_t *)data = (uint32_t)value;
|
||||
|
||||
return API_PLAYLISTS_SUCCESS;
|
||||
}
|
||||
case 8:
|
||||
{
|
||||
if ( value > _UI64_MAX )
|
||||
return API_PLAYLISTS_BAD_SIZE;
|
||||
|
||||
*(uint64_t *)data = (uint64_t)value;
|
||||
|
||||
return API_PLAYLISTS_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
return API_PLAYLISTS_BAD_SIZE;
|
||||
}
|
||||
|
||||
template <class val_t>
|
||||
static int SetWithSize( void *data, size_t dataLen, val_t *value )
|
||||
{
|
||||
switch ( dataLen )
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
*value = ( val_t ) * (uint8_t *)data;
|
||||
return API_PLAYLISTS_SUCCESS;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
*value = ( val_t ) * (uint16_t *)data;
|
||||
return API_PLAYLISTS_SUCCESS;
|
||||
}
|
||||
case 4:
|
||||
{
|
||||
*value = ( val_t ) * (uint32_t *)data;
|
||||
return API_PLAYLISTS_SUCCESS;
|
||||
}
|
||||
case 8:
|
||||
{
|
||||
*value = ( val_t ) * (uint64_t *)data;
|
||||
return API_PLAYLISTS_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
return API_PLAYLISTS_BAD_SIZE;
|
||||
}
|
||||
|
||||
int Playlists::GetInfo( size_t index, GUID info, void *data, size_t dataLen )
|
||||
{
|
||||
if ( !DelayLoad() )
|
||||
return API_PLAYLISTS_UNABLE_TO_LOAD_PLAYLISTS;
|
||||
|
||||
if ( index >= playlists.size() )
|
||||
return API_PLAYLISTS_INVALID_INDEX;
|
||||
|
||||
if ( info == api_playlists_itemCount )
|
||||
return GetWithSize( data, dataLen, playlists[ index ].numItems );
|
||||
else if ( info == api_playlists_totalTime )
|
||||
return GetWithSize( data, dataLen, playlists[ index ].length );
|
||||
else if ( info == api_playlists_iTunesID )
|
||||
return GetWithSize( data, dataLen, playlists[ index ].iTunesID );
|
||||
else if ( info == api_playlists_cloud )
|
||||
return GetWithSize( data, dataLen, playlists[ index ].cloud );
|
||||
|
||||
return API_PLAYLISTS_UNKNOWN_INFO_GUID;
|
||||
}
|
||||
|
||||
int Playlists::MoveBefore( size_t index1, size_t index2 )
|
||||
{
|
||||
if ( !DelayLoad() )
|
||||
return API_PLAYLISTS_UNABLE_TO_LOAD_PLAYLISTS;
|
||||
|
||||
if ( index1 >= playlists.size() )
|
||||
return API_PLAYLISTS_INVALID_INDEX;
|
||||
|
||||
PlaylistInfo copy = playlists[ index1 ];
|
||||
if ( index2 >= playlists.size() )
|
||||
{
|
||||
playlists.push_back( copy );
|
||||
playlists.erase(playlists.begin() + index1 );
|
||||
}
|
||||
else
|
||||
{
|
||||
playlists.insert(playlists.begin() + index2, copy );
|
||||
if ( index1 >= index2 )
|
||||
index1++;
|
||||
playlists.erase(playlists.begin() + index1 );
|
||||
}
|
||||
|
||||
dirty = true;
|
||||
++iterator;
|
||||
|
||||
return API_PLAYLISTS_SUCCESS;
|
||||
}
|
||||
|
||||
size_t Playlists::AddPlaylist( const wchar_t *filename, const wchar_t *playlistName, GUID playlist_guid )
|
||||
{
|
||||
if ( !DelayLoad() )
|
||||
return -1;
|
||||
|
||||
AutoLockT<Playlists> lock( this );
|
||||
|
||||
if ( playlist_guid != INVALID_GUID )
|
||||
{
|
||||
for ( size_t index = 0; index < playlists.size(); index++ )
|
||||
{
|
||||
if ( playlists[ index ].guid == playlist_guid )
|
||||
{
|
||||
if ( lstrcmpiW( playlists[ index ].title, playlistName ) )
|
||||
{
|
||||
dirty = true;
|
||||
StringCbCopyW( playlists[ index ].title, sizeof( playlists[ index ].title ), playlistName );
|
||||
WASABI_API_SYSCB->syscb_issueCallback( api_playlists::SYSCALLBACK, api_playlists::PLAYLIST_RENAMED, index, 0 );
|
||||
}
|
||||
|
||||
return -2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
size_t newIndex = AddPlaylist_NoCallback( filename, playlistName, playlist_guid );
|
||||
WASABI_API_SYSCB->syscb_issueCallback( api_playlists::SYSCALLBACK, api_playlists::PLAYLIST_ADDED, newIndex, 0 );
|
||||
|
||||
return newIndex;
|
||||
}
|
||||
|
||||
size_t Playlists::AddCloudPlaylist( const wchar_t *filename, const wchar_t *playlistName, GUID playlist_guid )
|
||||
{
|
||||
if ( !DelayLoad() )
|
||||
return -1;
|
||||
|
||||
AutoLockT<Playlists> lock( this );
|
||||
|
||||
if ( playlist_guid != INVALID_GUID )
|
||||
{
|
||||
for ( size_t index = 0; index < playlists.size(); index++ )
|
||||
{
|
||||
if ( playlists[ index ].guid == playlist_guid )
|
||||
{
|
||||
// we make sure that this playlist has a 'cloud' flag
|
||||
// as without it, our detection of thing isn't ideal.
|
||||
if ( !playlists[ index ].cloud )
|
||||
playlists[ index ].cloud = 1;
|
||||
|
||||
if ( lstrcmpW( playlists[ index ].title, playlistName ) )
|
||||
{
|
||||
dirty = true;
|
||||
StringCbCopyW( playlists[ index ].title, sizeof( playlists[ index ].title ), playlistName );
|
||||
WASABI_API_SYSCB->syscb_issueCallback( api_playlists::SYSCALLBACK, api_playlists::PLAYLIST_RENAMED, index, 0 );
|
||||
}
|
||||
|
||||
return -2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
size_t newIndex = AddPlaylist_NoCallback( filename, playlistName, playlist_guid );
|
||||
int cloud = 1;
|
||||
SetInfo( newIndex, api_playlists_cloud, &cloud, sizeof( cloud ) );
|
||||
WASABI_API_SYSCB->syscb_issueCallback( api_playlists::SYSCALLBACK, api_playlists::PLAYLIST_ADDED, newIndex, 0 );
|
||||
|
||||
return newIndex;
|
||||
}
|
||||
|
||||
size_t Playlists::AddPlaylist_internal( const wchar_t *filename, const wchar_t *playlistName, GUID playlist_guid, size_t numItems, size_t length, uint64_t iTunesID, size_t cloud )
|
||||
{
|
||||
PlaylistInfo newPlaylist( filename, playlistName, playlist_guid );
|
||||
newPlaylist.numItems = (int)numItems;
|
||||
newPlaylist.length = (int)length;
|
||||
newPlaylist.iTunesID = iTunesID;
|
||||
newPlaylist.cloud = (int)cloud;
|
||||
|
||||
playlists.push_back( newPlaylist );
|
||||
size_t newIndex = playlists.size() - 1;
|
||||
|
||||
return newIndex;
|
||||
}
|
||||
|
||||
size_t Playlists::AddPlaylist_NoCallback( const wchar_t *filename, const wchar_t *playlistName, GUID playlist_guid )
|
||||
{
|
||||
AutoLockT<Playlists> lock( this );
|
||||
PlaylistInfo newPlaylist( filename, playlistName, playlist_guid );
|
||||
|
||||
dirty = true;
|
||||
playlists.push_back( newPlaylist );
|
||||
|
||||
++iterator;
|
||||
|
||||
size_t newIndex = playlists.size() - 1;
|
||||
|
||||
return newIndex;
|
||||
}
|
||||
|
||||
int Playlists::SetGUID( size_t index, GUID playlist_guid )
|
||||
{
|
||||
if ( !DelayLoad() )
|
||||
return API_PLAYLISTS_UNABLE_TO_LOAD_PLAYLISTS;
|
||||
|
||||
if ( index >= playlists.size() )
|
||||
return API_PLAYLISTS_INVALID_INDEX;
|
||||
|
||||
dirty = true;
|
||||
playlists[ index ].guid = playlist_guid;
|
||||
|
||||
return API_PLAYLISTS_SUCCESS;
|
||||
}
|
||||
|
||||
int Playlists::RenamePlaylist( size_t index, const wchar_t *name )
|
||||
{
|
||||
if ( !DelayLoad() )
|
||||
return API_PLAYLISTS_UNABLE_TO_LOAD_PLAYLISTS;
|
||||
|
||||
if ( index >= playlists.size() )
|
||||
return API_PLAYLISTS_INVALID_INDEX;
|
||||
|
||||
dirty = true;
|
||||
|
||||
if ( lstrcmpW( playlists[ index ].title, name ) )
|
||||
{
|
||||
StringCbCopyW( playlists[ index ].title, sizeof( playlists[ index ].title ), name );
|
||||
WASABI_API_SYSCB->syscb_issueCallback( api_playlists::SYSCALLBACK, api_playlists::PLAYLIST_RENAMED, index, 0 );
|
||||
}
|
||||
|
||||
return API_PLAYLISTS_SUCCESS;
|
||||
}
|
||||
|
||||
int Playlists::MovePlaylist( size_t index, const wchar_t *filename )
|
||||
{
|
||||
if ( !DelayLoad() )
|
||||
return API_PLAYLISTS_UNABLE_TO_LOAD_PLAYLISTS;
|
||||
|
||||
if ( index >= playlists.size() )
|
||||
return API_PLAYLISTS_INVALID_INDEX;
|
||||
|
||||
dirty = true;
|
||||
StringCbCopyW( playlists[ index ].filename, sizeof( playlists[ index ].filename ), filename );
|
||||
iterator++;
|
||||
|
||||
return API_PLAYLISTS_SUCCESS;
|
||||
}
|
||||
|
||||
int Playlists::SetInfo( size_t index, GUID info, void *data, size_t dataLen )
|
||||
{
|
||||
if ( !DelayLoad() )
|
||||
return API_PLAYLISTS_UNABLE_TO_LOAD_PLAYLISTS;
|
||||
|
||||
if ( index >= playlists.size() )
|
||||
return API_PLAYLISTS_INVALID_INDEX;
|
||||
|
||||
dirty = true;
|
||||
if ( info == api_playlists_itemCount )
|
||||
return SetWithSize( data, dataLen, &playlists[ index ].numItems );
|
||||
else if ( info == api_playlists_totalTime )
|
||||
return SetWithSize( data, dataLen, &playlists[ index ].length );
|
||||
else if ( info == api_playlists_iTunesID )
|
||||
return SetWithSize( data, dataLen, &playlists[ index ].iTunesID );
|
||||
else if ( info == api_playlists_cloud )
|
||||
return SetWithSize( data, dataLen, &playlists[ index ].cloud );
|
||||
|
||||
dirty = false;
|
||||
|
||||
return API_PLAYLISTS_UNKNOWN_INFO_GUID;
|
||||
}
|
||||
|
||||
int Playlists::RemovePlaylist( size_t index )
|
||||
{
|
||||
if ( !DelayLoad() )
|
||||
return API_PLAYLISTS_UNABLE_TO_LOAD_PLAYLISTS;
|
||||
|
||||
if ( index >= playlists.size() )
|
||||
return API_PLAYLISTS_INVALID_INDEX;
|
||||
|
||||
dirty = true;
|
||||
WASABI_API_SYSCB->syscb_issueCallback( api_playlists::SYSCALLBACK, api_playlists::PLAYLIST_REMOVED_PRE, index, 0 );
|
||||
playlists.erase(playlists.begin() + index );
|
||||
iterator++;
|
||||
WASABI_API_SYSCB->syscb_issueCallback( api_playlists::SYSCALLBACK, api_playlists::PLAYLIST_REMOVED_POST, index, 0 );
|
||||
|
||||
return API_PLAYLISTS_SUCCESS;
|
||||
}
|
||||
|
||||
int Playlists::ClearPlaylists()
|
||||
{
|
||||
AutoLockT<Playlists> lock( this );
|
||||
|
||||
if ( !DelayLoad() )
|
||||
return API_PLAYLISTS_UNABLE_TO_LOAD_PLAYLISTS;
|
||||
|
||||
dirty = true;
|
||||
playlists.clear();
|
||||
|
||||
return API_PLAYLISTS_SUCCESS;
|
||||
}
|
||||
|
||||
const PlaylistInfo &Playlists::GetPlaylistInfo(size_t i)
|
||||
{
|
||||
return playlists[i];
|
||||
}
|
||||
|
||||
#define CBCLASS Playlists
|
||||
START_DISPATCH;
|
||||
VCB( API_PLAYLISTS_LOCK, Lock );
|
||||
VCB( API_PLAYLISTS_UNLOCK, Unlock );
|
||||
CB( API_PLAYLISTS_GETITERATOR, GetIterator );
|
||||
VCB( API_PLAYLISTS_FLUSH, Flush );
|
||||
CB( API_PLAYLISTS_GETCOUNT, GetCount );
|
||||
CB( API_PLAYLISTS_GETFILENAME, GetFilename );
|
||||
CB( API_PLAYLISTS_GETNAME, GetName );
|
||||
CB( API_PLAYLISTS_GETGUID, GetGUID );
|
||||
CB( API_PLAYLISTS_GETPOSITION, GetPosition );
|
||||
CB( API_PLAYLISTS_GETINFO, GetInfo );
|
||||
CB( API_PLAYLISTS_MOVEBEFORE, MoveBefore );
|
||||
CB( API_PLAYLISTS_ADDPLAYLIST, AddPlaylist );
|
||||
CB( API_PLAYLISTS_ADDPLAYLISTNOCB, AddPlaylist_NoCallback );
|
||||
CB( API_PLAYLISTS_ADDCLOUDPLAYLIST, AddCloudPlaylist );
|
||||
CB( API_PLAYLISTS_SETGUID, SetGUID );
|
||||
CB( API_PLAYLISTS_RENAMEPLAYLIST, RenamePlaylist );
|
||||
CB( API_PLAYLISTS_MOVEPLAYLIST, MovePlaylist );
|
||||
CB( API_PLAYLISTS_SETINFO, SetInfo );
|
||||
CB( API_PLAYLISTS_REMOVEPLAYLIST, RemovePlaylist );
|
||||
CB( API_PLAYLISTS_CLEARPLAYLISTS, ClearPlaylists );
|
||||
CB( API_PLAYLISTS_SORT, Sort );
|
||||
END_DISPATCH;
|
||||
#undef CBCLASS
|
74
Src/playlist/Playlists.h
Normal file
74
Src/playlist/Playlists.h
Normal file
@ -0,0 +1,74 @@
|
||||
#ifndef NULLSOFT_PLAYLIST_PLAYLISTS_H
|
||||
#define NULLSOFT_PLAYLIST_PLAYLISTS_H
|
||||
|
||||
#include "api_playlists.h"
|
||||
#include <vector>
|
||||
#include "../nu/AutoLock.h"
|
||||
|
||||
class PlaylistInfo
|
||||
{
|
||||
public:
|
||||
PlaylistInfo();
|
||||
PlaylistInfo(const wchar_t *_filename, const wchar_t *_title, GUID playlist_guid = INVALID_GUID);
|
||||
PlaylistInfo(const PlaylistInfo ©);
|
||||
wchar_t filename[MAX_PATH];
|
||||
wchar_t title[1024];
|
||||
int length; // in seconds
|
||||
int numItems;
|
||||
GUID guid;
|
||||
uint64_t iTunesID; // this is used by ml_impex
|
||||
int cloud; // this is used by ml_playlists
|
||||
};
|
||||
|
||||
class Playlists : public api_playlists
|
||||
{
|
||||
public:
|
||||
Playlists();
|
||||
bool DelayLoad();
|
||||
|
||||
// api_playlists implementations
|
||||
void Lock();
|
||||
void Unlock();
|
||||
|
||||
size_t GetIterator();
|
||||
int Sort(size_t sort_type);
|
||||
void Flush();
|
||||
|
||||
// get information about playlists
|
||||
size_t GetCount(); // returns number of playlists
|
||||
const wchar_t *GetFilename(size_t index); // returns API_PLAYLISTS_SUCCESS or API_PLAYLISTS_FAILURE. only valid until you Unlock()
|
||||
const wchar_t *GetName(size_t index); // returns API_PLAYLISTS_SUCCESS or API_PLAYLISTS_FAILURE. only valid until you Unlock()
|
||||
GUID GetGUID(size_t index); // retrieves a unique ID which identifies this playlist
|
||||
int GetPosition(GUID playlist_guid, size_t *index); // retrieves the index where a particular playlist ID lives. returns API_PLAYLISTS_SUCCESS or API_PLAYLISTS_FAILURE
|
||||
int GetInfo(size_t index, GUID info, void *data, size_t dataLen); // This is for getting "extra" data, see list of GUIDs below. returns API_PLAYLISTS_SUCCESS or API_PLAYLISTS_FAILURE
|
||||
|
||||
// manipulating playlists
|
||||
int MoveBefore(size_t index1, size_t index2); // moves playlist at position index1 to before index2. setting index2 to anything larger than GetCount() moves to end
|
||||
size_t AddPlaylist(const wchar_t *filename, const wchar_t *playlistName, GUID playlist_guid = INVALID_GUID); // adds a new playlist, returns new index. Generates a GUID if you don't pass third parameter.
|
||||
size_t AddPlaylist_NoCallback(const wchar_t *filename, const wchar_t *playlistName, GUID playlist_guid = INVALID_GUID);
|
||||
size_t AddCloudPlaylist(const wchar_t *filename, const wchar_t *playlistName, GUID playlist_guid = INVALID_GUID); // adds a new playlist, returns new index. Generates a GUID if you don't pass third parameter.
|
||||
int SetGUID(size_t index, GUID playlist_guid); // sets (overrides) a playlist ID. Don't use unless you have some very specific need
|
||||
int RenamePlaylist(size_t index, const wchar_t *name);
|
||||
int MovePlaylist(size_t index, const wchar_t *filename); // sets a new filename. NOTE: IT'S UP TO YOU TO PHYSICALLY MOVE/RENAME/CREATE THE NEW FILENAME.
|
||||
int SetInfo(size_t index, GUID info, void *data, size_t dataLen); // returns API_PLAYLISTS_SUCCESS or API_PLAYLISTS_FAILURE
|
||||
int RemovePlaylist(size_t index); // removes a particular playlist
|
||||
int ClearPlaylists(); // [*] clears the entire playlist. Use at your own risk :)
|
||||
|
||||
size_t AddPlaylist_internal(const wchar_t *filename, const wchar_t *playlistName, GUID playlist_guid, size_t numItems, size_t length, uint64_t iTunesID, size_t cloud);
|
||||
|
||||
// for SPlaylists to use
|
||||
const PlaylistInfo &GetPlaylistInfo(size_t i);
|
||||
private:
|
||||
bool loaded; // whether or not playlists.xml has been loaded
|
||||
bool triedLoaded; // whether or not we tried to load
|
||||
bool dirty; // whether a flush should save on Flush()
|
||||
size_t iterator; // a counter to help clients determine if the list data has changed
|
||||
typedef std::vector<PlaylistInfo> PlaylistsList;
|
||||
PlaylistsList playlists;
|
||||
|
||||
Nullsoft::Utility::LockGuard playlistsGuard;
|
||||
|
||||
RECVS_DISPATCH;
|
||||
};
|
||||
|
||||
#endif
|
149
Src/playlist/PlaylistsXML.cpp
Normal file
149
Src/playlist/PlaylistsXML.cpp
Normal file
@ -0,0 +1,149 @@
|
||||
#include "PlaylistsXML.h"
|
||||
#include "api__playlist.h"
|
||||
#include "../nu/AutoLock.h"
|
||||
#include "Playlists.h"
|
||||
#include <shlwapi.h>
|
||||
#include <stdint.h>
|
||||
|
||||
using namespace Nullsoft::Utility;
|
||||
|
||||
void PlaylistsXML::StartTag( const wchar_t *xmlpath, const wchar_t *xmltag, ifc_xmlreaderparams *params )
|
||||
{
|
||||
const wchar_t *filename = params->getItemValue( L"filename" );
|
||||
const wchar_t *title = params->getItemValue( L"title" );
|
||||
const wchar_t *countString = params->getItemValue( L"songs" );
|
||||
|
||||
size_t numItems = 0;
|
||||
|
||||
if ( countString && *countString )
|
||||
numItems = _wtoi( countString );
|
||||
|
||||
const wchar_t *lengthString = params->getItemValue( L"seconds" );
|
||||
size_t length = 0;
|
||||
if ( lengthString && *lengthString )
|
||||
length = _wtoi( lengthString );
|
||||
|
||||
const wchar_t *iTunesIDString = params->getItemValue( L"iTunesID" );
|
||||
uint64_t iTunesID = 0;
|
||||
if ( iTunesIDString && *iTunesIDString )
|
||||
iTunesID = _wtoi64( iTunesIDString );
|
||||
|
||||
const wchar_t *cloudString = params->getItemValue( L"cloud" );
|
||||
size_t cloud = 0;
|
||||
if ( cloudString && *cloudString )
|
||||
cloud = _wtoi( cloudString );
|
||||
|
||||
// parse GUID
|
||||
GUID guid = INVALID_GUID;
|
||||
const wchar_t *guidString = params->getItemValue( L"id" );
|
||||
if ( guidString && *guidString )
|
||||
{
|
||||
int Data1, Data2, Data3;
|
||||
int Data4[ 8 ];
|
||||
|
||||
int n = swscanf( guidString, L" { %08x - %04x - %04x - %02x%02x - %02x%02x%02x%02x%02x%02x } ",
|
||||
&Data1, &Data2, &Data3, Data4 + 0, Data4 + 1,
|
||||
Data4 + 2, Data4 + 3, Data4 + 4, Data4 + 5, Data4 + 6, Data4 + 7 );
|
||||
|
||||
if ( n == 11 ) // GUID was
|
||||
{
|
||||
// Cross assign all the values
|
||||
guid.Data1 = Data1;
|
||||
guid.Data2 = Data2;
|
||||
guid.Data3 = Data3;
|
||||
guid.Data4[ 0 ] = Data4[ 0 ];
|
||||
guid.Data4[ 1 ] = Data4[ 1 ];
|
||||
guid.Data4[ 2 ] = Data4[ 2 ];
|
||||
guid.Data4[ 3 ] = Data4[ 3 ];
|
||||
guid.Data4[ 4 ] = Data4[ 4 ];
|
||||
guid.Data4[ 5 ] = Data4[ 5 ];
|
||||
guid.Data4[ 6 ] = Data4[ 6 ];
|
||||
guid.Data4[ 7 ] = Data4[ 7 ];
|
||||
}
|
||||
}
|
||||
|
||||
if ( PathIsFileSpecW( filename ) )
|
||||
{
|
||||
wchar_t playlistFilename[ MAX_PATH ] = { 0 };
|
||||
PathCombineW( playlistFilename, rootPath, filename );
|
||||
playlists->AddPlaylist_internal( playlistFilename, title, guid, numItems, length, iTunesID, cloud );
|
||||
}
|
||||
else
|
||||
{
|
||||
playlists->AddPlaylist_internal( filename, title, guid, numItems, length, iTunesID, cloud );
|
||||
}
|
||||
}
|
||||
|
||||
int PlaylistsXML::LoadFile( const wchar_t *filename )
|
||||
{
|
||||
if ( !parser )
|
||||
return PLAYLISTSXML_NO_PARSER; // no sense in continuing if there's no parser available
|
||||
|
||||
HANDLE file = CreateFileW( filename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, NULL, NULL );
|
||||
|
||||
if ( file == INVALID_HANDLE_VALUE )
|
||||
return PLAYLISTSXML_NO_FILE;
|
||||
|
||||
while ( true )
|
||||
{
|
||||
int8_t data[ 1024 ] = { 0 };
|
||||
DWORD bytesRead = 0;
|
||||
if ( ReadFile( file, data, 1024, &bytesRead, NULL ) && bytesRead )
|
||||
{
|
||||
if ( parser->xmlreader_feed( data, bytesRead ) != API_XML_SUCCESS )
|
||||
{
|
||||
CloseHandle( file );
|
||||
return PLAYLISTSXML_XML_PARSE_ERROR;
|
||||
}
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
CloseHandle( file );
|
||||
parser->xmlreader_feed( 0, 0 );
|
||||
|
||||
return PLAYLISTSXML_SUCCESS;
|
||||
}
|
||||
|
||||
PlaylistsXML::PlaylistsXML( Playlists *_playlists ) : playlists( _playlists )
|
||||
{
|
||||
const wchar_t *g_path = WASABI_API_APP->path_getUserSettingsPath();
|
||||
PathCombineW( rootPath, g_path, L"plugins\\ml\\playlists" );
|
||||
|
||||
playlists->AddRef();
|
||||
|
||||
parserFactory = WASABI_API_SVC->service_getServiceByGuid( obj_xmlGUID );
|
||||
if ( parserFactory )
|
||||
parser = (obj_xml *)parserFactory->getInterface();
|
||||
|
||||
if ( parser )
|
||||
{
|
||||
parser->xmlreader_setCaseSensitive();
|
||||
parser->xmlreader_registerCallback( L"Winamp:Playlists\fplaylist", this );
|
||||
parser->xmlreader_registerCallback( L"playlists\fplaylist", this );
|
||||
parser->xmlreader_open();
|
||||
}
|
||||
}
|
||||
|
||||
PlaylistsXML::~PlaylistsXML()
|
||||
{
|
||||
playlists->Release();
|
||||
if ( parser )
|
||||
{
|
||||
parser->xmlreader_unregisterCallback( this );
|
||||
parser->xmlreader_close();
|
||||
}
|
||||
|
||||
if ( parserFactory && parser )
|
||||
parserFactory->releaseInterface( parser );
|
||||
|
||||
parserFactory = 0;
|
||||
parser = 0;
|
||||
}
|
||||
|
||||
#define CBCLASS PlaylistsXML
|
||||
START_DISPATCH;
|
||||
VCB( ONSTARTELEMENT, StartTag )
|
||||
END_DISPATCH;
|
||||
#undef CBCLASS
|
38
Src/playlist/PlaylistsXML.h
Normal file
38
Src/playlist/PlaylistsXML.h
Normal file
@ -0,0 +1,38 @@
|
||||
#ifndef NULLSOFT_AGAVE_PLAYLISTSXML_H
|
||||
#define NULLSOFT_AGAVE_PLAYLISTSXML_H
|
||||
|
||||
#include "../xml/obj_xml.h"
|
||||
#include "../xml/ifc_xmlreadercallback.h"
|
||||
#include <api/service/waServiceFactory.h>
|
||||
class Playlists;
|
||||
|
||||
enum
|
||||
{
|
||||
PLAYLISTSXML_SUCCESS = 0,
|
||||
PLAYLISTSXML_FAILURE = 1,
|
||||
PLAYLISTSXML_NO_PARSER = 2,
|
||||
PLAYLISTSXML_NO_FILE = 3,
|
||||
PLAYLISTSXML_XML_PARSE_ERROR = 4,
|
||||
};
|
||||
|
||||
class PlaylistsXML : public ifc_xmlreadercallback
|
||||
{
|
||||
public:
|
||||
PlaylistsXML( Playlists *_playlists );
|
||||
~PlaylistsXML();
|
||||
|
||||
int LoadFile( const wchar_t *filename );
|
||||
|
||||
private:
|
||||
RECVS_DISPATCH;
|
||||
/* XML callbacks */
|
||||
void StartTag( const wchar_t *xmlpath, const wchar_t *xmltag, ifc_xmlreaderparams *params );
|
||||
|
||||
obj_xml *parser = 0;
|
||||
waServiceFactory *parserFactory = 0;
|
||||
Playlists *playlists = 0;
|
||||
|
||||
wchar_t rootPath[ MAX_PATH ];
|
||||
};
|
||||
|
||||
#endif
|
270
Src/playlist/SPlaylist.cpp
Normal file
270
Src/playlist/SPlaylist.cpp
Normal file
@ -0,0 +1,270 @@
|
||||
#include "SPlaylist.h"
|
||||
#include "api__playlist.h"
|
||||
#include "PlaylistManager.h"
|
||||
|
||||
extern ScriptObjectController *script_root;
|
||||
extern PlaylistScriptController playlistController;
|
||||
|
||||
|
||||
// -- Functions table -------------------------------------
|
||||
function_descriptor_struct PlaylistScriptController::exportedFunction[] = {
|
||||
{L"Clear", 0, (void*)SPlaylist::script_vcpu_Clear },
|
||||
{L"GetNumItems", 0, (void*)SPlaylist::script_vcpu_GetNumItems },
|
||||
{L"GetItem", 1, (void*)SPlaylist::script_vcpu_GetItem },
|
||||
{L"GetItemTitle", 1, (void*)SPlaylist::script_vcpu_GetItemTitle },
|
||||
{L"GetItemLength", 1, (void*)SPlaylist::script_vcpu_GetItemLength },
|
||||
{L"GetItemExtendedInfo", 2, (void*)SPlaylist::script_vcpu_GetItemExtendedInfo },
|
||||
{L"Reverse", 0, (void*)SPlaylist::script_vcpu_Reverse },
|
||||
{L"Swap", 2, (void*)SPlaylist::script_vcpu_Swap },
|
||||
{L"Randomize", 0, (void*)SPlaylist::script_vcpu_Randomize },
|
||||
{L"Remove", 1, (void*)SPlaylist::script_vcpu_Remove },
|
||||
{L"SortByTitle", 0, (void*)SPlaylist::script_vcpu_SortByTitle },
|
||||
{L"SortByFilename", 0, (void*)SPlaylist::script_vcpu_SortByFilename },
|
||||
/* TODO:
|
||||
{L"Append", 3, (void*)SPlaylist::script_vcpu_Append },
|
||||
{L"Insert", 4, (void*)SPlaylist::script_vcpu_Insert },
|
||||
{L"SetItemFilename", 2, (void*)SPlaylist::script_vcpu_SetItemFilename },
|
||||
{L"SetItemTitle", 2, (void*)SPlaylist::script_vcpu_SetItemTitle },
|
||||
{L"SetItemLengthMilliseconds", 2, (void*)SPlaylist::script_vcpu_SetItemLengthMilliseconds },
|
||||
{L"SortByDirectory", 0, (void*)SPlaylist::script_vcpu_SortByDirectory },
|
||||
*/
|
||||
|
||||
};
|
||||
// --------------------------------------------------------
|
||||
|
||||
const wchar_t *PlaylistScriptController::getClassName()
|
||||
{
|
||||
return L"Playlist";
|
||||
}
|
||||
|
||||
const wchar_t *PlaylistScriptController::getAncestorClassName()
|
||||
{
|
||||
return L"Object";
|
||||
}
|
||||
|
||||
ScriptObjectController *PlaylistScriptController::getAncestorController()
|
||||
{
|
||||
return script_root;
|
||||
}
|
||||
|
||||
ScriptObject *PlaylistScriptController::instantiate()
|
||||
{
|
||||
SPlaylist *xd = new SPlaylist;
|
||||
|
||||
ASSERT( xd != NULL );
|
||||
|
||||
return xd->getScriptObject();
|
||||
}
|
||||
|
||||
void PlaylistScriptController::destroy( ScriptObject *o )
|
||||
{
|
||||
SPlaylist *xd = static_cast<SPlaylist *>( o->vcpu_getInterface( makiPlaylistGUID ) );
|
||||
|
||||
ASSERT( xd != NULL );
|
||||
|
||||
delete xd;
|
||||
}
|
||||
|
||||
void *PlaylistScriptController::encapsulate( ScriptObject *o )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void PlaylistScriptController::deencapsulate( void *o )
|
||||
{}
|
||||
|
||||
int PlaylistScriptController::getNumFunctions()
|
||||
{
|
||||
return sizeof( exportedFunction ) / sizeof( function_descriptor_struct );
|
||||
}
|
||||
|
||||
const function_descriptor_struct *PlaylistScriptController::getExportedFunctions()
|
||||
{
|
||||
return exportedFunction;
|
||||
}
|
||||
|
||||
GUID PlaylistScriptController::getClassGuid()
|
||||
{
|
||||
return makiPlaylistGUID;
|
||||
}
|
||||
|
||||
|
||||
/* ---- */
|
||||
SPlaylist::SPlaylist()
|
||||
{
|
||||
getScriptObject()->vcpu_setInterface( makiPlaylistGUID, static_cast<SPlaylist *>( this ) );
|
||||
getScriptObject()->vcpu_setClassName( L"Playlist" );
|
||||
getScriptObject()->vcpu_setController( &playlistController );
|
||||
}
|
||||
|
||||
scriptVar SPlaylist::script_vcpu_Clear( SCRIPT_FUNCTION_PARAMS, ScriptObject *o )
|
||||
{
|
||||
SCRIPT_FUNCTION_INIT;
|
||||
SPlaylist *playlist = static_cast<SPlaylist *>( o->vcpu_getInterface( makiPlaylistGUID ) );
|
||||
if ( playlist )
|
||||
{
|
||||
playlist->playlist.Clear();
|
||||
}
|
||||
RETURN_SCRIPT_VOID
|
||||
}
|
||||
|
||||
scriptVar SPlaylist::script_vcpu_GetNumItems( SCRIPT_FUNCTION_PARAMS, ScriptObject *o )
|
||||
{
|
||||
SCRIPT_FUNCTION_INIT;
|
||||
SPlaylist *playlist = static_cast<SPlaylist *>( o->vcpu_getInterface( makiPlaylistGUID ) );
|
||||
if ( playlist )
|
||||
{
|
||||
size_t count = playlist->playlist.GetNumItems();
|
||||
|
||||
return MAKE_SCRIPT_INT( (int)count );
|
||||
}
|
||||
RETURN_SCRIPT_ZERO
|
||||
}
|
||||
|
||||
static wchar_t splaylist_string_return[ 1024 ];
|
||||
static wchar_t *splaylist_string_empty = L"";
|
||||
|
||||
scriptVar SPlaylist::script_vcpu_GetItem( SCRIPT_FUNCTION_PARAMS, ScriptObject *o, scriptVar itemNumber )
|
||||
{
|
||||
SCRIPT_FUNCTION_INIT;
|
||||
|
||||
SPlaylist *playlist = static_cast<SPlaylist *>( o->vcpu_getInterface( makiPlaylistGUID ) );
|
||||
if ( playlist )
|
||||
{
|
||||
int item = GET_SCRIPT_INT( itemNumber );
|
||||
size_t cch = playlist->playlist.GetItem( item, splaylist_string_return, sizeof( splaylist_string_return ) / sizeof( *splaylist_string_return ) );
|
||||
|
||||
if ( cch == 0 )
|
||||
return MAKE_SCRIPT_STRING( splaylist_string_empty );
|
||||
else
|
||||
return MAKE_SCRIPT_STRING( splaylist_string_return );
|
||||
}
|
||||
|
||||
return MAKE_SCRIPT_STRING( splaylist_string_empty );
|
||||
}
|
||||
|
||||
scriptVar SPlaylist::script_vcpu_GetItemTitle( SCRIPT_FUNCTION_PARAMS, ScriptObject *o, scriptVar itemNumber )
|
||||
{
|
||||
SCRIPT_FUNCTION_INIT;
|
||||
|
||||
SPlaylist *playlist = static_cast<SPlaylist *>( o->vcpu_getInterface( makiPlaylistGUID ) );
|
||||
if ( playlist )
|
||||
{
|
||||
int item = GET_SCRIPT_INT( itemNumber );
|
||||
size_t cch = playlist->playlist.GetItemTitle( item, splaylist_string_return, sizeof( splaylist_string_return ) / sizeof( *splaylist_string_return ) );
|
||||
|
||||
if ( cch == 0 )
|
||||
return MAKE_SCRIPT_STRING( splaylist_string_empty );
|
||||
else
|
||||
return MAKE_SCRIPT_STRING( splaylist_string_return );
|
||||
}
|
||||
|
||||
return MAKE_SCRIPT_STRING( splaylist_string_empty );
|
||||
}
|
||||
|
||||
scriptVar SPlaylist::script_vcpu_GetItemLength( SCRIPT_FUNCTION_PARAMS, ScriptObject *o, scriptVar itemNumber )
|
||||
{
|
||||
SCRIPT_FUNCTION_INIT;
|
||||
|
||||
SPlaylist *playlist = static_cast<SPlaylist *>( o->vcpu_getInterface( makiPlaylistGUID ) );
|
||||
if ( playlist )
|
||||
{
|
||||
int item = GET_SCRIPT_INT( itemNumber );
|
||||
int length = playlist->playlist.GetItemLengthMilliseconds( item );
|
||||
|
||||
return MAKE_SCRIPT_INT( length );
|
||||
}
|
||||
|
||||
return MAKE_SCRIPT_INT( -1 );
|
||||
}
|
||||
|
||||
scriptVar SPlaylist::script_vcpu_GetItemExtendedInfo( SCRIPT_FUNCTION_PARAMS, ScriptObject *o, scriptVar itemNumber, scriptVar metadata )
|
||||
{
|
||||
SCRIPT_FUNCTION_INIT;
|
||||
|
||||
SPlaylist *playlist = static_cast<SPlaylist *>( o->vcpu_getInterface( makiPlaylistGUID ) );
|
||||
if ( playlist )
|
||||
{
|
||||
int item = GET_SCRIPT_INT( itemNumber );
|
||||
const wchar_t *tag = GET_SCRIPT_STRING( metadata );
|
||||
size_t cch = playlist->playlist.GetItemExtendedInfo( item, tag, splaylist_string_return, sizeof( splaylist_string_return ) / sizeof( *splaylist_string_return ) );
|
||||
|
||||
if ( cch == 0 )
|
||||
return MAKE_SCRIPT_STRING( splaylist_string_empty );
|
||||
else
|
||||
return MAKE_SCRIPT_STRING( splaylist_string_return );
|
||||
}
|
||||
|
||||
return MAKE_SCRIPT_STRING( splaylist_string_empty );
|
||||
}
|
||||
|
||||
scriptVar SPlaylist::script_vcpu_Reverse( SCRIPT_FUNCTION_PARAMS, ScriptObject *o )
|
||||
{
|
||||
SCRIPT_FUNCTION_INIT;
|
||||
SPlaylist *playlist = static_cast<SPlaylist *>( o->vcpu_getInterface( makiPlaylistGUID ) );
|
||||
if ( playlist )
|
||||
{
|
||||
playlist->playlist.Reverse();
|
||||
}
|
||||
RETURN_SCRIPT_VOID
|
||||
}
|
||||
|
||||
scriptVar SPlaylist::script_vcpu_Swap( SCRIPT_FUNCTION_PARAMS, ScriptObject *o, scriptVar position1, scriptVar position2 )
|
||||
{
|
||||
SCRIPT_FUNCTION_INIT;
|
||||
SPlaylist *playlist = static_cast<SPlaylist *>( o->vcpu_getInterface( makiPlaylistGUID ) );
|
||||
if ( playlist )
|
||||
{
|
||||
int item1 = GET_SCRIPT_INT( position1 );
|
||||
int item2 = GET_SCRIPT_INT( position2 );
|
||||
|
||||
playlist->playlist.Swap( item1, item2 );
|
||||
}
|
||||
RETURN_SCRIPT_VOID
|
||||
}
|
||||
|
||||
scriptVar SPlaylist::script_vcpu_Randomize( SCRIPT_FUNCTION_PARAMS, ScriptObject *o )
|
||||
{
|
||||
SCRIPT_FUNCTION_INIT;
|
||||
SPlaylist *playlist = static_cast<SPlaylist *>( o->vcpu_getInterface( makiPlaylistGUID ) );
|
||||
if ( playlist )
|
||||
{
|
||||
playlistManager.Randomize( &playlist->playlist );
|
||||
}
|
||||
RETURN_SCRIPT_VOID
|
||||
}
|
||||
|
||||
|
||||
scriptVar SPlaylist::script_vcpu_Remove( SCRIPT_FUNCTION_PARAMS, ScriptObject *o, scriptVar itemIndex )
|
||||
{
|
||||
SCRIPT_FUNCTION_INIT;
|
||||
SPlaylist *playlist = static_cast<SPlaylist *>( o->vcpu_getInterface( makiPlaylistGUID ) );
|
||||
if ( playlist )
|
||||
{
|
||||
int item = GET_SCRIPT_INT( itemIndex );
|
||||
playlist->playlist.Remove( item );
|
||||
}
|
||||
RETURN_SCRIPT_VOID
|
||||
}
|
||||
|
||||
scriptVar SPlaylist::script_vcpu_SortByTitle( SCRIPT_FUNCTION_PARAMS, ScriptObject *o )
|
||||
{
|
||||
SCRIPT_FUNCTION_INIT;
|
||||
SPlaylist *playlist = static_cast<SPlaylist *>( o->vcpu_getInterface( makiPlaylistGUID ) );
|
||||
if ( playlist )
|
||||
{
|
||||
playlist->playlist.SortByTitle();
|
||||
}
|
||||
RETURN_SCRIPT_VOID
|
||||
}
|
||||
|
||||
scriptVar SPlaylist::script_vcpu_SortByFilename( SCRIPT_FUNCTION_PARAMS, ScriptObject *o )
|
||||
{
|
||||
SCRIPT_FUNCTION_INIT;
|
||||
SPlaylist *playlist = static_cast<SPlaylist *>( o->vcpu_getInterface( makiPlaylistGUID ) );
|
||||
if ( playlist )
|
||||
{
|
||||
playlist->playlist.SortByFilename();
|
||||
}
|
||||
RETURN_SCRIPT_VOID
|
||||
}
|
52
Src/playlist/SPlaylist.h
Normal file
52
Src/playlist/SPlaylist.h
Normal file
@ -0,0 +1,52 @@
|
||||
#pragma once
|
||||
|
||||
#include "api/script/objcontroller.h"
|
||||
#include "api/script/objects/rootobj.h"
|
||||
#include "Playlist.h"
|
||||
|
||||
class PlaylistScriptController : public ScriptObjectControllerI
|
||||
{
|
||||
public:
|
||||
virtual const wchar_t *getClassName();
|
||||
virtual const wchar_t *getAncestorClassName();
|
||||
virtual ScriptObjectController *getAncestorController();
|
||||
virtual int getNumFunctions();
|
||||
virtual const function_descriptor_struct *getExportedFunctions();
|
||||
virtual GUID getClassGuid();
|
||||
virtual ScriptObject *instantiate();
|
||||
virtual void destroy( ScriptObject *o );
|
||||
virtual void *encapsulate( ScriptObject *o );
|
||||
virtual void deencapsulate( void *o );
|
||||
|
||||
private:
|
||||
static function_descriptor_struct exportedFunction[];
|
||||
};
|
||||
|
||||
class SPlaylist : public RootObjectInstance
|
||||
{
|
||||
public:
|
||||
SPlaylist();
|
||||
|
||||
/* ifc_playlist wrapper */
|
||||
static scriptVar script_vcpu_Clear( SCRIPT_FUNCTION_PARAMS, ScriptObject *o );
|
||||
static scriptVar script_vcpu_GetNumItems( SCRIPT_FUNCTION_PARAMS, ScriptObject *o );
|
||||
static scriptVar script_vcpu_GetItem( SCRIPT_FUNCTION_PARAMS, ScriptObject *o, scriptVar itemNumber );
|
||||
static scriptVar script_vcpu_GetItemTitle( SCRIPT_FUNCTION_PARAMS, ScriptObject *o, scriptVar itemNumber );
|
||||
static scriptVar script_vcpu_GetItemLength( SCRIPT_FUNCTION_PARAMS, ScriptObject *o, scriptVar itemNumber );
|
||||
static scriptVar script_vcpu_GetItemExtendedInfo( SCRIPT_FUNCTION_PARAMS, ScriptObject *o, scriptVar itemNumber, scriptVar metadata );
|
||||
static scriptVar script_vcpu_Reverse( SCRIPT_FUNCTION_PARAMS, ScriptObject *o );
|
||||
static scriptVar script_vcpu_Swap( SCRIPT_FUNCTION_PARAMS, ScriptObject *o, scriptVar position1, scriptVar position2 );
|
||||
static scriptVar script_vcpu_Randomize( SCRIPT_FUNCTION_PARAMS, ScriptObject *o );
|
||||
static scriptVar script_vcpu_Remove( SCRIPT_FUNCTION_PARAMS, ScriptObject *o, scriptVar itemIndex );
|
||||
static scriptVar script_vcpu_SortByTitle( SCRIPT_FUNCTION_PARAMS, ScriptObject *o );
|
||||
static scriptVar script_vcpu_SortByFilename( SCRIPT_FUNCTION_PARAMS, ScriptObject *o );
|
||||
|
||||
/* extra functions */
|
||||
//private:
|
||||
Playlist playlist;
|
||||
};
|
||||
|
||||
|
||||
// {632883FC-159F-4330-B193-CFD62CA47EC1}
|
||||
static const GUID makiPlaylistGUID =
|
||||
{ 0x632883fc, 0x159f, 0x4330, { 0xb1, 0x93, 0xcf, 0xd6, 0x2c, 0xa4, 0x7e, 0xc1 } };
|
117
Src/playlist/SPlaylistManager.cpp
Normal file
117
Src/playlist/SPlaylistManager.cpp
Normal file
@ -0,0 +1,117 @@
|
||||
#include "SPlaylistManager.h"
|
||||
#include "SPlaylist.h"
|
||||
#include "api__playlist.h"
|
||||
#include "PlaylistManager.h"
|
||||
|
||||
extern ScriptObjectController *script_root;
|
||||
extern PlaylistManagerScriptController playlistManagerController;
|
||||
|
||||
// {C6207729-2600-4bb8-B562-2E0BC04E4416}
|
||||
static const GUID makePlaylistManagerGUID =
|
||||
{ 0xc6207729, 0x2600, 0x4bb8, { 0xb5, 0x62, 0x2e, 0xb, 0xc0, 0x4e, 0x44, 0x16 } };
|
||||
|
||||
|
||||
// -- Functions table -------------------------------------
|
||||
function_descriptor_struct PlaylistManagerScriptController::exportedFunction[] = {
|
||||
{L"OpenPlaylist", 1, (void*)SPlaylistManager::script_vcpu_OpenPlaylist },
|
||||
{L"SavePlaylist", 2, (void*)SPlaylistManager::script_vcpu_SavePlaylist },
|
||||
};
|
||||
// --------------------------------------------------------
|
||||
|
||||
const wchar_t *PlaylistManagerScriptController::getClassName() {
|
||||
return L"PlaylistManager";
|
||||
}
|
||||
|
||||
const wchar_t *PlaylistManagerScriptController::getAncestorClassName() {
|
||||
return L"Object";
|
||||
}
|
||||
|
||||
ScriptObjectController *PlaylistManagerScriptController::getAncestorController()
|
||||
{
|
||||
return script_root;
|
||||
}
|
||||
|
||||
int PlaylistManagerScriptController::getInstantiable()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int PlaylistManagerScriptController::getReferenceable()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
ScriptObject *PlaylistManagerScriptController::instantiate() {
|
||||
SPlaylistManager *xd = new SPlaylistManager;
|
||||
ASSERT(xd != NULL);
|
||||
return xd->getScriptObject();
|
||||
}
|
||||
|
||||
void PlaylistManagerScriptController::destroy(ScriptObject *o) {
|
||||
SPlaylistManager *xd = static_cast<SPlaylistManager *>(o->vcpu_getInterface(makePlaylistManagerGUID));
|
||||
ASSERT(xd != NULL);
|
||||
delete xd;
|
||||
}
|
||||
|
||||
void *PlaylistManagerScriptController::encapsulate(ScriptObject *o) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void PlaylistManagerScriptController::deencapsulate(void *o) {
|
||||
}
|
||||
|
||||
int PlaylistManagerScriptController::getNumFunctions() {
|
||||
return sizeof(exportedFunction) / sizeof(function_descriptor_struct);
|
||||
}
|
||||
|
||||
const function_descriptor_struct *PlaylistManagerScriptController::getExportedFunctions() {
|
||||
return exportedFunction;
|
||||
}
|
||||
|
||||
GUID PlaylistManagerScriptController::getClassGuid() {
|
||||
return makePlaylistManagerGUID;
|
||||
}
|
||||
|
||||
/* --- */
|
||||
|
||||
SPlaylistManager::SPlaylistManager()
|
||||
{
|
||||
getScriptObject()->vcpu_setInterface(makePlaylistManagerGUID, static_cast<SPlaylistManager *>(this));
|
||||
getScriptObject()->vcpu_setClassName(L"PlaylistManager");
|
||||
getScriptObject()->vcpu_setController(&playlistManagerController);
|
||||
}
|
||||
|
||||
scriptVar SPlaylistManager::script_vcpu_OpenPlaylist(SCRIPT_FUNCTION_PARAMS, ScriptObject *o, scriptVar scriptFilename)
|
||||
{
|
||||
SCRIPT_FUNCTION_INIT;
|
||||
const wchar_t *filename = GET_SCRIPT_STRING(scriptFilename);
|
||||
if (filename && *filename)
|
||||
{
|
||||
SPlaylist *playlist = new SPlaylist;
|
||||
if (playlistManager.Load(filename, &playlist->playlist) == PLAYLISTMANAGER_SUCCESS)
|
||||
{
|
||||
return MAKE_SCRIPT_OBJECT(playlist->getScriptObject());
|
||||
}
|
||||
else
|
||||
{
|
||||
delete playlist;
|
||||
return MAKE_SCRIPT_OBJECT(0);
|
||||
}
|
||||
}
|
||||
|
||||
return MAKE_SCRIPT_OBJECT(0);
|
||||
}
|
||||
|
||||
scriptVar SPlaylistManager::script_vcpu_SavePlaylist(SCRIPT_FUNCTION_PARAMS, ScriptObject *o, scriptVar scriptFilename, scriptVar scriptPlaylist)
|
||||
{
|
||||
SCRIPT_FUNCTION_INIT;
|
||||
const wchar_t *filename = GET_SCRIPT_STRING(scriptFilename);
|
||||
SPlaylist *playlist = static_cast<SPlaylist *>(GET_SCRIPT_OBJECT_AS(scriptPlaylist, makiPlaylistGUID));
|
||||
if (filename && *filename && playlist)
|
||||
{
|
||||
playlistManager.Save(filename, &playlist->playlist);
|
||||
}
|
||||
|
||||
RETURN_SCRIPT_VOID;
|
||||
}
|
||||
|
38
Src/playlist/SPlaylistManager.h
Normal file
38
Src/playlist/SPlaylistManager.h
Normal file
@ -0,0 +1,38 @@
|
||||
#pragma once
|
||||
|
||||
#include <api/script/objcontroller.h>
|
||||
#include <api/script/objects/rootobj.h>
|
||||
|
||||
class PlaylistManagerScriptController : public ScriptObjectControllerI
|
||||
{
|
||||
public:
|
||||
const wchar_t *getClassName();
|
||||
const wchar_t *getAncestorClassName();
|
||||
ScriptObjectController *getAncestorController();
|
||||
int getNumFunctions();
|
||||
const function_descriptor_struct *getExportedFunctions();
|
||||
GUID getClassGuid();
|
||||
|
||||
ScriptObject *instantiate();
|
||||
void destroy( ScriptObject *o );
|
||||
|
||||
void *encapsulate( ScriptObject *o );
|
||||
void deencapsulate( void *o );
|
||||
|
||||
int getInstantiable();
|
||||
int getReferenceable();
|
||||
|
||||
private:
|
||||
static function_descriptor_struct exportedFunction[];
|
||||
};
|
||||
|
||||
class SPlaylistManager : public RootObjectInstance
|
||||
{
|
||||
public:
|
||||
SPlaylistManager();
|
||||
|
||||
static scriptVar script_vcpu_OpenPlaylist( SCRIPT_FUNCTION_PARAMS, ScriptObject *o, scriptVar filename );
|
||||
static scriptVar script_vcpu_SavePlaylist( SCRIPT_FUNCTION_PARAMS, ScriptObject *o, scriptVar filename, scriptVar playlist );
|
||||
|
||||
private:
|
||||
};
|
157
Src/playlist/SPlaylists.cpp
Normal file
157
Src/playlist/SPlaylists.cpp
Normal file
@ -0,0 +1,157 @@
|
||||
#include "SPlaylists.h"
|
||||
#include "api__playlist.h"
|
||||
#include "Playlists.h"
|
||||
#include "SPlaylistsEnumerator.h"
|
||||
#include "SPlaylist.h"
|
||||
#include "PlaylistManager.h"
|
||||
|
||||
extern Playlists playlists;
|
||||
|
||||
extern ScriptObjectController *script_root;
|
||||
extern PlaylistsScriptController playlistsController;
|
||||
|
||||
// {5829EE15-3648-4c6e-B2FE-8736CBBF39DB}
|
||||
static const GUID makiPlaylistsGUID =
|
||||
{ 0x5829ee15, 0x3648, 0x4c6e, { 0xb2, 0xfe, 0x87, 0x36, 0xcb, 0xbf, 0x39, 0xdb } };
|
||||
|
||||
// -- Functions table -------------------------------------
|
||||
function_descriptor_struct PlaylistsScriptController::exportedFunction[] = {
|
||||
{L"GetEnumerator", 0, (void*)SPlaylists::script_vcpu_GetEnumerator },
|
||||
{L"OpenPlaylist", 1, (void*)SPlaylists::script_vcpu_OpenPlaylist },
|
||||
{L"SavePlaylist", 2, (void*)SPlaylists::script_vcpu_SavePlaylist },
|
||||
};
|
||||
// --------------------------------------------------------
|
||||
|
||||
const wchar_t *PlaylistsScriptController::getClassName()
|
||||
{
|
||||
return L"Playlists";
|
||||
}
|
||||
|
||||
const wchar_t *PlaylistsScriptController::getAncestorClassName()
|
||||
{
|
||||
return L"Object";
|
||||
}
|
||||
|
||||
ScriptObjectController *PlaylistsScriptController::getAncestorController()
|
||||
{
|
||||
return script_root;
|
||||
}
|
||||
|
||||
int PlaylistsScriptController::getInstantiable()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int PlaylistsScriptController::getReferenceable()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
ScriptObject *PlaylistsScriptController::instantiate()
|
||||
{
|
||||
SPlaylists *xd = new SPlaylists;
|
||||
ASSERT(xd != NULL);
|
||||
return xd->getScriptObject();
|
||||
}
|
||||
|
||||
void PlaylistsScriptController::destroy(ScriptObject *o)
|
||||
{
|
||||
SPlaylists *xd = static_cast<SPlaylists *>(o->vcpu_getInterface(makiPlaylistsGUID));
|
||||
ASSERT(xd != NULL);
|
||||
delete xd;
|
||||
}
|
||||
|
||||
void *PlaylistsScriptController::encapsulate(ScriptObject *o)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void PlaylistsScriptController::deencapsulate(void *o)
|
||||
{}
|
||||
|
||||
int PlaylistsScriptController::getNumFunctions()
|
||||
{
|
||||
return sizeof(exportedFunction) / sizeof(function_descriptor_struct);
|
||||
}
|
||||
|
||||
const function_descriptor_struct *PlaylistsScriptController::getExportedFunctions()
|
||||
{
|
||||
return exportedFunction;
|
||||
}
|
||||
|
||||
GUID PlaylistsScriptController::getClassGuid()
|
||||
{
|
||||
return makiPlaylistsGUID;
|
||||
}
|
||||
|
||||
/* --- */
|
||||
|
||||
SPlaylists::SPlaylists()
|
||||
{
|
||||
getScriptObject()->vcpu_setInterface(makiPlaylistsGUID, static_cast<SPlaylists *>(this));
|
||||
getScriptObject()->vcpu_setClassName(L"Playlists");
|
||||
getScriptObject()->vcpu_setController(&playlistsController);
|
||||
}
|
||||
|
||||
scriptVar SPlaylists::script_vcpu_GetEnumerator(SCRIPT_FUNCTION_PARAMS, ScriptObject *o)
|
||||
{
|
||||
SCRIPT_FUNCTION_INIT;
|
||||
SPlaylistsEnumerator *enumerator = new SPlaylistsEnumerator();
|
||||
playlists.Lock();
|
||||
size_t count = playlists.GetCount();
|
||||
enumerator->Reserve(count);
|
||||
for (size_t i=0;i!=count;i++)
|
||||
{
|
||||
const PlaylistInfo &info = playlists.GetPlaylistInfo(i);
|
||||
enumerator->AppendPlaylist(info);
|
||||
}
|
||||
playlists.Unlock();
|
||||
return MAKE_SCRIPT_OBJECT(enumerator->getScriptObject());
|
||||
}
|
||||
|
||||
scriptVar SPlaylists::script_vcpu_OpenPlaylist( SCRIPT_FUNCTION_PARAMS, ScriptObject *o, scriptVar scriptPlaylistGUID )
|
||||
{
|
||||
SCRIPT_FUNCTION_INIT;
|
||||
GUID playlist_guid = nsGUID::fromCharW( GET_SCRIPT_STRING( scriptPlaylistGUID ) );
|
||||
SPlaylist *playlist = 0;
|
||||
|
||||
playlists.Lock();
|
||||
size_t index;
|
||||
if ( playlists.GetPosition( playlist_guid, &index ) == API_PLAYLISTS_SUCCESS )
|
||||
{
|
||||
const wchar_t *filename = playlists.GetFilename( index );
|
||||
if ( filename )
|
||||
{
|
||||
playlist = new SPlaylist;
|
||||
if ( playlistManager.Load( filename, &playlist->playlist ) != PLAYLISTMANAGER_SUCCESS )
|
||||
{
|
||||
delete playlist;
|
||||
playlist = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
playlists.Unlock();
|
||||
|
||||
return MAKE_SCRIPT_OBJECT( playlist ? playlist->getScriptObject() : 0 );
|
||||
}
|
||||
|
||||
scriptVar SPlaylists::script_vcpu_SavePlaylist( SCRIPT_FUNCTION_PARAMS, ScriptObject *o, scriptVar scriptPlaylistGUID, scriptVar scriptPlaylist )
|
||||
{
|
||||
SCRIPT_FUNCTION_INIT;
|
||||
GUID playlist_guid = nsGUID::fromCharW( GET_SCRIPT_STRING( scriptPlaylistGUID ) );
|
||||
SPlaylist *playlist = static_cast<SPlaylist *>( GET_SCRIPT_OBJECT_AS( scriptPlaylist, makiPlaylistGUID ) );
|
||||
if ( playlist )
|
||||
{
|
||||
playlists.Lock();
|
||||
size_t index;
|
||||
if ( playlists.GetPosition( playlist_guid, &index ) == API_PLAYLISTS_SUCCESS )
|
||||
{
|
||||
const wchar_t *filename = playlists.GetFilename( index );
|
||||
if ( filename )
|
||||
playlistManager.Save( filename, &playlist->playlist );
|
||||
}
|
||||
playlists.Unlock();
|
||||
}
|
||||
|
||||
return MAKE_SCRIPT_OBJECT( playlist ? playlist->getScriptObject() : 0 );
|
||||
}
|
40
Src/playlist/SPlaylists.h
Normal file
40
Src/playlist/SPlaylists.h
Normal file
@ -0,0 +1,40 @@
|
||||
#pragma once
|
||||
|
||||
#include <api/script/objcontroller.h>
|
||||
#include <api/script/objects/rootobj.h>
|
||||
|
||||
class PlaylistsScriptController : public ScriptObjectControllerI
|
||||
{
|
||||
public:
|
||||
const wchar_t *getClassName();
|
||||
const wchar_t *getAncestorClassName();
|
||||
ScriptObjectController *getAncestorController();
|
||||
int getNumFunctions();
|
||||
const function_descriptor_struct *getExportedFunctions();
|
||||
GUID getClassGuid();
|
||||
|
||||
ScriptObject *instantiate();
|
||||
void destroy( ScriptObject *o );
|
||||
|
||||
void *encapsulate( ScriptObject *o );
|
||||
void deencapsulate( void *o );
|
||||
|
||||
int getInstantiable();
|
||||
int getReferenceable();
|
||||
|
||||
private:
|
||||
static function_descriptor_struct exportedFunction[];
|
||||
};
|
||||
|
||||
class SPlaylists : public RootObjectInstance
|
||||
{
|
||||
public:
|
||||
SPlaylists();
|
||||
|
||||
static scriptVar script_vcpu_GetEnumerator( SCRIPT_FUNCTION_PARAMS, ScriptObject *o );
|
||||
static scriptVar script_vcpu_OpenPlaylist( SCRIPT_FUNCTION_PARAMS, ScriptObject *o, scriptVar scriptPlaylistGUID );
|
||||
static scriptVar script_vcpu_SavePlaylist( SCRIPT_FUNCTION_PARAMS, ScriptObject *o, scriptVar scriptPlaylistGUID, scriptVar scriptPlaylist );
|
||||
|
||||
private:
|
||||
|
||||
};
|
184
Src/playlist/SPlaylistsEnumerator.cpp
Normal file
184
Src/playlist/SPlaylistsEnumerator.cpp
Normal file
@ -0,0 +1,184 @@
|
||||
#include "SPlaylistsEnumerator.h"
|
||||
#include "api__playlist.h"
|
||||
#include <bfc/nsguid.h>
|
||||
#include "Playlists.h"
|
||||
|
||||
extern ScriptObjectController *script_root;
|
||||
extern PlaylistsEnumeratorScriptController playlistsEnumeratorController;
|
||||
|
||||
// {C18F8E50-2C81-4001-9F46-FD942B07ECCD}
|
||||
static const GUID makiPlaylistsEnumeratorGUID =
|
||||
{ 0xc18f8e50, 0x2c81, 0x4001, { 0x9f, 0x46, 0xfd, 0x94, 0x2b, 0x7, 0xec, 0xcd } };
|
||||
|
||||
// -- Functions table -------------------------------------
|
||||
function_descriptor_struct PlaylistsEnumeratorScriptController::exportedFunction[] = {
|
||||
{L"GetCount", 0, (void *)SPlaylistsEnumerator::script_vcpu_GetCount },
|
||||
{L"GetFilename", 1, (void *)SPlaylistsEnumerator::script_vcpu_GetFilename },
|
||||
{L"GetTitle", 1, (void *)SPlaylistsEnumerator::script_vcpu_GetTitle },
|
||||
{L"GetLength", 1, (void *)SPlaylistsEnumerator::script_vcpu_GetLength },
|
||||
{L"GetNumItems", 1, (void *)SPlaylistsEnumerator::script_vcpu_GetNumItems },
|
||||
{L"GetGUID", 1, (void *)SPlaylistsEnumerator::script_vcpu_GetGUID },
|
||||
|
||||
};
|
||||
// --------------------------------------------------------
|
||||
|
||||
const wchar_t *PlaylistsEnumeratorScriptController::getClassName()
|
||||
{
|
||||
return L"PlaylistsEnumerator";
|
||||
}
|
||||
|
||||
const wchar_t *PlaylistsEnumeratorScriptController::getAncestorClassName()
|
||||
{
|
||||
return L"Object";
|
||||
}
|
||||
|
||||
ScriptObjectController *PlaylistsEnumeratorScriptController::getAncestorController()
|
||||
{
|
||||
return script_root;
|
||||
}
|
||||
|
||||
ScriptObject *PlaylistsEnumeratorScriptController::instantiate()
|
||||
{
|
||||
SPlaylistsEnumerator *xd = new SPlaylistsEnumerator;
|
||||
ASSERT(xd != NULL);
|
||||
return xd->getScriptObject();
|
||||
}
|
||||
|
||||
void PlaylistsEnumeratorScriptController::destroy( ScriptObject *o )
|
||||
{
|
||||
SPlaylistsEnumerator *xd = static_cast<SPlaylistsEnumerator *>( o->vcpu_getInterface( makiPlaylistsEnumeratorGUID ) );
|
||||
ASSERT( xd != NULL );
|
||||
delete xd;
|
||||
}
|
||||
|
||||
void *PlaylistsEnumeratorScriptController::encapsulate( ScriptObject *o )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void PlaylistsEnumeratorScriptController::deencapsulate( void *o )
|
||||
{}
|
||||
|
||||
int PlaylistsEnumeratorScriptController::getNumFunctions()
|
||||
{
|
||||
return sizeof( exportedFunction ) / sizeof( function_descriptor_struct );
|
||||
}
|
||||
|
||||
const function_descriptor_struct *PlaylistsEnumeratorScriptController::getExportedFunctions()
|
||||
{
|
||||
return exportedFunction;
|
||||
}
|
||||
|
||||
GUID PlaylistsEnumeratorScriptController::getClassGuid()
|
||||
{
|
||||
return makiPlaylistsEnumeratorGUID;
|
||||
}
|
||||
|
||||
/* --- */
|
||||
|
||||
SPlaylistsEnumerator::SPlaylistsEnumerator()
|
||||
{
|
||||
getScriptObject()->vcpu_setInterface( makiPlaylistsEnumeratorGUID, static_cast<SPlaylistsEnumerator *>( this ) );
|
||||
getScriptObject()->vcpu_setClassName( L"PlaylistsEnumerator" );
|
||||
getScriptObject()->vcpu_setController( &playlistsEnumeratorController );
|
||||
}
|
||||
|
||||
SPlaylistsEnumerator::~SPlaylistsEnumerator()
|
||||
{
|
||||
//info.deleteAll();
|
||||
for (auto obj : info)
|
||||
{
|
||||
delete obj;
|
||||
}
|
||||
info.clear();
|
||||
}
|
||||
|
||||
scriptVar SPlaylistsEnumerator::script_vcpu_GetCount( SCRIPT_FUNCTION_PARAMS, ScriptObject *o )
|
||||
{
|
||||
SCRIPT_FUNCTION_INIT;
|
||||
SPlaylistsEnumerator *enumerator = static_cast<SPlaylistsEnumerator *>( o->vcpu_getInterface( makiPlaylistsEnumeratorGUID ) );
|
||||
if ( enumerator )
|
||||
{
|
||||
return MAKE_SCRIPT_INT( (int)enumerator->info.size() );
|
||||
}
|
||||
|
||||
return MAKE_SCRIPT_INT( 0 );
|
||||
}
|
||||
|
||||
static const wchar_t *static_splaylistsenumerator_empty_string = L"";
|
||||
scriptVar SPlaylistsEnumerator::script_vcpu_GetFilename( SCRIPT_FUNCTION_PARAMS, ScriptObject *o, scriptVar playlistNumber )
|
||||
{
|
||||
SCRIPT_FUNCTION_INIT;
|
||||
SPlaylistsEnumerator *enumerator = static_cast<SPlaylistsEnumerator *>( o->vcpu_getInterface( makiPlaylistsEnumeratorGUID ) );
|
||||
size_t i = GET_SCRIPT_INT( playlistNumber );
|
||||
if ( enumerator && i < enumerator->info.size() )
|
||||
{
|
||||
return MAKE_SCRIPT_STRING( enumerator->info[ i ]->filename );
|
||||
}
|
||||
|
||||
return MAKE_SCRIPT_STRING( static_splaylistsenumerator_empty_string );
|
||||
}
|
||||
|
||||
scriptVar SPlaylistsEnumerator::script_vcpu_GetTitle( SCRIPT_FUNCTION_PARAMS, ScriptObject *o, scriptVar playlistNumber )
|
||||
{
|
||||
SCRIPT_FUNCTION_INIT;
|
||||
SPlaylistsEnumerator *enumerator = static_cast<SPlaylistsEnumerator *>( o->vcpu_getInterface( makiPlaylistsEnumeratorGUID ) );
|
||||
size_t i = GET_SCRIPT_INT( playlistNumber );
|
||||
if ( enumerator && i < enumerator->info.size() )
|
||||
{
|
||||
return MAKE_SCRIPT_STRING( enumerator->info[ i ]->title );
|
||||
}
|
||||
|
||||
return MAKE_SCRIPT_STRING( static_splaylistsenumerator_empty_string );
|
||||
}
|
||||
|
||||
scriptVar SPlaylistsEnumerator::script_vcpu_GetLength( SCRIPT_FUNCTION_PARAMS, ScriptObject *o, scriptVar playlistNumber )
|
||||
{
|
||||
SCRIPT_FUNCTION_INIT;
|
||||
SPlaylistsEnumerator *enumerator = static_cast<SPlaylistsEnumerator *>( o->vcpu_getInterface( makiPlaylistsEnumeratorGUID ) );
|
||||
size_t i = GET_SCRIPT_INT( playlistNumber );
|
||||
if ( enumerator && i < enumerator->info.size() )
|
||||
{
|
||||
return MAKE_SCRIPT_INT( enumerator->info[ i ]->length );
|
||||
}
|
||||
|
||||
return MAKE_SCRIPT_INT( -1 );
|
||||
}
|
||||
|
||||
scriptVar SPlaylistsEnumerator::script_vcpu_GetNumItems( SCRIPT_FUNCTION_PARAMS, ScriptObject *o, scriptVar playlistNumber )
|
||||
{
|
||||
SCRIPT_FUNCTION_INIT;
|
||||
SPlaylistsEnumerator *enumerator = static_cast<SPlaylistsEnumerator *>( o->vcpu_getInterface( makiPlaylistsEnumeratorGUID ) );
|
||||
size_t i = GET_SCRIPT_INT( playlistNumber );
|
||||
if ( enumerator && i < enumerator->info.size() )
|
||||
{
|
||||
return MAKE_SCRIPT_INT( enumerator->info[ i ]->numItems );
|
||||
}
|
||||
|
||||
return MAKE_SCRIPT_INT( 0 );
|
||||
}
|
||||
|
||||
static wchar_t static_splaylistsenumerator_guid_string[39];
|
||||
scriptVar SPlaylistsEnumerator::script_vcpu_GetGUID( SCRIPT_FUNCTION_PARAMS, ScriptObject *o, scriptVar playlistNumber )
|
||||
{
|
||||
SCRIPT_FUNCTION_INIT;
|
||||
SPlaylistsEnumerator *enumerator = static_cast<SPlaylistsEnumerator *>( o->vcpu_getInterface( makiPlaylistsEnumeratorGUID ) );
|
||||
size_t i = GET_SCRIPT_INT( playlistNumber );
|
||||
if ( enumerator && i < enumerator->info.size() )
|
||||
{
|
||||
nsGUID::toCharW( enumerator->info[ i ]->guid, static_splaylistsenumerator_guid_string );
|
||||
return MAKE_SCRIPT_STRING( static_splaylistsenumerator_guid_string );
|
||||
}
|
||||
|
||||
return MAKE_SCRIPT_STRING( static_splaylistsenumerator_empty_string );
|
||||
}
|
||||
|
||||
void SPlaylistsEnumerator::Reserve( size_t count )
|
||||
{
|
||||
info.reserve( count );
|
||||
}
|
||||
|
||||
void SPlaylistsEnumerator::AppendPlaylist( const PlaylistInfo &newPlaylist )
|
||||
{
|
||||
info.push_back( new PlaylistInfo( newPlaylist ) );
|
||||
}
|
45
Src/playlist/SPlaylistsEnumerator.h
Normal file
45
Src/playlist/SPlaylistsEnumerator.h
Normal file
@ -0,0 +1,45 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <api/script/objcontroller.h>
|
||||
#include <api/script/objects/rootobj.h>
|
||||
#include "Playlists.h"
|
||||
#include <vector>
|
||||
|
||||
class PlaylistsEnumeratorScriptController : public ScriptObjectControllerI
|
||||
{
|
||||
public:
|
||||
const wchar_t *getClassName();
|
||||
const wchar_t *getAncestorClassName();
|
||||
ScriptObjectController *getAncestorController();
|
||||
int getNumFunctions();
|
||||
const function_descriptor_struct *getExportedFunctions();
|
||||
GUID getClassGuid();
|
||||
ScriptObject *instantiate();
|
||||
void destroy(ScriptObject *o);
|
||||
void *encapsulate(ScriptObject *o);
|
||||
void deencapsulate(void *o);
|
||||
|
||||
private:
|
||||
static function_descriptor_struct exportedFunction[];
|
||||
};
|
||||
|
||||
class SPlaylistsEnumerator : public RootObjectInstance
|
||||
{
|
||||
public:
|
||||
SPlaylistsEnumerator();
|
||||
~SPlaylistsEnumerator();
|
||||
|
||||
void Reserve(size_t count);
|
||||
void AppendPlaylist(const PlaylistInfo &newPlaylist);
|
||||
|
||||
static scriptVar script_vcpu_GetCount(SCRIPT_FUNCTION_PARAMS, ScriptObject *o);
|
||||
static scriptVar script_vcpu_GetFilename(SCRIPT_FUNCTION_PARAMS, ScriptObject *o, scriptVar itemNumber);
|
||||
static scriptVar script_vcpu_GetTitle(SCRIPT_FUNCTION_PARAMS, ScriptObject *o, scriptVar itemNumber);
|
||||
static scriptVar script_vcpu_GetLength(SCRIPT_FUNCTION_PARAMS, ScriptObject *o, scriptVar itemNumber);
|
||||
static scriptVar script_vcpu_GetNumItems(SCRIPT_FUNCTION_PARAMS, ScriptObject *o, scriptVar itemNumber);
|
||||
static scriptVar script_vcpu_GetGUID(SCRIPT_FUNCTION_PARAMS, ScriptObject *o, scriptVar itemNumber);
|
||||
|
||||
private:
|
||||
std::vector<PlaylistInfo*> info;
|
||||
};
|
67
Src/playlist/ScriptObjectFactory.cpp
Normal file
67
Src/playlist/ScriptObjectFactory.cpp
Normal file
@ -0,0 +1,67 @@
|
||||
#include "ScriptObjectFactory.h"
|
||||
#include "api__playlist.h"
|
||||
#include "ScriptObjectService.h"
|
||||
|
||||
ScriptObjectService svc;
|
||||
static const char serviceName[] = "Playlist Maki Objects";
|
||||
|
||||
// {2406A46C-9740-4af7-A0EB-A544AAB8F00C}
|
||||
static const GUID playlist_script_object_guid =
|
||||
{ 0x2406a46c, 0x9740, 0x4af7, { 0xa0, 0xeb, 0xa5, 0x44, 0xaa, 0xb8, 0xf0, 0xc } };
|
||||
|
||||
|
||||
FOURCC ScriptObjectFactory::GetServiceType()
|
||||
{
|
||||
return svc.getServiceType();
|
||||
}
|
||||
|
||||
const char *ScriptObjectFactory::GetServiceName()
|
||||
{
|
||||
return serviceName;
|
||||
}
|
||||
|
||||
GUID ScriptObjectFactory::GetGUID()
|
||||
{
|
||||
return playlist_script_object_guid;
|
||||
}
|
||||
|
||||
void *ScriptObjectFactory::GetInterface(int global_lock)
|
||||
{
|
||||
// if (global_lock)
|
||||
// WASABI_API_SVC->service_lock(this, (void *)ifc);
|
||||
return &svc;
|
||||
}
|
||||
|
||||
int ScriptObjectFactory::SupportNonLockingInterface()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
int ScriptObjectFactory::ReleaseInterface(void *ifc)
|
||||
{
|
||||
//WASABI_API_SVC->service_unlock(ifc);
|
||||
return 1;
|
||||
}
|
||||
|
||||
const char *ScriptObjectFactory::GetTestString()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ScriptObjectFactory::ServiceNotify(int msg, int param1, int param2)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
#define CBCLASS ScriptObjectFactory
|
||||
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
|
23
Src/playlist/ScriptObjectFactory.h
Normal file
23
Src/playlist/ScriptObjectFactory.h
Normal file
@ -0,0 +1,23 @@
|
||||
#pragma once
|
||||
|
||||
#include "api__playlist.h"
|
||||
#include <api/service/waservicefactory.h>
|
||||
#include <api/service/services.h>
|
||||
|
||||
class ScriptObjectFactory : 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;
|
||||
};
|
||||
|
||||
|
42
Src/playlist/ScriptObjectService.cpp
Normal file
42
Src/playlist/ScriptObjectService.cpp
Normal file
@ -0,0 +1,42 @@
|
||||
#include "ScriptObjectService.h"
|
||||
#include <api/script/objects/rootobjcontroller.h>
|
||||
#include "SPlaylist.h"
|
||||
#include "SPlaylists.h"
|
||||
#include "SPlaylistsEnumerator.h"
|
||||
#include "SPlaylistManager.h"
|
||||
|
||||
ScriptObjectController *script_root=0;
|
||||
PlaylistScriptController playlistController;
|
||||
PlaylistsScriptController playlistsController;
|
||||
PlaylistsEnumeratorScriptController playlistsEnumeratorController;
|
||||
PlaylistManagerScriptController playlistManagerController;
|
||||
|
||||
ScriptObjectController *ScriptObjectService::getController(int n)
|
||||
{
|
||||
switch (n)
|
||||
{
|
||||
case 0:
|
||||
return &playlistController;
|
||||
case 1:
|
||||
return &playlistsController;
|
||||
case 2:
|
||||
return &playlistsEnumeratorController;
|
||||
case 3:
|
||||
return &playlistManagerController;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void ScriptObjectService::onRegisterClasses(ScriptObjectController *rootController)
|
||||
{
|
||||
script_root = rootController;
|
||||
}
|
||||
|
||||
#define CBCLASS ScriptObjectService
|
||||
START_DISPATCH;
|
||||
CB(GETCONTROLLER, getController);
|
||||
VCB(ONREGISTER, onRegisterClasses);
|
||||
END_DISPATCH;
|
||||
#undef CBCLASS
|
11
Src/playlist/ScriptObjectService.h
Normal file
11
Src/playlist/ScriptObjectService.h
Normal file
@ -0,0 +1,11 @@
|
||||
#pragma once
|
||||
#include <api/service/svcs/svc_scriptobj.h>
|
||||
|
||||
class ScriptObjectService : public svc_scriptObject
|
||||
{
|
||||
public:
|
||||
ScriptObjectController *getController(int n);
|
||||
void onRegisterClasses(ScriptObjectController *rootController);
|
||||
protected:
|
||||
RECVS_DISPATCH;
|
||||
};
|
42
Src/playlist/XMLString.cpp
Normal file
42
Src/playlist/XMLString.cpp
Normal file
@ -0,0 +1,42 @@
|
||||
#include "main.h"
|
||||
#include "XMLString.h"
|
||||
#include "../nu/strsafe.h"
|
||||
|
||||
XMLString::XMLString()
|
||||
{
|
||||
data[ 0 ] = 0;
|
||||
}
|
||||
|
||||
void XMLString::Reset()
|
||||
{
|
||||
data[ 0 ] = 0;
|
||||
}
|
||||
|
||||
const wchar_t *XMLString::GetString()
|
||||
{
|
||||
return data;
|
||||
}
|
||||
|
||||
void XMLString::StartTag( const wchar_t *xmlpath, const wchar_t *xmltag, ifc_xmlreaderparams *params )
|
||||
{
|
||||
data[ 0 ] = 0;
|
||||
}
|
||||
|
||||
|
||||
void XMLString::TextHandler( const wchar_t *xmlpath, const wchar_t *xmltag, const wchar_t *str )
|
||||
{
|
||||
StringCchCatW( data, 256, str );
|
||||
}
|
||||
|
||||
|
||||
void XMLString::ManualSet( const wchar_t *string )
|
||||
{
|
||||
StringCchCatW( data, 256, string );
|
||||
}
|
||||
|
||||
#define CBCLASS XMLString
|
||||
START_DISPATCH;
|
||||
VCB( ONSTARTELEMENT, StartTag )
|
||||
VCB( ONCHARDATA, TextHandler )
|
||||
END_DISPATCH;
|
||||
#undef CBCLASS
|
29
Src/playlist/XMLString.h
Normal file
29
Src/playlist/XMLString.h
Normal file
@ -0,0 +1,29 @@
|
||||
#ifndef NULLSOFT_WINAMP_XMLSTRING_H
|
||||
#define NULLSOFT_WINAMP_XMLSTRING_H
|
||||
|
||||
|
||||
#include "../xml/ifc_xmlreadercallback.h"
|
||||
/*
|
||||
this one is an xml callback that just saves the last encountered string
|
||||
*/
|
||||
|
||||
|
||||
class XMLString : public ifc_xmlreadercallback
|
||||
{
|
||||
public:
|
||||
XMLString();
|
||||
void Reset();
|
||||
const wchar_t *GetString();
|
||||
void ManualSet(const wchar_t *string);
|
||||
private:
|
||||
/* XML callbacks */
|
||||
void StartTag(const wchar_t *xmlpath, const wchar_t *xmltag, ifc_xmlreaderparams *params);
|
||||
void EndTag(const wchar_t *xmlpath, const wchar_t *xmltag);
|
||||
void TextHandler(const wchar_t *xmlpath, const wchar_t *xmltag, const wchar_t *str);
|
||||
|
||||
wchar_t data[256]; // for now, we'll make it dynamic later
|
||||
|
||||
RECVS_DISPATCH;
|
||||
};
|
||||
|
||||
#endif
|
49
Src/playlist/_ifc_playlistentry.h
Normal file
49
Src/playlist/_ifc_playlistentry.h
Normal file
@ -0,0 +1,49 @@
|
||||
#ifndef NULLSOFT_IFC_PLAYLIST_ENTRY_H
|
||||
#define NULLSOFT_IFC_PLAYLIST_ENTRY_H
|
||||
|
||||
#include <bfc/dispatch.h>
|
||||
|
||||
class ifc_playlistentry : public Dispatchable
|
||||
{
|
||||
protected:
|
||||
ifc_playlistentry() {}
|
||||
~ifc_playlistentry() {}
|
||||
|
||||
|
||||
public:
|
||||
DISPATCH_CODES
|
||||
{
|
||||
IFC_PLAYLISTENTRY_GETFILENAME = 10,
|
||||
IFC_PLAYLISTENTRY_GETTITLE = 20,
|
||||
IFC_PLAYLISTENTRY_GETLENGTHMS = 30,
|
||||
IFC_PLAYLISTENTRY_GETEXTENDEDINFO = 40,
|
||||
};
|
||||
|
||||
|
||||
size_t GetFilename( wchar_t *filename, size_t filenameCch );
|
||||
size_t GetTitle( wchar_t *title, size_t titleCch );
|
||||
int GetLengthInMilliseconds();
|
||||
size_t GetExtendedInfo( const wchar_t *metadata, wchar_t *info, size_t infoCch );
|
||||
};
|
||||
|
||||
inline size_t ifc_playlistentry::GetFilename( wchar_t *filename, size_t filenameCch )
|
||||
{
|
||||
return _call( IFC_PLAYLISTENTRY_GETFILENAME, (size_t)0, filename, filenameCch );
|
||||
}
|
||||
|
||||
inline size_t ifc_playlistentry::GetTitle( wchar_t *title, size_t titleCch )
|
||||
{
|
||||
return _call( IFC_PLAYLISTENTRY_GETTITLE, (size_t)0, title, titleCch );
|
||||
}
|
||||
|
||||
inline int ifc_playlistentry::GetLengthInMilliseconds()
|
||||
{
|
||||
return _call( IFC_PLAYLISTENTRY_GETLENGTHMS, (int)-1 );
|
||||
}
|
||||
|
||||
inline size_t ifc_playlistentry::GetExtendedInfo( const wchar_t *metadata, wchar_t *info, size_t infoCch )
|
||||
{
|
||||
return _call( IFC_PLAYLISTENTRY_GETEXTENDEDINFO, (size_t)0, metadata, info, infoCch );
|
||||
}
|
||||
|
||||
#endif
|
58
Src/playlist/api__playlist.h
Normal file
58
Src/playlist/api__playlist.h
Normal file
@ -0,0 +1,58 @@
|
||||
#ifndef NULLSOFT_PLAYLIST_API_H
|
||||
#define NULLSOFT_PLAYLIST_API_H
|
||||
|
||||
#include <api/service/api_service.h>
|
||||
|
||||
#include <api/application/api_application.h>
|
||||
#define WASABI_API_APP applicationApi
|
||||
|
||||
#include <api/syscb/api_syscb.h>
|
||||
#define WASABI_API_SYSCB sysCallbackApi
|
||||
|
||||
#ifndef ML_PLG_EXPORTS
|
||||
#include "../Agave/Config/api_config.h"
|
||||
#endif
|
||||
|
||||
#include <api/script/api_maki.h>
|
||||
#define WASABI_API_MAKI makiApi
|
||||
|
||||
#include "../Winamp/JSAPI2_api_security.h"
|
||||
extern JSAPI2::api_security *jsapi2_security;
|
||||
#define AGAVE_API_JSAPI2_SECURITY jsapi2_security
|
||||
|
||||
#include "../Winamp/api_stats.h"
|
||||
extern api_stats *statsApi;
|
||||
#define AGAVE_API_STATS statsApi
|
||||
|
||||
#include <api/service/waservicefactory.h>
|
||||
|
||||
template <class api_t>
|
||||
class QuickService
|
||||
{
|
||||
public:
|
||||
QuickService( GUID p_serviceGUID )
|
||||
{
|
||||
_sf = WASABI_API_SVC->service_getServiceByGuid( p_serviceGUID );
|
||||
if ( _sf )
|
||||
_api = (api_t *)_sf->getInterface();
|
||||
}
|
||||
~QuickService()
|
||||
{
|
||||
_sf->releaseInterface( _api );
|
||||
_api = 0;
|
||||
}
|
||||
bool OK()
|
||||
{
|
||||
return _api != 0;
|
||||
}
|
||||
api_t *operator ->()
|
||||
{
|
||||
return _api;
|
||||
}
|
||||
waServiceFactory *_sf = NULL;
|
||||
api_t *_api = 0;
|
||||
};
|
||||
|
||||
#include "../Agave/Language/api_language.h"
|
||||
|
||||
#endif // !NULLSOFT_PLAYLIST_API_H
|
161
Src/playlist/api_playlistmanager.h
Normal file
161
Src/playlist/api_playlistmanager.h
Normal file
@ -0,0 +1,161 @@
|
||||
#ifndef NULLSOFT_API_PLAYLISTMANAGER_H
|
||||
#define NULLSOFT_API_PLAYLISTMANAGER_H
|
||||
|
||||
#include <bfc/dispatch.h>
|
||||
|
||||
class ifc_playlistloadercallback;
|
||||
class ifc_playlist;
|
||||
class ifc_playlistdirectorycallback;
|
||||
enum
|
||||
{
|
||||
PLAYLISTMANAGER_SUCCESS = 0,
|
||||
|
||||
PLAYLISTMANAGER_FAILED = 1,
|
||||
PLAYLISTMANAGER_LOAD_NO_LOADER = 1,
|
||||
PLAYLISTMANAGER_LOAD_LOADER_OPEN_FAILED = 2,
|
||||
};
|
||||
|
||||
class api_playlistmanager : public Dispatchable
|
||||
{
|
||||
protected:
|
||||
api_playlistmanager() {}
|
||||
~api_playlistmanager() {}
|
||||
|
||||
public:
|
||||
int Load( const wchar_t *filename, ifc_playlistloadercallback *playlist );
|
||||
int LoadAs( const wchar_t *filename, const wchar_t *ext, ifc_playlistloadercallback *playlist ); // call with ext in the format ".pls"
|
||||
int LoadFromDialog( const wchar_t *fns, ifc_playlistloadercallback *playlist );
|
||||
int LoadFromANSIDialog( const char *fns, ifc_playlistloadercallback *playlist );
|
||||
|
||||
int Save( const wchar_t *filename, ifc_playlist *playlist );
|
||||
|
||||
size_t Copy( const wchar_t *destFn, const wchar_t *srcFn ); // returns number of items copied
|
||||
|
||||
size_t CountItems( const wchar_t *filename );
|
||||
|
||||
int GetLengthMilliseconds( const wchar_t *filename );
|
||||
uint64_t GetLongLengthMilliseconds( const wchar_t *filename );
|
||||
|
||||
void Randomize( ifc_playlist *playlist );
|
||||
void Reverse( ifc_playlist *playlist );
|
||||
|
||||
void LoadDirectory( const wchar_t *directory, ifc_playlistloadercallback *callback, ifc_playlistdirectorycallback *dirCallback );
|
||||
|
||||
bool CanLoad( const wchar_t *filename );
|
||||
|
||||
void GetExtensionList( wchar_t *extensionList, size_t extensionListCch );
|
||||
void GetFilterList( wchar_t *extensionList, size_t extensionListCch );
|
||||
|
||||
const wchar_t *EnumExtension( size_t num );
|
||||
|
||||
public:
|
||||
DISPATCH_CODES
|
||||
{
|
||||
API_PLAYLISTMANAGER_LOAD = 10,
|
||||
API_PLAYLISTMANAGER_LOADNULLDELIMITED = 11,
|
||||
API_PLAYLISTMANAGER_LOADNULLDELIMITED_ANSI = 12,
|
||||
API_PLAYLISTMANAGER_LOADAS = 13,
|
||||
API_PLAYLISTMANAGER_SAVE = 20,
|
||||
API_PLAYLISTMANAGER_COPY = 30,
|
||||
API_PLAYLISTMANAGER_COUNT = 40,
|
||||
API_PLAYLISTMANAGER_GETLENGTH = 50,
|
||||
API_PLAYLISTMANAGER_GETLONGLENGTH = 51,
|
||||
API_PLAYLISTMANAGER_LOADDIRECTORY = 60,
|
||||
API_PLAYLISTMANAGER_RANDOMIZE = 100,
|
||||
API_PLAYLISTMANAGER_REVERSE = 110,
|
||||
API_PLAYLISTMANAGER_CANLOAD = 120,
|
||||
API_PLAYLISTMANAGER_GETEXTENSIONLIST = 130,
|
||||
API_PLAYLISTMANAGER_GETFILTERLIST = 140,
|
||||
API_PLAYLISTMANAGER_ENUMEXTENSION = 150,
|
||||
};
|
||||
};
|
||||
|
||||
inline void api_playlistmanager::GetFilterList( wchar_t *extensionList, size_t extensionListCch )
|
||||
{
|
||||
extensionList[ 0 ] = 0; // just in case no one implements it
|
||||
extensionList[ 1 ] = 0;
|
||||
|
||||
_voidcall( API_PLAYLISTMANAGER_GETFILTERLIST, extensionList, extensionListCch );
|
||||
}
|
||||
|
||||
inline int api_playlistmanager::LoadAs( const wchar_t *filename, const wchar_t *ext, ifc_playlistloadercallback *playlist )
|
||||
{
|
||||
return _call( API_PLAYLISTMANAGER_LOADAS, (int)PLAYLISTMANAGER_FAILED, filename, ext, playlist );
|
||||
}
|
||||
|
||||
inline void api_playlistmanager::GetExtensionList( wchar_t *extensionList, size_t extensionListCch )
|
||||
{
|
||||
extensionList[ 0 ] = 0; // just in case no one implements it
|
||||
_voidcall( API_PLAYLISTMANAGER_GETEXTENSIONLIST, extensionList, extensionListCch );
|
||||
}
|
||||
|
||||
inline int api_playlistmanager::Load( const wchar_t *filename, ifc_playlistloadercallback *playlist )
|
||||
{
|
||||
return _call( API_PLAYLISTMANAGER_LOAD, (int)PLAYLISTMANAGER_FAILED, filename, playlist );
|
||||
}
|
||||
|
||||
inline int api_playlistmanager::LoadFromDialog( const wchar_t *filename, ifc_playlistloadercallback *playlist )
|
||||
{
|
||||
return _call( API_PLAYLISTMANAGER_LOADNULLDELIMITED, (int)PLAYLISTMANAGER_FAILED, filename, playlist );
|
||||
}
|
||||
|
||||
inline int api_playlistmanager::LoadFromANSIDialog( const char *filename, ifc_playlistloadercallback *playlist )
|
||||
{
|
||||
return _call( API_PLAYLISTMANAGER_LOADNULLDELIMITED_ANSI, (int)PLAYLISTMANAGER_FAILED, filename, playlist );
|
||||
}
|
||||
|
||||
inline int api_playlistmanager::Save( const wchar_t *filename, ifc_playlist *playlist )
|
||||
{
|
||||
return _call( API_PLAYLISTMANAGER_SAVE, (int)PLAYLISTMANAGER_FAILED, filename, playlist );
|
||||
}
|
||||
|
||||
inline size_t api_playlistmanager::Copy( const wchar_t *destFn, const wchar_t *srcFn )
|
||||
{
|
||||
return _call( API_PLAYLISTMANAGER_COPY, (size_t)0, destFn, srcFn );
|
||||
}
|
||||
|
||||
inline size_t api_playlistmanager::CountItems( const wchar_t *filename )
|
||||
{
|
||||
return _call( API_PLAYLISTMANAGER_COUNT, (size_t)0, filename );
|
||||
}
|
||||
|
||||
inline int api_playlistmanager::GetLengthMilliseconds( const wchar_t *filename )
|
||||
{
|
||||
return _call( API_PLAYLISTMANAGER_GETLENGTH, (int)0, filename );
|
||||
}
|
||||
|
||||
inline uint64_t api_playlistmanager::GetLongLengthMilliseconds( const wchar_t *filename )
|
||||
{
|
||||
return _call( API_PLAYLISTMANAGER_GETLONGLENGTH, (uint64_t)0, filename );
|
||||
}
|
||||
|
||||
inline void api_playlistmanager::Randomize( ifc_playlist *playlist )
|
||||
{
|
||||
_voidcall( API_PLAYLISTMANAGER_RANDOMIZE, playlist );
|
||||
}
|
||||
|
||||
inline void api_playlistmanager::Reverse( ifc_playlist *playlist )
|
||||
{
|
||||
_voidcall( API_PLAYLISTMANAGER_REVERSE, playlist );
|
||||
}
|
||||
|
||||
inline void api_playlistmanager::LoadDirectory( const wchar_t *directory, ifc_playlistloadercallback *callback, ifc_playlistdirectorycallback *dirCallback )
|
||||
{
|
||||
_voidcall( API_PLAYLISTMANAGER_LOADDIRECTORY, directory, callback, dirCallback );
|
||||
}
|
||||
|
||||
inline bool api_playlistmanager::CanLoad( const wchar_t *filename )
|
||||
{
|
||||
return _call( API_PLAYLISTMANAGER_CANLOAD, (bool)true, filename );
|
||||
}
|
||||
|
||||
inline const wchar_t *api_playlistmanager::EnumExtension( size_t num )
|
||||
{
|
||||
return _call( API_PLAYLISTMANAGER_ENUMEXTENSION, (const wchar_t *)0, num );
|
||||
}
|
||||
|
||||
// {C5618774-7177-43aa-9906-933C9F40EBDC}
|
||||
static const GUID api_playlistmanagerGUID =
|
||||
{ 0xc5618774, 0x7177, 0x43aa, { 0x99, 0x6, 0x93, 0x3c, 0x9f, 0x40, 0xeb, 0xdc } };
|
||||
|
||||
#endif
|
290
Src/playlist/api_playlists.h
Normal file
290
Src/playlist/api_playlists.h
Normal file
@ -0,0 +1,290 @@
|
||||
#ifndef NULLSOFT_PLAYLIST_API_PLAYLISTS_H
|
||||
#define NULLSOFT_PLAYLIST_API_PLAYLISTS_H
|
||||
|
||||
#include <bfc/dispatch.h>
|
||||
#include <bfc/platform/guid.h>
|
||||
#include <bfc/std_mkncc.h>
|
||||
// manages Winamp's master list of playlists
|
||||
|
||||
/* Important note to users of this API:
|
||||
This API does not actually parse or in any way read the contents of the playlist files themselves.
|
||||
It only manages the master "list" of playlists, used in e.g. ml_playlists.
|
||||
|
||||
--- important ---
|
||||
This also means that some information retrieved through this API can be inaccurate,
|
||||
such as playlist item length or total time. These values are provided as a cache,
|
||||
to speed up display of UI. They are not to be relied on for determining how many items
|
||||
are actually in the playlist. Don't use this value to allocate memory for data structures,
|
||||
unless it's just an initial guess and you allow for realloc'ing if the count is higher.
|
||||
-----------------
|
||||
|
||||
It is recommended (but not required) that you call SetInfo to update calculated values,
|
||||
such as playlist item length, whenever you parse the playlist and have accurate information.
|
||||
|
||||
If you need playlist parsing, use api_playlistmanager.
|
||||
|
||||
This API is thread-safe, as long as you properly call Lock/Unlock
|
||||
Methods which don't require external locking are marked with [*]
|
||||
Note that these methods still lock internally
|
||||
*/
|
||||
|
||||
enum
|
||||
{
|
||||
API_PLAYLISTS_SUCCESS = 0,
|
||||
API_PLAYLISTS_FAILURE = 1, // general purpose failure
|
||||
API_PLAYLISTS_UNKNOWN_INFO_GUID = 2, // bad GUID passed to Set/GetInfo
|
||||
API_PLAYLISTS_UNABLE_TO_LOAD_PLAYLISTS = 3, // take that variable name, FORTRAN77!
|
||||
API_PLAYLISTS_INVALID_INDEX = 4, // index you passed was out of range
|
||||
API_PLAYLISTS_BAD_SIZE = 5, // bad dataLen passed to Set/GetInfo
|
||||
};
|
||||
|
||||
class api_playlists : public Dispatchable
|
||||
{
|
||||
protected:
|
||||
api_playlists() {}
|
||||
virtual ~api_playlists() {}
|
||||
|
||||
public:
|
||||
// call these to lock the list of playlists so no one changes in the middle of an operation. be careful with this!
|
||||
// you can use AutoLockT<api_playlists> to help you out
|
||||
// indices are only valid between these two calls. call GetGUID() if you need session-persistent identifiers
|
||||
void Lock();
|
||||
void Unlock();
|
||||
|
||||
size_t GetIterator();
|
||||
/* this value changes each time a modification is made that would invalidate indices previously retrieved.
|
||||
It does not change when information is changed
|
||||
Use it to test if your index is out of date.
|
||||
example:
|
||||
size_t playlistIterator = playlists->GetIterator();
|
||||
playlists->GetPosition(myGUID, &index);
|
||||
// ... do a bunch of stuff
|
||||
if (playlistIterator != playlists->GetIterator())
|
||||
playlists->GetPosition(myGUID, &index);
|
||||
|
||||
This is meant as a tool to aid implementations that want to cache indices to prevent too many GetPosition() lookups
|
||||
you don't need this function for casual usage of the API
|
||||
*/
|
||||
|
||||
int Sort( size_t sort_type );
|
||||
|
||||
void Flush(); // [*] flushes playlists to disk. avoid usage - mainly useful when some program is parsing the playlists.xml file externally
|
||||
|
||||
// get information about playlists
|
||||
size_t GetCount(); // returns number of playlists
|
||||
|
||||
const wchar_t *GetFilename( size_t index ); // returns API_PLAYLISTS_SUCCESS or API_PLAYLISTS_FAILURE. only valid until you Unlock()
|
||||
const wchar_t *GetName( size_t index ); // returns API_PLAYLISTS_SUCCESS or API_PLAYLISTS_FAILURE. only valid until you Unlock()
|
||||
|
||||
GUID GetGUID( size_t index ); // retrieves a unique ID which identifies this playlist
|
||||
|
||||
int GetPosition( GUID playlist_guid, size_t *index ); // retrieves the index where a particular playlist ID lives. returns API_PLAYLISTS_SUCCESS or API_PLAYLISTS_FAILURE
|
||||
int GetInfo( size_t index, GUID info, void *data, size_t dataLen ); // This is for getting "extra" data, see list of GUIDs below. returns API_PLAYLISTS_SUCCESS or API_PLAYLISTS_FAILURE
|
||||
|
||||
// manipulating playlists
|
||||
// at this time, it is not recommended that you use this API. It is reserved for ml_playlists.
|
||||
int MoveBefore( size_t index1, size_t index2 ); // moves playlist at position index1 to before index2. setting index2 to anything larger than GetCount() moves to end
|
||||
|
||||
size_t AddPlaylist( const wchar_t *filename, const wchar_t *playlistName, GUID playlist_guid = INVALID_GUID ); // [*] adds a new playlist, returns new index. Generates a GUID if you don't pass third parameter. returns (size_t)-1 on error and (size_t)-2 if already exists
|
||||
// note: AddPlaylist locks internally, but you need to lock externally if you want to trust the return value
|
||||
|
||||
size_t AddCloudPlaylist( const wchar_t *filename, const wchar_t *playlistName, GUID playlist_guid = INVALID_GUID ); // [*] adds a new playlist, returns new index. Generates a GUID if you don't pass third parameter. returns (size_t)-1 on error and (size_t)-2 if already exists
|
||||
// note: AddCloudPlaylist locks internally, but you need to lock externally if you want to trust the return value
|
||||
|
||||
size_t AddPlaylist_NoCallback( const wchar_t *filename, const wchar_t *playlistName, GUID playlist_guid = INVALID_GUID );
|
||||
// same as AddPlaylist, but doesn't do a syscallback, use when you want to make a few SetInfo calls,
|
||||
// when you are done, call WASABI_API_SYSCB->syscb_issueCallback(api_playlists::SYSCALLBACK, api_playlists::PLAYLIST_REMOVED_POST, index, 0); yourself
|
||||
|
||||
int SetGUID( size_t index, GUID playlist_guid ); // sets (overrides) a playlist ID. Don't use unless you have some very specific need
|
||||
int RenamePlaylist( size_t index, const wchar_t *name );
|
||||
int MovePlaylist( size_t index, const wchar_t *filename ); // sets a new filename. NOTE: IT'S UP TO YOU TO PHYSICALLY MOVE/RENAME/CREATE THE NEW FILENAME.
|
||||
int SetInfo( size_t index, GUID info, void *data, size_t dataLen ); // returns API_PLAYLISTS_SUCCESS or API_PLAYLISTS_FAILURE
|
||||
int RemovePlaylist( size_t index ); // removes a particular playlist
|
||||
int ClearPlaylists(); // [*] clears the entire list of playlists. Use at your own risk :)
|
||||
|
||||
/*
|
||||
callbacks. these are sent through api_syscb.
|
||||
callbacks are typically done within the api_playlists Lock,
|
||||
so be careful not to deadlock by waiting on another thread that is also using api_playlists
|
||||
TODO
|
||||
probably want move, remove, add
|
||||
need to think through adding, though. Someone might add a playlist and then SetInfo, so don't want to call syscb too early
|
||||
*/
|
||||
|
||||
enum
|
||||
{
|
||||
SYSCALLBACK = MK4CC( 'p', 'l', 'a', 'y' ),
|
||||
PLAYLIST_ADDED = 10, // param1 = index
|
||||
PLAYLIST_REMOVED_PRE = 20, // param1 = index, called BEFORE it's removed internally, so you can still query for data (Get* function calls)
|
||||
PLAYLIST_REMOVED_POST = 30, // no parameters, called after it's removed internally
|
||||
PLAYLIST_RENAMED = 40, // param1 = index
|
||||
/* These two callbacks are made by you (not api_playlists)
|
||||
* pass some unique ID as param2 (e.g. some function pointer or pointer to a global variable)
|
||||
* so that you can identify your own callbacks if you also listen for these events
|
||||
*/
|
||||
PLAYLIST_SAVED = 50, // param1 = index. You should send this when you save a playlist. Surround with Lock()/Unlock() so that the index is valid
|
||||
PLAYLIST_FLUSH_REQUEST = 60, // param1 = index. Call before you load a playlist to request anyone who might be currently modifying the same playlist to save
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
SORT_TITLE_ASCENDING,
|
||||
SORT_TITLE_DESCENDING,
|
||||
SORT_NUMBER_ASCENDING,
|
||||
SORT_NUMBER_DESCENDING,
|
||||
};
|
||||
|
||||
DISPATCH_CODES
|
||||
{
|
||||
API_PLAYLISTS_LOCK = 10,
|
||||
API_PLAYLISTS_UNLOCK = 20,
|
||||
API_PLAYLISTS_GETITERATOR = 30,
|
||||
API_PLAYLISTS_FLUSH = 40,
|
||||
API_PLAYLISTS_GETCOUNT = 50,
|
||||
API_PLAYLISTS_GETFILENAME = 60,
|
||||
API_PLAYLISTS_GETNAME = 70,
|
||||
API_PLAYLISTS_GETGUID = 80,
|
||||
API_PLAYLISTS_GETPOSITION = 90,
|
||||
API_PLAYLISTS_GETINFO = 100,
|
||||
API_PLAYLISTS_MOVEBEFORE = 110,
|
||||
API_PLAYLISTS_ADDPLAYLIST = 120,
|
||||
API_PLAYLISTS_ADDPLAYLISTNOCB = 121,
|
||||
API_PLAYLISTS_ADDCLOUDPLAYLIST = 122,
|
||||
API_PLAYLISTS_SETGUID = 130,
|
||||
API_PLAYLISTS_RENAMEPLAYLIST = 140,
|
||||
API_PLAYLISTS_MOVEPLAYLIST = 150,
|
||||
API_PLAYLISTS_SETINFO = 160,
|
||||
API_PLAYLISTS_REMOVEPLAYLIST = 170,
|
||||
API_PLAYLISTS_CLEARPLAYLISTS = 180,
|
||||
API_PLAYLISTS_SORT = 190,
|
||||
};
|
||||
};
|
||||
|
||||
// Info GUIDS
|
||||
|
||||
// {C4FAD6CE-DA38-47b0-AAA9-E966D8E8E7C5}
|
||||
static const GUID api_playlists_itemCount =
|
||||
{ 0xc4fad6ce, 0xda38, 0x47b0, { 0xaa, 0xa9, 0xe9, 0x66, 0xd8, 0xe8, 0xe7, 0xc5 } };
|
||||
|
||||
// {D4E0E000-A3F5-4f18-ADA5-F2BA40689593}
|
||||
static const GUID api_playlists_totalTime =
|
||||
{ 0xd4e0e000, 0xa3f5, 0x4f18, { 0xad, 0xa5, 0xf2, 0xba, 0x40, 0x68, 0x95, 0x93 } };
|
||||
|
||||
// {F6E1AB19-6931-4cc9-BCBA-4B40DE2A959F}
|
||||
static const GUID api_playlists_iTunesID =
|
||||
{ 0xf6e1ab19, 0x6931, 0x4cc9, { 0xbc, 0xba, 0x4b, 0x40, 0xde, 0x2a, 0x95, 0x9f } };
|
||||
|
||||
// {B83AD244-7CD3-4a24-B2C5-41F42CA37F14}
|
||||
static const GUID api_playlists_cloud =
|
||||
{ 0xb83ad244, 0x7cd3, 0x4a24, { 0xb2, 0xc5, 0x41, 0xf4, 0x2c, 0xa3, 0x7f, 0x14 } };
|
||||
|
||||
|
||||
inline void api_playlists::Lock()
|
||||
{
|
||||
_voidcall( API_PLAYLISTS_LOCK );
|
||||
}
|
||||
inline void api_playlists::Unlock()
|
||||
{
|
||||
_voidcall( API_PLAYLISTS_UNLOCK );
|
||||
}
|
||||
|
||||
inline size_t api_playlists::GetIterator()
|
||||
{
|
||||
return _call( API_PLAYLISTS_GETITERATOR, 0 );
|
||||
}
|
||||
|
||||
inline void api_playlists::Flush()
|
||||
{
|
||||
_voidcall( API_PLAYLISTS_FLUSH );
|
||||
}
|
||||
|
||||
inline int api_playlists::Sort( size_t sort_type )
|
||||
{
|
||||
return _call( API_PLAYLISTS_SORT, 0, sort_type );
|
||||
}
|
||||
|
||||
inline size_t api_playlists::GetCount()
|
||||
{
|
||||
return _call( API_PLAYLISTS_GETCOUNT, 0 );
|
||||
}
|
||||
|
||||
inline const wchar_t *api_playlists::GetFilename( size_t index )
|
||||
{
|
||||
return _call( API_PLAYLISTS_GETFILENAME, (const wchar_t *)0, index );
|
||||
}
|
||||
|
||||
inline const wchar_t *api_playlists::GetName( size_t index )
|
||||
{
|
||||
return _call( API_PLAYLISTS_GETNAME, (const wchar_t *)0, index );
|
||||
}
|
||||
|
||||
inline GUID api_playlists::GetGUID( size_t index )
|
||||
{
|
||||
return _call( API_PLAYLISTS_GETGUID, INVALID_GUID, index );
|
||||
}
|
||||
|
||||
inline int api_playlists::GetPosition( GUID playlist_guid, size_t *index )
|
||||
{
|
||||
return _call( API_PLAYLISTS_GETPOSITION, API_PLAYLISTS_FAILURE, playlist_guid, index );
|
||||
}
|
||||
|
||||
inline int api_playlists::GetInfo( size_t index, GUID info, void *data, size_t dataLen )
|
||||
{
|
||||
return _call( API_PLAYLISTS_GETINFO, API_PLAYLISTS_FAILURE, index, info, data, dataLen );
|
||||
}
|
||||
|
||||
inline int api_playlists::MoveBefore( size_t index1, size_t index2 )
|
||||
{
|
||||
return _call( API_PLAYLISTS_MOVEBEFORE, API_PLAYLISTS_FAILURE, index1, index2 );
|
||||
}
|
||||
|
||||
inline size_t api_playlists::AddPlaylist( const wchar_t *filename, const wchar_t *playlistName, GUID playlist_guid )
|
||||
{
|
||||
return _call( API_PLAYLISTS_ADDPLAYLIST, (size_t)-1, filename, playlistName, playlist_guid );
|
||||
}
|
||||
|
||||
inline size_t api_playlists::AddPlaylist_NoCallback( const wchar_t *filename, const wchar_t *playlistName, GUID playlist_guid )
|
||||
{
|
||||
return _call( API_PLAYLISTS_ADDPLAYLISTNOCB, (size_t)-1, filename, playlistName, playlist_guid );
|
||||
}
|
||||
|
||||
inline size_t api_playlists::AddCloudPlaylist( const wchar_t *filename, const wchar_t *playlistName, GUID playlist_guid )
|
||||
{
|
||||
return _call( API_PLAYLISTS_ADDCLOUDPLAYLIST, (size_t)-1, filename, playlistName, playlist_guid );
|
||||
}
|
||||
|
||||
inline int api_playlists::SetGUID( size_t index, GUID playlist_guid )
|
||||
{
|
||||
return _call( API_PLAYLISTS_SETGUID, API_PLAYLISTS_FAILURE, index, playlist_guid );
|
||||
}
|
||||
|
||||
inline int api_playlists::RenamePlaylist( size_t index, const wchar_t *name )
|
||||
{
|
||||
return _call( API_PLAYLISTS_RENAMEPLAYLIST, API_PLAYLISTS_FAILURE, index, name );
|
||||
}
|
||||
|
||||
inline int api_playlists::MovePlaylist( size_t index, const wchar_t *filename )
|
||||
{
|
||||
return _call( API_PLAYLISTS_MOVEPLAYLIST, API_PLAYLISTS_FAILURE, index, filename );
|
||||
}
|
||||
|
||||
inline int api_playlists::SetInfo( size_t index, GUID info, void *data, size_t dataLen )
|
||||
{
|
||||
return _call( API_PLAYLISTS_SETINFO, API_PLAYLISTS_FAILURE, index, info, data, dataLen );
|
||||
}
|
||||
|
||||
inline int api_playlists::RemovePlaylist( size_t index )
|
||||
{
|
||||
return _call( API_PLAYLISTS_REMOVEPLAYLIST, API_PLAYLISTS_FAILURE, index );
|
||||
}
|
||||
|
||||
inline int api_playlists::ClearPlaylists()
|
||||
{
|
||||
return _call( API_PLAYLISTS_CLEARPLAYLISTS, API_PLAYLISTS_FAILURE );
|
||||
}
|
||||
|
||||
// {2DC3C390-D9B8-4a49-B230-EF240ADDDCDB}
|
||||
static const GUID api_playlistsGUID =
|
||||
{ 0x2dc3c390, 0xd9b8, 0x4a49, { 0xb2, 0x30, 0xef, 0x24, 0xa, 0xdd, 0xdc, 0xdb } };
|
||||
|
||||
#endif
|
97
Src/playlist/factory_Handler.cpp
Normal file
97
Src/playlist/factory_Handler.cpp
Normal file
@ -0,0 +1,97 @@
|
||||
#include "api__playlist.h"
|
||||
#include "factory_Handler.h"
|
||||
#include "handler.h"
|
||||
#include "api/service/services.h"
|
||||
|
||||
M3UHandler m3uHandler;
|
||||
PLSHandler plsHandler;
|
||||
B4SHandler b4sHandler;
|
||||
|
||||
static const char m3uServiceName[] = "M3U Playlist Handler";
|
||||
static const char plsServiceName[] = "PLS Playlist Handler";
|
||||
|
||||
#define DEFINE_HANDLER_FACTORY(CLASSNAME, className) const char *CLASSNAME ## HandlerFactory::GetServiceName() { return #CLASSNAME ## "Playlist Handler"; }\
|
||||
GUID CLASSNAME ## HandlerFactory::GetGUID(){ return className ## HandlerGUID;}\
|
||||
void *CLASSNAME ## HandlerFactory::GetInterface(int global_lock){ return &className ## Handler;}
|
||||
|
||||
DEFINE_HANDLER_FACTORY(M3U, m3u);
|
||||
DEFINE_HANDLER_FACTORY(PLS, pls);
|
||||
DEFINE_HANDLER_FACTORY(B4S, b4s);
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
FOURCC CommonHandlerFactory::GetServiceType()
|
||||
{
|
||||
return WaSvc::PLAYLISTHANDLER;
|
||||
}
|
||||
|
||||
int CommonHandlerFactory::SupportNonLockingInterface()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
int CommonHandlerFactory::ReleaseInterface(void *ifc)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
const char *CommonHandlerFactory::GetTestString()
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int CommonHandlerFactory::ServiceNotify(int msg, int param1, int param2)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
#ifdef CBCLASS
|
||||
#undef CBCLASS
|
||||
#endif
|
||||
|
||||
#define CBCLASS M3UHandlerFactory
|
||||
START_DISPATCH;
|
||||
CB(WASERVICEFACTORY_GETSERVICENAME, GetServiceName)
|
||||
CB(WASERVICEFACTORY_GETGUID, GetGUID)
|
||||
CB(WASERVICEFACTORY_GETINTERFACE, GetInterface)
|
||||
#undef CBCLASS
|
||||
#define CBCLASS CommonHandlerFactory
|
||||
CB(WASERVICEFACTORY_GETSERVICETYPE, GetServiceType)
|
||||
CB(WASERVICEFACTORY_SUPPORTNONLOCKINGGETINTERFACE, SupportNonLockingInterface)
|
||||
CB(WASERVICEFACTORY_RELEASEINTERFACE, ReleaseInterface)
|
||||
CB(WASERVICEFACTORY_GETTESTSTRING, GetTestString)
|
||||
CB(WASERVICEFACTORY_SERVICENOTIFY, ServiceNotify)
|
||||
END_DISPATCH;
|
||||
|
||||
#undef CBCLASS
|
||||
#define CBCLASS PLSHandlerFactory
|
||||
START_DISPATCH;
|
||||
CB(WASERVICEFACTORY_GETSERVICENAME, GetServiceName)
|
||||
CB(WASERVICEFACTORY_GETGUID, GetGUID)
|
||||
CB(WASERVICEFACTORY_GETINTERFACE, GetInterface)
|
||||
#undef CBCLASS
|
||||
#define CBCLASS CommonHandlerFactory
|
||||
CB(WASERVICEFACTORY_GETSERVICETYPE, GetServiceType)
|
||||
CB(WASERVICEFACTORY_SUPPORTNONLOCKINGGETINTERFACE, SupportNonLockingInterface)
|
||||
CB(WASERVICEFACTORY_RELEASEINTERFACE, ReleaseInterface)
|
||||
CB(WASERVICEFACTORY_GETTESTSTRING, GetTestString)
|
||||
CB(WASERVICEFACTORY_SERVICENOTIFY, ServiceNotify)
|
||||
END_DISPATCH;
|
||||
|
||||
|
||||
|
||||
#undef CBCLASS
|
||||
#define CBCLASS B4SHandlerFactory
|
||||
START_DISPATCH;
|
||||
CB(WASERVICEFACTORY_GETSERVICENAME, GetServiceName)
|
||||
CB(WASERVICEFACTORY_GETGUID, GetGUID)
|
||||
CB(WASERVICEFACTORY_GETINTERFACE, GetInterface)
|
||||
#undef CBCLASS
|
||||
#define CBCLASS CommonHandlerFactory
|
||||
CB(WASERVICEFACTORY_GETSERVICETYPE, GetServiceType)
|
||||
CB(WASERVICEFACTORY_SUPPORTNONLOCKINGGETINTERFACE, SupportNonLockingInterface)
|
||||
CB(WASERVICEFACTORY_RELEASEINTERFACE, ReleaseInterface)
|
||||
CB(WASERVICEFACTORY_GETTESTSTRING, GetTestString)
|
||||
CB(WASERVICEFACTORY_SERVICENOTIFY, ServiceNotify)
|
||||
END_DISPATCH;
|
||||
|
||||
|
30
Src/playlist/factory_Handler.h
Normal file
30
Src/playlist/factory_Handler.h
Normal file
@ -0,0 +1,30 @@
|
||||
#ifndef NULLSOFT_FACTORY_HANDLER_H
|
||||
#define NULLSOFT_FACTORY_HANDLER_H
|
||||
|
||||
#include <api/service/waservicefactory.h>
|
||||
#include <api/service/services.h>
|
||||
|
||||
class CommonHandlerFactory : public waServiceFactory
|
||||
{
|
||||
public:
|
||||
|
||||
FOURCC GetServiceType();
|
||||
int SupportNonLockingInterface();
|
||||
int ReleaseInterface(void *ifc);
|
||||
const char *GetTestString();
|
||||
int ServiceNotify(int msg, int param1, int param2);
|
||||
|
||||
};
|
||||
|
||||
#define DECLARE_HANDLER_FACTORY(CLASSNAME) class CLASSNAME : public CommonHandlerFactory {\
|
||||
public:\
|
||||
const char *GetServiceName();\
|
||||
GUID GetGUID();\
|
||||
void *GetInterface(int global_lock);\
|
||||
protected:\
|
||||
RECVS_DISPATCH;}
|
||||
|
||||
DECLARE_HANDLER_FACTORY(M3UHandlerFactory);
|
||||
DECLARE_HANDLER_FACTORY(PLSHandlerFactory);
|
||||
DECLARE_HANDLER_FACTORY(B4SHandlerFactory);
|
||||
#endif
|
65
Src/playlist/factory_playlistmanager.cpp
Normal file
65
Src/playlist/factory_playlistmanager.cpp
Normal file
@ -0,0 +1,65 @@
|
||||
#include "main.h"
|
||||
#include "api__playlist.h"
|
||||
#include "factory_playlistmanager.h"
|
||||
#include "PlaylistManager.h"
|
||||
|
||||
static const char serviceName[] = "Playlist Manager";
|
||||
|
||||
FOURCC PlaylistManagerFactory::GetServiceType()
|
||||
{
|
||||
return WaSvc::UNIQUE;
|
||||
}
|
||||
|
||||
const char *PlaylistManagerFactory::GetServiceName()
|
||||
{
|
||||
return serviceName;
|
||||
}
|
||||
|
||||
GUID PlaylistManagerFactory::GetGUID()
|
||||
{
|
||||
return api_playlistmanagerGUID;
|
||||
}
|
||||
|
||||
void *PlaylistManagerFactory::GetInterface(int global_lock)
|
||||
{
|
||||
// if (global_lock)
|
||||
// WASABI_API_SVC->service_lock(this, (void *)ifc);
|
||||
return &playlistManager;
|
||||
}
|
||||
|
||||
int PlaylistManagerFactory::SupportNonLockingInterface()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
int PlaylistManagerFactory::ReleaseInterface(void *ifc)
|
||||
{
|
||||
//WASABI_API_SVC->service_unlock(ifc);
|
||||
return 1;
|
||||
}
|
||||
|
||||
const char *PlaylistManagerFactory::GetTestString()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int PlaylistManagerFactory::ServiceNotify(int msg, int param1, int param2)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
#ifdef CBCLASS
|
||||
#undef CBCLASS
|
||||
#endif
|
||||
|
||||
#define CBCLASS PlaylistManagerFactory
|
||||
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;
|
28
Src/playlist/factory_playlistmanager.h
Normal file
28
Src/playlist/factory_playlistmanager.h
Normal file
@ -0,0 +1,28 @@
|
||||
#ifndef NULLSOFT_FACTORY_PLAYLISTMANAGER_H
|
||||
#define NULLSOFT_FACTORY_PLAYLISTMANAGER_H
|
||||
|
||||
#include "api__playlist.h"
|
||||
#include "api/service/waservicefactory.h"
|
||||
#include "api/service/services.h"
|
||||
|
||||
class PlaylistManagerFactory : 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
|
63
Src/playlist/factory_playlists.cpp
Normal file
63
Src/playlist/factory_playlists.cpp
Normal file
@ -0,0 +1,63 @@
|
||||
#include "main.h"
|
||||
#include "api__playlist.h"
|
||||
#include "factory_playlists.h"
|
||||
#include "Playlists.h"
|
||||
|
||||
Playlists playlists;
|
||||
static const char serviceName[] = "Playlists";
|
||||
|
||||
FOURCC PlaylistsFactory::GetServiceType()
|
||||
{
|
||||
return WaSvc::UNIQUE;
|
||||
}
|
||||
|
||||
const char *PlaylistsFactory::GetServiceName()
|
||||
{
|
||||
return serviceName;
|
||||
}
|
||||
|
||||
GUID PlaylistsFactory::GetGUID()
|
||||
{
|
||||
return api_playlistsGUID;
|
||||
}
|
||||
|
||||
void *PlaylistsFactory::GetInterface(int global_lock)
|
||||
{
|
||||
// if (global_lock)
|
||||
// WASABI_API_SVC->service_lock(this, (void *)ifc);
|
||||
return &playlists;
|
||||
}
|
||||
|
||||
int PlaylistsFactory::SupportNonLockingInterface()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
int PlaylistsFactory::ReleaseInterface(void *ifc)
|
||||
{
|
||||
//WASABI_API_SVC->service_unlock(ifc);
|
||||
return 1;
|
||||
}
|
||||
|
||||
const char *PlaylistsFactory::GetTestString()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int PlaylistsFactory::ServiceNotify(int msg, int param1, int param2)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
#define CBCLASS PlaylistsFactory
|
||||
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
|
25
Src/playlist/factory_playlists.h
Normal file
25
Src/playlist/factory_playlists.h
Normal file
@ -0,0 +1,25 @@
|
||||
#ifndef NULLSOFT_FACTORY_PLAYLISTS_H
|
||||
#define NULLSOFT_FACTORY_PLAYLISTS_H
|
||||
|
||||
#include "api__playlist.h"
|
||||
#include "api/service/waservicefactory.h"
|
||||
#include "api/service/services.h"
|
||||
|
||||
class PlaylistsFactory : 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
|
139
Src/playlist/ifc_playlist.h
Normal file
139
Src/playlist/ifc_playlist.h
Normal file
@ -0,0 +1,139 @@
|
||||
#ifndef NULLSOFT_IFC_PLAYLIST_H
|
||||
#define NULLSOFT_IFC_PLAYLIST_H
|
||||
|
||||
#include "bfc/dispatch.h"
|
||||
#include "bfc/platform/types.h"
|
||||
|
||||
enum
|
||||
{
|
||||
PLAYLIST_SUCCESS = 0,
|
||||
PLAYLIST_UNIMPLEMENTED = 1,
|
||||
};
|
||||
|
||||
class ifc_playlist : public Dispatchable
|
||||
{
|
||||
protected:
|
||||
ifc_playlist() {}
|
||||
~ifc_playlist() {}
|
||||
|
||||
public:
|
||||
DISPATCH_CODES
|
||||
{
|
||||
IFC_PLAYLIST_CLEAR = 10,
|
||||
//IFC_PLAYLIST_APPENDWITHINFO = 20,
|
||||
//IFC_PLAYLIST_APPEND = 30,
|
||||
IFC_PLAYLIST_GETNUMITEMS = 40,
|
||||
IFC_PLAYLIST_GETITEM = 50,
|
||||
IFC_PLAYLIST_GETITEMTITLE = 60,
|
||||
IFC_PLAYLIST_GETITEMLENGTHMILLISECONDS = 70,
|
||||
IFC_PLAYLIST_GETITEMEXTENDEDINFO = 80,
|
||||
IFC_PLAYLIST_REVERSE = 90,
|
||||
IFC_PLAYLIST_SWAP = 100,
|
||||
IFC_PLAYLIST_RANDOMIZE = 110,
|
||||
IFC_PLAYLIST_REMOVE = 120,
|
||||
IFC_PLAYLIST_SORTBYTITLE = 130,
|
||||
IFC_PLAYLIST_SORTBYFILENAME = 140,
|
||||
IFC_PLAYLIST_SORTBYDIRECTORY = 150,
|
||||
};
|
||||
|
||||
void Clear();
|
||||
//void AppendWithInfo(const wchar_t *filename, const char *title, int lengthInMS);
|
||||
//void Append(const wchar_t *filename);
|
||||
|
||||
size_t GetNumItems();
|
||||
|
||||
size_t GetItem( size_t item, wchar_t *filename, size_t filenameCch );
|
||||
|
||||
size_t GetItemTitle( size_t item, wchar_t *title, size_t titleCch );
|
||||
|
||||
int GetItemLengthMilliseconds( size_t item ); // TODO: maybe microsecond for better resolution?
|
||||
|
||||
size_t GetItemExtendedInfo( size_t item, const wchar_t *metadata, wchar_t *info, size_t infoCch );
|
||||
|
||||
int Reverse(); // optional, return 1 to indicate that you did the reversal (otherwise, caller must perform manually)
|
||||
int Swap( size_t item1, size_t item2 );
|
||||
int Randomize( int ( *generator )( ) ); // optional, return 1 to indicate that you did the randomization (otherwise, caller must perform manually)
|
||||
void Remove( size_t item );
|
||||
|
||||
int SortByTitle(); // optional, return 1 to indicate that you did the sort (otherwise, caller must perform manually)
|
||||
int SortByFilename(); // optional, return 1 to indicate that you did the sort (otherwise, caller must perform manually)
|
||||
int SortByDirectory();
|
||||
};
|
||||
|
||||
inline void ifc_playlist::Clear()
|
||||
{
|
||||
_voidcall( IFC_PLAYLIST_CLEAR );
|
||||
}
|
||||
/*
|
||||
inline void ifc_playlist::AppendWithInfo(const wchar_t *filename, const char *title, int lengthInMS)
|
||||
{
|
||||
_voidcall(IFC_PLAYLIST_APPENDWITHINFO, filename, title, lengthInMS);
|
||||
}
|
||||
*/
|
||||
/*
|
||||
inline void ifc_playlist::Append(const wchar_t *filename)
|
||||
{
|
||||
_voidcall(IFC_PLAYLIST_APPEND, filename);
|
||||
}*/
|
||||
|
||||
inline size_t ifc_playlist::GetNumItems()
|
||||
{
|
||||
return _call( IFC_PLAYLIST_GETNUMITEMS, (size_t)0 );
|
||||
}
|
||||
|
||||
inline size_t ifc_playlist::GetItem( size_t item, wchar_t *filename, size_t filenameCch )
|
||||
{
|
||||
return _call( IFC_PLAYLIST_GETITEM, (size_t)0, item, filename, filenameCch );
|
||||
}
|
||||
|
||||
inline size_t ifc_playlist::GetItemTitle( size_t item, wchar_t *title, size_t titleCch )
|
||||
{
|
||||
return _call( IFC_PLAYLIST_GETITEMTITLE, (size_t)0, item, title, titleCch );
|
||||
}
|
||||
|
||||
inline int ifc_playlist::GetItemLengthMilliseconds( size_t item )
|
||||
{
|
||||
return _call( IFC_PLAYLIST_GETITEMLENGTHMILLISECONDS, (int)-1, item );
|
||||
}
|
||||
|
||||
inline size_t ifc_playlist::GetItemExtendedInfo( size_t item, const wchar_t *metadata, wchar_t *info, size_t infoCch )
|
||||
{
|
||||
return _call( IFC_PLAYLIST_GETITEMEXTENDEDINFO, (size_t)0, item, metadata, info, infoCch );
|
||||
}
|
||||
|
||||
inline int ifc_playlist::Reverse()
|
||||
{
|
||||
return _call( IFC_PLAYLIST_REVERSE, (int)PLAYLIST_UNIMPLEMENTED );
|
||||
}
|
||||
|
||||
inline int ifc_playlist::Swap( size_t item1, size_t item2 )
|
||||
{
|
||||
return _call( IFC_PLAYLIST_SWAP, (int)PLAYLIST_UNIMPLEMENTED, item1, item2 );
|
||||
}
|
||||
|
||||
inline int ifc_playlist::Randomize( int ( *generator )( ) )
|
||||
{
|
||||
return _call( IFC_PLAYLIST_RANDOMIZE, (int)PLAYLIST_UNIMPLEMENTED, generator );
|
||||
}
|
||||
|
||||
inline void ifc_playlist::Remove( size_t item )
|
||||
{
|
||||
_voidcall( IFC_PLAYLIST_REMOVE, item );
|
||||
}
|
||||
|
||||
inline int ifc_playlist::SortByTitle()
|
||||
{
|
||||
return _call( IFC_PLAYLIST_SORTBYTITLE, (int)0 );
|
||||
}
|
||||
|
||||
inline int ifc_playlist::SortByFilename()
|
||||
{
|
||||
return _call( IFC_PLAYLIST_SORTBYFILENAME, (int)0 );
|
||||
}
|
||||
|
||||
inline int ifc_playlist::SortByDirectory()
|
||||
{
|
||||
return _call( IFC_PLAYLIST_SORTBYDIRECTORY, (int)0 );
|
||||
}
|
||||
|
||||
#endif
|
48
Src/playlist/ifc_playlistT.h
Normal file
48
Src/playlist/ifc_playlistT.h
Normal file
@ -0,0 +1,48 @@
|
||||
#pragma once
|
||||
#include "ifc_playlist.h"
|
||||
template <class T>
|
||||
class ifc_playlistT : public ifc_playlist
|
||||
{
|
||||
protected:
|
||||
ifc_playlistT() {}
|
||||
~ifc_playlistT() {}
|
||||
|
||||
void Clear();
|
||||
//void AppendWithInfo(const wchar_t *filename, const char *title, int lengthInMS);
|
||||
//void Append(const wchar_t *filename);
|
||||
|
||||
size_t GetNumItems() { return 0; }
|
||||
size_t GetItem( size_t item, wchar_t *filename, size_t filenameCch ) { return 0; }
|
||||
size_t GetItemTitle( size_t item, wchar_t *title, size_t titleCch ) { return 0; }
|
||||
int GetItemLengthMilliseconds( size_t item ) { return -1; }
|
||||
size_t GetItemExtendedInfo( size_t item, const wchar_t *metadata, wchar_t *info, size_t infoCch ) { return 0; }
|
||||
int Reverse() { return PLAYLIST_UNIMPLEMENTED; }
|
||||
int Swap( size_t item1, size_t item2 ) { return PLAYLIST_UNIMPLEMENTED; }
|
||||
int Randomize( int ( *generator )( ) ) { return PLAYLIST_UNIMPLEMENTED; }
|
||||
void Remove( size_t item ) {}
|
||||
int SortByTitle() { return 0; }
|
||||
int SortByFilename() { return 0; }
|
||||
int SortByDirectory() { return 0; }
|
||||
|
||||
#define CBCLASS T
|
||||
#define CBCLASST ifc_playlistT<T>
|
||||
START_DISPATCH_INLINE;
|
||||
VCBT( IFC_PLAYLIST_CLEAR, Clear )
|
||||
//M_VCB( IFC_PLAYLIST_APPENDWITHINFO, AppendWithInfo)
|
||||
//M_VCB( IFC_PLAYLIST_APPEND, Append)
|
||||
CBT( IFC_PLAYLIST_GETNUMITEMS, GetNumItems )
|
||||
CBT( IFC_PLAYLIST_GETITEM, GetItem )
|
||||
CBT( IFC_PLAYLIST_GETITEMTITLE, GetItemTitle )
|
||||
CBT( IFC_PLAYLIST_GETITEMLENGTHMILLISECONDS, GetItemLengthMilliseconds )
|
||||
CBT( IFC_PLAYLIST_GETITEMEXTENDEDINFO, GetItemExtendedInfo )
|
||||
CBT( IFC_PLAYLIST_REVERSE, Reverse )
|
||||
CBT( IFC_PLAYLIST_SWAP, Swap )
|
||||
CBT( IFC_PLAYLIST_RANDOMIZE, Randomize )
|
||||
VCBT( IFC_PLAYLIST_REMOVE, Remove )
|
||||
CBT( IFC_PLAYLIST_SORTBYTITLE, SortByTitle )
|
||||
CBT( IFC_PLAYLIST_SORTBYFILENAME, SortByFilename )
|
||||
CBT( IFC_PLAYLIST_SORTBYDIRECTORY, SortByDirectory )
|
||||
END_DISPATCH;
|
||||
#undef CBCLASS
|
||||
#undef CBCLASST
|
||||
};
|
33
Src/playlist/ifc_playlistdirectorycallback.h
Normal file
33
Src/playlist/ifc_playlistdirectorycallback.h
Normal file
@ -0,0 +1,33 @@
|
||||
#ifndef NULLSOFT_IFC_PLAYLISTDIRECTORYCALLBACK_H
|
||||
#define NULLSOFT_IFC_PLAYLISTDIRECTORYCALLBACK_H
|
||||
|
||||
#include <bfc/dispatch.h>
|
||||
#include <bfc/platform/types.h>
|
||||
|
||||
class ifc_playlistdirectorycallback : public Dispatchable
|
||||
{
|
||||
protected:
|
||||
ifc_playlistdirectorycallback() {}
|
||||
~ifc_playlistdirectorycallback() {}
|
||||
|
||||
public:
|
||||
bool ShouldRecurse(const wchar_t *path);
|
||||
bool ShouldLoad(const wchar_t *filename);
|
||||
|
||||
DISPATCH_CODES
|
||||
{
|
||||
IFC_PLAYLISTDIRECTORYCALLBACK_SHOULDRECURSE = 10,
|
||||
IFC_PLAYLISTDIRECTORYCALLBACK_SHOULDLOAD = 20,
|
||||
};
|
||||
};
|
||||
|
||||
inline bool ifc_playlistdirectorycallback::ShouldRecurse(const wchar_t *path)
|
||||
{
|
||||
return _call(IFC_PLAYLISTDIRECTORYCALLBACK_SHOULDRECURSE, (bool)false, path);
|
||||
}
|
||||
|
||||
inline bool ifc_playlistdirectorycallback::ShouldLoad(const wchar_t *filename)
|
||||
{
|
||||
return _call(IFC_PLAYLISTDIRECTORYCALLBACK_SHOULDLOAD, (bool)true, filename);
|
||||
}
|
||||
#endif
|
37
Src/playlist/ifc_playlistloader.h
Normal file
37
Src/playlist/ifc_playlistloader.h
Normal file
@ -0,0 +1,37 @@
|
||||
#ifndef NULLSOFT_IFC_PLAYLISTLOADER_H
|
||||
#define NULLSOFT_IFC_PLAYLISTLOADER_H
|
||||
|
||||
#include <bfc/dispatch.h>
|
||||
#include <wchar.h>
|
||||
#include "ifc_playlistloadercallback.h"
|
||||
|
||||
enum
|
||||
{
|
||||
IFC_PLAYLISTLOADER_SUCCESS = 0,
|
||||
IFC_PLAYLISTLOADER_FAILED = 1,
|
||||
|
||||
IFC_PLAYLISTLOADER_NEXTITEM_EOF = 1,
|
||||
};
|
||||
|
||||
class ifc_playlistloader : public Dispatchable
|
||||
{
|
||||
protected:
|
||||
ifc_playlistloader() {}
|
||||
~ifc_playlistloader() {}
|
||||
|
||||
public:
|
||||
int Load( const wchar_t *filename, ifc_playlistloadercallback *playlist );
|
||||
|
||||
DISPATCH_CODES
|
||||
{
|
||||
IFC_PLAYLISTLOADER_LOAD = 10,
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
inline int ifc_playlistloader::Load( const wchar_t *filename, ifc_playlistloadercallback *playlist )
|
||||
{
|
||||
return _call( IFC_PLAYLISTLOADER_LOAD, (int)IFC_PLAYLISTLOADER_FAILED, filename, playlist );
|
||||
}
|
||||
|
||||
#endif
|
96
Src/playlist/ifc_playlistloadercallback.h
Normal file
96
Src/playlist/ifc_playlistloadercallback.h
Normal file
@ -0,0 +1,96 @@
|
||||
#ifndef NULLSOFT_IFC_PLAYLISTLOADERCALLBACK_H
|
||||
#define NULLSOFT_IFC_PLAYLISTLOADERCALLBACK_H
|
||||
|
||||
#include <bfc/dispatch.h>
|
||||
#include <bfc/platform/types.h>
|
||||
#include "ifc_plentryinfo.h"
|
||||
|
||||
#ifndef FILENAME_SIZE
|
||||
#define FILENAME_SIZE (MAX_PATH * 4)
|
||||
#endif
|
||||
|
||||
#ifndef FILETITLE_SIZE
|
||||
#define FILETITLE_SIZE 400
|
||||
#endif
|
||||
|
||||
class ifc_playlistinfo; // TODO
|
||||
class ifc_playlistloadercallback : public Dispatchable
|
||||
{
|
||||
protected:
|
||||
ifc_playlistloadercallback() {}
|
||||
~ifc_playlistloadercallback() {}
|
||||
|
||||
public:
|
||||
// return 0 to continue enumeration, or 1 to quit
|
||||
|
||||
// title will be NULL if no title found, length will be -1
|
||||
int OnFile( const wchar_t *filename, const wchar_t *title, int lengthInMS, ifc_plentryinfo *info );
|
||||
void OnFileOld( const wchar_t *filename, const wchar_t *title, int lengthInMS, ifc_plentryinfo *info );
|
||||
|
||||
// numEntries is just a hint, there is no gaurantee. 0 means "don't know"
|
||||
int OnPlaylistInfo( const wchar_t *playlistName, size_t numEntries, ifc_plentryinfo *info );
|
||||
void OnPlaylistInfoOld( const wchar_t *playlistName, size_t numEntries, ifc_plentryinfo *info );
|
||||
|
||||
const wchar_t *GetBasePath(); // return 0 to use playlist file path as base (or just don't implement)
|
||||
|
||||
DISPATCH_CODES
|
||||
{
|
||||
IFC_PLAYLISTLOADERCALLBACK_ONFILE = 10,
|
||||
IFC_PLAYLISTLOADERCALLBACK_ONFILE_RET = 11,
|
||||
IFC_PLAYLISTLOADERCALLBACK_ONPLAYLISTINFO = 20,
|
||||
IFC_PLAYLISTLOADERCALLBACK_ONPLAYLISTINFO_RET = 21,
|
||||
IFC_PLAYLISTLOADERCALLBACK_GETBASEPATH = 30,
|
||||
};
|
||||
enum
|
||||
{
|
||||
LOAD_CONTINUE = 0,
|
||||
LOAD_ABORT = 1,
|
||||
};
|
||||
};
|
||||
|
||||
inline void ifc_playlistloadercallback::OnFileOld( const wchar_t *filename, const wchar_t *title, int lengthInMS, ifc_plentryinfo *info )
|
||||
{
|
||||
_voidcall( IFC_PLAYLISTLOADERCALLBACK_ONFILE, filename, title, lengthInMS, info );
|
||||
}
|
||||
|
||||
inline int ifc_playlistloadercallback::OnFile( const wchar_t *filename, const wchar_t *title, int lengthInMS, ifc_plentryinfo *info )
|
||||
{
|
||||
void *params[ 4 ] = { &filename, &title, &lengthInMS, &info };
|
||||
int retval;
|
||||
|
||||
if ( _dispatch( IFC_PLAYLISTLOADERCALLBACK_ONFILE_RET, &retval, params, 4 ) == 0 )
|
||||
{
|
||||
_dispatch( IFC_PLAYLISTLOADERCALLBACK_ONFILE, 0, params, 4 );
|
||||
|
||||
return LOAD_CONTINUE;
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
inline void ifc_playlistloadercallback::OnPlaylistInfoOld( const wchar_t *playlistName, size_t numEntries, ifc_plentryinfo *info )
|
||||
{
|
||||
_voidcall( IFC_PLAYLISTLOADERCALLBACK_ONPLAYLISTINFO, playlistName, numEntries, info );
|
||||
}
|
||||
|
||||
inline int ifc_playlistloadercallback::OnPlaylistInfo( const wchar_t *playlistName, size_t numEntries, ifc_plentryinfo *info )
|
||||
{
|
||||
void *params[ 3 ] = { &playlistName, &numEntries, &info };
|
||||
int retval;
|
||||
|
||||
if ( _dispatch( IFC_PLAYLISTLOADERCALLBACK_ONPLAYLISTINFO_RET, &retval, params, 3 ) == 0 )
|
||||
{
|
||||
_dispatch( IFC_PLAYLISTLOADERCALLBACK_ONPLAYLISTINFO, 0, params, 3 );
|
||||
|
||||
return LOAD_CONTINUE;
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
inline const wchar_t *ifc_playlistloadercallback::GetBasePath()
|
||||
{
|
||||
return _call( IFC_PLAYLISTLOADERCALLBACK_GETBASEPATH, (const wchar_t *)0 );
|
||||
}
|
||||
|
||||
#endif
|
29
Src/playlist/ifc_playlistloadercallbackT.h
Normal file
29
Src/playlist/ifc_playlistloadercallbackT.h
Normal file
@ -0,0 +1,29 @@
|
||||
#pragma once
|
||||
#include "ifc_playlistloadercallback.h"
|
||||
|
||||
template <class T>
|
||||
class ifc_playlistloadercallbackT : public ifc_playlistloadercallback
|
||||
{
|
||||
protected:
|
||||
ifc_playlistloadercallbackT() {}
|
||||
~ifc_playlistloadercallbackT() {}
|
||||
protected:
|
||||
// return 0 to continue enumeration, or 1 to quit
|
||||
|
||||
// title will be NULL if no title found, length will be -1
|
||||
int OnFile(const wchar_t *filename, const wchar_t *title, int lengthInMS, ifc_plentryinfo *info) { return LOAD_ABORT; }
|
||||
// numEntries is just a hint, there is no gaurantee. 0 means "don't know"
|
||||
int OnPlaylistInfo(const wchar_t *playlistName, size_t numEntries, ifc_plentryinfo *info) { return LOAD_ABORT; }
|
||||
// return 0 to use playlist file path as base (or just don't implement)
|
||||
const wchar_t *GetBasePath() { return 0; }
|
||||
|
||||
#define CBCLASS T
|
||||
#define CBCLASST ifc_playlistloadercallbackT<T>
|
||||
START_DISPATCH_INLINE;
|
||||
CBT(IFC_PLAYLISTLOADERCALLBACK_ONFILE_RET, OnFile);
|
||||
CBT(IFC_PLAYLISTLOADERCALLBACK_ONPLAYLISTINFO_RET, OnPlaylistInfo);
|
||||
CBT(IFC_PLAYLISTLOADERCALLBACK_GETBASEPATH, GetBasePath);
|
||||
END_DISPATCH;
|
||||
#undef CBCLASS
|
||||
#undef CBCLASST
|
||||
};
|
28
Src/playlist/ifc_plentryinfo.h
Normal file
28
Src/playlist/ifc_plentryinfo.h
Normal file
@ -0,0 +1,28 @@
|
||||
#ifndef NULLSOFT_IFC_PLENTRYINFO_H
|
||||
#define NULLSOFT_IFC_PLENTRYINFO_H
|
||||
|
||||
#include <bfc/dispatch.h>
|
||||
#include <bfc/platform/types.h>
|
||||
|
||||
class ifc_plentryinfo : public Dispatchable
|
||||
{
|
||||
protected:
|
||||
ifc_plentryinfo() {}
|
||||
~ifc_plentryinfo() {}
|
||||
|
||||
public:
|
||||
// TODO: you can't guarantee that this wchar_t * pointer will last, make a copy before calling again!
|
||||
const wchar_t *GetExtendedInfo( const wchar_t *parameter );
|
||||
|
||||
DISPATCH_CODES
|
||||
{
|
||||
IFC_PLENTRYINFO_GETEXTENDEDINFO = 10,
|
||||
};
|
||||
};
|
||||
|
||||
inline const wchar_t *ifc_plentryinfo::GetExtendedInfo( const wchar_t *parameter )
|
||||
{
|
||||
return _call( IFC_PLENTRYINFO_GETEXTENDEDINFO, (const wchar_t *)0, parameter );
|
||||
}
|
||||
|
||||
#endif
|
134
Src/playlist/main.cpp
Normal file
134
Src/playlist/main.cpp
Normal file
@ -0,0 +1,134 @@
|
||||
#include "api__playlist.h"
|
||||
#include "main.h"
|
||||
|
||||
#include "factory_Handler.h"
|
||||
#include "factory_playlistmanager.h"
|
||||
#include "factory_playlists.h"
|
||||
#include "../Winamp/api_random.h"
|
||||
#include "Playlists.h"
|
||||
#include "plstring.h"
|
||||
#include "ScriptObjectFactory.h"
|
||||
#include "../nu/ServiceWatcher.h"
|
||||
#include "JSAPI2_Creator.h"
|
||||
|
||||
extern Playlists playlists;
|
||||
int (*warand)(void) = 0;
|
||||
|
||||
M3UHandlerFactory m3uHandlerFactory;
|
||||
PLSHandlerFactory plsHandlerFactory;
|
||||
B4SHandlerFactory b4sHandlerFactory;
|
||||
PlaylistManagerFactory playlistManagerFactory;
|
||||
PlaylistsFactory playlistsFactory;
|
||||
ScriptObjectFactory scriptObjectFactory;
|
||||
JSAPI2Factory jsapi2Factory;
|
||||
ServiceWatcher serviceWatcher;
|
||||
PlaylistComponent playlistComponent;
|
||||
|
||||
api_service *WASABI_API_SVC = 0;
|
||||
api_application *WASABI_API_APP = 0;
|
||||
api_config *AGAVE_API_CONFIG = 0;
|
||||
api_syscb *WASABI_API_SYSCB = 0;
|
||||
api_maki *WASABI_API_MAKI = 0;
|
||||
JSAPI2::api_security *AGAVE_API_JSAPI2_SECURITY = 0;
|
||||
api_stats *AGAVE_API_STATS = 0;
|
||||
|
||||
// wasabi based services for localisation support
|
||||
api_language *WASABI_API_LNG = 0;
|
||||
HINSTANCE WASABI_API_LNG_HINST = 0, WASABI_API_ORIG_HINST = 0;
|
||||
|
||||
template <class api_t>
|
||||
api_t *GetService( GUID serviceGUID )
|
||||
{
|
||||
waServiceFactory *sf = WASABI_API_SVC->service_getServiceByGuid( serviceGUID );
|
||||
if ( sf )
|
||||
return (api_t *)sf->getInterface();
|
||||
else
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
inline void ReleaseService( GUID serviceGUID, void *service )
|
||||
{
|
||||
if ( service )
|
||||
{
|
||||
waServiceFactory *sf = WASABI_API_SVC->service_getServiceByGuid( serviceGUID );
|
||||
if ( sf )
|
||||
sf->releaseInterface( service );
|
||||
}
|
||||
}
|
||||
|
||||
void PlaylistComponent::RegisterServices( api_service *service )
|
||||
{
|
||||
WASABI_API_SVC = service;
|
||||
|
||||
warand = QuickService<api_random>( randomApiGUID )->GetFunction();
|
||||
|
||||
WASABI_API_APP = GetService<api_application>( applicationApiServiceGuid );
|
||||
WASABI_API_SYSCB = GetService<api_syscb>( syscbApiServiceGuid );
|
||||
AGAVE_API_CONFIG = GetService<api_config>( AgaveConfigGUID );
|
||||
AGAVE_API_JSAPI2_SECURITY = GetService<JSAPI2::api_security>( JSAPI2::api_securityGUID );
|
||||
AGAVE_API_STATS = GetService<api_stats>( AnonymousStatsGUID );
|
||||
|
||||
serviceWatcher.WatchWith( WASABI_API_SVC );
|
||||
serviceWatcher.WatchFor( &WASABI_API_MAKI, makiApiServiceGuid );
|
||||
|
||||
// need to get WASABI_API_APP first
|
||||
plstring_init();
|
||||
|
||||
WASABI_API_SVC->service_register( &m3uHandlerFactory );
|
||||
WASABI_API_SVC->service_register( &plsHandlerFactory );
|
||||
WASABI_API_SVC->service_register( &b4sHandlerFactory );
|
||||
WASABI_API_SVC->service_register( &playlistManagerFactory );
|
||||
WASABI_API_SVC->service_register( &playlistsFactory );
|
||||
WASABI_API_SVC->service_register( &scriptObjectFactory );
|
||||
WASABI_API_SVC->service_register( &jsapi2Factory );
|
||||
|
||||
WASABI_API_LNG = GetService<api_language>( languageApiGUID );
|
||||
// need to have this initialised before we try to do anything with localisation features
|
||||
WASABI_API_START_LANG( hModule, playlistLangGUID );
|
||||
|
||||
// register for service callbacks in case any of these don't exist yet
|
||||
WASABI_API_SYSCB->syscb_registerCallback( &serviceWatcher );
|
||||
}
|
||||
|
||||
int PlaylistComponent::RegisterServicesSafeModeOk()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
void PlaylistComponent::DeregisterServices( api_service *service )
|
||||
{
|
||||
playlists.Flush();
|
||||
|
||||
service->service_deregister( &playlistsFactory );
|
||||
service->service_deregister( &playlistManagerFactory );
|
||||
service->service_deregister( &m3uHandlerFactory );
|
||||
service->service_deregister( &plsHandlerFactory );
|
||||
service->service_deregister( &b4sHandlerFactory );
|
||||
service->service_deregister( &scriptObjectFactory );
|
||||
service->service_deregister( &jsapi2Factory );
|
||||
|
||||
serviceWatcher.StopWatching();
|
||||
serviceWatcher.Clear();
|
||||
|
||||
ReleaseService( makiApiServiceGuid, WASABI_API_MAKI );
|
||||
ReleaseService( applicationApiServiceGuid, WASABI_API_APP );
|
||||
ReleaseService( AgaveConfigGUID, AGAVE_API_CONFIG );
|
||||
ReleaseService( syscbApiServiceGuid, WASABI_API_SYSCB );
|
||||
ReleaseService( languageApiGUID, WASABI_API_LNG );
|
||||
ReleaseService( JSAPI2::api_securityGUID, AGAVE_API_JSAPI2_SECURITY );
|
||||
ReleaseService( AnonymousStatsGUID, AGAVE_API_STATS );
|
||||
}
|
||||
|
||||
extern "C" __declspec(dllexport) ifc_wa5component *GetWinamp5SystemComponent()
|
||||
{
|
||||
return &playlistComponent;
|
||||
}
|
||||
|
||||
#define CBCLASS PlaylistComponent
|
||||
START_DISPATCH;
|
||||
VCB( API_WA5COMPONENT_REGISTERSERVICES, RegisterServices )
|
||||
CB( API_WA5COMPONENT_REGISTERSERVICES_SAFE_MODE, RegisterServicesSafeModeOk )
|
||||
VCB( API_WA5COMPONENT_DEREEGISTERSERVICES, DeregisterServices )
|
||||
END_DISPATCH;
|
||||
#undef CBCLASS
|
26
Src/playlist/main.h
Normal file
26
Src/playlist/main.h
Normal file
@ -0,0 +1,26 @@
|
||||
#ifndef NULLSOFT_PLAYLIST_MAIN_H
|
||||
#define NULLSOFT_PLAYLIST_MAIN_H
|
||||
|
||||
#include <windows.h>
|
||||
#include <shlwapi.h>
|
||||
#include "..\Components\wac_network\wac_network_http_receiver_api.h"
|
||||
|
||||
extern int (*warand)(void);
|
||||
HRESULT ResolveShortCut(HWND hwnd, LPCWSTR pszShortcutFile, LPWSTR pszPath);
|
||||
bool IsUrl(const wchar_t *url);
|
||||
void SetUserAgent(api_httpreceiver *http);
|
||||
const char *GetProxy();
|
||||
|
||||
#include "../Agave/Component/ifc_wa5component.h"
|
||||
|
||||
class PlaylistComponent : public ifc_wa5component
|
||||
{
|
||||
public:
|
||||
void RegisterServices(api_service *service);
|
||||
int RegisterServicesSafeModeOk();
|
||||
void DeregisterServices(api_service *service);
|
||||
protected:
|
||||
RECVS_DISPATCH;
|
||||
};
|
||||
extern PlaylistComponent playlistComponent;
|
||||
#endif
|
336
Src/playlist/pl_entry.cpp
Normal file
336
Src/playlist/pl_entry.cpp
Normal file
@ -0,0 +1,336 @@
|
||||
#include "main.h"
|
||||
#include "pl_entry.h"
|
||||
#include "plstring.h"
|
||||
#include <wchar.h>
|
||||
#include "../nu/strsafe.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
static const wchar_t *_INFO_NAME_MEDIA_HASH = L"mediahash";
|
||||
static const wchar_t *_INFO_NAME_META_HASH = L"metahash";
|
||||
static const wchar_t *_INFO_NAME_CLOUD_ID = L"cloud_id";
|
||||
static const wchar_t *_INFO_NAME_CLOUD_STATUS = L"cloud_status";
|
||||
static const wchar_t *_INFO_NAME_CLOUD_DEVICES = L"cloud_devices";
|
||||
|
||||
pl_entry::pl_entry( const wchar_t *p_filename, const wchar_t *p_title, int p_length_ms )
|
||||
{
|
||||
SetFilename( p_filename );
|
||||
SetTitle( p_title );
|
||||
SetLengthMilliseconds( p_length_ms );
|
||||
}
|
||||
|
||||
pl_entry::pl_entry( const wchar_t *p_filename, const wchar_t *p_title, int p_length_ms, int p_size )
|
||||
{
|
||||
SetFilename( p_filename );
|
||||
SetTitle( p_title );
|
||||
SetLengthMilliseconds( p_length_ms );
|
||||
SetSizeBytes( p_size );
|
||||
}
|
||||
|
||||
pl_entry::pl_entry( const wchar_t *p_filename, const wchar_t *p_title, int p_length_ms, ifc_plentryinfo *p_info )
|
||||
{
|
||||
SetFilename( p_filename );
|
||||
SetTitle( p_title );
|
||||
SetLengthMilliseconds( p_length_ms );
|
||||
|
||||
if ( p_info )
|
||||
{
|
||||
SetMediahash( p_info->GetExtendedInfo( _INFO_NAME_MEDIA_HASH ) );
|
||||
SetMetahash( p_info->GetExtendedInfo( _INFO_NAME_META_HASH ) );
|
||||
SetCloudID( p_info->GetExtendedInfo( _INFO_NAME_CLOUD_ID ) );
|
||||
SetCloudStatus( p_info->GetExtendedInfo( _INFO_NAME_CLOUD_STATUS ) );
|
||||
SetCloudDevices( p_info->GetExtendedInfo( _INFO_NAME_CLOUD_DEVICES ) );
|
||||
|
||||
const wchar_t *l_tvg_name = p_info->GetExtendedInfo( L"tvg-name" );
|
||||
|
||||
if ( l_tvg_name && wcslen( l_tvg_name ) > 0 )
|
||||
{
|
||||
_extended_infos.emplace( L"tvg-name", l_tvg_name );
|
||||
|
||||
const wchar_t *l_tvg_id = p_info->GetExtendedInfo( L"tvg-id" );
|
||||
if ( l_tvg_id && *l_tvg_id )
|
||||
_extended_infos.emplace( L"tvg-id", l_tvg_id );
|
||||
|
||||
const wchar_t *l_tvg_logo = p_info->GetExtendedInfo( L"tvg-logo" );
|
||||
if ( l_tvg_logo && *l_tvg_logo )
|
||||
_extended_infos.emplace( L"tvg-logo", l_tvg_logo );
|
||||
|
||||
const wchar_t *l_tvg_title = p_info->GetExtendedInfo( L"tvg-title" );
|
||||
if ( l_tvg_title && *l_tvg_title )
|
||||
_extended_infos.emplace( L"group-title", l_tvg_title );
|
||||
}
|
||||
|
||||
const wchar_t *l_ext = p_info->GetExtendedInfo( L"ext" );
|
||||
|
||||
if ( l_ext && wcslen( l_ext ) )
|
||||
_extended_infos.emplace( L"ext", l_ext );
|
||||
}
|
||||
}
|
||||
|
||||
pl_entry::pl_entry( const wchar_t *p_filename, const wchar_t *p_title, int p_length_ms, int p_size, ifc_plentryinfo *p_info )
|
||||
{
|
||||
SetFilename( p_filename );
|
||||
SetTitle( p_title );
|
||||
SetLengthMilliseconds( p_length_ms );
|
||||
SetSizeBytes( p_size );
|
||||
|
||||
if ( p_info )
|
||||
{
|
||||
SetMediahash( p_info->GetExtendedInfo( _INFO_NAME_MEDIA_HASH ) );
|
||||
SetMetahash( p_info->GetExtendedInfo( _INFO_NAME_META_HASH ) );
|
||||
SetCloudID( p_info->GetExtendedInfo( _INFO_NAME_CLOUD_ID ) );
|
||||
SetCloudStatus( p_info->GetExtendedInfo( _INFO_NAME_CLOUD_STATUS ) );
|
||||
SetCloudDevices( p_info->GetExtendedInfo( _INFO_NAME_CLOUD_DEVICES ) );
|
||||
|
||||
const wchar_t *l_tvg_name = p_info->GetExtendedInfo( L"tvg-name" );
|
||||
|
||||
if ( l_tvg_name && wcslen( l_tvg_name ) > 0 )
|
||||
{
|
||||
_extended_infos.emplace( L"tvg-id", p_info->GetExtendedInfo( L"tvg-id" ) );
|
||||
_extended_infos.emplace( L"tvg-name", l_tvg_name );
|
||||
_extended_infos.emplace( L"tvg-logo", p_info->GetExtendedInfo( L"tvg-logo" ) );
|
||||
_extended_infos.emplace( L"group-title", p_info->GetExtendedInfo( L"group-title" ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pl_entry::pl_entry( const wchar_t *p_filename, const wchar_t *p_title, int p_length_ms,
|
||||
const wchar_t *mediahash, const wchar_t *metahash,
|
||||
const wchar_t *cloud_id, const wchar_t *cloud_status,
|
||||
const wchar_t *cloud_devices )
|
||||
{
|
||||
SetFilename( p_filename );
|
||||
SetTitle( p_title );
|
||||
SetLengthMilliseconds( p_length_ms );
|
||||
|
||||
SetMediahash( mediahash );
|
||||
SetMetahash( metahash );
|
||||
SetCloudID( cloud_id );
|
||||
SetCloudStatus( cloud_status );
|
||||
SetCloudDevices( cloud_devices );
|
||||
}
|
||||
|
||||
pl_entry::~pl_entry()
|
||||
{
|
||||
plstring_release( filename );
|
||||
plstring_release( filetitle );
|
||||
plstring_release( mediahash );
|
||||
plstring_release( metahash );
|
||||
plstring_release( cloud_id );
|
||||
plstring_release( cloud_status );
|
||||
plstring_release( cloud_devices );
|
||||
}
|
||||
|
||||
|
||||
size_t pl_entry::GetFilename( wchar_t *p_filename, size_t filenameCch )
|
||||
{
|
||||
if ( !this->filename )
|
||||
return 0;
|
||||
|
||||
if ( !p_filename )
|
||||
return wcslen( this->filename );
|
||||
|
||||
if ( !this->filename[ 0 ] )
|
||||
return 0;
|
||||
|
||||
StringCchCopyW( p_filename, filenameCch, this->filename );
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
size_t pl_entry::GetTitle( wchar_t *title, size_t titleCch )
|
||||
{
|
||||
if ( !this->filetitle )
|
||||
return 0;
|
||||
|
||||
if ( !title )
|
||||
return wcslen( this->filetitle );
|
||||
|
||||
if ( !this->filetitle[ 0 ] )
|
||||
return 0;
|
||||
|
||||
StringCchCopyW( title, titleCch, this->filetitle );
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int pl_entry::GetLengthInMilliseconds()
|
||||
{
|
||||
return this->length;
|
||||
}
|
||||
|
||||
int pl_entry::GetSizeInBytes()
|
||||
{
|
||||
return this->size;
|
||||
}
|
||||
|
||||
size_t pl_entry::GetExtendedInfo( const wchar_t *metadata, wchar_t *info, size_t infoCch )
|
||||
{
|
||||
if ( cloud_id )
|
||||
{
|
||||
if ( !_wcsnicmp( _INFO_NAME_MEDIA_HASH, metadata, 9 ) && mediahash )
|
||||
{
|
||||
lstrcpynW( info, mediahash, (int)infoCch );
|
||||
return 1;
|
||||
}
|
||||
else if ( !_wcsnicmp( _INFO_NAME_META_HASH, metadata, 8 ) && metahash )
|
||||
{
|
||||
lstrcpynW( info, metahash, (int)infoCch );
|
||||
return 1;
|
||||
}
|
||||
else if ( !_wcsnicmp( _INFO_NAME_CLOUD_ID, metadata, 8 ) && cloud_id )
|
||||
{
|
||||
lstrcpynW( info, cloud_id, (int)infoCch );
|
||||
return 1;
|
||||
}
|
||||
else if ( !_wcsnicmp( _INFO_NAME_CLOUD_STATUS, metadata, 12 ) && cloud_status )
|
||||
{
|
||||
lstrcpynW( info, cloud_status, (int)infoCch );
|
||||
return 1;
|
||||
}
|
||||
else if ( !_wcsnicmp( _INFO_NAME_CLOUD_DEVICES, metadata, 13 ) && cloud_devices )
|
||||
{
|
||||
lstrcpynW( info, cloud_devices, (int)infoCch );
|
||||
return 1;
|
||||
}
|
||||
else if ( !_wcsnicmp( metadata, L"cloud", 5 ) )
|
||||
{
|
||||
if ( _wtoi( cloud_id ) > 0 )
|
||||
{
|
||||
StringCchPrintfW( info, infoCch, L"#EXT-X-NS-CLOUD:mediahash=%s,metahash=%s,cloud_id=%s,cloud_status=%s,cloud_devices=%s",
|
||||
( mediahash && *mediahash ? mediahash : L"" ),
|
||||
( metahash && *metahash ? metahash : L"" ), cloud_id,
|
||||
( cloud_status && *cloud_status ? cloud_status : L"" ),
|
||||
( cloud_devices && *cloud_devices ? cloud_devices : L"" ) );
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
auto l_extended_infos_iterator = _extended_infos.find( metadata );
|
||||
|
||||
if ( l_extended_infos_iterator != _extended_infos.end() )
|
||||
{
|
||||
lstrcpynW( info, ( *l_extended_infos_iterator ).second.c_str(), (int)infoCch);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( !this->_extended_infos.empty() )
|
||||
{
|
||||
for ( std::map<std::wstring, std::wstring>::iterator l_extented_infos_iterator = _extended_infos.begin(); l_extented_infos_iterator != _extended_infos.end(); l_extented_infos_iterator++ )
|
||||
{
|
||||
const std::wstring &l_parameter_name = ( *l_extented_infos_iterator ).first;
|
||||
|
||||
if ( l_parameter_name.compare( metadata ) == 0 )
|
||||
{
|
||||
lstrcpynW( info, ( *l_extented_infos_iterator ).second.c_str(), (int)infoCch);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void pl_entry::SetFilename( const wchar_t *p_filename )
|
||||
{
|
||||
plstring_release( this->filename );
|
||||
|
||||
if ( p_filename && p_filename[ 0 ] )
|
||||
{
|
||||
this->filename = plstring_wcsdup( p_filename );
|
||||
|
||||
if ( wcslen( p_filename ) > 4 )
|
||||
_is_local_file = wcsncmp( this->filename, L"http", 4 ) != 0;
|
||||
}
|
||||
else
|
||||
this->filename = 0;
|
||||
}
|
||||
|
||||
void pl_entry::SetTitle( const wchar_t *title )
|
||||
{
|
||||
plstring_release( this->filetitle );
|
||||
|
||||
if ( title && title[ 0 ] )
|
||||
{
|
||||
const wchar_t *t = L" \t\n\r\f\v";
|
||||
std::wstring l_title( title );
|
||||
|
||||
l_title.erase( 0, l_title.find_first_not_of( t ) );
|
||||
|
||||
this->filetitle = plstring_wcsdup( l_title.c_str() );
|
||||
this->cached = true;
|
||||
}
|
||||
else
|
||||
this->filetitle = 0;
|
||||
}
|
||||
|
||||
void pl_entry::SetLengthMilliseconds( int length )
|
||||
{
|
||||
if ( length <= 0 )
|
||||
this->length = -1000;
|
||||
else
|
||||
this->length = length;
|
||||
}
|
||||
|
||||
void pl_entry::SetMediahash( const wchar_t *mediahash )
|
||||
{
|
||||
plstring_release( this->mediahash );
|
||||
|
||||
if ( mediahash && mediahash[ 0 ] )
|
||||
this->mediahash = plstring_wcsdup( mediahash );
|
||||
else
|
||||
this->mediahash = 0;
|
||||
}
|
||||
|
||||
void pl_entry::SetSizeBytes( int size )
|
||||
{
|
||||
if ( size <= 0 )
|
||||
this->size = 0;
|
||||
else
|
||||
this->size = size;
|
||||
}
|
||||
|
||||
void pl_entry::SetMetahash( const wchar_t *metahash )
|
||||
{
|
||||
plstring_release( this->metahash );
|
||||
|
||||
if ( metahash && metahash[ 0 ] )
|
||||
this->metahash = plstring_wcsdup( metahash );
|
||||
else
|
||||
this->metahash = 0;
|
||||
}
|
||||
|
||||
void pl_entry::SetCloudID( const wchar_t *cloud_id )
|
||||
{
|
||||
plstring_release( this->cloud_id );
|
||||
|
||||
if ( cloud_id && cloud_id[ 0 ] && _wtoi( cloud_id ) > 0 )
|
||||
this->cloud_id = plstring_wcsdup( cloud_id );
|
||||
else
|
||||
this->cloud_id = 0;
|
||||
}
|
||||
|
||||
void pl_entry::SetCloudStatus( const wchar_t *cloud_status )
|
||||
{
|
||||
plstring_release( this->cloud_status );
|
||||
|
||||
if ( cloud_status && cloud_status[ 0 ] && _wtoi( cloud_status ) >= 0 )
|
||||
this->cloud_status = plstring_wcsdup( cloud_status );
|
||||
else
|
||||
this->cloud_status = 0;
|
||||
}
|
||||
|
||||
void pl_entry::SetCloudDevices( const wchar_t *cloud_devices )
|
||||
{
|
||||
plstring_release( this->cloud_devices );
|
||||
|
||||
if ( cloud_devices && cloud_devices[ 0 ] )
|
||||
this->cloud_devices = plstring_wcsdup( cloud_devices );
|
||||
else
|
||||
this->cloud_devices = 0;
|
||||
}
|
61
Src/playlist/pl_entry.h
Normal file
61
Src/playlist/pl_entry.h
Normal file
@ -0,0 +1,61 @@
|
||||
#ifndef NULLSOFT_ML_PLAYLISTS_PL_ENTRY_H
|
||||
#define NULLSOFT_ML_PLAYLISTS_PL_ENTRY_H
|
||||
|
||||
#include "ifc_plentryinfo.h"
|
||||
#include <windows.h>
|
||||
#include <map>
|
||||
#include <iostream>
|
||||
|
||||
|
||||
class pl_entry
|
||||
{
|
||||
public:
|
||||
pl_entry() {}
|
||||
pl_entry( const wchar_t *p_filename, const wchar_t *p_title, int p_length_ms );
|
||||
pl_entry( const wchar_t *p_filename, const wchar_t *p_title, int p_length_ms, int p_size );
|
||||
pl_entry( const wchar_t *p_filename, const wchar_t *p_title, int p_length_ms, ifc_plentryinfo *p_info );
|
||||
pl_entry( const wchar_t *p_filename, const wchar_t *p_title, int p_length_ms, int p_size, ifc_plentryinfo *p_info );
|
||||
pl_entry( const wchar_t *p_filename, const wchar_t *p_title, int p_length_ms,
|
||||
const wchar_t *mediahash, const wchar_t *metahash,
|
||||
const wchar_t *cloud_id, const wchar_t *cloud_status,
|
||||
const wchar_t *cloud_devices );
|
||||
~pl_entry();
|
||||
|
||||
size_t GetFilename( wchar_t *p_filename, size_t filenameCch );
|
||||
size_t GetTitle( wchar_t *title, size_t titleCch );
|
||||
int GetLengthInMilliseconds();
|
||||
int GetSizeInBytes();
|
||||
size_t GetExtendedInfo( const wchar_t *metadata, wchar_t *info, size_t infoCch );
|
||||
|
||||
void SetFilename( const wchar_t *p_filename );
|
||||
void SetTitle( const wchar_t *title );
|
||||
void SetLengthMilliseconds( int length );
|
||||
void SetSizeBytes( int size );
|
||||
|
||||
void SetMediahash( const wchar_t *mediahash );
|
||||
void SetMetahash( const wchar_t *metahash );
|
||||
void SetCloudID( const wchar_t *cloud_id );
|
||||
void SetCloudStatus( const wchar_t *cloud_status );
|
||||
void SetCloudDevices( const wchar_t *cloud_devices );
|
||||
|
||||
bool isLocal() const { return _is_local_file; }
|
||||
|
||||
wchar_t *filename = 0;
|
||||
wchar_t *filetitle = 0;
|
||||
|
||||
wchar_t *mediahash = 0;
|
||||
wchar_t *metahash = 0;
|
||||
wchar_t *cloud_id = 0;
|
||||
wchar_t *cloud_status = 0;
|
||||
wchar_t *cloud_devices = 0;
|
||||
|
||||
std::map<std::wstring, std::wstring> _extended_infos;
|
||||
|
||||
int length = -1;
|
||||
int size = 0;
|
||||
|
||||
bool cached = false;
|
||||
bool _is_local_file = false;
|
||||
};
|
||||
|
||||
#endif
|
49
Src/playlist/playlist.mi
Normal file
49
Src/playlist/playlist.mi
Normal file
@ -0,0 +1,49 @@
|
||||
#ifndef __PLAYLIST_MI
|
||||
#define __PLAYLIST_MI
|
||||
|
||||
extern class @{632883FC-159F-4330-B193-CFD62CA47EC1}@ Object &Playlist;
|
||||
extern class @{5829EE15-3648-4c6e-B2FE-8736CBBF39DB}@ Object _predecl Playlists;
|
||||
extern class @{C18F8E50-2C81-4001-9F46-FD942B07ECCD}@ Object &PlaylistsEnumerator;
|
||||
extern class @{C6207729-2600-4bb8-B562-2E0BC04E4416}@ Object _predecl PlaylistManager;
|
||||
|
||||
/* ===== Playlist ===== */
|
||||
extern Playlist.Clear();
|
||||
extern int Playlist.GetNumItems();
|
||||
/*
|
||||
Retrieve the filename for some item in the playlist
|
||||
*/
|
||||
extern String Playlist.GetItem(int itemNumber);
|
||||
extern String Playlist.GetItemTitle(int itemNumber);
|
||||
extern int Playlist.GetItemLength(int itemNumber);
|
||||
extern String Playlist.GetItemExtendedInfo(int itemNumber, String metadata);
|
||||
extern Playlist.Reverse();
|
||||
extern Playlist.Swap(int item1, int item2);
|
||||
extern Playlist.Randomize();
|
||||
extern Playlist.Remove(int itemNumber);
|
||||
extern Playlist.SortByTitle();
|
||||
extern Playlist.SortByFilename();
|
||||
|
||||
/* ===== Playlists ===== */
|
||||
|
||||
extern PlaylistsEnumerator Playlists.GetEnumerator();
|
||||
extern Playlist Playlists.OpenPlaylist(String playlistGUID);
|
||||
extern Playlists.SavePlaylist(String playlistGUID, Playlist playlist_to_save);
|
||||
|
||||
/* ===== PlaylistsEnumerator ===== */
|
||||
|
||||
/* returns the number of playlists in the enumerator object */
|
||||
extern int PlaylistsEnumerator.GetCount();
|
||||
extern String PlaylistsEnumerator.GetFilename(int playlistNumber);
|
||||
extern String PlaylistsEnumerator.GetTitle(int playlistNumber);
|
||||
extern int PlaylistsEnumerator.GetLength(int playlistNumber);
|
||||
/*
|
||||
returns number of items in one of the playlists
|
||||
*/
|
||||
extern int PlaylistsEnumerator.GetNumItems(int playlistNumber);
|
||||
extern String PlaylistsEnumerator.GetGUID(int playlistNumber);
|
||||
|
||||
/* ===== Playlist Manager ===== */
|
||||
extern Playlist PlaylistManager.OpenPlaylist(String filename);
|
||||
extern PlaylistManager.SavePlaylist(String filename, Playlist playlist_to_save);
|
||||
|
||||
#endif
|
86
Src/playlist/playlist.rc
Normal file
86
Src/playlist/playlist.rc
Normal file
@ -0,0 +1,86 @@
|
||||
// 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\n"
|
||||
"\0"
|
||||
END
|
||||
|
||||
3 TEXTINCLUDE
|
||||
BEGIN
|
||||
"#include ""version.rc2""\r\n"
|
||||
"\0"
|
||||
END
|
||||
|
||||
#endif // APSTUDIO_INVOKED
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// String Table
|
||||
//
|
||||
|
||||
STRINGTABLE
|
||||
BEGIN
|
||||
65535 "{9E398E5F-EDEC-4dd8-A40D-E29B385A88C0}"
|
||||
END
|
||||
|
||||
STRINGTABLE
|
||||
BEGIN
|
||||
IDS_M3U_PLAYLIST "M3U Playlist"
|
||||
IDS_PLS_PLAYLIST "PLS Playlist"
|
||||
IDS_WINAMP3_PLAYLIST "Winamp3 Playlist"
|
||||
IDS_ALL_PLAYLIST_TYPES "All Playlist Types"
|
||||
IDS_PLAYLIST "Playlist"
|
||||
IDS_MPCPL_PLAYLIST "Media Player Classic Playlist (MPCPL)"
|
||||
IDS_FPL_PLAYLIST "Foobar2000 Playlist (FPL)"
|
||||
IDS_XSPF_PLAYLIST "XML Shareable Playlist Format"
|
||||
END
|
||||
|
||||
#endif // English (U.S.) resources
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
#ifndef APSTUDIO_INVOKED
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Generated from the TEXTINCLUDE 3 resource.
|
||||
//
|
||||
#include "version.rc2"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
#endif // not APSTUDIO_INVOKED
|
||||
|
30
Src/playlist/playlist.sln
Normal file
30
Src/playlist/playlist.sln
Normal file
@ -0,0 +1,30 @@
|
||||
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}") = "playlist", "playlist.vcxproj", "{B2C0F048-C7FA-4864-B5B3-75E69458BA9E}"
|
||||
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
|
||||
{B2C0F048-C7FA-4864-B5B3-75E69458BA9E}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{B2C0F048-C7FA-4864-B5B3-75E69458BA9E}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{B2C0F048-C7FA-4864-B5B3-75E69458BA9E}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{B2C0F048-C7FA-4864-B5B3-75E69458BA9E}.Release|Win32.Build.0 = Release|Win32
|
||||
{B2C0F048-C7FA-4864-B5B3-75E69458BA9E}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{B2C0F048-C7FA-4864-B5B3-75E69458BA9E}.Debug|x64.Build.0 = Debug|x64
|
||||
{B2C0F048-C7FA-4864-B5B3-75E69458BA9E}.Release|x64.ActiveCfg = Release|x64
|
||||
{B2C0F048-C7FA-4864-B5B3-75E69458BA9E}.Release|x64.Build.0 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {3815C7C8-CBE1-4F34-B885-16D73AD02A60}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
342
Src/playlist/playlist.vcxproj
Normal file
342
Src/playlist/playlist.vcxproj
Normal file
@ -0,0 +1,342 @@
|
||||
<?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>{B2C0F048-C7FA-4864-B5B3-75E69458BA9E}</ProjectGuid>
|
||||
<RootNamespace>playlist</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>
|
||||
<TargetExt>.w5s</TargetExt>
|
||||
<IncludePath>$(IncludePath)</IncludePath>
|
||||
<LibraryPath>$(LibraryPath)</LibraryPath>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<OutDir>$(PlatformShortName)_$(Configuration)\</OutDir>
|
||||
<IntDir>$(PlatformShortName)_$(Configuration)\</IntDir>
|
||||
<TargetExt>.w5s</TargetExt>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<OutDir>$(PlatformShortName)_$(Configuration)\</OutDir>
|
||||
<IntDir>$(PlatformShortName)_$(Configuration)\</IntDir>
|
||||
<TargetExt>.w5s</TargetExt>
|
||||
<IncludePath>$(IncludePath)</IncludePath>
|
||||
<LibraryPath>$(LibraryPath)</LibraryPath>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<OutDir>$(PlatformShortName)_$(Configuration)\</OutDir>
|
||||
<IntDir>$(PlatformShortName)_$(Configuration)\</IntDir>
|
||||
<TargetExt>.w5s</TargetExt>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Label="Vcpkg">
|
||||
<VcpkgEnabled>false</VcpkgEnabled>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<VcpkgTriplet>x86-windows-static-md</VcpkgTriplet>
|
||||
<VcpkgConfiguration>Debug</VcpkgConfiguration>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<VcpkgTriplet>x86-windows-static-md</VcpkgTriplet>
|
||||
<VcpkgConfiguration>Debug</VcpkgConfiguration>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<VcpkgTriplet>x86-windows-static-md</VcpkgTriplet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<VcpkgTriplet>x86-windows-static-md</VcpkgTriplet>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<AdditionalIncludeDirectories>.;..;../Wasabi;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;PLAYLIST_EXPORTS;_WIN32_WINNT=0x0601;WINVER=0x0601;_WIN32_IE=0x0A00;_CRT_SECURE_NO_WARNINGS;_CRT_NON_CONFORMING_WCSTOK;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<MinimalRebuild>false</MinimalRebuild>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
|
||||
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
<ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<RandomizedBaseAddress>false</RandomizedBaseAddress>
|
||||
<ImportLibrary>$(ProjectDir)x86_Debug\$(ProjectName).lib</ImportLibrary>
|
||||
<TargetMachine>MachineX86</TargetMachine>
|
||||
<ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
|
||||
<AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
<PostBuildEvent>
|
||||
<Command>xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\System\
|
||||
xcopy /Y /D $(IntDir)$(TargetName).pdb ..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\System\ </Command>
|
||||
<Message>Post build event: 'xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\System\'</Message>
|
||||
</PostBuildEvent>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<AdditionalIncludeDirectories>.;..;../Wasabi;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>WIN64;_DEBUG;_WINDOWS;_USRDLL;PLAYLIST_EXPORTS;_WIN32_WINNT=0x0601;WINVER=0x0601;_WIN32_IE=0x0A00;_CRT_SECURE_NO_WARNINGS;_CRT_NON_CONFORMING_WCSTOK;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<MinimalRebuild>false</MinimalRebuild>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
|
||||
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
<DisableSpecificWarnings>4244;%(DisableSpecificWarnings)</DisableSpecificWarnings>
|
||||
<ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<RandomizedBaseAddress>false</RandomizedBaseAddress>
|
||||
<ImportLibrary>$(ProjectDir)x64_Debug\$(ProjectName).lib</ImportLibrary>
|
||||
<ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
|
||||
<AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
<PostBuildEvent>
|
||||
<Command>xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\System\
|
||||
xcopy /Y /D $(IntDir)$(TargetName).pdb ..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\System\ </Command>
|
||||
<Message>Post build event: 'xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\System\'</Message>
|
||||
</PostBuildEvent>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<Optimization>MinSpace</Optimization>
|
||||
<FavorSizeOrSpeed>Size</FavorSizeOrSpeed>
|
||||
<AdditionalIncludeDirectories>.;..;../Wasabi;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;PLAYLIST_EXPORTS;_WIN32_WINNT=0x0601;WINVER=0x0601;_WIN32_IE=0x0A00;_CRT_SECURE_NO_WARNINGS;_CRT_NON_CONFORMING_WCSTOK;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<StringPooling>true</StringPooling>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
|
||||
<BufferSecurityCheck>true</BufferSecurityCheck>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<DebugInformationFormat>None</DebugInformationFormat>
|
||||
<ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
|
||||
<DelayLoadDLLs>ole32.dll;rpcrt4.dll;%(DelayLoadDLLs)</DelayLoadDLLs>
|
||||
<GenerateDebugInformation>false</GenerateDebugInformation>
|
||||
<ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<RandomizedBaseAddress>false</RandomizedBaseAddress>
|
||||
<ImportLibrary>$(ProjectDir)x86_Release\$(ProjectName).lib</ImportLibrary>
|
||||
<TargetMachine>MachineX86</TargetMachine>
|
||||
<ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
|
||||
<AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
<PostBuildEvent>
|
||||
<Command>xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\System\ </Command>
|
||||
<Message>Post build event: 'xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\System\'</Message>
|
||||
</PostBuildEvent>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<Optimization>MinSpace</Optimization>
|
||||
<FavorSizeOrSpeed>Size</FavorSizeOrSpeed>
|
||||
<AdditionalIncludeDirectories>.;..;../Wasabi;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>WIN64;NDEBUG;_WINDOWS;_USRDLL;PLAYLIST_EXPORTS;_WIN32_WINNT=0x0601;WINVER=0x0601;_WIN32_IE=0x0A00;_CRT_SECURE_NO_WARNINGS;_CRT_NON_CONFORMING_WCSTOK;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<StringPooling>true</StringPooling>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
|
||||
<BufferSecurityCheck>true</BufferSecurityCheck>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<DebugInformationFormat>None</DebugInformationFormat>
|
||||
<DisableSpecificWarnings>4244;%(DisableSpecificWarnings)</DisableSpecificWarnings>
|
||||
<ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
|
||||
<DelayLoadDLLs>ole32.dll;rpcrt4.dll;%(DelayLoadDLLs)</DelayLoadDLLs>
|
||||
<GenerateDebugInformation>false</GenerateDebugInformation>
|
||||
<ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<RandomizedBaseAddress>false</RandomizedBaseAddress>
|
||||
<ImportLibrary>$(ProjectDir)x64_Release\$(ProjectName).lib</ImportLibrary>
|
||||
<ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
|
||||
<AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
<PostBuildEvent>
|
||||
<Command>xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\System\ </Command>
|
||||
<Message>Post build event: 'xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\System\'</Message>
|
||||
</PostBuildEvent>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\nu\ServiceWatcher.cpp" />
|
||||
<ClCompile Include="..\Wasabi\api\script\objcontroller.cpp" />
|
||||
<ClCompile Include="..\Wasabi\api\script\objects\rootobj.cpp" />
|
||||
<ClCompile Include="..\Wasabi\api\script\objects\rootobjcbx.cpp" />
|
||||
<ClCompile Include="..\Wasabi\api\script\scriptobji.cpp" />
|
||||
<ClCompile Include="..\Wasabi\api\script\scriptobjx.cpp" />
|
||||
<ClCompile Include="..\Wasabi\bfc\assert.cpp" />
|
||||
<ClCompile Include="..\Wasabi\bfc\foreach.cpp" />
|
||||
<ClCompile Include="..\Wasabi\bfc\memblock.cpp" />
|
||||
<ClCompile Include="..\Wasabi\bfc\nsguid.cpp" />
|
||||
<ClCompile Include="..\Wasabi\bfc\parse\PathParseW.cpp" />
|
||||
<ClCompile Include="..\Wasabi\bfc\std_string.cpp" />
|
||||
<ClCompile Include="..\Wasabi\bfc\string\string.cpp" />
|
||||
<ClCompile Include="..\Wasabi\bfc\string\StringW.cpp" />
|
||||
<ClCompile Include="..\Wasabi\bfc\wasabi_std.cpp" />
|
||||
<ClCompile Include="..\Winamp\JSAPI_CallbackParameters.cpp" />
|
||||
<ClCompile Include="..\Winamp\JSAPI_ObjectArray.cpp" />
|
||||
<ClCompile Include="..\Winamp\strutil.cpp" />
|
||||
<ClCompile Include="B4SLoader.cpp" />
|
||||
<ClCompile Include="B4SWriter.cpp" />
|
||||
<ClCompile Include="factory_Handler.cpp" />
|
||||
<ClCompile Include="factory_playlistmanager.cpp" />
|
||||
<ClCompile Include="factory_playlists.cpp" />
|
||||
<ClCompile Include="Handler.cpp" />
|
||||
<ClCompile Include="JSAPI2_Creator.cpp" />
|
||||
<ClCompile Include="JSAPI2_Playlist.cpp" />
|
||||
<ClCompile Include="JSAPI2_Playlists.cpp" />
|
||||
<ClCompile Include="M3U8Writer.cpp" />
|
||||
<ClCompile Include="M3ULoader.cpp" />
|
||||
<ClCompile Include="M3UWriter.cpp" />
|
||||
<ClCompile Include="main.cpp" />
|
||||
<ClCompile Include="Playlist.cpp" />
|
||||
<ClCompile Include="PlaylistCounter.cpp" />
|
||||
<ClCompile Include="PlaylistManager.cpp" />
|
||||
<ClCompile Include="Playlists.cpp" />
|
||||
<ClCompile Include="PlaylistsXML.cpp" />
|
||||
<ClCompile Include="PLSLoader.cpp" />
|
||||
<ClCompile Include="plstring.cpp" />
|
||||
<ClCompile Include="PLSWriter.cpp" />
|
||||
<ClCompile Include="pl_entry.cpp" />
|
||||
<ClCompile Include="ScriptObjectFactory.cpp" />
|
||||
<ClCompile Include="ScriptObjectService.cpp" />
|
||||
<ClCompile Include="SPlaylist.cpp" />
|
||||
<ClCompile Include="SPlaylistManager.cpp" />
|
||||
<ClCompile Include="SPlaylists.cpp" />
|
||||
<ClCompile Include="SPlaylistsEnumerator.cpp" />
|
||||
<ClCompile Include="util.cpp" />
|
||||
<ClCompile Include="XMLString.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\Winamp\JSAPI_ObjectArray.h" />
|
||||
<ClInclude Include="..\Winamp\strutil.h" />
|
||||
<ClInclude Include="api__playlist.h" />
|
||||
<ClInclude Include="api_playlistmanager.h" />
|
||||
<ClInclude Include="api_playlists.h" />
|
||||
<ClInclude Include="B4SLoader.h" />
|
||||
<ClInclude Include="B4SWriter.h" />
|
||||
<ClInclude Include="factory_Handler.h" />
|
||||
<ClInclude Include="factory_playlistmanager.h" />
|
||||
<ClInclude Include="factory_playlists.h" />
|
||||
<ClInclude Include="Handler.h" />
|
||||
<ClInclude Include="ifc_playlist.h" />
|
||||
<ClInclude Include="ifc_playlistloader.h" />
|
||||
<ClInclude Include="JSAPI2_Creator.h" />
|
||||
<ClInclude Include="JSAPI2_Playlist.h" />
|
||||
<ClInclude Include="JSAPI2_Playlists.h" />
|
||||
<ClInclude Include="M3U8Writer.h" />
|
||||
<ClInclude Include="M3ULoader.h" />
|
||||
<ClInclude Include="M3UWriter.h" />
|
||||
<ClInclude Include="main.h" />
|
||||
<ClInclude Include="PlaylistCounter.h" />
|
||||
<ClInclude Include="PlaylistManager.h" />
|
||||
<ClInclude Include="Playlists.h" />
|
||||
<ClInclude Include="PlaylistsXML.h" />
|
||||
<ClInclude Include="PlaylistWriter.h" />
|
||||
<ClInclude Include="PLSLoader.h" />
|
||||
<ClInclude Include="plstring.h" />
|
||||
<ClInclude Include="PLSWriter.h" />
|
||||
<ClInclude Include="pl_entry.h" />
|
||||
<ClInclude Include="resource.h" />
|
||||
<ClInclude Include="ScriptObjectFactory.h" />
|
||||
<ClInclude Include="ScriptObjectService.h" />
|
||||
<ClInclude Include="SPlaylist.h" />
|
||||
<ClInclude Include="SPlaylistManager.h" />
|
||||
<ClInclude Include="SPlaylists.h" />
|
||||
<ClInclude Include="SPlaylistsEnumerator.h" />
|
||||
<ClInclude Include="svc_playlisthandler.h" />
|
||||
<ClInclude Include="XMLString.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="playlist.rc" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<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>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
299
Src/playlist/playlist.vcxproj.filters
Normal file
299
Src/playlist/playlist.vcxproj.filters
Normal file
@ -0,0 +1,299 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<ClCompile Include="B4SLoader.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="B4SWriter.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="factory_Handler.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="factory_playlistmanager.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="factory_playlists.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Handler.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="JSAPI2_Creator.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="JSAPI2_Playlist.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="JSAPI2_Playlists.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="M3U8Writer.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="M3UWriter.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="M3ULoader.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="main.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="pl_entry.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Playlist.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="PlaylistCounter.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="PlaylistManager.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Playlists.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="PlaylistsXML.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="PLSLoader.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="plstring.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="PLSWriter.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ScriptObjectFactory.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ScriptObjectService.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="SPlaylist.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="SPlaylistManager.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="SPlaylists.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="SPlaylistsEnumerator.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="util.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="XMLString.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\Wasabi\bfc\assert.cpp">
|
||||
<Filter>Source Files\Wasabi\bfc</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\Wasabi\bfc\foreach.cpp">
|
||||
<Filter>Source Files\Wasabi\bfc</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\Winamp\JSAPI_CallbackParameters.cpp">
|
||||
<Filter>Source Files\Winamp</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\Winamp\JSAPI_ObjectArray.cpp">
|
||||
<Filter>Source Files\Winamp</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\Wasabi\bfc\memblock.cpp">
|
||||
<Filter>Source Files\Wasabi\bfc</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\Wasabi\bfc\nsguid.cpp">
|
||||
<Filter>Source Files\Wasabi\bfc</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\Wasabi\api\script\objcontroller.cpp">
|
||||
<Filter>Source Files\Wasabi\api</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\Wasabi\bfc\parse\PathParseW.cpp">
|
||||
<Filter>Source Files\Wasabi\bfc</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\Wasabi\api\script\objects\rootobj.cpp">
|
||||
<Filter>Source Files\Wasabi\api</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\Wasabi\api\script\objects\rootobjcbx.cpp">
|
||||
<Filter>Source Files\Wasabi\api</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\Wasabi\api\script\scriptobji.cpp">
|
||||
<Filter>Source Files\Wasabi\api</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\Wasabi\api\script\scriptobjx.cpp">
|
||||
<Filter>Source Files\Wasabi\api</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\nu\ServiceWatcher.cpp">
|
||||
<Filter>Source Files\nu</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\Wasabi\bfc\std_string.cpp">
|
||||
<Filter>Source Files\Wasabi\bfc</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\Wasabi\bfc\string\StringW.cpp">
|
||||
<Filter>Source Files\Wasabi\bfc</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\Wasabi\bfc\string\string.cpp">
|
||||
<Filter>Source Files\Wasabi\bfc</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\Winamp\strutil.cpp">
|
||||
<Filter>Source Files\Winamp</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\Wasabi\bfc\wasabi_std.cpp">
|
||||
<Filter>Source Files\Wasabi\bfc</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="api__playlist.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="api_playlistmanager.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="api_playlists.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="B4SLoader.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="B4SWriter.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="factory_Handler.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="factory_playlistmanager.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="factory_playlists.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Handler.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="ifc_playlist.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="ifc_playlistloader.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\Winamp\JSAPI_ObjectArray.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="JSAPI2_Creator.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="JSAPI2_Playlist.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="JSAPI2_Playlists.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="M3U8Writer.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="M3ULoader.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="M3UWriter.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="main.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="pl_entry.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="PlaylistCounter.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="PlaylistManager.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Playlists.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="PlaylistsXML.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="PlaylistWriter.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="PLSLoader.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="plstring.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="PLSWriter.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="resource.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="ScriptObjectFactory.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="ScriptObjectService.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="SPlaylist.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="SPlaylistManager.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="SPlaylists.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="SPlaylistsEnumerator.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="svc_playlisthandler.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="XMLString.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\Winamp\strutil.h">
|
||||
<Filter>Header Files\Winamp</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{e091476c-aae2-467b-9b96-08b12796cbcb}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Ressource Files">
|
||||
<UniqueIdentifier>{b035c0ae-5ec9-481d-a5ce-02d790985bc9}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{3c7b3569-6627-448b-a320-57a5fc880fe1}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Source Files\Wasabi">
|
||||
<UniqueIdentifier>{158dd0e1-252e-49be-8630-9d3b31313f79}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Source Files\Wasabi\bfc">
|
||||
<UniqueIdentifier>{9b816713-5c43-4613-9a32-54c9413d76fd}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Source Files\Winamp">
|
||||
<UniqueIdentifier>{95d29037-d9f4-4431-8b6d-9312dcbdc38e}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Source Files\Wasabi\api">
|
||||
<UniqueIdentifier>{93f96976-a073-46d0-822d-c7da3c1c8286}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Source Files\nu">
|
||||
<UniqueIdentifier>{01f330ce-f18e-43d9-9b79-b8def37065b1}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Header Files\Winamp">
|
||||
<UniqueIdentifier>{31801414-58c9-4a09-bd1a-2a71d7255072}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="playlist.rc">
|
||||
<Filter>Ressource Files</Filter>
|
||||
</ResourceCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
199
Src/playlist/playlist.xcodeproj/project.pbxproj
Normal file
199
Src/playlist/playlist.xcodeproj/project.pbxproj
Normal file
@ -0,0 +1,199 @@
|
||||
// !$*UTF8*$!
|
||||
{
|
||||
archiveVersion = 1;
|
||||
classes = {
|
||||
};
|
||||
objectVersion = 42;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
0C19117B0BC1D80B005443D9 /* PlaylistCounter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0C19117A0BC1D80B005443D9 /* PlaylistCounter.cpp */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
0C19117A0BC1D80B005443D9 /* PlaylistCounter.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = PlaylistCounter.cpp; sourceTree = "<group>"; };
|
||||
D2AAC0630554660B00DB518D /* playlist.w5s */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = playlist.w5s; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
D289988505E68E00004EDB86 /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
08FB7794FE84155DC02AAC07 /* playlist */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
08FB7795FE84155DC02AAC07 /* Source */,
|
||||
1AB674ADFE9D54B511CA2CBB /* Products */,
|
||||
);
|
||||
name = playlist;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
08FB7795FE84155DC02AAC07 /* Source */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
0C19117A0BC1D80B005443D9 /* PlaylistCounter.cpp */,
|
||||
0C1911740BC1D456005443D9 /* PLS */,
|
||||
);
|
||||
name = Source;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
0C1911740BC1D456005443D9 /* PLS */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
);
|
||||
name = PLS;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
1AB674ADFE9D54B511CA2CBB /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
D2AAC0630554660B00DB518D /* playlist.w5s */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXHeadersBuildPhase section */
|
||||
D2AAC0600554660B00DB518D /* Headers */ = {
|
||||
isa = PBXHeadersBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXHeadersBuildPhase section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
D2AAC0620554660B00DB518D /* playlist */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 1DEB914A08733D8E0010E9CD /* Build configuration list for PBXNativeTarget "playlist" */;
|
||||
buildPhases = (
|
||||
D2AAC0600554660B00DB518D /* Headers */,
|
||||
D2AAC0610554660B00DB518D /* Sources */,
|
||||
D289988505E68E00004EDB86 /* Frameworks */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
);
|
||||
name = playlist;
|
||||
productName = playlist;
|
||||
productReference = D2AAC0630554660B00DB518D /* playlist.w5s */;
|
||||
productType = "com.apple.product-type.library.dynamic";
|
||||
};
|
||||
/* End PBXNativeTarget section */
|
||||
|
||||
/* Begin PBXProject section */
|
||||
08FB7793FE84155DC02AAC07 /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
buildConfigurationList = 1DEB914E08733D8E0010E9CD /* Build configuration list for PBXProject "playlist" */;
|
||||
hasScannedForEncodings = 1;
|
||||
mainGroup = 08FB7794FE84155DC02AAC07 /* playlist */;
|
||||
projectDirPath = "";
|
||||
targets = (
|
||||
D2AAC0620554660B00DB518D /* playlist */,
|
||||
);
|
||||
};
|
||||
/* End PBXProject section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
D2AAC0610554660B00DB518D /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
0C19117B0BC1D80B005443D9 /* PlaylistCounter.cpp in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXSourcesBuildPhase section */
|
||||
|
||||
/* Begin XCBuildConfiguration section */
|
||||
1DEB914B08733D8E0010E9CD /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
EXECUTABLE_EXTENSION = w5s;
|
||||
EXECUTABLE_PREFIX = "";
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
GCC_ENABLE_FIX_AND_CONTINUE = YES;
|
||||
GCC_MODEL_TUNING = G5;
|
||||
GCC_OPTIMIZATION_LEVEL = 0;
|
||||
HEADER_SEARCH_PATHS = ../Wasabi;
|
||||
INSTALL_PATH = /usr/local/lib;
|
||||
PRODUCT_NAME = playlist;
|
||||
ZERO_LINK = YES;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
1DEB914C08733D8E0010E9CD /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ALWAYS_SEARCH_USER_PATHS = NO;
|
||||
ARCHS = (
|
||||
ppc,
|
||||
i386,
|
||||
);
|
||||
EXECUTABLE_EXTENSION = w5s;
|
||||
EXECUTABLE_PREFIX = "";
|
||||
GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
|
||||
GCC_MODEL_TUNING = G5;
|
||||
HEADER_SEARCH_PATHS = ../Wasabi;
|
||||
INSTALL_PATH = /usr/local/lib;
|
||||
PRODUCT_NAME = playlist;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
1DEB914F08733D8E0010E9CD /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
PREBINDING = NO;
|
||||
SDKROOT = /Developer/SDKs/MacOSX10.4u.sdk;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
1DEB915008733D8E0010E9CD /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
PREBINDING = NO;
|
||||
SDKROOT = /Developer/SDKs/MacOSX10.4u.sdk;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
/* End XCBuildConfiguration section */
|
||||
|
||||
/* Begin XCConfigurationList section */
|
||||
1DEB914A08733D8E0010E9CD /* Build configuration list for PBXNativeTarget "playlist" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
1DEB914B08733D8E0010E9CD /* Debug */,
|
||||
1DEB914C08733D8E0010E9CD /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
1DEB914E08733D8E0010E9CD /* Build configuration list for PBXProject "playlist" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
1DEB914F08733D8E0010E9CD /* Debug */,
|
||||
1DEB915008733D8E0010E9CD /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
/* End XCConfigurationList section */
|
||||
};
|
||||
rootObject = 08FB7793FE84155DC02AAC07 /* Project object */;
|
||||
}
|
86
Src/playlist/plstring.cpp
Normal file
86
Src/playlist/plstring.cpp
Normal file
@ -0,0 +1,86 @@
|
||||
#include "plstring.h"
|
||||
#include "api__playlist.h"
|
||||
#include <shlwapi.h>
|
||||
#include <stdint.h>
|
||||
|
||||
static wchar_t *_plstring_wcsdup( const wchar_t *str )
|
||||
{
|
||||
if ( !str )
|
||||
return 0;
|
||||
|
||||
size_t len = wcslen( str );
|
||||
size_t *self = (size_t *)calloc( ( len + 1 ) * sizeof( wchar_t ), sizeof( size_t ) );
|
||||
*self = 1;
|
||||
|
||||
wchar_t *new_str = (wchar_t *)( ( (int8_t *)self ) + sizeof( size_t ) );
|
||||
memcpy( new_str, str, ( len + 1 ) * sizeof( wchar_t ) );
|
||||
|
||||
return new_str;
|
||||
}
|
||||
|
||||
static wchar_t *_plstring_malloc( size_t str_size )
|
||||
{
|
||||
size_t *self = (size_t *)calloc( ( str_size ), sizeof( size_t ) );
|
||||
*self = 1;
|
||||
|
||||
wchar_t *new_str = (wchar_t *)( ( (int8_t *)self ) + sizeof( size_t ) );
|
||||
|
||||
return new_str;
|
||||
}
|
||||
|
||||
static void _plstring_release( wchar_t *str )
|
||||
{
|
||||
if ( str )
|
||||
{
|
||||
size_t *self = (size_t *)( ( (int8_t *)str ) - sizeof( size_t ) );
|
||||
( *self )--;
|
||||
|
||||
if ( *self == 0 )
|
||||
free( self );
|
||||
}
|
||||
}
|
||||
|
||||
static void _plstring_retain( wchar_t *str )
|
||||
{
|
||||
if ( str )
|
||||
{
|
||||
size_t *self = (size_t *)( ( (int8_t *)str ) - sizeof( size_t ) );
|
||||
( *self )++;
|
||||
}
|
||||
}
|
||||
|
||||
wchar_t *( *plstring_wcsdup )( const wchar_t *str ) = _plstring_wcsdup;
|
||||
wchar_t *( *plstring_malloc )( size_t str_size ) = _plstring_malloc;
|
||||
void ( *plstring_release )( wchar_t *str ) = _plstring_release;
|
||||
void ( *plstring_retain )( wchar_t *str ) = _plstring_retain;
|
||||
|
||||
static bool ndestring_tried_load = false;
|
||||
|
||||
void plstring_init()
|
||||
{
|
||||
if ( !ndestring_tried_load )
|
||||
{
|
||||
wchar_t path[ MAX_PATH ] = { 0 };
|
||||
const wchar_t *PROGDIR = WASABI_API_APP->path_getAppPath();
|
||||
|
||||
PathCombineW( path, PROGDIR, L"winamp.exe" );
|
||||
HMODULE ndelib = LoadLibraryW( path );
|
||||
if ( ndelib )
|
||||
{
|
||||
FARPROC ndestring_wcsdup = GetProcAddress( ndelib, "plstring_wcsdup" );
|
||||
FARPROC ndestring_malloc = GetProcAddress( ndelib, "plstring_malloc" );
|
||||
FARPROC ndestring_release = GetProcAddress( ndelib, "plstring_release" );
|
||||
FARPROC ndestring_retain = GetProcAddress( ndelib, "plstring_retain" );
|
||||
|
||||
if ( ndestring_wcsdup && ndestring_malloc && ndestring_release && ndestring_retain )
|
||||
{
|
||||
*(FARPROC *)&plstring_wcsdup = *(FARPROC *)ndestring_wcsdup;
|
||||
*(FARPROC *)&plstring_malloc = *(FARPROC *)ndestring_malloc;
|
||||
*(FARPROC *)&plstring_release = *(FARPROC *)ndestring_release;
|
||||
*(FARPROC *)&plstring_retain = *(FARPROC *)ndestring_retain;
|
||||
}
|
||||
}
|
||||
|
||||
ndestring_tried_load = true;
|
||||
}
|
||||
}
|
7
Src/playlist/plstring.h
Normal file
7
Src/playlist/plstring.h
Normal file
@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
#include <bfc/platform/types.h>
|
||||
extern wchar_t *(*plstring_wcsdup)(const wchar_t *str);
|
||||
extern wchar_t *(*plstring_malloc)(size_t str_size);
|
||||
extern void (*plstring_release)(wchar_t *str);
|
||||
extern void (*plstring_retain)(wchar_t *str);
|
||||
void plstring_init();
|
29
Src/playlist/resource.h
Normal file
29
Src/playlist/resource.h
Normal file
@ -0,0 +1,29 @@
|
||||
//{{NO_DEPENDENCIES}}
|
||||
// Microsoft Visual C++ generated include file.
|
||||
// Used by playlist.rc
|
||||
//
|
||||
#define IDS_STRING0 1
|
||||
#define IDS_M3U_PLAYLIST 1
|
||||
#define IDS_PLS_PLAYLIST 2
|
||||
#define IDS_WINAMP3_PLAYLIST 3
|
||||
#define IDS_ALL_PLAYLIST_TYPES 4
|
||||
#define IDS_PLAYLIST 5
|
||||
#define IDS_MPCPL_PLAYLIST 6
|
||||
#define IDS_FPL_PLAYLIST 7
|
||||
#define IDS_XSPF_PLAYLIST 8
|
||||
#define IDC_ALLOW_ALWAYS 1001
|
||||
#define IDC_ALLOW 1002
|
||||
#define IDC_BUTTON3 1003
|
||||
#define IDC_DENY 1003
|
||||
#define IDC_CHECK1 1004
|
||||
|
||||
// Next default values for new objects
|
||||
//
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
#ifndef APSTUDIO_READONLY_SYMBOLS
|
||||
#define _APS_NEXT_RESOURCE_VALUE 103
|
||||
#define _APS_NEXT_COMMAND_VALUE 40001
|
||||
#define _APS_NEXT_CONTROL_VALUE 1005
|
||||
#define _APS_NEXT_SYMED_VALUE 101
|
||||
#endif
|
||||
#endif
|
110
Src/playlist/svc_playlisthandler.h
Normal file
110
Src/playlist/svc_playlisthandler.h
Normal file
@ -0,0 +1,110 @@
|
||||
#ifndef NULLSOFT_SVC_PLAYLISTHANDLER_H
|
||||
#define NULLSOFT_SVC_PLAYLISTHANDLER_H
|
||||
|
||||
#include <bfc/dispatch.h>
|
||||
#include <bfc/platform/types.h>
|
||||
#include "ifc_playlistloader.h"
|
||||
#include <stdint.h>
|
||||
|
||||
enum
|
||||
{
|
||||
SVC_PLAYLISTHANDLER_SUCCESS = 0,
|
||||
SVC_PLAYLISTHANDLER_FAILED = 1,
|
||||
};
|
||||
class svc_playlisthandler : public Dispatchable
|
||||
{
|
||||
protected:
|
||||
svc_playlisthandler() {}
|
||||
~svc_playlisthandler() {}
|
||||
|
||||
public:
|
||||
static FOURCC getServiceType() { return svc_playlisthandler::SERVICETYPE; }
|
||||
const wchar_t *EnumerateExtensions(size_t n); // returns 0 when it's done
|
||||
const char *EnumerateMIMETypes(size_t n); // returns 0 when it's done, returns char * to match HTTP specs
|
||||
const wchar_t *GetName(); // returns a name suitable for display to user of this playlist form (e.g. PLS Playlist)
|
||||
int SupportedFilename(const wchar_t *filename); // returns SUCCESS and FAILED, so be careful ...
|
||||
int SupportedMIMEType(const char *filename); // returns SUCCESS and FAILED, so be careful ...
|
||||
ifc_playlistloader *CreateLoader(const wchar_t *filename);
|
||||
void ReleaseLoader(ifc_playlistloader *loader);
|
||||
int HasWriter(); // returns 1 if writing is supported
|
||||
//ifc_playlistwriter CreateWriter(const wchar_t *writer);
|
||||
//void ReleaseWriter(ifc_playlistwriter *writer);
|
||||
|
||||
size_t SniffSizeRequired(); // return number of bytes required for detection on an unknown file
|
||||
bool IsOurs(const int8_t *data, size_t sizeBytes);
|
||||
|
||||
public:
|
||||
DISPATCH_CODES
|
||||
{
|
||||
SVC_PLAYLISTHANDLER_ENUMEXTENSIONS = 10,
|
||||
SVC_PLAYLISTHANDLER_ENUMMIMETYPES = 20,
|
||||
SVC_PLAYLISTHANDLER_SUPPORTFILENAME= 30,
|
||||
SVC_PLAYLISTHANDLER_SUPPORTMIME= 40,
|
||||
SVC_PLAYLISTHANDLER_CREATELOADER = 50,
|
||||
SVC_PLAYLISTHANDLER_RELEASELOADER = 60,
|
||||
SVC_PLAYLISTHANDLER_CREATEWRITER= 70,
|
||||
SVC_PLAYLISTHANDLER_RELEASEWRITER= 80,
|
||||
SVC_PLAYLISTHANDLER_SNIFFSIZE=90,
|
||||
SVC_PLAYLISTHANDLER_SNIFF=100,
|
||||
SVC_PLAYLISTHANDLER_GETNAME=110,
|
||||
SVC_PLAYLISTHANDLER_HASWRITER=120,
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
SERVICETYPE = MK3CC('p','l','h')
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
inline const wchar_t *svc_playlisthandler::GetName()
|
||||
{
|
||||
return _call(SVC_PLAYLISTHANDLER_GETNAME, (const wchar_t *)0);
|
||||
}
|
||||
|
||||
inline const wchar_t *svc_playlisthandler::EnumerateExtensions(size_t n)
|
||||
{
|
||||
return _call(SVC_PLAYLISTHANDLER_ENUMEXTENSIONS, (const wchar_t *)0, n);
|
||||
};
|
||||
|
||||
inline const char *svc_playlisthandler::EnumerateMIMETypes(size_t n)
|
||||
{
|
||||
return _call(SVC_PLAYLISTHANDLER_ENUMMIMETYPES, (const char *)0, n);
|
||||
}
|
||||
|
||||
inline int svc_playlisthandler::SupportedFilename(const wchar_t *filename)
|
||||
{
|
||||
return _call(SVC_PLAYLISTHANDLER_SUPPORTFILENAME, (int)SVC_PLAYLISTHANDLER_FAILED, filename);
|
||||
}
|
||||
|
||||
inline int svc_playlisthandler::SupportedMIMEType(const char *filename)
|
||||
{
|
||||
return _call(SVC_PLAYLISTHANDLER_SUPPORTMIME, (int)SVC_PLAYLISTHANDLER_FAILED, filename);
|
||||
}
|
||||
|
||||
inline ifc_playlistloader *svc_playlisthandler::CreateLoader(const wchar_t *filename)
|
||||
{
|
||||
return _call(SVC_PLAYLISTHANDLER_CREATELOADER, (ifc_playlistloader *)0, filename);
|
||||
}
|
||||
|
||||
inline void svc_playlisthandler::ReleaseLoader(ifc_playlistloader *loader)
|
||||
{
|
||||
_voidcall(SVC_PLAYLISTHANDLER_RELEASELOADER, loader);
|
||||
}
|
||||
|
||||
inline size_t svc_playlisthandler::SniffSizeRequired()
|
||||
{
|
||||
return _call(SVC_PLAYLISTHANDLER_SNIFFSIZE, (size_t)0);
|
||||
}
|
||||
|
||||
inline bool svc_playlisthandler::IsOurs(const int8_t *data, size_t sizeBytes)
|
||||
{
|
||||
return _call(SVC_PLAYLISTHANDLER_SNIFF, (bool)false, data, sizeBytes);
|
||||
}
|
||||
|
||||
inline int svc_playlisthandler::HasWriter()
|
||||
{
|
||||
return _call(SVC_PLAYLISTHANDLER_HASWRITER, (int)0);
|
||||
}
|
||||
|
||||
#endif
|
77
Src/playlist/util.cpp
Normal file
77
Src/playlist/util.cpp
Normal file
@ -0,0 +1,77 @@
|
||||
#include <shlobj.h>
|
||||
#include <strsafe.h>
|
||||
|
||||
#include "main.h"
|
||||
#include "api__playlist.h"
|
||||
#include "../nu/ns_wc.h"
|
||||
|
||||
HRESULT ResolveShortCut(HWND hwnd, LPCWSTR pszShortcutFile, LPWSTR pszPath)
|
||||
{
|
||||
IShellLinkW *psl = 0;
|
||||
WIN32_FIND_DATAW wfd = {0};
|
||||
|
||||
*pszPath = 0; // assume failure
|
||||
|
||||
HRESULT hres = CoCreateInstance( CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLinkW, (void **)&psl );
|
||||
if ( SUCCEEDED( hres ) )
|
||||
{
|
||||
IPersistFile *ppf = 0;
|
||||
hres = psl->QueryInterface( &ppf ); // OLE 2! Yay! --YO
|
||||
if ( SUCCEEDED( hres ) )
|
||||
{
|
||||
hres = ppf->Load( pszShortcutFile, STGM_READ );
|
||||
if ( SUCCEEDED( hres ) )
|
||||
{
|
||||
hres = psl->Resolve( hwnd, SLR_ANY_MATCH );
|
||||
if ( SUCCEEDED( hres ) )
|
||||
{
|
||||
wchar_t szGotPath[ MAX_PATH ] = { 0 };
|
||||
StringCchCopyW( szGotPath, MAX_PATH, pszShortcutFile );
|
||||
hres = psl->GetPath( szGotPath, MAX_PATH, &wfd, SLGP_SHORTPATH );
|
||||
StringCchCopyW( pszPath, MAX_PATH, szGotPath );
|
||||
}
|
||||
}
|
||||
|
||||
ppf->Release();
|
||||
}
|
||||
|
||||
psl->Release();
|
||||
}
|
||||
|
||||
return SUCCEEDED(hres);
|
||||
}
|
||||
|
||||
bool IsUrl(const wchar_t *url)
|
||||
{
|
||||
return !!wcsstr(url, L"://");
|
||||
}
|
||||
|
||||
void SetUserAgent(api_httpreceiver *http)
|
||||
{
|
||||
char agent[256] = {0};
|
||||
StringCchPrintfA(agent, 256, "User-Agent: %S/%S", WASABI_API_APP->main_getAppName(), WASABI_API_APP->main_getVersionNumString());
|
||||
http->addheader(agent);
|
||||
}
|
||||
|
||||
const char *GetProxy()
|
||||
{
|
||||
static char proxy[ 256 ] = "";
|
||||
// {C0A565DC-0CFE-405a-A27C-468B0C8A3A5C}
|
||||
const GUID internetConfigGroupGUID =
|
||||
{ 0xc0a565dc, 0xcfe, 0x405a, { 0xa2, 0x7c, 0x46, 0x8b, 0xc, 0x8a, 0x3a, 0x5c } };
|
||||
ifc_configgroup *group = AGAVE_API_CONFIG->GetGroup( internetConfigGroupGUID );
|
||||
if ( group )
|
||||
{
|
||||
ifc_configitem *item = group->GetItem( L"Proxy" );
|
||||
if ( item )
|
||||
{
|
||||
const wchar_t *wideProxy = item->GetString();
|
||||
if ( wideProxy )
|
||||
{
|
||||
WideCharToMultiByteSZ( CP_ACP, 0, wideProxy, -1, proxy, 256, 0, 0 );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return proxy;
|
||||
}
|
39
Src/playlist/version.rc2
Normal file
39
Src/playlist/version.rc2
Normal file
@ -0,0 +1,39 @@
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Version
|
||||
//
|
||||
#include "../Winamp/buildType.h"
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION WINAMP_PRODUCTVER
|
||||
PRODUCTVERSION WINAMP_PRODUCTVER
|
||||
FILEFLAGSMASK 0x17L
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
#else
|
||||
FILEFLAGS 0x0L
|
||||
#endif
|
||||
FILEOS 0x4L
|
||||
FILETYPE 0x2L
|
||||
FILESUBTYPE 0x0L
|
||||
BEGIN
|
||||
BLOCK "StringFileInfo"
|
||||
BEGIN
|
||||
BLOCK "040904b0"
|
||||
BEGIN
|
||||
VALUE "CompanyName", "Winamp SA"
|
||||
VALUE "FileDescription", "Winamp 5.x System Component"
|
||||
VALUE "FileVersion", STR_WINAMP_PRODUCTVER
|
||||
VALUE "InternalName", "playlist.w5s"
|
||||
VALUE "LegalCopyright", "Copyright <20> 2005-2023 Winamp SA"
|
||||
VALUE "LegalTrademarks", "Nullsoft and Winamp are trademarks of Winamp SA"
|
||||
VALUE "OriginalFilename", "playlist.w5s"
|
||||
VALUE "ProductName", "Winamp Playlists Core Service"
|
||||
VALUE "ProductVersion", STR_WINAMP_PRODUCTVER
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
BEGIN
|
||||
VALUE "Translation", 0x409, 1200
|
||||
END
|
||||
END
|
Reference in New Issue
Block a user