mirror of
https://github.com/WinampDesktop/winamp.git
synced 2025-06-17 17:05:46 -04:00
Initial community commit
This commit is contained in:
241
Src/Plugins/Library/ml_playlists/AMNWatcher.cpp
Normal file
241
Src/Plugins/Library/ml_playlists/AMNWatcher.cpp
Normal file
@ -0,0 +1,241 @@
|
||||
#include "main.h"
|
||||
|
||||
#include "./amnwatcher.h"
|
||||
#include <shlobj.h>
|
||||
#include <strsafe.h>
|
||||
|
||||
#include "playlists.h"
|
||||
#include "PlaylistManager.h"
|
||||
#include "PlaylistView.h"
|
||||
|
||||
waServiceFactory *AMNWatcher::watcherFactory = NULL;
|
||||
|
||||
BOOL IsMusicNowWantUs(void)
|
||||
{
|
||||
HKEY key;
|
||||
DWORD value = 0, length = sizeof(DWORD);
|
||||
if (ERROR_SUCCESS == RegOpenKeyExW( HKEY_CURRENT_USER, L"Software\\AOL Music Now\\UserPreferences", 0, KEY_QUERY_VALUE, &key ))
|
||||
{
|
||||
long retCode = RegQueryValueExW(key, L"IntegrateWithWinamp", NULL, NULL, (LPBYTE) & value, &length);
|
||||
if (ERROR_SUCCESS != retCode) value = TRUE;
|
||||
RegCloseKey(key);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
BOOL GetMusicNowPlaylistPath(LPWSTR *pathNew, LPWSTR *pathOld) // CAUTION!!! this function will allocate memory for the string using malloc
|
||||
{
|
||||
// first check rgistry
|
||||
HKEY key;
|
||||
*pathNew = NULL;
|
||||
*pathOld = NULL;
|
||||
|
||||
if (ERROR_SUCCESS == RegOpenKeyExW( HKEY_CURRENT_USER, L"Software\\AOL Music Now\\UserPreferences", 0, KEY_QUERY_VALUE, &key ))
|
||||
{
|
||||
const wchar_t *rPath = L"PlaylistDirectory";
|
||||
DWORD length;
|
||||
if (ERROR_SUCCESS == RegQueryValueExW(key, rPath, NULL, NULL, NULL, &length)) // try registry ( for future)
|
||||
{
|
||||
*pathNew = (LPWSTR)malloc(length);
|
||||
if (ERROR_SUCCESS != RegQueryValueExW(key, rPath, NULL, NULL, (LPBYTE)*pathNew, &length)) { free(*pathNew); *pathNew = NULL; }
|
||||
}
|
||||
RegCloseKey(key);
|
||||
|
||||
if (*pathNew && !PathFileExists(*pathNew)) { free(*pathNew); *pathNew = NULL; } //check that path is actualy exist
|
||||
|
||||
LPITEMIDLIST pidl;
|
||||
if (S_OK == SHGetSpecialFolderLocation(NULL, CSIDL_PERSONAL, &pidl))
|
||||
{
|
||||
wchar_t path[MAX_PATH*4] = {0};
|
||||
if(SHGetPathFromIDListW(pidl, path))
|
||||
{
|
||||
const wchar_t *suffix = L"Music Now Playlists";
|
||||
int cchLen = lstrlenW(path) + lstrlenW(suffix) + 32;
|
||||
if (!*pathNew) // no luck - use deafult's
|
||||
{
|
||||
*pathNew = (LPWSTR)malloc(cchLen*sizeof(wchar_t));
|
||||
StringCchPrintfW(*pathNew, cchLen, L"%s\\%s", path, suffix);
|
||||
if (!PathFileExists(*pathNew)) {free(*pathNew); *pathNew = NULL; }// i give up - can't find anything
|
||||
}
|
||||
// now let's try old path
|
||||
*pathOld = (LPWSTR)malloc(cchLen*sizeof(wchar_t));
|
||||
StringCchPrintfW(*pathOld, cchLen, L"%s\\AOL %s", path, suffix);
|
||||
if (!PathFileExists(*pathOld)) { free(*pathOld); *pathOld = NULL; }
|
||||
}
|
||||
CoTaskMemFree(pidl);
|
||||
}
|
||||
}
|
||||
return (NULL != *pathNew) || (NULL != *pathOld);
|
||||
}
|
||||
|
||||
AMNWatcher::AMNWatcher(void) : watcherOld(NULL), watcherNew(NULL), dirty(FALSE)
|
||||
{}
|
||||
|
||||
AMNWatcher::~AMNWatcher(void)
|
||||
{
|
||||
//Destroy(); // have to just let it leak. you should call Destroy() manually
|
||||
}
|
||||
|
||||
int AMNWatcher::Init(api_service *service, const wchar_t *trackPath)
|
||||
{
|
||||
BOOL retCode = FALSE;
|
||||
if (!IsMusicNowWantUs()) return retCode;
|
||||
if (watcherFactory) return retCode;
|
||||
|
||||
LPWSTR pathNew, pathOld;
|
||||
if (!GetMusicNowPlaylistPath(&pathNew, &pathOld)) return retCode;
|
||||
int cchLen = lstrlenW(pathNew);
|
||||
if (cchLen > 1 && pathNew[cchLen -1] == L'\\') pathNew[cchLen -1] = 0x00;
|
||||
cchLen = lstrlenW(pathOld);
|
||||
if (cchLen > 1 && pathOld[cchLen -1] == L'\\') pathOld[cchLen -1] = 0x00;
|
||||
|
||||
watcherFactory = service->service_getServiceByGuid(watcherGUID);
|
||||
if (watcherFactory)
|
||||
{
|
||||
if (pathNew)
|
||||
{
|
||||
watcherNew = (api_watcher*)watcherFactory->getInterface();
|
||||
watcherNew->Create( L"WAMN_PLS_NEW", pathNew, TRUE, WATCHER_TRACKMODE_CENTRAL, OnWatcherNotify);
|
||||
}
|
||||
if (pathOld)
|
||||
{
|
||||
watcherOld = (api_watcher*)watcherFactory->getInterface();
|
||||
watcherOld->Create( L"WAMN_PLS_OLD", pathOld, TRUE, WATCHER_TRACKMODE_CENTRAL, OnWatcherNotify);
|
||||
}
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
api_watcher *watcher = (i) ? watcherOld : watcherNew;
|
||||
if (!watcher) continue;
|
||||
|
||||
watcher->SetExtensionFilter(L"WPL", WATCHER_FILTERTYPE_INCLUDE);
|
||||
watcher->SetUserData(this);
|
||||
watcher->SetCallBack(OnWatcherNotify);
|
||||
watcher->SetTrackingPath(trackPath);
|
||||
watcher->Start();
|
||||
watcher->ForceScan(FALSE, SCANPRIORITY_IDLE);
|
||||
}
|
||||
}
|
||||
free(pathNew);
|
||||
free(pathOld);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void AMNWatcher::Destroy(void)
|
||||
{
|
||||
if (watcherNew)
|
||||
{
|
||||
watcherNew->Stop();
|
||||
watcherFactory->releaseInterface(watcherNew);
|
||||
watcherNew = NULL;
|
||||
}
|
||||
if (watcherOld)
|
||||
{
|
||||
watcherOld->Stop();
|
||||
watcherFactory->releaseInterface(watcherOld);
|
||||
watcherOld = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int AMNWatcher::OnWatcherNotify(api_watcher *sender, UINT message, LONG_PTR param, void* userdata)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(sender);
|
||||
|
||||
AMNWatcher *watcher = (AMNWatcher*)userdata;
|
||||
if (WATCHER_MSG_FILE == message)
|
||||
{
|
||||
WATCHERCHANGEINFO *info = (WATCHERCHANGEINFO*)param;
|
||||
|
||||
// ignore some names
|
||||
if (info->cchFile >= 21) // can be "AOL Music Now - Auido.wpl" or "AOL Music Now - Video.wpl"
|
||||
{
|
||||
const wchar_t *testname = info->file + info->cchFile - 21;
|
||||
if (CSTR_EQUAL == CompareString(LOCALE_USER_DEFAULT, NULL, testname, 9, L"Music Now", 9)) return 1;
|
||||
}
|
||||
else if ( 17 == info->cchFile && CSTR_EQUAL == CompareString(LOCALE_USER_DEFAULT, NULL, info->file, 13, L"AOL Music Now", 13)) return 1;
|
||||
|
||||
wchar_t fullName[MAX_PATH*4];
|
||||
PathCombineW(fullName, info->path, info->file);
|
||||
|
||||
size_t i(0);
|
||||
|
||||
switch (info->state)
|
||||
{
|
||||
case WATCHER_FILESTATE_ADDED:
|
||||
case WATCHER_FILESTATE_CHANGED:
|
||||
{
|
||||
if (!info->file)
|
||||
break;
|
||||
wchar_t *title = _wcsdup(info->file);
|
||||
unsigned int len = lstrlen(title);
|
||||
while (len && title[len] != '.') len--;
|
||||
if (len != 0) title[len] = 0x00;
|
||||
while (i != playlists.size() && lstrcmpW(fullName, playlists.at(i).filename)) i++;
|
||||
if ( i == playlists.size())
|
||||
{
|
||||
AddPlaylist(title, fullName, TRUE, playlistManager->CountItems(fullName));
|
||||
watcher->dirty = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
int length = playlistManager->GetLengthMilliseconds(fullName);
|
||||
int numItems = (int)playlistManager->CountItems(fullName);
|
||||
if (playlists.at(i).length != length || playlists.at(i).numItems != numItems)
|
||||
{
|
||||
StringCchCopy(playlists.at(i).title, 1024, title);
|
||||
playlists.at(i).length = length;
|
||||
playlists.at(i).numItems = numItems;
|
||||
|
||||
HWND hwnd = (HWND) SendMessage(plugin.hwndLibraryParent, WM_ML_IPC, 0, ML_IPC_GETCURRENTVIEW);
|
||||
if (hwnd)
|
||||
{
|
||||
wchar_t* title = (wchar_t*)GetPropW(hwnd, L"TITLE");
|
||||
if (title && 0 == lstrcmp(title, playlists[i].title)) SendMessage(hwnd, WM_PLAYLIST_RELOAD, 0, 0);
|
||||
}
|
||||
watcher->dirty = TRUE;
|
||||
}
|
||||
|
||||
}
|
||||
free(title);
|
||||
}
|
||||
break;
|
||||
case WATCHER_FILESTATE_REMOVED:
|
||||
{
|
||||
for ( i = 0; i < playlists.size(); i++)
|
||||
{
|
||||
if (0 == lstrcmpW(fullName, playlists.at(i).filename))
|
||||
{
|
||||
HWND hwnd = (HWND) SendMessage(plugin.hwndLibraryParent, WM_ML_IPC, 0, ML_IPC_GETCURRENTVIEW);
|
||||
if (hwnd)
|
||||
{
|
||||
wchar_t* title = (wchar_t *)GetPropW(hwnd, L"TITLE");
|
||||
if (title && 0 == lstrcmp(title, playlists[i].title)) SendMessage(hwnd, WM_PLAYLIST_UNLOAD, 0, 0);
|
||||
}
|
||||
if (playlists.at(i).treeId)
|
||||
mediaLibrary.RemoveTreeItem(playlists.at(i).treeId);
|
||||
playlists.eraseAt(i);
|
||||
i--;
|
||||
watcher->dirty = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (WATCHER_MSG_STATUS == message)
|
||||
{
|
||||
if (STATUS_SCANER_STOPPED == param || STATUS_SCANER_FINISHED == param)
|
||||
{
|
||||
if (watcher->dirty)
|
||||
{
|
||||
SavePlaylists();
|
||||
RefreshPlaylistsList();
|
||||
watcher->dirty = FALSE;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return 1;
|
||||
}
|
124
Src/Plugins/Library/ml_playlists/AddPlaylist.cpp
Normal file
124
Src/Plugins/Library/ml_playlists/AddPlaylist.cpp
Normal file
@ -0,0 +1,124 @@
|
||||
#include "main.h"
|
||||
#include <shlwapi.h>
|
||||
#include "resource.h"
|
||||
|
||||
wchar_t *createPlayListDBFileName(wchar_t *filename) // filename is ignored but used for temp space, make sure it's 1024+256 chars =)
|
||||
{
|
||||
wchar_t *filenameptr;
|
||||
int x = 32;
|
||||
for (;;)
|
||||
{
|
||||
GetTempFileNameW(g_path, L"plf", GetTickCount() + x*5000, filename);
|
||||
if ( wcslen(filename) > 4)
|
||||
{
|
||||
if (g_config->ReadInt(L"playlist_m3u8", 1))
|
||||
lstrcpyW(filename + wcslen(filename) - 4, L".m3u8");
|
||||
else
|
||||
lstrcpyW(filename + wcslen(filename) - 4, L".m3u");
|
||||
}
|
||||
HANDLE h = CreateFileW(filename, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, CREATE_NEW, 0, 0);
|
||||
if (h != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
filenameptr = filename + wcslen(g_path) + 1;
|
||||
CloseHandle(h);
|
||||
break;
|
||||
}
|
||||
if (++x > 4096)
|
||||
{
|
||||
filenameptr = L"error.m3u";
|
||||
break;
|
||||
}
|
||||
}
|
||||
return filenameptr;
|
||||
}
|
||||
|
||||
void playlists_AddToCloudPrompt(HWND hwndDlg)
|
||||
{
|
||||
if (g_config->ReadInt(L"cloud_always", 0) && !g_config->ReadInt(L"cloud_prompt", 0) && g_config->ReadInt(L"cloud", 1))
|
||||
{
|
||||
wchar_t titleStr[64] = {0};
|
||||
if (MessageBox(hwndDlg, WASABI_API_LNGSTRINGW(IDS_CLOUD_UNCHECKED),
|
||||
WASABI_API_LNGSTRINGW_BUF(IDS_SENDTO_NEW_CLOUD_PLAYLIST, titleStr, 64),
|
||||
MB_YESNO | MB_ICONQUESTION | MB_DEFBUTTON2) == IDYES)
|
||||
{
|
||||
g_config->WriteInt(L"cloud", (IsDlgButtonChecked(hwndDlg, IDC_CLOUD) == BST_CHECKED));
|
||||
}
|
||||
else
|
||||
{
|
||||
CheckDlgButton(hwndDlg, IDC_CLOUD, playlists_CloudAvailable() && g_config->ReadInt(L"cloud", 1));
|
||||
}
|
||||
g_config->WriteInt(L"cloud_prompt", 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_config->WriteInt(L"cloud", (IsDlgButtonChecked(hwndDlg, IDC_CLOUD) == BST_CHECKED));
|
||||
}
|
||||
}
|
||||
|
||||
int AddToCloud()
|
||||
{
|
||||
if (playlists_CloudAvailable())
|
||||
{
|
||||
if (g_config->ReadInt(L"cloud_always", 1))
|
||||
{
|
||||
g_config->WriteInt(L"cloud", 1);
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
g_config->WriteInt(L"cloud", 0);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
INT_PTR CALLBACK AddPlaylistDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
switch (uMsg)
|
||||
{
|
||||
case WM_INITDIALOG:
|
||||
{
|
||||
SetProp(hwndDlg, L"pladdcb", (HANDLE)lParam);
|
||||
CheckDlgButton(hwndDlg, IDC_CLOUD, AddToCloud());
|
||||
PostMessage(hwndDlg, WM_NEXTDLGCTL, (WPARAM)GetDlgItem(hwndDlg, IDC_NAME), TRUE);
|
||||
break;
|
||||
}
|
||||
|
||||
case WM_COMMAND:
|
||||
switch (LOWORD(wParam))
|
||||
{
|
||||
case IDOK:
|
||||
{
|
||||
wchar_t name[256] = {0};
|
||||
GetDlgItemText(hwndDlg, IDC_NAME, name, 255);
|
||||
if (!name[0])
|
||||
{
|
||||
wchar_t titleStr[32] = {0};
|
||||
MessageBox(hwndDlg, WASABI_API_LNGSTRINGW(IDS_ENTER_A_NAME),
|
||||
WASABI_API_LNGSTRINGW_BUF(IDS_ERROR, titleStr, 32), MB_OK);
|
||||
break;
|
||||
}
|
||||
|
||||
wchar_t filename[1024 + 256] = {0};
|
||||
createPlayListDBFileName(filename);
|
||||
bool callback = !!GetProp(hwndDlg, L"pladdcb");
|
||||
AddPlaylist(callback, name, filename, true, (playlists_CloudAvailable() ? g_config->ReadInt(L"cloud", 1) : 0));
|
||||
if (callback) AGAVE_API_PLAYLISTS->Flush(); // REVIEW: save immediately? or only at the end?
|
||||
EndDialog(hwndDlg, 1);
|
||||
}
|
||||
break;
|
||||
|
||||
case IDCANCEL:
|
||||
EndDialog(hwndDlg, 0);
|
||||
break;
|
||||
|
||||
case IDC_CLOUD:
|
||||
{
|
||||
playlists_AddToCloudPrompt(hwndDlg);
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return FALSE;
|
||||
};
|
313
Src/Plugins/Library/ml_playlists/CurrentPlaylist.cpp
Normal file
313
Src/Plugins/Library/ml_playlists/CurrentPlaylist.cpp
Normal file
@ -0,0 +1,313 @@
|
||||
#include <shlobj.h>
|
||||
#include <shlwapi.h>
|
||||
#include <strsafe.h>
|
||||
|
||||
#include "main.h"
|
||||
#include "CurrentPlaylist.h"
|
||||
#include "Playlist.h"
|
||||
#include "../winamp/wa_ipc.h"
|
||||
#include "../nu/AutoWide.h"
|
||||
#include "PlaylistDirectoryCallback.h"
|
||||
#include "api__ml_playlists.h"
|
||||
|
||||
extern Playlist currentPlaylist;
|
||||
|
||||
bool currentPlaylist_ImportFromDisk( HWND hwnd )
|
||||
{
|
||||
wchar_t oldCurPath[MAX_PATH] = {0};
|
||||
GetCurrentDirectoryW(MAX_PATH, oldCurPath);
|
||||
|
||||
wchar_t temp[1024] = {0};
|
||||
wchar_t filter[1024] = {0};
|
||||
AGAVE_API_PLAYLISTMANAGER->GetFilterList(filter, 1024);
|
||||
OPENFILENAMEW l = {sizeof(l), };
|
||||
l.hwndOwner = hwnd;
|
||||
l.lpstrFilter = filter;
|
||||
l.lpstrFile = temp;
|
||||
l.nMaxFile = 1023;
|
||||
l.lpstrTitle = WASABI_API_LNGSTRINGW(IDS_IMPORT_PLAYLIST);
|
||||
l.lpstrDefExt = L"m3u";
|
||||
l.lpstrInitialDir = WASABI_API_APP->path_getWorkingPath();
|
||||
|
||||
l.Flags = OFN_HIDEREADONLY | OFN_EXPLORER;
|
||||
|
||||
bool ret = false;
|
||||
if ( GetOpenFileNameW( &l ) )
|
||||
{
|
||||
wchar_t newCurPath[ MAX_PATH ] = { 0 };
|
||||
GetCurrentDirectoryW( MAX_PATH, newCurPath );
|
||||
WASABI_API_APP->path_setWorkingPath( newCurPath );
|
||||
|
||||
wchar_t titleStr[ 32 ] = { 0 };
|
||||
int w = currentPlaylist.GetNumItems() == 0 ? IDYES :
|
||||
MessageBox( hwnd, WASABI_API_LNGSTRINGW( IDS_APPEND_IMPORTED_PLAYLIST ),
|
||||
WASABI_API_LNGSTRINGW_BUF( IDS_LIBRARY_QUESTION, titleStr, 32 ),
|
||||
MB_YESNOCANCEL | MB_ICONQUESTION );
|
||||
|
||||
if ( w != IDCANCEL )
|
||||
{
|
||||
if ( w == IDNO )
|
||||
currentPlaylist.Clear();
|
||||
|
||||
AGAVE_API_PLAYLISTMANAGER->Load( temp, ¤tPlaylist );
|
||||
ret = true;
|
||||
}
|
||||
}
|
||||
|
||||
SetCurrentDirectoryW( oldCurPath );
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool currentPlaylist_ImportFromWinamp( HWND hwnd )
|
||||
{
|
||||
wchar_t titleStr[ 32 ] = { 0 };
|
||||
int w = currentPlaylist.GetNumItems() == 0 ? IDNO :
|
||||
MessageBox( hwnd, WASABI_API_LNGSTRINGW( IDS_APPEND_ACTIVE_PLAYLIST ),
|
||||
WASABI_API_LNGSTRINGW_BUF( IDS_LIBRARY_QUESTION, titleStr, 32 ),
|
||||
MB_YESNOCANCEL | MB_ICONQUESTION );
|
||||
|
||||
if ( w != IDCANCEL )
|
||||
{
|
||||
if ( w == IDNO )
|
||||
currentPlaylist.Clear();
|
||||
|
||||
SendMessage( plugin.hwndWinampParent, WM_WA_IPC, 0, IPC_WRITEPLAYLIST );
|
||||
wchar_t *m3udir = (wchar_t *)SendMessage( plugin.hwndWinampParent, WM_WA_IPC, 0, IPC_GETM3UDIRECTORYW );
|
||||
wchar_t s[ MAX_PATH ] = { 0 };
|
||||
PathCombineW( s, m3udir, L"winamp.m3u8" );
|
||||
|
||||
AGAVE_API_PLAYLISTMANAGER->Load( s, ¤tPlaylist );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CurrentPlaylist_DeleteMissing()
|
||||
{
|
||||
bool ret = false;
|
||||
size_t x = currentPlaylist.GetNumItems();
|
||||
while ( x-- )
|
||||
{
|
||||
wchar_t fn[ 1024 ] = { 0 };
|
||||
currentPlaylist.GetItem( x, fn, 1024 );
|
||||
if ( !wcsstr( fn, L"://" ) && !wcsstr( fn, L":\\\\" ) && !( PathFileExistsW( fn ) ) )
|
||||
{
|
||||
currentPlaylist.Remove( x );
|
||||
ret = true;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void CurrentPlaylist_Export(HWND dlgparent)
|
||||
{
|
||||
wchar_t oldCurPath[MAX_PATH] = {0};
|
||||
GetCurrentDirectoryW(MAX_PATH, oldCurPath);
|
||||
|
||||
wchar_t temp[MAX_PATH] = {0};
|
||||
OPENFILENAMEW l = {sizeof(OPENFILENAMEW), 0};
|
||||
lstrcpynW(temp, (wchar_t*)GetPropW(dlgparent, L"TITLE"), MAX_PATH);
|
||||
Playlists_ReplaceBadPathChars(temp);
|
||||
l.hwndOwner = dlgparent;
|
||||
l.hInstance = plugin.hDllInstance;
|
||||
l.nFilterIndex = g_config->ReadInt(L"filter", 3);
|
||||
l.lpstrFilter = (LPCWSTR)SendMessage(plugin.hwndWinampParent, WM_WA_IPC, 3, IPC_GET_PLAYLIST_EXTLISTW);
|
||||
l.lpstrFile = temp;
|
||||
l.nMaxFile = MAX_PATH;
|
||||
l.lpstrTitle = WASABI_API_LNGSTRINGW(IDS_EXPORT_PLAYLIST);
|
||||
l.lpstrDefExt = L"m3u";
|
||||
l.Flags = OFN_HIDEREADONLY | OFN_EXPLORER | OFN_OVERWRITEPROMPT;
|
||||
|
||||
if ( GetSaveFileNameW( &l ) )
|
||||
{
|
||||
wchar_t newCurPath[ MAX_PATH ] = { 0 };
|
||||
GetCurrentDirectoryW( MAX_PATH, newCurPath );
|
||||
|
||||
WASABI_API_APP->path_setWorkingPath( newCurPath );
|
||||
AGAVE_API_PLAYLISTMANAGER->Save( temp, ¤tPlaylist );
|
||||
}
|
||||
|
||||
g_config->WriteInt( L"filter", l.nFilterIndex );
|
||||
|
||||
SetCurrentDirectoryW( oldCurPath );
|
||||
}
|
||||
|
||||
bool CurrentPlaylist_AddLocation( HWND hwndDlg )
|
||||
{
|
||||
bool ret = false;
|
||||
char *p = (char *)SendMessage( plugin.hwndWinampParent, WM_WA_IPC, (WPARAM)hwndDlg, IPC_OPENURLBOX );
|
||||
if ( p )
|
||||
{
|
||||
//size_t s = currentPlaylist.GetNumItems();
|
||||
AutoWide wideFn( p );
|
||||
if ( AGAVE_API_PLAYLISTMANAGER->Load( wideFn, ¤tPlaylist ) != PLAYLISTMANAGER_SUCCESS )
|
||||
{
|
||||
wchar_t title[ FILETITLE_SIZE ] = { 0 };
|
||||
int length = -1;
|
||||
mediaLibrary.GetFileInfo( wideFn, title, FILETITLE_SIZE, &length );
|
||||
currentPlaylist.AppendWithInfo( wideFn, title, length * 1000 );
|
||||
}
|
||||
|
||||
ret = true;
|
||||
|
||||
// TODO: if (GetPrivateProfileInt("winamp", "rofiob", 1, WINAMP_INI)&1) PlayList_sort(2, s);
|
||||
|
||||
GlobalFree( (HGLOBAL)p );
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static INT_PTR CALLBACK browseCheckBoxProc( HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam )
|
||||
{
|
||||
if ( uMsg == WM_INITDIALOG )
|
||||
{
|
||||
int rofiob = GetPrivateProfileIntA( "winamp", "rofiob", 1, mediaLibrary.GetWinampIni() );
|
||||
if ( !( rofiob & 2 ) )
|
||||
CheckDlgButton( hwndDlg, IDC_CHECK1, BST_CHECKED );
|
||||
}
|
||||
|
||||
if ( uMsg == WM_COMMAND )
|
||||
{
|
||||
if ( LOWORD( wParam ) == IDC_CHECK1 )
|
||||
{
|
||||
int rofiob = GetPrivateProfileIntA( "winamp", "rofiob", 1, mediaLibrary.GetWinampIni() );
|
||||
if ( IsDlgButtonChecked( hwndDlg, IDC_CHECK1 ) )
|
||||
rofiob &= ~2;
|
||||
else
|
||||
rofiob |= 2;
|
||||
|
||||
char blah[ 32 ] = { 0 };
|
||||
StringCchPrintfA( blah, 32, "%d", rofiob );
|
||||
WritePrivateProfileStringA( "winamp", "rofiob", blah, mediaLibrary.GetWinampIni() );
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int CALLBACK WINAPI BrowseCallbackProc( HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData )
|
||||
{
|
||||
switch ( uMsg )
|
||||
{
|
||||
case BFFM_INITIALIZED:
|
||||
{
|
||||
SetWindowTextW( hwnd, WASABI_API_LNGSTRINGW( IDS_ADD_DIR_TO_PLAYLIST ) );
|
||||
SendMessageW( hwnd, BFFM_SETSELECTIONW, 1, (LPARAM)WASABI_API_APP->path_getWorkingPath() );
|
||||
|
||||
HWND h2 = FindWindowEx( hwnd, NULL, NULL, L"__foo2" );
|
||||
if ( h2 )
|
||||
ShowWindow( h2, SW_HIDE );
|
||||
|
||||
HWND h = WASABI_API_CREATEDIALOGW( IDD_BROWSE_PLFLD, hwnd, browseCheckBoxProc );
|
||||
SetWindowPos( h, 0, 4, 4, 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE );
|
||||
ShowWindow( h, SW_SHOWNA );
|
||||
|
||||
// this is not nice but it fixes the selection not working correctly on all OSes
|
||||
EnumChildWindows( hwnd, browseEnumProc, 0 );
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool CurrentPlaylist_AddDirectory( HWND hwndDlg )
|
||||
{
|
||||
BROWSEINFOW bi = { 0 };
|
||||
wchar_t name[ MAX_PATH ] = { 0 };
|
||||
bi.hwndOwner = hwndDlg;
|
||||
bi.pidlRoot = 0;
|
||||
bi.pszDisplayName = name;
|
||||
bi.lpszTitle = L"__foo2";
|
||||
bi.ulFlags = BIF_RETURNONLYFSDIRS | BIF_NEWDIALOGSTYLE;
|
||||
bi.lpfn = BrowseCallbackProc;
|
||||
bi.lParam = 0;
|
||||
|
||||
ITEMIDLIST *idlist = SHBrowseForFolderW( &bi );
|
||||
if ( idlist )
|
||||
{
|
||||
//size_t s = currentPlaylist.GetNumItems();
|
||||
wchar_t path[ MAX_PATH ] = { 0 };
|
||||
SHGetPathFromIDListW( idlist, path );
|
||||
WASABI_API_APP->path_setWorkingPath( path );
|
||||
|
||||
extern void Shell_Free( void *p );
|
||||
Shell_Free( idlist );
|
||||
WASABI_API_APP->path_setWorkingPath( path );
|
||||
|
||||
PlaylistDirectoryCallback dirCallback( mediaLibrary.GetExtensionList(), mediaLibrary.GetWinampIni() );
|
||||
|
||||
AGAVE_API_PLAYLISTMANAGER->LoadDirectory( path, ¤tPlaylist, &dirCallback );
|
||||
|
||||
//int rofiob = GetPrivateProfileInt("winamp", "rofiob", 1, WINAMP_INI);
|
||||
// TODO: if (rofiob&1) PlayList_sort(2, s);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CurrentPlaylist_AddFiles( HWND hwndDlg )
|
||||
{
|
||||
wchar_t oldCurPath[ MAX_PATH ] = { 0 };
|
||||
GetCurrentDirectoryW( MAX_PATH, oldCurPath );
|
||||
|
||||
const int len = 256 * 1024 - 128;
|
||||
wchar_t *temp;
|
||||
OPENFILENAMEW l = { sizeof( l ), };
|
||||
|
||||
static int q;
|
||||
if ( q )
|
||||
return false;
|
||||
|
||||
q = 1;
|
||||
temp = (wchar_t *)GlobalAlloc( GPTR, sizeof( wchar_t ) * len );
|
||||
l.hwndOwner = hwndDlg;
|
||||
wchar_t *fsb = (wchar_t *)SendMessage( plugin.hwndWinampParent, WM_WA_IPC, 1, IPC_GET_EXTLISTW );
|
||||
|
||||
l.lpstrFilter = fsb;
|
||||
l.lpstrFile = temp;
|
||||
l.nMaxFile = len - 1;
|
||||
l.lpstrTitle = WASABI_API_LNGSTRINGW( IDS_ADD_FILES_TO_PLAYLIST );
|
||||
l.lpstrDefExt = L"";
|
||||
l.lpstrInitialDir = WASABI_API_APP->path_getWorkingPath();
|
||||
|
||||
l.Flags = OFN_HIDEREADONLY | OFN_EXPLORER | OFN_ALLOWMULTISELECT;
|
||||
|
||||
bool ret = false;
|
||||
if ( GetOpenFileNameW( &l ) )
|
||||
{
|
||||
wchar_t newCurPath[ MAX_PATH ] = { 0 };
|
||||
GetCurrentDirectoryW( MAX_PATH, newCurPath );
|
||||
WASABI_API_APP->path_setWorkingPath( newCurPath );
|
||||
|
||||
if ( temp[ wcslen( temp ) + 1 ] )
|
||||
{
|
||||
AGAVE_API_PLAYLISTMANAGER->LoadFromDialog( temp, ¤tPlaylist );
|
||||
ret = true;
|
||||
// TODO: if (GetPrivateProfileInt("winamp", "rofiob", 1, WINAMP_INI)&1) PlayList_sort(2, sp);
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( AGAVE_API_PLAYLISTMANAGER->Load( temp, ¤tPlaylist ) != PLAYLISTMANAGER_SUCCESS )
|
||||
{
|
||||
wchar_t title[ FILETITLE_SIZE ] = { 0 };
|
||||
int length;
|
||||
mediaLibrary.GetFileInfo( temp, title, FILETITLE_SIZE, &length );
|
||||
currentPlaylist.AppendWithInfo( temp, title, length * 1000 );
|
||||
ret = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SetCurrentDirectoryW( oldCurPath );
|
||||
GlobalFree( fsb );
|
||||
GlobalFree( temp );
|
||||
|
||||
q = 0;
|
||||
|
||||
return ret;
|
||||
}
|
12
Src/Plugins/Library/ml_playlists/CurrentPlaylist.h
Normal file
12
Src/Plugins/Library/ml_playlists/CurrentPlaylist.h
Normal file
@ -0,0 +1,12 @@
|
||||
#ifndef NULLSOFT_ML_PLAYLISTS_CURRENTPLAYLIST_H
|
||||
#define NULLSOFT_ML_PLAYLISTS_CURRENTPLAYLIST_H
|
||||
|
||||
bool currentPlaylist_ImportFromDisk(HWND hwnd);
|
||||
bool currentPlaylist_ImportFromWinamp(HWND hwnd);
|
||||
bool CurrentPlaylist_DeleteMissing();
|
||||
void CurrentPlaylist_Export(HWND dlgparent);
|
||||
bool CurrentPlaylist_AddLocation(HWND hwndDlg);
|
||||
bool CurrentPlaylist_AddDirectory(HWND hwndDlg);
|
||||
bool CurrentPlaylist_AddFiles(HWND hwndDlg);
|
||||
|
||||
#endif
|
7
Src/Plugins/Library/ml_playlists/DESIGN.TXT
Normal file
7
Src/Plugins/Library/ml_playlists/DESIGN.TXT
Normal file
@ -0,0 +1,7 @@
|
||||
since everything (hopefully) is being done on the main thread,
|
||||
there isn't any locking done around the playlists vector.
|
||||
We probably want to change that in the future
|
||||
|
||||
|
||||
TODO:
|
||||
ability to take a path from elsewhere
|
331
Src/Plugins/Library/ml_playlists/Playlist.cpp
Normal file
331
Src/Plugins/Library/ml_playlists/Playlist.cpp
Normal file
@ -0,0 +1,331 @@
|
||||
#include "main.h"
|
||||
#include "./playlist.h"
|
||||
#include <algorithm>
|
||||
#include "nu/MediaLibraryInterface.h"
|
||||
#include "Winamp/strutil.h"
|
||||
|
||||
Playlist::~Playlist()
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
|
||||
|
||||
void Playlist::Clear()
|
||||
{
|
||||
for ( pl_entry *entry : entries )
|
||||
delete entry;
|
||||
|
||||
entries.clear();
|
||||
|
||||
lengthInMS = 0;
|
||||
}
|
||||
|
||||
void Playlist::OnFile( const wchar_t *filename, const wchar_t *title, int lengthInMS, ifc_plentryinfo *info )
|
||||
{
|
||||
entries.push_back( new pl_entry( filename, title, lengthInMS, info ) );
|
||||
|
||||
this->lengthInMS += lengthInMS;
|
||||
}
|
||||
|
||||
void Playlist::AppendWithInfo( const wchar_t *filename, const wchar_t *title, int lengthInMS )
|
||||
{
|
||||
this->lengthInMS += lengthInMS;
|
||||
entries.push_back( new pl_entry( filename, title, lengthInMS ) );
|
||||
}
|
||||
|
||||
void Playlist::AppendWithInfo( const wchar_t *filename, const wchar_t *title, int lengthInMS, std::map<std::wstring, std::wstring> &p_extended_infos )
|
||||
{
|
||||
this->lengthInMS += lengthInMS;
|
||||
|
||||
pl_entry *l_new_pl_entry = new pl_entry( filename, title, lengthInMS );
|
||||
|
||||
if ( !p_extended_infos.empty() )
|
||||
{
|
||||
for ( auto l_extended_info : p_extended_infos )
|
||||
l_new_pl_entry->_extended_infos.emplace( _wcsdup( l_extended_info.first.c_str() ), _wcsdup( l_extended_info.second.c_str() ) );
|
||||
}
|
||||
|
||||
entries.push_back( l_new_pl_entry );
|
||||
}
|
||||
|
||||
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 )
|
||||
{
|
||||
lengthInMS -= entries[item]->length;
|
||||
delete entries[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() )
|
||||
{
|
||||
lengthInMS -= entries[ item ]->length;
|
||||
entries[ item ]->SetLengthMilliseconds( length );
|
||||
lengthInMS += length;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void GetTitle( pl_entry *&a )
|
||||
{
|
||||
if ( !a->cached )
|
||||
{
|
||||
wchar_t title[ FILETITLE_SIZE ] = { 0 };
|
||||
int length = -1;
|
||||
|
||||
mediaLibrary.GetFileInfo( a->filename, title, FILETITLE_SIZE, &length );
|
||||
|
||||
a->SetLengthMilliseconds( length * 1000 );
|
||||
a->SetTitle( title );
|
||||
}
|
||||
}
|
||||
|
||||
static bool PlayList_sortByTitle( pl_entry *&a, pl_entry *&b )
|
||||
{
|
||||
GetTitle( a );
|
||||
GetTitle( 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 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 );
|
||||
|
||||
size_t dirLen1 = directoryEnd1 - directory1;
|
||||
size_t dirLen2 = 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;
|
||||
}*/
|
||||
|
||||
bool Playlist::IsCached( size_t item )
|
||||
{
|
||||
return entries[ item ]->cached;
|
||||
}
|
||||
|
||||
bool Playlist::IsLocal( size_t item )
|
||||
{
|
||||
return entries[ item ]->isLocal();
|
||||
}
|
||||
|
||||
void Playlist::ClearCache( size_t item )
|
||||
{
|
||||
entries[ item ]->cached = false;
|
||||
}
|
||||
|
||||
void Playlist::InsertPlaylist( Playlist ©, size_t index )
|
||||
{
|
||||
for ( pl_entry *l_entry : copy.entries )
|
||||
{
|
||||
entries.insert( entries.begin() + index, l_entry );
|
||||
++index;
|
||||
lengthInMS += l_entry->length;
|
||||
}
|
||||
|
||||
copy.entries.clear();
|
||||
}
|
||||
|
||||
void Playlist::AppendPlaylist( Playlist © )
|
||||
{
|
||||
for ( pl_entry *l_entry : copy.entries )
|
||||
{
|
||||
this->entries.push_back( l_entry );
|
||||
lengthInMS += l_entry->length;
|
||||
}
|
||||
|
||||
copy.entries.clear();
|
||||
}
|
||||
|
||||
#ifdef CBCLASS
|
||||
#undef CBCLASS
|
||||
#endif
|
||||
|
||||
#define CBCLASS Playlist
|
||||
|
||||
START_MULTIPATCH;
|
||||
START_PATCH( patch_playlist )
|
||||
M_VCB( patch_playlist, ifc_playlist, IFC_PLAYLIST_CLEAR, Clear )
|
||||
//M_VCB(patch_playlist, ifc_playlist, IFC_PLAYLIST_APPENDWITHINFO, AppendWithInfo)
|
||||
//M_VCB(patch_playlist, ifc_playlist, IFC_PLAYLIST_APPEND, Append)
|
||||
M_CB( patch_playlist, ifc_playlist, IFC_PLAYLIST_GETNUMITEMS, GetNumItems )
|
||||
M_CB( patch_playlist, ifc_playlist, IFC_PLAYLIST_GETITEM, GetItem )
|
||||
M_CB( patch_playlist, ifc_playlist, IFC_PLAYLIST_GETITEMTITLE, GetItemTitle )
|
||||
M_CB( patch_playlist, ifc_playlist, IFC_PLAYLIST_GETITEMLENGTHMILLISECONDS, GetItemLengthMilliseconds )
|
||||
M_CB( patch_playlist, ifc_playlist, IFC_PLAYLIST_GETITEMEXTENDEDINFO, GetItemExtendedInfo )
|
||||
M_CB( patch_playlist, ifc_playlist, IFC_PLAYLIST_REVERSE, Reverse )
|
||||
M_CB( patch_playlist, ifc_playlist, IFC_PLAYLIST_SWAP, Swap )
|
||||
M_CB( patch_playlist, ifc_playlist, IFC_PLAYLIST_RANDOMIZE, Randomize )
|
||||
M_VCB( patch_playlist, ifc_playlist, IFC_PLAYLIST_REMOVE, Remove )
|
||||
M_CB( patch_playlist, ifc_playlist, IFC_PLAYLIST_SORTBYTITLE, SortByTitle )
|
||||
M_CB( patch_playlist, ifc_playlist, IFC_PLAYLIST_SORTBYFILENAME, SortByFilename )
|
||||
M_CB( patch_playlist, ifc_playlist, IFC_PLAYLIST_SORTBYDIRECTORY, SortByDirectory )
|
||||
NEXT_PATCH( patch_playlistloadercallback )
|
||||
M_VCB( patch_playlistloadercallback, ifc_playlistloadercallback, IFC_PLAYLISTLOADERCALLBACK_ONFILE, OnFile );
|
||||
END_PATCH
|
||||
END_MULTIPATCH;
|
66
Src/Plugins/Library/ml_playlists/Playlist.h
Normal file
66
Src/Plugins/Library/ml_playlists/Playlist.h
Normal file
@ -0,0 +1,66 @@
|
||||
#ifndef NULLSOFT_ML_PLAYLISTS_PLAYLIST_H
|
||||
#define NULLSOFT_ML_PLAYLISTS_PLAYLIST_H
|
||||
|
||||
#include "playlist/ifc_playlist.h"
|
||||
|
||||
#include "bfc/multipatch.h"
|
||||
#include "playlist/pl_entry.h"
|
||||
#include "playlist/ifc_playlistloadercallback.h"
|
||||
|
||||
enum
|
||||
{
|
||||
patch_playlist,
|
||||
patch_playlistloadercallback
|
||||
};
|
||||
|
||||
class Playlist : public MultiPatch<patch_playlist, ifc_playlist>, public MultiPatch<patch_playlistloadercallback, ifc_playlistloadercallback>
|
||||
{
|
||||
public:
|
||||
Playlist() {}
|
||||
virtual ~Playlist();
|
||||
|
||||
void Clear();
|
||||
void OnFile( const wchar_t *filename, const wchar_t *title, int lengthInMS, ifc_plentryinfo *info );
|
||||
|
||||
void AppendWithInfo( const wchar_t *filename, const wchar_t *title, int lengthInMS );
|
||||
void AppendWithInfo( const wchar_t *filename, const wchar_t *title, int lengthInMS, std::map<std::wstring, std::wstring> &p_extended_infos );
|
||||
|
||||
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 );
|
||||
|
||||
bool IsCached( size_t item );
|
||||
bool IsLocal( size_t item );
|
||||
void ClearCache( size_t item );
|
||||
|
||||
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
|
||||
|
||||
void InsertPlaylist( Playlist ©, size_t index );
|
||||
void AppendPlaylist( Playlist © );
|
||||
|
||||
protected:
|
||||
RECVS_MULTIPATCH;
|
||||
|
||||
public:
|
||||
typedef std::vector<pl_entry*> PlaylistEntries;
|
||||
PlaylistEntries entries;
|
||||
uint64_t lengthInMS = 0;
|
||||
};
|
||||
|
||||
#endif // !NULLSOFT_ML_PLAYLISTS_PLAYLIST_H
|
@ -0,0 +1,41 @@
|
||||
#include "main.h"
|
||||
#include "PlaylistDirectoryCallback.h"
|
||||
|
||||
PlaylistDirectoryCallback::PlaylistDirectoryCallback(const char *_extlist, const char *winampIni)
|
||||
: extlist(_extlist), recurse(true)
|
||||
{
|
||||
if (winampIni)
|
||||
{
|
||||
int rofiob = GetPrivateProfileIntA("winamp", "rofiob", 1, winampIni);
|
||||
recurse = (rofiob & 2) ? false : true;
|
||||
}
|
||||
}
|
||||
|
||||
bool PlaylistDirectoryCallback::ShouldRecurse(const wchar_t *path)
|
||||
{
|
||||
return recurse;
|
||||
}
|
||||
|
||||
bool PlaylistDirectoryCallback::ShouldLoad(const wchar_t *filename)
|
||||
{
|
||||
const wchar_t *ext = PathFindExtensionW(filename);
|
||||
if (!*ext)
|
||||
return false;
|
||||
|
||||
ext++;
|
||||
|
||||
const char *a = extlist;
|
||||
while (a && *a)
|
||||
{
|
||||
if (!lstrcmpiW(AutoWide(a), ext))
|
||||
return true;
|
||||
a += lstrlenA(a) + 1;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#define CBCLASS PlaylistDirectoryCallback
|
||||
START_DISPATCH;
|
||||
CB( IFC_PLAYLISTDIRECTORYCALLBACK_SHOULDRECURSE, ShouldRecurse )
|
||||
CB( IFC_PLAYLISTDIRECTORYCALLBACK_SHOULDLOAD, ShouldLoad )
|
||||
END_DISPATCH;
|
15
Src/Plugins/Library/ml_playlists/PlaylistDirectoryCallback.h
Normal file
15
Src/Plugins/Library/ml_playlists/PlaylistDirectoryCallback.h
Normal file
@ -0,0 +1,15 @@
|
||||
#include "../playlist/ifc_playlistdirectorycallback.h"
|
||||
|
||||
class PlaylistDirectoryCallback : public ifc_playlistdirectorycallback
|
||||
{
|
||||
public:
|
||||
PlaylistDirectoryCallback(const char *_extlist, const char *winampIni=0);
|
||||
bool ShouldRecurse(const wchar_t *path);
|
||||
bool ShouldLoad(const wchar_t *filename);
|
||||
|
||||
const char *extlist;
|
||||
bool recurse;
|
||||
|
||||
protected:
|
||||
RECVS_DISPATCH;
|
||||
};
|
233
Src/Plugins/Library/ml_playlists/PlaylistInfo.cpp
Normal file
233
Src/Plugins/Library/ml_playlists/PlaylistInfo.cpp
Normal file
@ -0,0 +1,233 @@
|
||||
#include <assert.h>
|
||||
#include <strsafe.h>
|
||||
|
||||
#include "main.h"
|
||||
#include "PlaylistInfo.h"
|
||||
#include "nu/AutoLock.h"
|
||||
|
||||
int uniqueAddress;
|
||||
|
||||
using namespace Nullsoft::Utility;
|
||||
|
||||
static INT_PTR FindTreeID( GUID playlist_guid )
|
||||
{
|
||||
INT_PTR treeId = 0;
|
||||
|
||||
//if ( tree_to_guid_map.reverseLookup( playlist_guid, &treeId ) )
|
||||
// return treeId;
|
||||
//else
|
||||
// return 0;
|
||||
|
||||
// Look for values and return the index
|
||||
for (auto& item : tree_to_guid_map)
|
||||
{
|
||||
if (0 == memcmp(&item.second, &playlist_guid, sizeof(GUID)))
|
||||
{
|
||||
return item.first;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
PlaylistInfo::PlaylistInfo()
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
|
||||
void PlaylistInfo::Clear()
|
||||
{
|
||||
length = 0;
|
||||
numItems = 0;
|
||||
treeId = 0;
|
||||
index = 0;
|
||||
iterator = 0;
|
||||
cloud = 0;
|
||||
playlist_guid = INVALID_GUID;
|
||||
}
|
||||
|
||||
bool PlaylistInfo::Associate( INT_PTR _treeId )
|
||||
{
|
||||
Clear();
|
||||
|
||||
treeId = _treeId;
|
||||
playlist_guid = tree_to_guid_map[treeId];
|
||||
|
||||
if ( AGAVE_API_PLAYLISTS->GetPosition( playlist_guid, &index ) == API_PLAYLISTS_SUCCESS )
|
||||
{
|
||||
iterator = AGAVE_API_PLAYLISTS->GetIterator();
|
||||
|
||||
AGAVE_API_PLAYLISTS->GetInfo( index, api_playlists_itemCount, &numItems, sizeof( numItems ) );
|
||||
AGAVE_API_PLAYLISTS->GetInfo( index, api_playlists_totalTime, &length, sizeof( length ) );
|
||||
AGAVE_API_PLAYLISTS->GetInfo( index, api_playlists_cloud, &cloud, sizeof( cloud ) );
|
||||
}
|
||||
else
|
||||
playlist_guid = INVALID_GUID;
|
||||
|
||||
return Valid();
|
||||
}
|
||||
|
||||
// as a pre-condition, AGAVE_API_PLAYLISTS needs to be locked
|
||||
PlaylistInfo::PlaylistInfo( size_t p_index )
|
||||
{
|
||||
Clear();
|
||||
|
||||
index = p_index;
|
||||
iterator = AGAVE_API_PLAYLISTS->GetIterator();
|
||||
playlist_guid = AGAVE_API_PLAYLISTS->GetGUID( index );
|
||||
|
||||
AGAVE_API_PLAYLISTS->GetInfo( index, api_playlists_itemCount, &numItems, sizeof( numItems ) );
|
||||
AGAVE_API_PLAYLISTS->GetInfo( index, api_playlists_totalTime, &length, sizeof( length ) );
|
||||
AGAVE_API_PLAYLISTS->GetInfo( index, api_playlists_cloud, &cloud, sizeof( cloud ) );
|
||||
|
||||
treeId = FindTreeID( playlist_guid ); // try to find treeId
|
||||
}
|
||||
|
||||
// as a pre-condition, AGAVE_API_PLAYLISTS needs to be locked
|
||||
PlaylistInfo::PlaylistInfo( GUID p_playlist_guid )
|
||||
{
|
||||
Clear();
|
||||
|
||||
playlist_guid = p_playlist_guid;
|
||||
|
||||
if ( AGAVE_API_PLAYLISTS->GetPosition( playlist_guid, &index ) == API_PLAYLISTS_SUCCESS )
|
||||
{
|
||||
iterator = AGAVE_API_PLAYLISTS->GetIterator();
|
||||
|
||||
AGAVE_API_PLAYLISTS->GetInfo( index, api_playlists_itemCount, &numItems, sizeof( numItems ) );
|
||||
AGAVE_API_PLAYLISTS->GetInfo( index, api_playlists_totalTime, &length, sizeof( length ) );
|
||||
AGAVE_API_PLAYLISTS->GetInfo( index, api_playlists_cloud, &cloud, sizeof( cloud ) );
|
||||
|
||||
treeId = FindTreeID( playlist_guid ); // try to find treeId
|
||||
}
|
||||
else
|
||||
playlist_guid = INVALID_GUID;
|
||||
}
|
||||
|
||||
PlaylistInfo::PlaylistInfo( const PlaylistInfo © )
|
||||
{
|
||||
Clear();
|
||||
|
||||
index = copy.index;
|
||||
iterator = copy.iterator;
|
||||
playlist_guid = copy.playlist_guid;
|
||||
length = copy.length;
|
||||
numItems = copy.numItems;
|
||||
treeId = copy.treeId;
|
||||
cloud = copy.cloud;
|
||||
}
|
||||
|
||||
size_t PlaylistInfo::GetIndex()
|
||||
{
|
||||
assert( Valid() );
|
||||
|
||||
AutoLockT<api_playlists> lock( AGAVE_API_PLAYLISTS );
|
||||
size_t curIterator = AGAVE_API_PLAYLISTS->GetIterator();
|
||||
if ( curIterator != iterator )
|
||||
{
|
||||
iterator = curIterator;
|
||||
AGAVE_API_PLAYLISTS->GetPosition( playlist_guid, &index );
|
||||
}
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
void PlaylistInfo::IssueSaveCallback()
|
||||
{
|
||||
assert( Valid() );
|
||||
|
||||
AutoLockT<api_playlists> lock( AGAVE_API_PLAYLISTS );
|
||||
WASABI_API_SYSCB->syscb_issueCallback( api_playlists::SYSCALLBACK, api_playlists::PLAYLIST_SAVED, GetIndex(), (intptr_t)&uniqueAddress );
|
||||
}
|
||||
|
||||
void PlaylistInfo::Refresh()
|
||||
{
|
||||
assert( Valid() );
|
||||
|
||||
if ( AGAVE_API_PLAYLISTS->GetPosition( playlist_guid, &index ) == API_PLAYLISTS_SUCCESS )
|
||||
{
|
||||
iterator = AGAVE_API_PLAYLISTS->GetIterator();
|
||||
|
||||
AGAVE_API_PLAYLISTS->GetInfo( index, api_playlists_itemCount, &numItems, sizeof( numItems ) );
|
||||
AGAVE_API_PLAYLISTS->GetInfo( index, api_playlists_totalTime, &length, sizeof( length ) );
|
||||
}
|
||||
else
|
||||
playlist_guid = INVALID_GUID;
|
||||
}
|
||||
|
||||
const wchar_t *PlaylistInfo::GetFilename()
|
||||
{
|
||||
assert( Valid() );
|
||||
|
||||
if ( _filename.empty() )
|
||||
_filename = AGAVE_API_PLAYLISTS->GetFilename( GetIndex() );
|
||||
|
||||
return _filename.c_str();
|
||||
}
|
||||
|
||||
// TODO: we should investigate caching the title
|
||||
const wchar_t *PlaylistInfo::GetName()
|
||||
{
|
||||
assert( Valid() );
|
||||
|
||||
if ( _title.empty() )
|
||||
_title = AGAVE_API_PLAYLISTS->GetName( GetIndex() );
|
||||
|
||||
return _title.c_str();
|
||||
}
|
||||
|
||||
size_t PlaylistInfo::GetLength()
|
||||
{
|
||||
assert( Valid() );
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
void PlaylistInfo::SetLength( size_t newLength )
|
||||
{
|
||||
assert( Valid() );
|
||||
|
||||
length = newLength;
|
||||
|
||||
AutoLockT<api_playlists> lock( AGAVE_API_PLAYLISTS );
|
||||
AGAVE_API_PLAYLISTS->SetInfo( GetIndex(), api_playlists_totalTime, &length, sizeof( length ) );
|
||||
}
|
||||
|
||||
size_t PlaylistInfo::GetSize()
|
||||
{
|
||||
assert( Valid() );
|
||||
|
||||
return numItems;
|
||||
}
|
||||
|
||||
size_t PlaylistInfo::GetCloud()
|
||||
{
|
||||
assert( Valid() );
|
||||
|
||||
return cloud;
|
||||
}
|
||||
|
||||
void PlaylistInfo::SetCloud(size_t newCloud)
|
||||
{
|
||||
assert( Valid() );
|
||||
|
||||
cloud = newCloud;
|
||||
|
||||
AutoLockT<api_playlists> lock( AGAVE_API_PLAYLISTS );
|
||||
AGAVE_API_PLAYLISTS->SetInfo( GetIndex(), api_playlists_cloud, &cloud, sizeof( cloud ) );
|
||||
}
|
||||
|
||||
bool PlaylistInfo::Valid()
|
||||
{
|
||||
return !!( playlist_guid != INVALID_GUID );
|
||||
}
|
||||
|
||||
void PlaylistInfo::SetSize( size_t newSize )
|
||||
{
|
||||
assert( Valid() );
|
||||
|
||||
numItems = newSize;
|
||||
|
||||
AutoLockT<api_playlists> lock( AGAVE_API_PLAYLISTS );
|
||||
AGAVE_API_PLAYLISTS->SetInfo( GetIndex(), api_playlists_itemCount, &numItems, sizeof( numItems ) );
|
||||
}
|
58
Src/Plugins/Library/ml_playlists/PlaylistInfo.h
Normal file
58
Src/Plugins/Library/ml_playlists/PlaylistInfo.h
Normal file
@ -0,0 +1,58 @@
|
||||
#ifndef NULLSOFT_ML_PLAYLISTS_PLAYLIST_INFO_H
|
||||
#define NULLSOFT_ML_PLAYLISTS_PLAYLIST_INFO_H
|
||||
|
||||
#include <windows.h> // for MAX_PATH
|
||||
#include <iostream> // for std::wstring
|
||||
|
||||
// REVIEW: what if we want this to be an ifc_playlist * from elsewhere instead of a physical m3u file
|
||||
// maybe this should be a playlist factory instead?
|
||||
class PlaylistInfo
|
||||
{
|
||||
/* --- Methods --- */
|
||||
public:
|
||||
PlaylistInfo();
|
||||
PlaylistInfo( GUID _playlist_guid );
|
||||
PlaylistInfo( size_t p_index ); // as a pre-condition, AGAVE_API_PLAYLISTS needs to be locked
|
||||
PlaylistInfo( const PlaylistInfo © );
|
||||
|
||||
bool Valid();
|
||||
|
||||
bool Associate( INT_PTR _treeId );
|
||||
|
||||
size_t GetIndex();
|
||||
const wchar_t *GetFilename();
|
||||
const wchar_t *GetName();
|
||||
|
||||
size_t GetLength();
|
||||
void SetLength( size_t newLength );
|
||||
|
||||
size_t GetSize();
|
||||
void SetSize( size_t newSize );
|
||||
|
||||
size_t GetCloud();
|
||||
void SetCloud( size_t newCloud );
|
||||
|
||||
void Refresh();
|
||||
|
||||
void IssueSaveCallback();
|
||||
|
||||
private:
|
||||
void Clear();
|
||||
|
||||
/* --- Data --- */
|
||||
public:
|
||||
INT_PTR treeId; // if it's being displayed as a media library tree, the id is here (0 otherwise)
|
||||
GUID playlist_guid;
|
||||
|
||||
private:
|
||||
size_t index;
|
||||
size_t iterator;
|
||||
size_t length; // in seconds
|
||||
size_t numItems;
|
||||
size_t cloud;
|
||||
|
||||
std::wstring _title;
|
||||
std::wstring _filename;
|
||||
};
|
||||
|
||||
#endif
|
300
Src/Plugins/Library/ml_playlists/PlaylistView.cpp
Normal file
300
Src/Plugins/Library/ml_playlists/PlaylistView.cpp
Normal file
@ -0,0 +1,300 @@
|
||||
#include "main.h"
|
||||
#include "PlaylistView.h"
|
||||
#include "Playlist.h"
|
||||
#include "CurrentPlaylist.h"
|
||||
#include "api__ml_playlists.h"
|
||||
#include "../ml_local/api_mldb.h"
|
||||
#include "../ml_pmp/pmp.h"
|
||||
#include <strsafe.h>
|
||||
|
||||
extern Playlist currentPlaylist;
|
||||
|
||||
static BOOL playlist_GetDisplayInfo( NMLVDISPINFO *lpdi )
|
||||
{
|
||||
size_t item = lpdi->item.iItem;
|
||||
if ( item < 0 || item >= currentPlaylist.GetNumItems() )
|
||||
return 0;
|
||||
|
||||
if ( lpdi->item.mask & LVIF_TEXT )
|
||||
{
|
||||
switch ( lpdi->item.iSubItem )
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
if ( !currentPlaylist.IsCached( item ) )
|
||||
{
|
||||
wchar_t title[ FILETITLE_SIZE ] = { 0 };
|
||||
int length = -1;
|
||||
mediaLibrary.GetFileInfo( currentPlaylist.ItemName( item ), title, FILETITLE_SIZE, &length );
|
||||
currentPlaylist.SetItemLengthMilliseconds( item, length * 1000 );
|
||||
currentPlaylist.SetItemTitle( item, title );
|
||||
}
|
||||
|
||||
// CUT: currentPlaylist.GetItemTitle(item, lpdi->item.pszText, lpdi->item.cchTextMax);
|
||||
const wchar_t *title = currentPlaylist.ItemTitle( item );
|
||||
if ( !title )
|
||||
title = currentPlaylist.ItemName( item );
|
||||
|
||||
// TODO - just using for debugging to check values
|
||||
#ifdef DEBUG
|
||||
wchar_t info[ 128 ] = { 0 };
|
||||
if ( currentPlaylist.GetItemExtendedInfo( item, L"cloud", info, 128 ) )
|
||||
{
|
||||
StringCchPrintf( lpdi->item.pszText, lpdi->item.cchTextMax, L"[%s] %d. %s", info, item + 1, title );
|
||||
}
|
||||
else
|
||||
{
|
||||
#endif
|
||||
StringCchPrintf( lpdi->item.pszText, lpdi->item.cchTextMax, L"%d. %s", item + 1, title );
|
||||
#ifdef DEBUG
|
||||
}
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
|
||||
case 1:
|
||||
{
|
||||
wchar_t info[ 16 ] = { 0 };
|
||||
if ( currentPlaylist.GetItemExtendedInfo( item, L"cloud_status", info, 16 ) )
|
||||
{
|
||||
StringCchPrintf( lpdi->item.pszText, lpdi->item.cchTextMax, L"%s", info );
|
||||
}
|
||||
else
|
||||
StringCchPrintf( lpdi->item.pszText, lpdi->item.cchTextMax, L"%d", 4 );
|
||||
}
|
||||
break;
|
||||
|
||||
case 2:
|
||||
{
|
||||
if ( currentPlaylist.GetItemLengthMilliseconds( item ) == 0 ) // if the length is 0, then we'll re-read it
|
||||
{
|
||||
wchar_t title[ FILETITLE_SIZE ] = { 0 };
|
||||
int length = 0;
|
||||
mediaLibrary.GetFileInfo( currentPlaylist.ItemName( item ), title, FILETITLE_SIZE, &length );
|
||||
if ( length == 0 )
|
||||
currentPlaylist.SetItemLengthMilliseconds( item, -1000 );
|
||||
else
|
||||
{
|
||||
currentPlaylist.SetItemLengthMilliseconds( item, length * 1000 );
|
||||
}
|
||||
}
|
||||
|
||||
int length = currentPlaylist.GetItemLengthMilliseconds( item ) / 1000;
|
||||
if ( length <= 0 )
|
||||
lpdi->item.pszText[ 0 ] = 0;
|
||||
else
|
||||
StringCchPrintf( lpdi->item.pszText, lpdi->item.cchTextMax, L"%d:%02d", length / 60, length % 60 );
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
BOOL playlist_OnCustomDraw( HWND hwndDlg, NMLVCUSTOMDRAW *plvcd, LRESULT *pResult )
|
||||
{
|
||||
static BOOL bDrawFocus;
|
||||
static RECT rcView;
|
||||
static CLOUDCOLUMNPAINT cloudColumnPaint;
|
||||
|
||||
*pResult = CDRF_DODEFAULT;
|
||||
|
||||
switch ( plvcd->nmcd.dwDrawStage )
|
||||
{
|
||||
case CDDS_PREPAINT:
|
||||
*pResult |= CDRF_NOTIFYITEMDRAW;
|
||||
CopyRect( &rcView, &plvcd->nmcd.rc );
|
||||
|
||||
cloudColumnPaint.hwndList = plvcd->nmcd.hdr.hwndFrom;
|
||||
cloudColumnPaint.hdc = plvcd->nmcd.hdc;
|
||||
cloudColumnPaint.prcView = &rcView;
|
||||
return TRUE;
|
||||
|
||||
case CDDS_ITEMPREPAINT:
|
||||
*pResult |= CDRF_NOTIFYSUBITEMDRAW;
|
||||
bDrawFocus = ( CDIS_FOCUS & plvcd->nmcd.uItemState );
|
||||
if ( bDrawFocus )
|
||||
{
|
||||
plvcd->nmcd.uItemState &= ~CDIS_FOCUS;
|
||||
*pResult |= CDRF_NOTIFYPOSTPAINT;
|
||||
}
|
||||
return TRUE;
|
||||
|
||||
case CDDS_ITEMPOSTPAINT:
|
||||
if ( bDrawFocus )
|
||||
{
|
||||
RECT rc;
|
||||
rc.left = LVIR_BOUNDS;
|
||||
SendMessageW( plvcd->nmcd.hdr.hwndFrom, LVM_GETITEMRECT, plvcd->nmcd.dwItemSpec, (LPARAM)&rc );
|
||||
|
||||
rc.left += 3;
|
||||
DrawFocusRect( plvcd->nmcd.hdc, &rc );
|
||||
|
||||
plvcd->nmcd.uItemState |= CDIS_FOCUS;
|
||||
bDrawFocus = FALSE;
|
||||
}
|
||||
*pResult = CDRF_SKIPDEFAULT;
|
||||
return TRUE;
|
||||
|
||||
case( CDDS_SUBITEM | CDDS_ITEMPREPAINT ):
|
||||
// TODO need to have a map between column ids so we do this correctly
|
||||
if ( plvcd->iSubItem == 1 )
|
||||
{
|
||||
if ( 0 == plvcd->iSubItem && 0 == plvcd->nmcd.rc.right )
|
||||
break;
|
||||
|
||||
cloudColumnPaint.iItem = plvcd->nmcd.dwItemSpec;
|
||||
cloudColumnPaint.iSubItem = plvcd->iSubItem;
|
||||
|
||||
int cloud_icon = 4;
|
||||
size_t item = plvcd->nmcd.dwItemSpec;
|
||||
|
||||
wchar_t info[ 16 ] = { 0 };
|
||||
if ( currentPlaylist.GetItemExtendedInfo( item, L"cloud_status", info, 16 ) )
|
||||
cloud_icon = _wtoi( info );
|
||||
|
||||
// TODO have this show an appropriate cloud icon for the playlist
|
||||
// currently all we have is cloud or nothing as we'll only
|
||||
// have files locally for this for the moment (need todo!!!)
|
||||
cloudColumnPaint.value = cloud_icon;
|
||||
cloudColumnPaint.prcItem = &plvcd->nmcd.rc;
|
||||
cloudColumnPaint.rgbBk = plvcd->clrTextBk;
|
||||
cloudColumnPaint.rgbFg = plvcd->clrText;
|
||||
|
||||
if ( MLCloudColumn_Paint( plugin.hwndLibraryParent, &cloudColumnPaint ) )
|
||||
{
|
||||
*pResult = CDRF_SKIPDEFAULT;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL playlist_Notify( HWND hwndDlg, WPARAM wParam, LPARAM lParam )
|
||||
{
|
||||
LPNMHDR l = (LPNMHDR)lParam;
|
||||
if ( l->idFrom == IDC_PLAYLIST_EDITOR )
|
||||
{
|
||||
switch ( l->code )
|
||||
{
|
||||
case NM_DBLCLK:
|
||||
PlaySelection( g_config->ReadInt( L"enqueuedef", 0 ) == 1, g_config->ReadInt( L"plplaymode", 1 ) );
|
||||
break;
|
||||
|
||||
case LVN_GETDISPINFO:
|
||||
return playlist_GetDisplayInfo( (NMLVDISPINFO *)lParam );
|
||||
|
||||
case LVN_BEGINDRAG:
|
||||
we_are_drag_and_dropping = 1;
|
||||
SetCapture( hwndDlg );
|
||||
break;
|
||||
|
||||
case LVN_ITEMCHANGED:
|
||||
case LVN_ODSTATECHANGED:
|
||||
UpdatePlaylistTime( hwndDlg );
|
||||
break;
|
||||
|
||||
case NM_CUSTOMDRAW:
|
||||
{
|
||||
LRESULT result = 0;
|
||||
if ( cloud_avail && playlist_OnCustomDraw( hwndDlg, (NMLVCUSTOMDRAW *)lParam, &result ) )
|
||||
{
|
||||
SetWindowLongPtrW( hwndDlg, DWLP_MSGRESULT, (LONG_PTR)result );
|
||||
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case NM_CLICK:
|
||||
{
|
||||
LPNMITEMACTIVATE pnmitem = (LPNMITEMACTIVATE)lParam;
|
||||
if ( cloud_avail && pnmitem->iItem != -1 && pnmitem->iSubItem == 1 )
|
||||
{
|
||||
RECT itemRect = { 0 };
|
||||
if ( pnmitem->iSubItem )
|
||||
ListView_GetSubItemRect( pnmitem->hdr.hwndFrom, pnmitem->iItem, pnmitem->iSubItem, LVIR_BOUNDS, &itemRect );
|
||||
else
|
||||
{
|
||||
ListView_GetItemRect( pnmitem->hdr.hwndFrom, pnmitem->iItem, &itemRect, LVIR_BOUNDS );
|
||||
itemRect.right = itemRect.left + ListView_GetColumnWidth( pnmitem->hdr.hwndFrom, pnmitem->iSubItem );
|
||||
}
|
||||
|
||||
MapWindowPoints( l->hwndFrom, HWND_DESKTOP, (POINT *)&itemRect, 2 );
|
||||
|
||||
//int cloud_devices = 0;
|
||||
HMENU cloud_hmenu = 0;
|
||||
int mark = playlist_list.GetSelectionMark();
|
||||
if ( mark != -1 )
|
||||
{
|
||||
wchar_t filename[ MAX_PATH ] = { 0 };
|
||||
currentPlaylist.entries[ mark ]->GetFilename( filename, MAX_PATH );
|
||||
|
||||
cloud_hmenu = CreatePopupMenu();
|
||||
WASABI_API_SYSCB->syscb_issueCallback( api_mldb::SYSCALLBACK, api_mldb::MLDB_FILE_GET_CLOUD_STATUS, (intptr_t)&filename, (intptr_t)&cloud_hmenu );
|
||||
if ( cloud_hmenu )
|
||||
{
|
||||
int r = Menu_TrackPopup( plugin.hwndLibraryParent, cloud_hmenu, TPM_RETURNCMD | TPM_RIGHTBUTTON | TPM_LEFTBUTTON | TPM_NONOTIFY, itemRect.right, itemRect.top, hwndDlg, NULL );
|
||||
if ( r >= CLOUD_SOURCE_MENUS && r < CLOUD_SOURCE_MENUS_UPPER )
|
||||
{ // deals with cloud specific menus
|
||||
// 0 = no change
|
||||
// 1 = adding to cloud
|
||||
// 2 = added locally
|
||||
// 4 = removed
|
||||
|
||||
int mode = 0; // deals with cloud specific menus
|
||||
WASABI_API_SYSCB->syscb_issueCallback( api_mldb::SYSCALLBACK, api_mldb::MLDB_FILE_PROCESS_CLOUD_STATUS, (intptr_t)r, (intptr_t)&mode );
|
||||
// TODO
|
||||
/*switch (mode)
|
||||
{
|
||||
case 1:
|
||||
setCloudValue(&itemCache.Items[pnmitem->iItem], L"5");
|
||||
break;
|
||||
|
||||
case 2:
|
||||
setCloudValue(&itemCache.Items[pnmitem->iItem], L"4");
|
||||
break;
|
||||
|
||||
case 4:
|
||||
setCloudValue(&itemCache.Items[pnmitem->iItem], L"4");
|
||||
break;
|
||||
}
|
||||
InvalidateRect(resultlist.getwnd(), NULL, TRUE);*/
|
||||
}
|
||||
|
||||
DestroyMenu( cloud_hmenu );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
switch ( l->code )
|
||||
{
|
||||
case HDN_ITEMCHANGING:
|
||||
{
|
||||
LPNMHEADERW phdr = (LPNMHEADERW)lParam;
|
||||
if ( phdr->pitem && ( HDI_WIDTH & phdr->pitem->mask ) && phdr->iItem == 1 )
|
||||
{
|
||||
if ( !cloud_avail )
|
||||
phdr->pitem->cxy = 0;
|
||||
else
|
||||
{
|
||||
INT width = phdr->pitem->cxy;
|
||||
if ( MLCloudColumn_GetWidth( plugin.hwndLibraryParent, &width ) )
|
||||
phdr->pitem->cxy = width;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
32
Src/Plugins/Library/ml_playlists/PlaylistView.h
Normal file
32
Src/Plugins/Library/ml_playlists/PlaylistView.h
Normal file
@ -0,0 +1,32 @@
|
||||
#ifndef NULLSOFT_ML_PLAYLISTS_PLAYLISTVIEW_H
|
||||
#define NULLSOFT_ML_PLAYLISTS_PLAYLISTVIEW_H
|
||||
|
||||
#include "../nu/listview.h"
|
||||
|
||||
#define WM_PLAYLIST WM_USER + 1980
|
||||
|
||||
#define WM_PLAYLIST_RELOAD WM_PLAYLIST + 1
|
||||
#define WM_PLAYLIST_UNLOAD WM_PLAYLIST + 2
|
||||
|
||||
|
||||
extern int we_are_drag_and_dropping;
|
||||
extern W_ListView playlist_list;
|
||||
|
||||
class PlayListView : public W_ListView
|
||||
{
|
||||
public:
|
||||
|
||||
};
|
||||
// TODO: make a nice pretty class to wrap the playlist view
|
||||
|
||||
BOOL playlist_Notify( HWND hwndDlg, WPARAM wParam, LPARAM lParam );
|
||||
void PlaySelection( int enqueue, int is_all );
|
||||
void UpdatePlaylistTime( HWND hwndDlg );
|
||||
void TagEditor( HWND hwnd );
|
||||
void SyncPlaylist();
|
||||
void Playlist_DeleteSelected( int selected );
|
||||
void Playlist_ResetSelected();
|
||||
void EditEntry( HWND parent );
|
||||
void DownloadSelectedEntries( HWND hwndDlg );
|
||||
|
||||
#endif
|
120
Src/Plugins/Library/ml_playlists/PlaylistsCB.cpp
Normal file
120
Src/Plugins/Library/ml_playlists/PlaylistsCB.cpp
Normal file
@ -0,0 +1,120 @@
|
||||
#include "main.h"
|
||||
#include "PlaylistsCB.h"
|
||||
using namespace Nullsoft::Utility;
|
||||
|
||||
static UINT_PTR refreshTimer;
|
||||
void CALLBACK RefreshPlaylistsCallback(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
|
||||
{
|
||||
if (idEvent == 777)
|
||||
{
|
||||
KillTimer(plugin.hwndWinampParent, idEvent);
|
||||
refreshTimer = 0;
|
||||
RefreshPlaylistsList();
|
||||
}
|
||||
}
|
||||
|
||||
int PlaylistsCB::notify(int msg, intptr_t param1, intptr_t param2)
|
||||
{
|
||||
switch (msg)
|
||||
{
|
||||
case api_playlists::PLAYLIST_ADDED:
|
||||
{
|
||||
AutoLockT<api_playlists> lock(AGAVE_API_PLAYLISTS); // should already be locked, but can't hurt
|
||||
size_t newIndex = static_cast<size_t>(param1);
|
||||
PlaylistInfo playlist(newIndex);
|
||||
if (playlist.Valid())
|
||||
{
|
||||
// TODO: check where newIndex is, so we can insert into the middle of the list if necessary
|
||||
/* TODO: maybe stuff this in Set/GetInfo somewhere
|
||||
if (makeTree)
|
||||
*/
|
||||
MakeTree(playlist);
|
||||
if (refreshTimer) KillTimer(plugin.hwndWinampParent, refreshTimer);
|
||||
refreshTimer = SetTimer(plugin.hwndWinampParent, 777, 250, RefreshPlaylistsCallback);
|
||||
if (!param2) AGAVE_API_PLAYLISTS->Flush(); // REVIEW: save immediately? or only at the end?
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
case api_playlists::PLAYLIST_REMOVED_PRE:
|
||||
{
|
||||
AutoLockT<api_playlists> lock(AGAVE_API_PLAYLISTS); // should already be locked, but can't hurt
|
||||
size_t index = static_cast<size_t>(param1),
|
||||
count = AGAVE_API_PLAYLISTS->GetCount();
|
||||
PlaylistInfo info(index);
|
||||
if (info.Valid())
|
||||
{
|
||||
// is a number of cases where this just seems to fail and so we revert to manually
|
||||
// parsing the playlists tree inorder to find and remove the expected playlist by
|
||||
// the index of the playlist (since we don't alter the order, this should be safe)
|
||||
if (!info.treeId)
|
||||
{
|
||||
INT_PTR id = mediaLibrary.GetChildId(playlistsTreeId);
|
||||
if (id)
|
||||
{
|
||||
for (size_t i = 0; i < count; i++)
|
||||
{
|
||||
if (i == index)
|
||||
{
|
||||
mediaLibrary.RemoveTreeItem(id);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!(id = mediaLibrary.GetNextId(id))) break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
mediaLibrary.RemoveTreeItem(info.treeId);
|
||||
|
||||
tree_to_guid_map.erase(info.treeId);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
case api_playlists::PLAYLIST_REMOVED_POST:
|
||||
{
|
||||
if (refreshTimer) KillTimer(plugin.hwndWinampParent, refreshTimer);
|
||||
refreshTimer = SetTimer(plugin.hwndWinampParent, 777, 250, RefreshPlaylistsCallback);
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
case api_playlists::PLAYLIST_RENAMED:
|
||||
{
|
||||
AutoLockT<api_playlists> lock(AGAVE_API_PLAYLISTS); // should already be locked, but can't hurt
|
||||
// tell the media library to rename the treeview node
|
||||
size_t index = static_cast<size_t>(param1);
|
||||
PlaylistInfo playlist(index);
|
||||
if (playlist.Valid())
|
||||
{
|
||||
mediaLibrary.RenameTreeId(playlist.treeId, playlist.GetName());
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
break;
|
||||
case api_playlists::PLAYLIST_SAVED:
|
||||
if (param2 != (intptr_t)&uniqueAddress)
|
||||
{
|
||||
AutoLockT<api_playlists> lock(AGAVE_API_PLAYLISTS); // should already be locked, but can't hurt
|
||||
size_t index = static_cast<size_t>(param1);
|
||||
playlist_ReloadGUID(AGAVE_API_PLAYLISTS->GetGUID(index));
|
||||
}
|
||||
break;
|
||||
case api_playlists::PLAYLIST_FLUSH_REQUEST:
|
||||
if (param2 != (intptr_t)&uniqueAddress)
|
||||
{
|
||||
AutoLockT<api_playlists> lock(AGAVE_API_PLAYLISTS); // should already be locked, but can't hurt
|
||||
size_t index = static_cast<size_t>(param1);
|
||||
playlist_SaveGUID(AGAVE_API_PLAYLISTS->GetGUID(index));
|
||||
}
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define CBCLASS PlaylistsCB
|
||||
START_DISPATCH;
|
||||
CB(SYSCALLBACK_GETEVENTTYPE, getEventType);
|
||||
CB(SYSCALLBACK_NOTIFY, notify);
|
||||
END_DISPATCH;
|
||||
#undef CBCLASS
|
16
Src/Plugins/Library/ml_playlists/PlaylistsCB.h
Normal file
16
Src/Plugins/Library/ml_playlists/PlaylistsCB.h
Normal file
@ -0,0 +1,16 @@
|
||||
#ifndef NULLSOFT_ML_PLAYLISTS_PLAYLISTSCB_H
|
||||
#define NULLSOFT_ML_PLAYLISTS_PLAYLISTSCB_H
|
||||
|
||||
#include <api/syscb/callbacks/syscb.h>
|
||||
#include "../playlist/api_playlists.h"
|
||||
|
||||
class PlaylistsCB : public SysCallback
|
||||
{
|
||||
public:
|
||||
FOURCC getEventType() { return api_playlists::SYSCALLBACK; }
|
||||
int notify(int msg, intptr_t param1 = 0, intptr_t param2 = 0);
|
||||
|
||||
protected:
|
||||
RECVS_DISPATCH;
|
||||
};
|
||||
#endif
|
178
Src/Plugins/Library/ml_playlists/PlaylistsCOM.cpp
Normal file
178
Src/Plugins/Library/ml_playlists/PlaylistsCOM.cpp
Normal file
@ -0,0 +1,178 @@
|
||||
#include "main.h"
|
||||
#include "PlaylistsCOM.h"
|
||||
using namespace Nullsoft::Utility;
|
||||
|
||||
enum
|
||||
{
|
||||
DISP_PLALISTS_GETXML = 777,
|
||||
|
||||
};
|
||||
|
||||
#define CHECK_ID(str, id) if (wcscmp(rgszNames[i], L##str) == 0) { rgdispid[i] = id; continue; }
|
||||
HRESULT PlaylistsCOM::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++)
|
||||
{
|
||||
CHECK_ID("GetXML", DISP_PLALISTS_GETXML)
|
||||
|
||||
rgdispid[i] = DISPID_UNKNOWN;
|
||||
unknowns = true;
|
||||
}
|
||||
|
||||
if (unknowns)
|
||||
return DISP_E_UNKNOWNNAME;
|
||||
else
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT PlaylistsCOM::GetTypeInfo(unsigned int itinfo, LCID lcid, ITypeInfo FAR* FAR* pptinfo)
|
||||
{
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
HRESULT PlaylistsCOM::GetTypeInfoCount(unsigned int FAR * pctinfo)
|
||||
{
|
||||
return E_NOTIMPL;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
static void SavePlaylistsXML(const wchar_t *destination, size_t limit)
|
||||
{
|
||||
AutoLockT<api_playlists> lock (AGAVE_API_PLAYLISTS);
|
||||
FILE *fp = _wfopen(destination, L"wb");
|
||||
fputws(L"\xFEFF", fp);
|
||||
fwprintf(fp, L"<?xml version=\"1.0\" encoding=\"UTF-16\"?>");
|
||||
size_t numPlaylists = limit ? min(limit, AGAVE_API_PLAYLISTS->GetCount()) : AGAVE_API_PLAYLISTS->GetCount();
|
||||
fwprintf(fp, L"<playlists playlists=\"%lu\">", numPlaylists);
|
||||
|
||||
for (size_t i = 0; i != numPlaylists; i++)
|
||||
{
|
||||
fputws(L"<playlist filename=\"", fp);
|
||||
WriteEscaped(fp, AGAVE_API_PLAYLISTS->GetFilename(i));
|
||||
fputws(L"\" title=\"", fp);
|
||||
WriteEscaped(fp, AGAVE_API_PLAYLISTS->GetName(i));
|
||||
unsigned int numItems = 0, length = 0;
|
||||
|
||||
AGAVE_API_PLAYLISTS->GetInfo(i, api_playlists_itemCount, &numItems, sizeof(numItems));
|
||||
AGAVE_API_PLAYLISTS->GetInfo(i, api_playlists_totalTime, &length, sizeof(length));
|
||||
|
||||
fwprintf(fp, L"\" songs=\"%u\" seconds=\"%u\"/>",
|
||||
numItems,
|
||||
length);
|
||||
}
|
||||
fwprintf(fp, L"</playlists>");
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
HRESULT PlaylistsCOM::Invoke(DISPID dispid, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, EXCEPINFO FAR * pexecinfo, unsigned int FAR *puArgErr)
|
||||
{
|
||||
switch (dispid)
|
||||
{
|
||||
case DISP_PLALISTS_GETXML:
|
||||
{
|
||||
int max = 0;
|
||||
if (pdispparams->cArgs == 1)
|
||||
{
|
||||
max = _wtoi(pdispparams->rgvarg[0].bstrVal);
|
||||
}
|
||||
|
||||
wchar_t tempPath[MAX_PATH] = {0};
|
||||
GetTempPathW(MAX_PATH, tempPath);
|
||||
wchar_t tempFile[MAX_PATH] = {0};
|
||||
GetTempFileNameW(tempPath, L"mpx", 0, tempFile);
|
||||
|
||||
SavePlaylistsXML(tempFile, max);
|
||||
HANDLE plFile = CreateFile(tempFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, 0);
|
||||
size_t flen = SetFilePointer(plFile, 0, NULL, FILE_END);
|
||||
SetFilePointer(plFile, 0, NULL, FILE_BEGIN);
|
||||
|
||||
SAFEARRAY *bufferArray = SafeArrayCreateVector(VT_UI1, 0, flen);
|
||||
void *data;
|
||||
SafeArrayAccessData(bufferArray, &data);
|
||||
DWORD bytesRead = 0;
|
||||
ReadFile(plFile, data, flen, &bytesRead, 0);
|
||||
SafeArrayUnaccessData(bufferArray);
|
||||
CloseHandle(plFile);
|
||||
DeleteFile(tempFile);
|
||||
VariantInit(pvarResult);
|
||||
V_VT(pvarResult) = VT_ARRAY | VT_UI1;
|
||||
V_ARRAY(pvarResult) = bufferArray;
|
||||
|
||||
|
||||
}
|
||||
return S_OK;
|
||||
|
||||
|
||||
}
|
||||
return DISP_E_MEMBERNOTFOUND;
|
||||
}
|
||||
|
||||
STDMETHODIMP PlaylistsCOM::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 PlaylistsCOM::AddRef(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
ULONG PlaylistsCOM::Release(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
20
Src/Plugins/Library/ml_playlists/PlaylistsCOM.h
Normal file
20
Src/Plugins/Library/ml_playlists/PlaylistsCOM.h
Normal file
@ -0,0 +1,20 @@
|
||||
#ifndef NULLSOFT_PLAYLISTSCOM_H
|
||||
#define NULLSOFT_PLAYLISTSCOM_H
|
||||
|
||||
#include <ocidl.h>
|
||||
|
||||
class PlaylistsCOM : public IDispatch
|
||||
{
|
||||
public:
|
||||
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);
|
||||
};
|
||||
|
||||
|
||||
#endif
|
72
Src/Plugins/Library/ml_playlists/RenamePlaylist.cpp
Normal file
72
Src/Plugins/Library/ml_playlists/RenamePlaylist.cpp
Normal file
@ -0,0 +1,72 @@
|
||||
#include "main.h"
|
||||
#include "resource.h"
|
||||
using namespace Nullsoft::Utility;
|
||||
|
||||
static INT_PTR CALLBACK RenamePlaylistDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
static GUID playlist_guid = INVALID_GUID;
|
||||
switch (uMsg)
|
||||
{
|
||||
case WM_INITDIALOG:
|
||||
{
|
||||
playlist_guid = *(GUID *)lParam;
|
||||
|
||||
AutoLockT<api_playlists> lock (AGAVE_API_PLAYLISTS);
|
||||
PlaylistInfo playlist(playlist_guid);
|
||||
if (playlist.Valid())
|
||||
{
|
||||
size_t index = playlist.GetIndex();
|
||||
const wchar_t *title = AGAVE_API_PLAYLISTS->GetName(index);
|
||||
SetDlgItemText(hwndDlg, IDC_NAME, title);
|
||||
|
||||
SendMessage(GetDlgItem(hwndDlg, IDC_NAME), EM_SETSEL, 0, -1);
|
||||
SendMessage(hwndDlg, WM_NEXTDLGCTL, (WPARAM)GetDlgItem(hwndDlg, IDC_NAME), TRUE);
|
||||
|
||||
}
|
||||
else
|
||||
EndDialog(hwndDlg, 1);
|
||||
}
|
||||
break;
|
||||
case WM_COMMAND:
|
||||
switch (LOWORD(wParam))
|
||||
{
|
||||
case IDOK:
|
||||
{
|
||||
wchar_t name[1024] = {0};
|
||||
GetDlgItemText(hwndDlg, IDC_NAME, name, 1023);
|
||||
name[1023] = 0;
|
||||
if (!name[0])
|
||||
{
|
||||
wchar_t titleStr[32] = {0};
|
||||
MessageBox(hwndDlg, WASABI_API_LNGSTRINGW(IDS_ENTER_A_NAME),
|
||||
WASABI_API_LNGSTRINGW_BUF(IDS_ERROR,titleStr,32), MB_OK);
|
||||
break;
|
||||
}
|
||||
|
||||
AutoLockT<api_playlists> lock (AGAVE_API_PLAYLISTS);
|
||||
|
||||
PlaylistInfo playlist(playlist_guid);
|
||||
|
||||
if (playlist.Valid())
|
||||
{
|
||||
size_t index = playlist.GetIndex();
|
||||
AGAVE_API_PLAYLISTS->RenamePlaylist(index, name);
|
||||
AGAVE_API_PLAYLISTS->Flush(); // TODO: save immediately? or only at the end?
|
||||
}
|
||||
|
||||
EndDialog(hwndDlg, 1);
|
||||
}
|
||||
break;
|
||||
case IDCANCEL:
|
||||
EndDialog(hwndDlg, 0);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return FALSE;
|
||||
};
|
||||
|
||||
void RenamePlaylist(GUID _guid, HWND parent)
|
||||
{
|
||||
WASABI_API_DIALOGBOXPARAMW(IDD_RENAME_PLAYLIST, parent, RenamePlaylistDialogProc, (LPARAM)&_guid);
|
||||
}
|
697
Src/Plugins/Library/ml_playlists/SendTo.cpp
Normal file
697
Src/Plugins/Library/ml_playlists/SendTo.cpp
Normal file
@ -0,0 +1,697 @@
|
||||
#include <strsafe.h>
|
||||
|
||||
#include "main.h"
|
||||
#include "api__ml_playlists.h"
|
||||
#include "Playlist.h"
|
||||
#include "PlaylistView.h"
|
||||
#include "resource.h"
|
||||
#include "../nu/AutoWideFn.h"
|
||||
#include <vector>
|
||||
|
||||
/* TODO:
|
||||
Somehow replace index values in send-to with GUID's. Possibly by making a vector of GUIDs (like view_playlists).
|
||||
Since index values could (in theory) change in a background thread while send-to interaction is going on.
|
||||
*/
|
||||
|
||||
extern Playlist currentPlaylist;
|
||||
|
||||
using namespace Nullsoft::Utility;
|
||||
|
||||
static std::vector<GUID> sendto_playlistGUIDs;
|
||||
|
||||
int playlists_CloudAvailable()
|
||||
{
|
||||
if (IPC_GET_CLOUD_HINST == -1) IPC_GET_CLOUD_HINST = (INT)SendMessage(plugin.hwndWinampParent, WM_WA_IPC, (WPARAM)&"WinampCloud", IPC_REGISTER_WINAMP_IPCMESSAGE);
|
||||
if (IPC_GET_CLOUD_ACTIVE == -1) IPC_GET_CLOUD_ACTIVE = (INT)SendMessage(plugin.hwndWinampParent, WM_WA_IPC, (WPARAM)&"WinampCloudActive", IPC_REGISTER_WINAMP_IPCMESSAGE);
|
||||
if (!cloud_hinst) cloud_hinst = (HINSTANCE)SendMessage(plugin.hwndWinampParent, WM_WA_IPC, 0, IPC_GET_CLOUD_HINST);
|
||||
|
||||
return (cloud_avail = /*0/*/!(!cloud_hinst || cloud_hinst == (HINSTANCE)1 || !SendMessage(plugin.hwndWinampParent, WM_WA_IPC, 0, IPC_GET_CLOUD_ACTIVE))/**/);
|
||||
}
|
||||
|
||||
int playlists_CloudInstalled()
|
||||
{
|
||||
if (IPC_GET_CLOUD_HINST == -1) IPC_GET_CLOUD_HINST = (INT)SendMessage(plugin.hwndWinampParent, WM_WA_IPC, (WPARAM)&"WinampCloud", IPC_REGISTER_WINAMP_IPCMESSAGE);
|
||||
if (!cloud_hinst) cloud_hinst = (HINSTANCE)SendMessage(plugin.hwndWinampParent, WM_WA_IPC, 0, IPC_GET_CLOUD_HINST);
|
||||
|
||||
return (!(!cloud_hinst || cloud_hinst == (HINSTANCE)1));
|
||||
}
|
||||
|
||||
int playlists_BuildSendTo(int sourceType, INT_PTR context)
|
||||
{
|
||||
if (sourceType == ML_TYPE_ITEMRECORDLISTW || sourceType == ML_TYPE_ITEMRECORDLIST ||
|
||||
sourceType == ML_TYPE_FILENAMES || sourceType == ML_TYPE_STREAMNAMES ||
|
||||
sourceType == ML_TYPE_FILENAMESW || sourceType == ML_TYPE_STREAMNAMESW ||
|
||||
sourceType == ML_TYPE_CDTRACKS)
|
||||
{
|
||||
if (g_config->ReadInt(L"pl_send_to", DEFAULT_PL_SEND_TO))
|
||||
{
|
||||
mediaLibrary.BranchSendTo(context);
|
||||
mediaLibrary.AddToSendTo(WASABI_API_LNGSTRINGW(IDS_SENDTO_NEW_PLAYLIST), context, playlistsTreeId);
|
||||
|
||||
AutoLockT<api_playlists> lock (AGAVE_API_PLAYLISTS);
|
||||
sendto_playlistGUIDs.clear();
|
||||
size_t count = AGAVE_API_PLAYLISTS->GetCount();
|
||||
for (size_t i = 0;i != count;i++)
|
||||
{
|
||||
PlaylistInfo info(i);
|
||||
if (info.Valid())
|
||||
{
|
||||
sendto_playlistGUIDs.push_back(info.playlist_guid);
|
||||
if (sendToIgnoreID != info.treeId)
|
||||
{
|
||||
mediaLibrary.AddToBranchSendTo(info.GetName(), context, reinterpret_cast<INT_PTR>(pluginMessageProc) + i);
|
||||
}
|
||||
}
|
||||
}
|
||||
mediaLibrary.EndBranchSendTo(WASABI_API_LNGSTRINGW(IDS_SENDTO_ML_PLAYLISTS), context);
|
||||
}
|
||||
else
|
||||
{
|
||||
mediaLibrary.AddToSendTo(WASABI_API_LNGSTRINGW(IDS_SENDTO_PLAYLIST), context, playlistsTreeId);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void NewPlaylist( Playlist &newPlaylist, const wchar_t *playlistTitle, int makeTree, const wchar_t *newFilename = 0 )
|
||||
{
|
||||
if ( playlistTitle && *playlistTitle )
|
||||
{
|
||||
size_t numItems = newPlaylist.GetNumItems();
|
||||
wchar_t filename[ 1024 + 256 ] = { 0 };
|
||||
|
||||
if ( newFilename )
|
||||
{
|
||||
if ( PathIsFileSpecW( newFilename ) )
|
||||
PathCombineW( filename, g_path, newFilename );
|
||||
else
|
||||
lstrcpynW( filename, newFilename, MAX_PATH );
|
||||
}
|
||||
else
|
||||
PathCombineW( filename, g_path, createPlayListDBFileName( filename ) );
|
||||
|
||||
AGAVE_API_PLAYLISTMANAGER->Save( filename, &newPlaylist );
|
||||
AddPlaylist( true, playlistTitle, filename, ( LOWORD( makeTree ) != 0 ), HIWORD( makeTree ), numItems, newPlaylist.lengthInMS );
|
||||
}
|
||||
else
|
||||
{
|
||||
AutoLockT<api_playlists> lock( AGAVE_API_PLAYLISTS );
|
||||
size_t a = AGAVE_API_PLAYLISTS->GetCount();
|
||||
playlists_Add( plugin.hwndLibraryParent, false );
|
||||
|
||||
if ( AGAVE_API_PLAYLISTS->GetCount() == a + 1 )
|
||||
{
|
||||
PlaylistInfo info( a );
|
||||
if ( info.Valid() )
|
||||
{
|
||||
info.SetLength( (int)( newPlaylist.lengthInMS > 0 ? newPlaylist.lengthInMS / 1000 : 0 ) );
|
||||
info.SetSize( newPlaylist.GetNumItems() );
|
||||
info.SetCloud( HIWORD( makeTree ) );
|
||||
wchar_t fn[ MAX_PATH ] = { 0 };
|
||||
if ( PathIsFileSpecW( info.GetFilename() ) )
|
||||
PathCombineW( fn, g_path, info.GetFilename() );
|
||||
else
|
||||
lstrcpynW( fn, info.GetFilename(), MAX_PATH );
|
||||
|
||||
|
||||
for ( pl_entry *l_entry : newPlaylist.entries )
|
||||
{
|
||||
for ( pl_entry *l_current_entry : currentPlaylist.entries )
|
||||
{
|
||||
if ( wcscmp( l_entry->filename, l_current_entry->filename ) == 0 )
|
||||
{
|
||||
//SetTitle releases previously allocated string, no need to free previous one
|
||||
l_entry->SetTitle(l_current_entry->filetitle);
|
||||
|
||||
|
||||
if ( !l_current_entry->_extended_infos.empty() )
|
||||
{
|
||||
for ( auto l_current_extended_info : l_current_entry->_extended_infos )
|
||||
l_entry->_extended_infos.emplace( _wcsdup( l_current_extended_info.first.c_str() ), _wcsdup( l_current_extended_info.second.c_str() ) );
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AGAVE_API_PLAYLISTMANAGER->Save( fn, &newPlaylist );
|
||||
// delay the added notification being sent so for the cloud
|
||||
// we can have the complete playlist available to work with
|
||||
AGAVE_API_PLAYLISTS->Flush();
|
||||
WASABI_API_SYSCB->syscb_issueCallback( api_playlists::SYSCALLBACK, api_playlists::PLAYLIST_ADDED, a/* + 1*/, 0 );
|
||||
UpdateTree( info, info.treeId );
|
||||
}
|
||||
}
|
||||
}
|
||||
RefreshPlaylistsList();
|
||||
}
|
||||
|
||||
void AddPlaylistFromFilenames(const char *filenames, const wchar_t *playlistTitle, int makeTree, const wchar_t *filename)
|
||||
{
|
||||
Playlist newPlaylist;
|
||||
while (filenames && *filenames)
|
||||
{
|
||||
AutoWide wideFn(filenames);
|
||||
if (AGAVE_API_PLAYLISTMANAGER->Load(wideFn, &newPlaylist) != PLAYLISTMANAGER_SUCCESS) // try to load it as a playlist first
|
||||
{
|
||||
wchar_t title[FILETITLE_SIZE] = {0};
|
||||
int length = 0;
|
||||
mediaLibrary.GetFileInfo(wideFn, title, FILETITLE_SIZE, &length);
|
||||
newPlaylist.AppendWithInfo(wideFn, title, length*1000); // otherwise just add it to the playlist directly
|
||||
}
|
||||
|
||||
filenames += strlen(filenames) + 1;
|
||||
}
|
||||
|
||||
NewPlaylist(newPlaylist, playlistTitle, makeTree, filename);
|
||||
}
|
||||
|
||||
void AddPlaylistFromFilenamesW(const wchar_t *filenames, const wchar_t *playlistTitle, int makeTree, const wchar_t *filename)
|
||||
{
|
||||
Playlist newPlaylist;
|
||||
while (filenames && *filenames)
|
||||
{
|
||||
if (AGAVE_API_PLAYLISTMANAGER->Load(filenames, &newPlaylist) != PLAYLISTMANAGER_SUCCESS) // try to load it as a playlist first
|
||||
{
|
||||
wchar_t title[FILETITLE_SIZE] = {0};
|
||||
int length = 0;
|
||||
mediaLibrary.GetFileInfo(filenames, title, FILETITLE_SIZE, &length);
|
||||
newPlaylist.AppendWithInfo(filenames, title, (length > 0 ? length*1000 : 0)); // otherwise just add it to the playlist directly
|
||||
}
|
||||
|
||||
filenames += wcslen(filenames) + 1;
|
||||
}
|
||||
|
||||
NewPlaylist(newPlaylist, playlistTitle, makeTree, filename);
|
||||
}
|
||||
|
||||
static wchar_t *itemrecordTagFunc(wchar_t *tag, void * p) //return 0 if not found
|
||||
{
|
||||
itemRecord *t = (itemRecord *)p;
|
||||
char buf[128] = {0};
|
||||
char *value = NULL;
|
||||
|
||||
if (!_wcsicmp(tag, L"artist")) value = t->artist;
|
||||
else if (!_wcsicmp(tag, L"album")) value = t->album;
|
||||
else if (!_wcsicmp(tag, L"filename")) value = t->filename;
|
||||
else if (!_wcsicmp(tag, L"title")) value = t->title;
|
||||
else if (!_wcsicmp(tag, L"ext")) value = t->ext;
|
||||
else if (!_wcsicmp(tag, L"year"))
|
||||
{
|
||||
if (t->year > 0)
|
||||
{
|
||||
StringCchPrintfA(buf, 128, "%04d", t->year);
|
||||
value = buf;
|
||||
}
|
||||
}
|
||||
else if (!_wcsicmp(tag, L"genre")) value = t->genre;
|
||||
else if (!_wcsicmp(tag, L"comment")) value = t->comment;
|
||||
else if (!_wcsicmp(tag, L"tracknumber") || !_wcsicmp(tag, L"track"))
|
||||
{
|
||||
if (t->track > 0)
|
||||
{
|
||||
StringCchPrintfA(buf, 128, "%02d", t->track);
|
||||
value = buf;
|
||||
}
|
||||
}
|
||||
else if (!_wcsicmp(tag, L"rating")) value = getRecordExtendedItem(t, "RATING");
|
||||
else if (!_wcsicmp(tag, L"playcount")) value = getRecordExtendedItem(t, "PLAYCOUNT");
|
||||
else if (!_wcsicmp(tag, L"bitrate")) value = getRecordExtendedItem(t, "BITRATE");
|
||||
else
|
||||
return 0;
|
||||
|
||||
if (!value) return reinterpret_cast<wchar_t *>(-1);
|
||||
else return AutoWideDup(value);
|
||||
}
|
||||
|
||||
static wchar_t *itemrecordWTagFunc(wchar_t *tag, void * p) //return 0 if not found
|
||||
{
|
||||
itemRecordW *t = (itemRecordW *)p;
|
||||
wchar_t buf[128] = {0};
|
||||
wchar_t *value = NULL;
|
||||
|
||||
// TODO: more fields
|
||||
if (!_wcsicmp(tag, L"artist")) value = t->artist;
|
||||
else if (!_wcsicmp(tag, L"album")) value = t->album;
|
||||
else if (!_wcsicmp(tag, L"filename")) value = t->filename;
|
||||
else if (!_wcsicmp(tag, L"title")) value = t->title;
|
||||
else if (!_wcsicmp(tag, L"year"))
|
||||
{
|
||||
if (t->year > 0)
|
||||
{
|
||||
StringCchPrintfW(buf, 128, L"%04d", t->year);
|
||||
value = buf;
|
||||
}
|
||||
}
|
||||
else if (!_wcsicmp(tag, L"genre")) value = t->genre;
|
||||
else if (!_wcsicmp(tag, L"comment")) value = t->comment;
|
||||
else if (!_wcsicmp(tag, L"tracknumber") || !_wcsicmp(tag, L"track"))
|
||||
{
|
||||
if (t->track > 0)
|
||||
{
|
||||
StringCchPrintfW(buf, 128, L"%02d", t->track);
|
||||
value = buf;
|
||||
}
|
||||
}
|
||||
else if (!_wcsicmp(tag, L"rating"))
|
||||
{
|
||||
if (t->rating > 0)
|
||||
{
|
||||
StringCchPrintfW(buf, 128, L"%d", t->rating);
|
||||
value = buf;
|
||||
}
|
||||
}
|
||||
else if (!_wcsicmp(tag, L"playcount")) value = t->comment;
|
||||
else if (!_wcsicmp(tag, L"bitrate"))
|
||||
{
|
||||
if (t->bitrate > 0)
|
||||
{
|
||||
StringCchPrintfW(buf, 128, L"%d", t->bitrate);
|
||||
value = buf;
|
||||
}
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
|
||||
if (!value) return reinterpret_cast<wchar_t *>(-1);
|
||||
else return _wcsdup(value);
|
||||
}
|
||||
|
||||
static void fieldTagFuncFree(char * tag, void * p)
|
||||
{
|
||||
free(tag);
|
||||
}
|
||||
|
||||
static void BuildTitle(itemRecord *record, wchar_t *title, int lenCch)
|
||||
{
|
||||
AutoWideFn wfn(record->filename);
|
||||
waFormatTitleExtended fmt;
|
||||
fmt.filename = wfn;
|
||||
fmt.useExtendedInfo = 1;
|
||||
fmt.out = title;
|
||||
fmt.out_len = lenCch;
|
||||
fmt.p = record;
|
||||
fmt.spec = 0;
|
||||
*(void **)&fmt.TAGFUNC = itemrecordTagFunc;
|
||||
*(void **)&fmt.TAGFREEFUNC = fieldTagFuncFree;
|
||||
*title = 0;
|
||||
|
||||
SendMessage(plugin.hwndWinampParent, WM_WA_IPC, (WPARAM)&fmt, IPC_FORMAT_TITLE_EXTENDED);
|
||||
}
|
||||
|
||||
static void BuildTitleW(itemRecordW *record, wchar_t *title, int lenCch)
|
||||
{
|
||||
waFormatTitleExtended fmt;
|
||||
fmt.filename = record->filename;
|
||||
fmt.useExtendedInfo = 1;
|
||||
fmt.out = title;
|
||||
fmt.out_len = lenCch;
|
||||
fmt.p = record;
|
||||
fmt.spec = 0;
|
||||
*(void **)&fmt.TAGFUNC = itemrecordWTagFunc;
|
||||
*(void **)&fmt.TAGFREEFUNC = fieldTagFuncFree;
|
||||
*title = 0;
|
||||
|
||||
SendMessage(plugin.hwndWinampParent, WM_WA_IPC, (WPARAM)&fmt, IPC_FORMAT_TITLE_EXTENDED);
|
||||
}
|
||||
|
||||
void AddPlaylistFromItemRecordList(itemRecordList *obj, const wchar_t *playlistTitle, int makeTree, const wchar_t *filename)
|
||||
{
|
||||
Playlist newPlaylist;
|
||||
wchar_t title[FILETITLE_SIZE] = {0};
|
||||
for (int x = 0; x < obj->Size; x ++)
|
||||
{
|
||||
BuildTitle(&obj->Items[x], title, FILETITLE_SIZE);
|
||||
newPlaylist.AppendWithInfo(AutoWide(obj->Items[x].filename), title, obj->Items[x].length*1000);
|
||||
}
|
||||
|
||||
NewPlaylist(newPlaylist, playlistTitle, makeTree, filename);
|
||||
}
|
||||
|
||||
void AddPlaylistFromItemRecordListW(itemRecordListW *obj, const wchar_t *playlistTitle, int makeTree, const wchar_t *filename)
|
||||
{
|
||||
Playlist newPlaylist;
|
||||
wchar_t title[FILETITLE_SIZE] = {0};
|
||||
for (int x = 0; x < obj->Size; x ++)
|
||||
{
|
||||
BuildTitleW(&obj->Items[x], title, FILETITLE_SIZE);
|
||||
newPlaylist.AppendWithInfo(obj->Items[x].filename, title, obj->Items[x].length*1000);
|
||||
}
|
||||
|
||||
NewPlaylist(newPlaylist, playlistTitle, makeTree, filename);
|
||||
}
|
||||
|
||||
static void AddToPlaylist(GUID playlist_guid, int sourceType, INT_PTR data)
|
||||
{
|
||||
AutoLockT<api_playlists> lock (AGAVE_API_PLAYLISTS);
|
||||
|
||||
playlist_Save(plugin.hwndWinampParent);
|
||||
PlaylistInfo p(playlist_guid);
|
||||
if (p.Valid())
|
||||
{
|
||||
Playlist playlist;
|
||||
AGAVE_API_PLAYLISTMANAGER->Load(p.GetFilename(), &playlist);
|
||||
|
||||
if (sourceType == ML_TYPE_FILENAMES || sourceType == ML_TYPE_STREAMNAMES)
|
||||
{
|
||||
const char *ptr = (const char*)data;
|
||||
|
||||
while (ptr && *ptr)
|
||||
{
|
||||
AutoWide wideFn(ptr);
|
||||
// try to load in playlist manager first
|
||||
Playlist sentPlaylist;
|
||||
if (sourceType == ML_TYPE_FILENAMES
|
||||
&& AGAVE_API_PLAYLISTMANAGER->Load(wideFn, &sentPlaylist) == PLAYLISTMANAGER_SUCCESS)
|
||||
{
|
||||
playlist.AppendPlaylist(sentPlaylist);
|
||||
}
|
||||
else
|
||||
{
|
||||
wchar_t title[FILETITLE_SIZE] = {0};
|
||||
int length = -1;
|
||||
mediaLibrary.GetFileInfo(wideFn, title, FILETITLE_SIZE, &length);
|
||||
playlist.AppendWithInfo(wideFn, title, length*1000);
|
||||
}
|
||||
ptr += strlen(ptr) + 1;
|
||||
}
|
||||
}
|
||||
else if (sourceType == ML_TYPE_FILENAMESW || sourceType == ML_TYPE_STREAMNAMESW)
|
||||
{
|
||||
const wchar_t *ptr = (const wchar_t*)data;
|
||||
|
||||
while (ptr && *ptr)
|
||||
{
|
||||
// try to load in playlist manager first
|
||||
Playlist sentPlaylist;
|
||||
if (sourceType == ML_TYPE_FILENAMES
|
||||
&& AGAVE_API_PLAYLISTMANAGER->Load(ptr, &sentPlaylist) == PLAYLISTMANAGER_SUCCESS)
|
||||
{
|
||||
playlist.AppendPlaylist(sentPlaylist);
|
||||
}
|
||||
else
|
||||
{
|
||||
wchar_t title[FILETITLE_SIZE] = {0};
|
||||
int length = -1;
|
||||
mediaLibrary.GetFileInfo(ptr, title, FILETITLE_SIZE, &length);
|
||||
|
||||
std::map<std::wstring, std::wstring> l_extended_infos;
|
||||
|
||||
if ( PathIsURLW( title ) )
|
||||
{
|
||||
wchar_t *end = 0;
|
||||
for ( pl_entry *l_current_entry : currentPlaylist.entries )
|
||||
{
|
||||
if ( wcscmp( title, l_current_entry->filename ) == 0 )
|
||||
{
|
||||
StringCchCopyExW( title, FILETITLE_SIZE, l_current_entry->filetitle, &end, 0, 0 );
|
||||
|
||||
if ( !l_current_entry->_extended_infos.empty() )
|
||||
{
|
||||
for ( auto l_current_extended_info : l_current_entry->_extended_infos )
|
||||
l_extended_infos.emplace( _wcsdup( l_current_extended_info.first.c_str() ), _wcsdup( l_current_extended_info.second.c_str() ) );
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( l_extended_infos.empty() )
|
||||
playlist.AppendWithInfo( ptr, title, length * 1000 );
|
||||
else
|
||||
playlist.AppendWithInfo( ptr, title, length * 1000, l_extended_infos );
|
||||
}
|
||||
ptr += wcslen(ptr) + 1;
|
||||
}
|
||||
}
|
||||
else if (sourceType == ML_TYPE_ITEMRECORDLIST || sourceType == ML_TYPE_CDTRACKS)
|
||||
{
|
||||
itemRecordList *obj = (itemRecordList *)data;
|
||||
|
||||
wchar_t title[FILETITLE_SIZE] = {0};
|
||||
for (int x = 0; x < obj->Size; x ++)
|
||||
{
|
||||
BuildTitle(&obj->Items[x], title, FILETITLE_SIZE);
|
||||
playlist.AppendWithInfo(AutoWide(obj->Items[x].filename), title, obj->Items[x].length*1000);
|
||||
}
|
||||
}
|
||||
else if (sourceType == ML_TYPE_ITEMRECORDLISTW)
|
||||
{
|
||||
itemRecordListW *obj = (itemRecordListW *)data;
|
||||
|
||||
wchar_t title[FILETITLE_SIZE] = {0};
|
||||
for (int x = 0; x < obj->Size; x ++)
|
||||
{
|
||||
BuildTitleW(&obj->Items[x], title, FILETITLE_SIZE);
|
||||
playlist.AppendWithInfo(obj->Items[x].filename, title, obj->Items[x].length*1000);
|
||||
}
|
||||
}
|
||||
else if (sourceType == ML_TYPE_PLAYLIST)
|
||||
{
|
||||
mlPlaylist *ptr = (mlPlaylist *)data;
|
||||
|
||||
Playlist sentPlaylist;
|
||||
if (AGAVE_API_PLAYLISTMANAGER->Load(ptr->filename, &sentPlaylist) == PLAYLISTMANAGER_SUCCESS)
|
||||
{
|
||||
playlist.AppendPlaylist(sentPlaylist);
|
||||
}
|
||||
}
|
||||
else if (sourceType == ML_TYPE_PLAYLISTS)
|
||||
{
|
||||
mlPlaylist **playlists= (mlPlaylist **)data;
|
||||
|
||||
while(playlists && *playlists)
|
||||
{
|
||||
mlPlaylist *ptr = *playlists;
|
||||
Playlist sentPlaylist;
|
||||
if (AGAVE_API_PLAYLISTMANAGER->Load(ptr->filename, &sentPlaylist) == PLAYLISTMANAGER_SUCCESS)
|
||||
{
|
||||
playlist.AppendPlaylist(sentPlaylist);
|
||||
}
|
||||
playlists++;
|
||||
}
|
||||
}
|
||||
|
||||
AGAVE_API_PLAYLISTMANAGER->Save(p.GetFilename(), &playlist);
|
||||
p.SetSize(playlist.GetNumItems());
|
||||
p.IssueSaveCallback();
|
||||
|
||||
playlist_Reload();
|
||||
}
|
||||
}
|
||||
|
||||
int playlists_OnDropTarget(int id, int sourceType, INT_PTR data)
|
||||
{
|
||||
if (id == playlistsTreeId)
|
||||
{
|
||||
switch (sourceType)
|
||||
{
|
||||
case ML_TYPE_FILENAMES:
|
||||
case ML_TYPE_STREAMNAMES:
|
||||
if (data)
|
||||
AddPlaylistFromFilenames((const char *)data, 0, 1);
|
||||
return 1;
|
||||
case ML_TYPE_FILENAMESW:
|
||||
case ML_TYPE_STREAMNAMESW:
|
||||
if (data)
|
||||
AddPlaylistFromFilenamesW((const wchar_t *)data, 0, 1);
|
||||
return 1;
|
||||
case ML_TYPE_ITEMRECORDLIST:
|
||||
case ML_TYPE_CDTRACKS:
|
||||
if (data)
|
||||
AddPlaylistFromItemRecordList((itemRecordList *)data, 0, 1);
|
||||
return 1;
|
||||
case ML_TYPE_ITEMRECORDLISTW:
|
||||
if (data)
|
||||
AddPlaylistFromItemRecordListW((itemRecordListW *)data, 0, 1);
|
||||
return 1;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
else if (FindTreeItem(id))
|
||||
{
|
||||
switch (sourceType)
|
||||
{
|
||||
case ML_TYPE_FILENAMES:
|
||||
case ML_TYPE_STREAMNAMES:
|
||||
case ML_TYPE_FILENAMESW:
|
||||
case ML_TYPE_STREAMNAMESW:
|
||||
case ML_TYPE_ITEMRECORDLIST:
|
||||
case ML_TYPE_ITEMRECORDLISTW:
|
||||
case ML_TYPE_CDTRACKS:
|
||||
if (data && !we_are_drag_and_dropping)
|
||||
{
|
||||
AddToPlaylist(tree_to_guid_map[id], sourceType, data);
|
||||
}
|
||||
return 1;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static INT_PTR CALLBACK SelectPlaylistProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
switch (msg)
|
||||
{
|
||||
case WM_INITDIALOG:
|
||||
{
|
||||
LRESULT index = SendDlgItemMessage(hwndDlg, IDC_PLAYLISTS, CB_ADDSTRING, 0, (LPARAM) WASABI_API_LNGSTRINGW(IDS_SENDTO_NEW_PLAYLIST));
|
||||
SendDlgItemMessage(hwndDlg, IDC_PLAYLISTS, CB_SETITEMDATA , index, -1);
|
||||
/*if (playlists_CloudAvailable())
|
||||
{
|
||||
index = SendDlgItemMessage(hwndDlg, IDC_PLAYLISTS, CB_ADDSTRING, 0, (LPARAM) WASABI_API_LNGSTRINGW(IDS_SENDTO_NEW_CLOUD_PLAYLIST));
|
||||
SendDlgItemMessage(hwndDlg, IDC_PLAYLISTS, CB_SETITEMDATA , index, -1);
|
||||
}*/
|
||||
AutoLockT<api_playlists> lock (AGAVE_API_PLAYLISTS);
|
||||
sendto_playlistGUIDs.clear();
|
||||
size_t count = AGAVE_API_PLAYLISTS->GetCount();
|
||||
for (size_t i = 0;i != count; i++)
|
||||
{
|
||||
PlaylistInfo info(i);
|
||||
if (info.Valid())
|
||||
{
|
||||
sendto_playlistGUIDs.push_back(info.playlist_guid);
|
||||
if (sendToIgnoreID != info.treeId)
|
||||
{
|
||||
index = SendDlgItemMessage(hwndDlg, IDC_PLAYLISTS, CB_ADDSTRING, 0, (LPARAM)info.GetName());
|
||||
SendDlgItemMessage(hwndDlg, IDC_PLAYLISTS, CB_SETITEMDATA , index, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
SendDlgItemMessage(hwndDlg, IDC_PLAYLISTS, CB_SETCURSEL, 0, 0);
|
||||
}
|
||||
break;
|
||||
case WM_COMMAND:
|
||||
switch (LOWORD(wParam))
|
||||
{
|
||||
case IDOK:
|
||||
{
|
||||
int selection = SendDlgItemMessage(hwndDlg, IDC_PLAYLISTS, CB_GETCURSEL, 0, 0);
|
||||
if (selection != CB_ERR)
|
||||
EndDialog(hwndDlg, SendDlgItemMessage(hwndDlg, IDC_PLAYLISTS, CB_GETITEMDATA , selection, 0));
|
||||
else
|
||||
EndDialog(hwndDlg, -2);
|
||||
}
|
||||
break;
|
||||
case IDCANCEL:
|
||||
{
|
||||
EndDialog(hwndDlg, -2);
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int playlists_OnSendTo(int sourceType, INT_PTR data, int id)
|
||||
{
|
||||
if (id == playlistsTreeId || id == playlistsCloudTreeId)
|
||||
{
|
||||
if (g_config->ReadInt(L"pl_send_to", DEFAULT_PL_SEND_TO))
|
||||
{
|
||||
int is_cloud = (id == playlistsCloudTreeId) || (id == playlistsTreeId && g_config->ReadInt(L"cloud", 1));
|
||||
switch (sourceType)
|
||||
{
|
||||
case ML_TYPE_FILENAMES:
|
||||
case ML_TYPE_STREAMNAMES:
|
||||
AddPlaylistFromFilenames((const char *)data, 0, MAKELONG(1, is_cloud));
|
||||
return 1;
|
||||
case ML_TYPE_FILENAMESW:
|
||||
case ML_TYPE_STREAMNAMESW:
|
||||
AddPlaylistFromFilenamesW((const wchar_t *)data, 0, MAKELONG(1, is_cloud));
|
||||
return 1;
|
||||
case ML_TYPE_ITEMRECORDLIST:
|
||||
case ML_TYPE_CDTRACKS:
|
||||
AddPlaylistFromItemRecordList((itemRecordList *)data, 0, MAKELONG(1, is_cloud));
|
||||
return 1;
|
||||
case ML_TYPE_ITEMRECORDLISTW:
|
||||
AddPlaylistFromItemRecordListW((itemRecordListW *)data, 0, MAKELONG(1, is_cloud));
|
||||
return 1;
|
||||
case ML_TYPE_PLAYLIST:
|
||||
{
|
||||
mlPlaylist *ptr = (mlPlaylist *)data;
|
||||
AddPlaylistFromFilenamesW(ptr->filename, 0, MAKELONG(1, is_cloud));
|
||||
return 1;
|
||||
}
|
||||
case ML_TYPE_PLAYLISTS:
|
||||
{
|
||||
mlPlaylist **playlists= (mlPlaylist **)data;
|
||||
while(playlists && *playlists)
|
||||
{
|
||||
mlPlaylist *ptr = *playlists;
|
||||
AddPlaylistFromFilenamesW(ptr->filename, 0, MAKELONG(1, is_cloud));
|
||||
playlists++;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
size_t selection = WASABI_API_DIALOGBOXW(IDD_SELECT_PLAYLIST, NULL, SelectPlaylistProc);
|
||||
if (selection == -2)
|
||||
return -1;
|
||||
else if (selection == -1)
|
||||
{
|
||||
switch (sourceType)
|
||||
{
|
||||
case ML_TYPE_FILENAMES:
|
||||
case ML_TYPE_STREAMNAMES:
|
||||
AddPlaylistFromFilenames((const char *)data, 0, true);
|
||||
return 1;
|
||||
case ML_TYPE_FILENAMESW:
|
||||
case ML_TYPE_STREAMNAMESW:
|
||||
AddPlaylistFromFilenamesW((const wchar_t *)data, 0, true);
|
||||
return 1;
|
||||
case ML_TYPE_ITEMRECORDLIST:
|
||||
case ML_TYPE_CDTRACKS:
|
||||
AddPlaylistFromItemRecordList((itemRecordList *)data, 0, 1);
|
||||
return 1;
|
||||
case ML_TYPE_ITEMRECORDLISTW:
|
||||
AddPlaylistFromItemRecordListW((itemRecordListW *)data, 0, 1);
|
||||
return 1;
|
||||
case ML_TYPE_PLAYLIST:
|
||||
{
|
||||
mlPlaylist *ptr = (mlPlaylist *)data;
|
||||
AddPlaylistFromFilenamesW(ptr->filename, 0, true);
|
||||
return 1;
|
||||
}
|
||||
case ML_TYPE_PLAYLISTS:
|
||||
{
|
||||
mlPlaylist **playlists= (mlPlaylist **)data;
|
||||
while(playlists && *playlists)
|
||||
{
|
||||
mlPlaylist *ptr = *playlists;
|
||||
AddPlaylistFromFilenamesW(ptr->filename, 0, true);
|
||||
playlists++;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (selection >= 0 && selection < sendto_playlistGUIDs.size())
|
||||
{
|
||||
AddToPlaylist(sendto_playlistGUIDs[selection], sourceType, data);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
size_t x = id - reinterpret_cast<size_t>(pluginMessageProc);
|
||||
if (x < sendto_playlistGUIDs.size())
|
||||
{
|
||||
AddToPlaylist(sendto_playlistGUIDs[x], sourceType, data);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
100
Src/Plugins/Library/ml_playlists/SendTo.h
Normal file
100
Src/Plugins/Library/ml_playlists/SendTo.h
Normal file
@ -0,0 +1,100 @@
|
||||
#ifndef NULLSOFT_SEND_TO_HELPER_CLASS_H
|
||||
#define NULLSOFT_SEND_TO_HELPER_CLASS_H
|
||||
|
||||
#include "../../General/gen_ml/ml_ipc.h"
|
||||
#include "main.h"
|
||||
#include <strsafe.h>
|
||||
class SendToMenu
|
||||
{
|
||||
public:
|
||||
SendToMenu()
|
||||
{
|
||||
memset(&sendTo, 0, sizeof(sendTo));
|
||||
}
|
||||
void AddHere(HWND hwnd, HMENU hMenu, int type, int simple = 0, int trueSourceType = 0)
|
||||
{
|
||||
sendTo.mode = 0;
|
||||
sendTo.hwnd = 0;
|
||||
sendTo.build_hMenu = 0;
|
||||
|
||||
IPC_LIBRARY_SENDTOMENU = SendMessage(plugin.hwndWinampParent, WM_WA_IPC, (WPARAM)&"LibrarySendToMenu", IPC_REGISTER_WINAMP_IPCMESSAGE);
|
||||
if (IPC_LIBRARY_SENDTOMENU > 65536 && SendMessage(plugin.hwndWinampParent, WM_WA_IPC, (WPARAM)0, IPC_LIBRARY_SENDTOMENU) == (LRESULT)-1)
|
||||
{
|
||||
sendTo.mode = 1;
|
||||
sendTo.hwnd = hwnd;
|
||||
sendTo.data_type = type; //ML_TYPE_ITEMRECORDLIST;
|
||||
sendTo.ctx[1] = simple;
|
||||
sendTo.ctx[2] = trueSourceType;
|
||||
sendTo.build_hMenu = hMenu;
|
||||
}
|
||||
}
|
||||
bool WasClicked(int popUpReturnVal)
|
||||
{
|
||||
if (sendTo.mode == 2)
|
||||
{
|
||||
sendTo.menu_id = popUpReturnVal;
|
||||
if (SendMessage(plugin.hwndWinampParent, WM_WA_IPC, (WPARAM)&sendTo, IPC_LIBRARY_SENDTOMENU) == (LRESULT)-1)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
void Cleanup()
|
||||
{
|
||||
if (sendTo.mode)
|
||||
{
|
||||
sendTo.mode = 4;
|
||||
SendMessage(plugin.hwndWinampParent, WM_WA_IPC, (WPARAM)&sendTo, IPC_LIBRARY_SENDTOMENU); // cleanup
|
||||
}
|
||||
sendTo.build_hMenu = 0;
|
||||
}
|
||||
|
||||
bool InitPopupMenu(WPARAM wParam)
|
||||
{
|
||||
if (wParam && (HMENU)wParam == sendTo.build_hMenu && sendTo.mode == 1)
|
||||
{
|
||||
if (SendMessage(plugin.hwndWinampParent, WM_WA_IPC, (WPARAM)&sendTo, IPC_LIBRARY_SENDTOMENU) == (LRESULT)-1)
|
||||
sendTo.mode = 2;
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// still need to free it on your own
|
||||
void SendItemRecordList(itemRecordList *obj)
|
||||
{
|
||||
sendTo.data_type = ML_TYPE_ITEMRECORDLIST;
|
||||
sendTo.mode = 3;
|
||||
sendTo.data = (void*) & obj;
|
||||
SendMessage(plugin.hwndWinampParent, WM_WA_IPC, (WPARAM)&sendTo, IPC_LIBRARY_SENDTOMENU);
|
||||
}
|
||||
|
||||
void SendFilenames(const wchar_t *filenames)
|
||||
{
|
||||
sendTo.data_type = ML_TYPE_FILENAMESW;
|
||||
sendTo.mode = 3;
|
||||
sendTo.data = (void*)filenames;
|
||||
SendMessage(plugin.hwndWinampParent, WM_WA_IPC, (WPARAM)&sendTo, IPC_LIBRARY_SENDTOMENU);
|
||||
}
|
||||
|
||||
LRESULT SendPlaylist(mlPlaylist *playlist)
|
||||
{
|
||||
sendTo.data_type = ML_TYPE_PLAYLIST;
|
||||
sendTo.mode = 3;
|
||||
sendTo.data = (void*)playlist;
|
||||
return SendMessage(plugin.hwndWinampParent, WM_WA_IPC, (WPARAM)&sendTo, IPC_LIBRARY_SENDTOMENU);
|
||||
}
|
||||
|
||||
LRESULT SendPlaylists(mlPlaylist **playlists)
|
||||
{
|
||||
sendTo.data_type = ML_TYPE_PLAYLISTS;
|
||||
sendTo.mode = 3;
|
||||
sendTo.data = (void*)playlists;
|
||||
return SendMessage(plugin.hwndWinampParent, WM_WA_IPC, (WPARAM)&sendTo, IPC_LIBRARY_SENDTOMENU);
|
||||
}
|
||||
|
||||
private:
|
||||
librarySendToMenuStruct sendTo;
|
||||
};
|
||||
|
||||
#endif
|
27
Src/Plugins/Library/ml_playlists/api__ml_playlists.h
Normal file
27
Src/Plugins/Library/ml_playlists/api__ml_playlists.h
Normal file
@ -0,0 +1,27 @@
|
||||
#ifndef NULLSOFT_API_H
|
||||
#define NULLSOFT_API_H
|
||||
|
||||
#include "api/application/api_application.h"
|
||||
#define WASABI_API_APP applicationApi
|
||||
|
||||
#include "api/service/api_service.h"
|
||||
#define WASABI_API_SVC serviceApi
|
||||
|
||||
#include "api/syscb/api_syscb.h"
|
||||
#define WASABI_API_SYSCB sysCallbackApi
|
||||
|
||||
#include "../playlist/api_playlists.h"
|
||||
extern api_playlists *playlistsApi;
|
||||
#define AGAVE_API_PLAYLISTS playlistsApi
|
||||
|
||||
#include "../playlist/api_playlistmanager.h"
|
||||
extern api_playlistmanager *playlistManager;
|
||||
#define AGAVE_API_PLAYLISTMANAGER playlistManager
|
||||
|
||||
#include "../Components/wac_downloadManager/wac_downloadManager_api.h"
|
||||
|
||||
#include "../Agave/Language/api_language.h"
|
||||
|
||||
#include "../Agave/ExplorerFindFile/api_explorerfindfile.h"
|
||||
|
||||
#endif
|
148
Src/Plugins/Library/ml_playlists/main.h
Normal file
148
Src/Plugins/Library/ml_playlists/main.h
Normal file
@ -0,0 +1,148 @@
|
||||
#ifndef NULLSOFT_ML_PLAYLISTS_MAIN_H
|
||||
#define NULLSOFT_ML_PLAYLISTS_MAIN_H
|
||||
|
||||
#include <windows.h>
|
||||
#include <shlwapi.h>
|
||||
#include "resource.h"
|
||||
|
||||
#include "../../Plugins/General/gen_ml/ml.h"
|
||||
#include "../../Plugins/General/gen_ml/ml_ipc.h"
|
||||
#include "../../Plugins/General/gen_ml/ml_ipc_0313.h"
|
||||
#include "Winamp/wa_ipc.h"
|
||||
|
||||
#include "../../Plugins/General/gen_ml/config.h"
|
||||
#include "PlaylistInfo.h"
|
||||
|
||||
#include "nu/MediaLibraryInterface.h"
|
||||
#include "../../Plugins/General/gen_ml/menu.h"
|
||||
|
||||
#include "replicant/nu/AutoWide.h"
|
||||
#include "replicant/nu/AutoChar.h"
|
||||
|
||||
#include "nu/DialogSkinner.h"
|
||||
#include "api__ml_playlists.h"
|
||||
#include "..\..\..\nu\AutoLock.h"
|
||||
|
||||
#include "ml_downloads/DownloadStatus.h"
|
||||
#include "ml_downloads/DownloadsDialog.h"
|
||||
#include "ml_downloads/Downloaded.h"
|
||||
|
||||
#include <map>
|
||||
|
||||
#define WINAMP_MANAGEPLAYLISTS 40385
|
||||
#define ID_DOSHITMENU_ADDNEWPLAYLIST 40031
|
||||
|
||||
#ifndef FILENAME_SIZE
|
||||
#define FILENAME_SIZE (MAX_PATH * 4)
|
||||
#endif
|
||||
|
||||
INT_PTR pluginMessageProc(int message_type, INT_PTR param1, INT_PTR param2, INT_PTR param3);
|
||||
|
||||
extern INT_PTR playlistsTreeId, playlistsCloudTreeId;
|
||||
extern HNAVITEM playlistItem;
|
||||
extern int imgPL, imgCloudPL;
|
||||
extern wchar_t current_playing[FILENAME_SIZE];
|
||||
INT_PTR LoadPlaylist(INT_PTR treeId);
|
||||
void Playlists_ReplaceBadPathChars(LPWSTR pszPath);
|
||||
extern HMENU wa_playlists_cmdmenu;
|
||||
void HookPlaylistEditor();
|
||||
void UnhookPlaylistEditor();
|
||||
void UpdateMenuItems(HWND hwndDlg, HMENU menu);
|
||||
|
||||
INT_PTR CALLBACK view_playlistsDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
||||
|
||||
INT_PTR CALLBACK AddPlaylistDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
|
||||
INT_PTR CALLBACK view_playlistDialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam);
|
||||
|
||||
|
||||
extern winampMediaLibraryPlugin plugin;
|
||||
extern HMENU g_context_menus, g_context_menus2, g_context_menus3;
|
||||
extern wchar_t g_path[MAX_PATH];
|
||||
static const bool ADD_TO_TREE = true;
|
||||
extern HINSTANCE cloud_hinst;
|
||||
extern int IPC_GET_CLOUD_HINST, IPC_GET_CLOUD_ACTIVE;
|
||||
extern int cloud_avail, normalimage, cloudImage, groupBtn, customAllowed, enqueuedef;
|
||||
extern HWND currentView;
|
||||
|
||||
void AddPlaylist( int callback, const wchar_t *title, const wchar_t *filename, bool makeTree, int cloud, size_t numItems = 0, uint64_t length = 0 );
|
||||
void LoadPlaylists();
|
||||
void UpdatePlaylists();
|
||||
int AddToCloud();
|
||||
void playlists_Add(HWND parent, bool callback = true);
|
||||
void playlists_AddToCloudPrompt(HWND hwndDlg);
|
||||
|
||||
enum { SORT_TITLE_ASCENDING, SORT_TITLE_DESCENDING, SORT_NUMBER_ASCENDING, SORT_NUMBER_DESCENDING };
|
||||
void playlists_Sort(size_t sort_type);
|
||||
|
||||
wchar_t *createPlayListDBFileName(wchar_t *filename); // filename is ignored but used for temp space, make sure it's 1024+256 chars =)
|
||||
void Playlist_importFromWinamp();
|
||||
void Playlist_importFromFile(HWND dlgparent);
|
||||
void Playlist_importFromFolders(HWND dlgparent);
|
||||
bool FindTreeItem(INT_PTR treeId);
|
||||
|
||||
void RenamePlaylist(GUID _guid, HWND parent);
|
||||
void DeletePlaylist(GUID _guid, HWND parent, bool confirm);
|
||||
|
||||
void RefreshPlaylistsList();
|
||||
|
||||
void HookMediaLibrary();
|
||||
void UnhookMediaLibrary();
|
||||
void playlist_ContextMenu(HWND hwndDlg, POINT p);
|
||||
|
||||
extern C_Config *g_config;
|
||||
|
||||
extern int (*warand)(void);
|
||||
|
||||
void MakeTree(PlaylistInfo &playlist);
|
||||
void UpdateTree(PlaylistInfo &playlist, int tree_id);
|
||||
|
||||
LRESULT pluginHandleIpcMessage(int msg, WPARAM param);
|
||||
extern HCURSOR hDragNDropCursor;
|
||||
void FormatLength(wchar_t *str, int length, int buf_len);
|
||||
|
||||
extern int IPC_LIBRARY_SENDTOMENU;
|
||||
|
||||
void Hook(HWND winamp);
|
||||
|
||||
extern INT_PTR sendToIgnoreID;
|
||||
extern INT_PTR lastActiveID;
|
||||
void playlist_Reload(bool forced = false);
|
||||
void playlist_Save(HWND hwndDlg);
|
||||
void playlist_SaveGUID(GUID _guid);
|
||||
void playlist_ReloadGUID(GUID _guid);
|
||||
extern HWND activeHWND; // active playlist view
|
||||
|
||||
int CALLBACK WINAPI _bcp( HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData);
|
||||
INT_PTR PlayPlaylist(INT_PTR treeId);
|
||||
|
||||
INT_PTR playlists_OnClick(INT_PTR treeId, int clickType, HWND wnd);
|
||||
int playlists_OnKeyDown(int treeId, NMTVKEYDOWN *p, HWND hwndDlg);
|
||||
int playlists_OnDrag(int treeId, POINT *pt, int *type);
|
||||
int playlists_OnDrop(int treeId, POINT *pt, int destTreeId);
|
||||
|
||||
int playlists_CloudAvailable();
|
||||
int playlists_CloudInstalled();
|
||||
|
||||
/* SendTo.cpp */
|
||||
int playlists_BuildSendTo(int sourceType, INT_PTR context);
|
||||
void AddPlaylistFromFilenames(const char *filenames, const wchar_t *playlistTitle, int makeTree, const wchar_t *filename=0);
|
||||
void AddPlaylistFromFilenamesW(const wchar_t *filenames, const wchar_t *playlistTitle, int makeTree, const wchar_t *filename=0);
|
||||
void AddPlaylistFromItemRecordList(itemRecordList *obj, const wchar_t *playlistTitle, int makeTree, const wchar_t *filename=0);
|
||||
void AddPlaylistFromItemRecordListW(itemRecordListW *obj, const wchar_t *playlistTitle, int makeTree, const wchar_t *filename=0);
|
||||
int playlists_OnDropTarget(int id, int type, INT_PTR data);
|
||||
int playlists_OnSendTo(int sourceType, INT_PTR data, int id);
|
||||
|
||||
void SwapPlayEnqueueInMenu(HMENU listMenu);
|
||||
void SyncMenuWithAccelerators(HWND hwndDlg, HMENU menu);
|
||||
|
||||
BOOL CALLBACK browseEnumProc(HWND hwnd, LPARAM lParam);
|
||||
|
||||
extern int uniqueAddress;
|
||||
|
||||
typedef std::map<INT_PTR, GUID> TREE_TO_GUID_MAP;
|
||||
extern TREE_TO_GUID_MAP tree_to_guid_map;
|
||||
|
||||
extern viewButtons view;
|
||||
|
||||
#define DEFAULT_PL_SEND_TO 1
|
||||
#endif
|
237
Src/Plugins/Library/ml_playlists/ml_playlists.cpp
Normal file
237
Src/Plugins/Library/ml_playlists/ml_playlists.cpp
Normal file
@ -0,0 +1,237 @@
|
||||
//#define PLUGIN_NAME "Nullsoft Playlists"
|
||||
#define PLUGIN_VERSION L"1.78"
|
||||
|
||||
#include "main.h"
|
||||
#include "../../General/gen_ml/ml_ipc_0313.h"
|
||||
#include "api__ml_playlists.h"
|
||||
#include "replicant/nu/AutoChar.h"
|
||||
#include "PlaylistsCOM.h"
|
||||
#include "api/service/waservicefactory.h"
|
||||
#include "PlaylistsCB.h"
|
||||
#include "playlist/plstring.h"
|
||||
|
||||
#define PLAYLIST_IMAGE_INDEX 201
|
||||
#define PLAYLIST_CLOUD_IMAGE_INDEX 202
|
||||
|
||||
PlaylistsCOM playlistsCOM;
|
||||
HMENU wa_playlists_cmdmenu = NULL;
|
||||
HMENU wa_play_menu = NULL;
|
||||
INT_PTR playlistsTreeId = 0, playlistsCloudTreeId = 3002;
|
||||
HNAVITEM playlistItem = 0;
|
||||
wchar_t g_path[ MAX_PATH ] = { 0 };
|
||||
HMENU g_context_menus = 0, g_context_menus2 = 0, g_context_menus3 = 0;
|
||||
int Init();
|
||||
void Quit();
|
||||
int( *warand )( void ) = 0;
|
||||
INT_PTR sendToIgnoreID = 0;
|
||||
int IPC_LIBRARY_PLAYLISTS_REFRESH = -1, IPC_CLOUD_ENABLED = -1;
|
||||
|
||||
extern "C" winampMediaLibraryPlugin plugin =
|
||||
{
|
||||
MLHDR_VER,
|
||||
"nullsoft(ml_playlists.dll)",
|
||||
Init,
|
||||
Quit,
|
||||
pluginMessageProc,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
};
|
||||
|
||||
HCURSOR hDragNDropCursor;
|
||||
C_Config *g_config = 0;
|
||||
int imgPL = 0, imgCloudPL = 0;
|
||||
api_playlistmanager *AGAVE_API_PLAYLISTMANAGER = 0;
|
||||
api_application *WASABI_API_APP = 0;
|
||||
api_playlists *AGAVE_API_PLAYLISTS = 0;
|
||||
api_downloadManager *WAC_API_DOWNLOADMANAGER = 0;
|
||||
api_syscb *WASABI_API_SYSCB = 0;
|
||||
api_explorerfindfile *WASABI_API_EXPLORERFINDFILE = 0;
|
||||
PlaylistsCB playlistsCB;
|
||||
// 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 = plugin.service->service_getServiceByGuid( serviceGUID );
|
||||
if ( sf )
|
||||
return (api_t *)sf->getInterface();
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
inline void ReleaseService( GUID serviceGUID, void *service )
|
||||
{
|
||||
waServiceFactory *sf = plugin.service->service_getServiceByGuid( serviceGUID );
|
||||
if ( sf )
|
||||
sf->releaseInterface( service );
|
||||
}
|
||||
|
||||
wchar_t prefsname[ 64 ] = { 0 };
|
||||
extern WORD waMenuID;
|
||||
int Init()
|
||||
{
|
||||
waMenuID = (WORD)SendMessage( plugin.hwndWinampParent, WM_WA_IPC, 0, IPC_REGISTER_LOWORD_COMMAND );
|
||||
|
||||
AGAVE_API_PLAYLISTMANAGER = GetService<api_playlistmanager>( api_playlistmanagerGUID );
|
||||
if ( !AGAVE_API_PLAYLISTMANAGER ) // no sense in continuing
|
||||
return ML_INIT_FAILURE;
|
||||
|
||||
AGAVE_API_PLAYLISTS = GetService<api_playlists>( api_playlistsGUID );
|
||||
|
||||
if ( !AGAVE_API_PLAYLISTS ) // no sense in continuing
|
||||
return ML_INIT_FAILURE;
|
||||
|
||||
WAC_API_DOWNLOADMANAGER = GetService<api_downloadManager>( DownloadManagerGUID );
|
||||
|
||||
WASABI_API_APP = GetService<api_application>( applicationApiServiceGuid );
|
||||
WASABI_API_SYSCB = GetService<api_syscb>( syscbApiServiceGuid );
|
||||
|
||||
WASABI_API_SYSCB->syscb_registerCallback( &playlistsCB );
|
||||
|
||||
WASABI_API_EXPLORERFINDFILE = GetService<api_explorerfindfile>( ExplorerFindFileApiGUID );
|
||||
|
||||
// Hook(plugin.hwndWinampParent);
|
||||
warand = ( int( * )( void ) )SendMessage( plugin.hwndWinampParent, WM_WA_IPC, 0, IPC_GET_RANDFUNC );
|
||||
|
||||
// need to get WASABI_API_APP first
|
||||
plstring_init();
|
||||
|
||||
// loader so that we can get the localisation service api for use
|
||||
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( plugin.hDllInstance, MlPlaylistsLangGUID );
|
||||
|
||||
static wchar_t szDescription[ 256 ];
|
||||
swprintf( szDescription, ARRAYSIZE( szDescription ), WASABI_API_LNGSTRINGW( IDS_NULLSOFT_PLAYLISTS ), PLUGIN_VERSION );
|
||||
plugin.description = (char *)szDescription;
|
||||
|
||||
mediaLibrary.library = plugin.hwndLibraryParent;
|
||||
mediaLibrary.winamp = plugin.hwndWinampParent;
|
||||
mediaLibrary.instance = plugin.hDllInstance;
|
||||
|
||||
mediaLibrary.GetWinampIni(); // to prevent a SendMessage hang later
|
||||
|
||||
mediaLibrary.AddDispatch( L"Playlists", &playlistsCOM );
|
||||
wchar_t inifile[ MAX_PATH ] = { 0 };
|
||||
mediaLibrary.BuildPath( L"Plugins", inifile, MAX_PATH );
|
||||
CreateDirectoryW( inifile, NULL );
|
||||
mediaLibrary.BuildPath( L"Plugins\\gen_ml.ini", inifile, MAX_PATH );
|
||||
g_config = new C_Config( inifile );
|
||||
enqueuedef = g_config->ReadInt( L"enqueuedef", 0 );
|
||||
|
||||
// if m3udir has been changed (not the same as inidir) then
|
||||
// we attempt to use the same folder for our playlist files
|
||||
const wchar_t *m3udir = (wchar_t *)SendMessage( plugin.hwndWinampParent, WM_WA_IPC, 0, IPC_GETM3UDIRECTORYW );
|
||||
const wchar_t *inidir = mediaLibrary.GetIniDirectoryW();
|
||||
if ( !lstrcmpiW( m3udir, inidir ) )
|
||||
mediaLibrary.BuildPath( L"Plugins\\ml\\playlists", g_path, MAX_PATH );
|
||||
else
|
||||
lstrcpynW( g_path, m3udir, MAX_PATH );
|
||||
|
||||
CreateDirectoryW( g_path, NULL );
|
||||
|
||||
g_context_menus = WASABI_API_LOADMENU( IDR_MENU1 );
|
||||
g_context_menus2 = WASABI_API_LOADMENU( IDR_MENU1 ); // this and next one are used for the combined buttons
|
||||
g_context_menus3 = WASABI_API_LOADMENU( IDR_MENU1 ); // so we don't have to mess around the translators etc
|
||||
|
||||
HookMediaLibrary();
|
||||
|
||||
hDragNDropCursor = LoadCursor( GetModuleHandle( L"gen_ml.dll" ), MAKEINTRESOURCE( ML_IDC_DRAGDROP ) );
|
||||
|
||||
HMENU wa_plcontext_menu = GetSubMenu( (HMENU)SendMessage( plugin.hwndWinampParent, WM_WA_IPC, -1, IPC_GET_HMENU ), 2 );
|
||||
if ( wa_plcontext_menu )
|
||||
{
|
||||
wa_playlists_cmdmenu = GetSubMenu( wa_plcontext_menu, 4 );
|
||||
if ( wa_playlists_cmdmenu )
|
||||
{
|
||||
MENUITEMINFO i = { sizeof( i ), MIIM_TYPE, MFT_SEPARATOR, 0, 0 };
|
||||
InsertMenuItem( wa_playlists_cmdmenu, 9, TRUE, &i );
|
||||
MENUITEMINFO j = { sizeof( i ), MIIM_ID | MIIM_STATE | MIIM_TYPE, MFT_STRING, 0, WINAMP_MANAGEPLAYLISTS };
|
||||
j.dwTypeData = WASABI_API_LNGSTRINGW( IDS_MANAGE_PLAYLISTS );
|
||||
InsertMenuItem( wa_playlists_cmdmenu, 10, TRUE, &j );
|
||||
}
|
||||
}
|
||||
|
||||
IPC_CLOUD_ENABLED = SendMessage( plugin.hwndWinampParent, WM_WA_IPC, ( WPARAM ) & "WinampCloudEnabled", IPC_REGISTER_WINAMP_IPCMESSAGE );
|
||||
IPC_LIBRARY_PLAYLISTS_REFRESH = SendMessage( plugin.hwndWinampParent, WM_WA_IPC, ( WPARAM ) & "ml_playlist_refresh", IPC_REGISTER_WINAMP_IPCMESSAGE );
|
||||
wa_play_menu = GetSubMenu( (HMENU)SendMessage( plugin.hwndWinampParent, WM_WA_IPC, 0, IPC_GET_HMENU ), 2 );
|
||||
|
||||
// lets extend menu that called on button press
|
||||
int IPC_GET_ML_HMENU = (int)SendMessage( plugin.hwndWinampParent, WM_WA_IPC, ( WPARAM ) & "LibraryGetHmenu", IPC_REGISTER_WINAMP_IPCMESSAGE );
|
||||
HMENU context_menu = (HMENU)SendMessage( plugin.hwndWinampParent, WM_WA_IPC, 0, IPC_GET_ML_HMENU );
|
||||
|
||||
if ( context_menu )
|
||||
{
|
||||
HMENU btnMenu = GetSubMenu( context_menu, 0 );
|
||||
if ( btnMenu )
|
||||
{
|
||||
MENUITEMINFO mii = { sizeof( MENUITEMINFO ) };
|
||||
|
||||
mii.fMask = MIIM_FTYPE;
|
||||
mii.fType = MFT_SEPARATOR;
|
||||
mii.fState = MFS_ENABLED;
|
||||
InsertMenuItem( btnMenu, 0, TRUE, &mii );
|
||||
|
||||
mii.fMask = MIIM_TYPE | MIIM_ID;
|
||||
mii.fType = MFT_STRING;
|
||||
|
||||
mii.dwTypeData = WASABI_API_LNGSTRINGW( IDS_MANAGE_PLAYLISTS );
|
||||
mii.cch = (unsigned int)lstrlen( mii.dwTypeData );
|
||||
mii.wID = WINAMP_MANAGEPLAYLISTS;
|
||||
InsertMenuItem( btnMenu, 0, TRUE, &mii );
|
||||
|
||||
mii.dwTypeData = WASABI_API_LNGSTRINGW( IDS_NEW_PLAYLIST );
|
||||
mii.cch = (unsigned int)lstrlen( mii.dwTypeData );
|
||||
mii.wID = ID_DOSHITMENU_ADDNEWPLAYLIST;
|
||||
InsertMenuItem( btnMenu, 0, TRUE, &mii );
|
||||
}
|
||||
}
|
||||
|
||||
imgPL = mediaLibrary.AddTreeImage( IDB_TREEITEM_PLAYLIST, PLAYLIST_IMAGE_INDEX, (BMPFILTERPROC)FILTER_DEFAULT1 );
|
||||
imgCloudPL = mediaLibrary.AddTreeImage( IDB_TREEITEM_CLOUD_PLAYLIST, PLAYLIST_CLOUD_IMAGE_INDEX, (BMPFILTERPROC)FILTER_DEFAULT1 );
|
||||
|
||||
NAVINSERTSTRUCT nis = { 0 };
|
||||
nis.item.cbSize = sizeof( NAVITEM );
|
||||
nis.item.pszText = WASABI_API_LNGSTRINGW_BUF( IDS_PLAYLISTS, prefsname, 64 );
|
||||
nis.item.pszInvariant = L"Playlists";
|
||||
nis.item.id = playlistsTreeId = 3001; // for backwards compatability
|
||||
nis.item.style = NIS_HASCHILDREN;
|
||||
nis.item.mask = NIMF_TEXT | NIMF_TEXTINVARIANT | NIMF_ITEMID | NIMF_STYLE;
|
||||
|
||||
playlistItem = MLNavCtrl_InsertItem( plugin.hwndLibraryParent, &nis );
|
||||
|
||||
LoadPlaylists();
|
||||
|
||||
Hook( plugin.hwndWinampParent );
|
||||
HookPlaylistEditor();
|
||||
|
||||
return ML_INIT_SUCCESS;
|
||||
}
|
||||
|
||||
void Quit()
|
||||
{
|
||||
AGAVE_API_PLAYLISTS->Flush();
|
||||
WASABI_API_SYSCB->syscb_deregisterCallback( &playlistsCB );
|
||||
|
||||
ReleaseService( api_playlistmanagerGUID, AGAVE_API_PLAYLISTMANAGER );
|
||||
ReleaseService( api_playlistsGUID, AGAVE_API_PLAYLISTS );
|
||||
ReleaseService( DownloadManagerGUID, WAC_API_DOWNLOADMANAGER );
|
||||
ReleaseService( applicationApiServiceGuid, WASABI_API_APP );
|
||||
ReleaseService( syscbApiServiceGuid, WASABI_API_SYSCB );
|
||||
ReleaseService( ExplorerFindFileApiGUID, WASABI_API_EXPLORERFINDFILE );
|
||||
|
||||
UnhookPlaylistEditor();
|
||||
UnhookMediaLibrary();
|
||||
|
||||
delete g_config;
|
||||
}
|
||||
|
||||
extern "C" __declspec( dllexport ) winampMediaLibraryPlugin * winampGetMediaLibraryPlugin()
|
||||
{
|
||||
return &plugin;
|
||||
}
|
498
Src/Plugins/Library/ml_playlists/ml_playlists.rc
Normal file
498
Src/Plugins/Library/ml_playlists/ml_playlists.rc
Normal file
@ -0,0 +1,498 @@
|
||||
// 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
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Dialog
|
||||
//
|
||||
|
||||
IDD_BROWSE_PLFLD DIALOGEX 0, 0, 254, 29
|
||||
STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN
|
||||
FONT 8, "MS Shell Dlg", 0, 0, 0x0
|
||||
BEGIN
|
||||
CONTROL "Use original playlist instead of a Winamp managed copy", IDC_EXTERNAL,
|
||||
"Button", BS_AUTOCHECKBOX | WS_TABSTOP, 5, 4, 193, 10
|
||||
CONTROL "Recursive scan", IDC_CHECK1, "Button", BS_AUTOCHECKBOX | WS_TABSTOP, 5, 17, 64, 10
|
||||
CONTROL "Available in the Cloud", IDC_CLOUD, "Button", BS_AUTOCHECKBOX | WS_TABSTOP, 83, 17, 85, 10
|
||||
END
|
||||
|
||||
IDD_VIEW_PLAYLISTS DIALOGEX 0, 0, 184, 266
|
||||
STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_SYSMENU
|
||||
EXSTYLE WS_EX_ACCEPTFILES
|
||||
FONT 8, "MS Shell Dlg", 400, 0, 0x1
|
||||
BEGIN
|
||||
CONTROL "", IDC_PLAYLIST_LIST, "SysListView32", LVS_REPORT | LVS_SHOWSELALWAYS | LVS_OWNERDATA | LVS_NOSORTHEADER | WS_TABSTOP, 0, 0, 182, 253
|
||||
CONTROL "View Playlist", IDC_VIEWLIST, "Button", BS_OWNERDRAW | WS_TABSTOP, 0, 255, 37, 11
|
||||
CONTROL "Play", IDC_PLAY, "Button", BS_OWNERDRAW | WS_TABSTOP, 39, 255, 22, 11
|
||||
CONTROL "Enqueue", IDC_ENQUEUE, "Button", BS_OWNERDRAW | WS_TABSTOP, 63, 255, 36, 11
|
||||
CONTROL "New...", IDC_CREATENEWPL, "Button", BS_OWNERDRAW | WS_TABSTOP, 101, 255, 22, 11
|
||||
CONTROL "Import", IDC_IMPORT, "Button", BS_OWNERDRAW | WS_TABSTOP, 125, 255, 29, 11
|
||||
CONTROL "Save...", IDC_SAVE, "Button", BS_OWNERDRAW | WS_TABSTOP, 156, 255, 28, 11
|
||||
END
|
||||
|
||||
IDD_RENAME_PLAYLIST DIALOGEX 0, 0, 186, 42
|
||||
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
|
||||
CAPTION "Rename Playlist"
|
||||
FONT 8, "MS Shell Dlg", 400, 0, 0x1
|
||||
BEGIN
|
||||
LTEXT "Name:", IDC_STATIC, 5, 9, 22, 8
|
||||
EDITTEXT IDC_NAME, 35, 7, 145, 12, ES_AUTOHSCROLL
|
||||
DEFPUSHBUTTON "OK", IDOK, 76, 25, 50, 13
|
||||
PUSHBUTTON "Cancel", IDCANCEL, 130, 25, 50, 13
|
||||
END
|
||||
|
||||
IDD_ADD_PLAYLIST DIALOGEX 0, 0, 186, 42
|
||||
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
|
||||
CAPTION "New Playlist"
|
||||
FONT 8, "MS Shell Dlg", 400, 0, 0x1
|
||||
BEGIN
|
||||
LTEXT "Name:", IDC_STATIC, 5, 9, 22, 8
|
||||
EDITTEXT IDC_NAME, 35, 7, 145, 12, ES_AUTOHSCROLL
|
||||
DEFPUSHBUTTON "OK", IDOK, 76, 25, 50, 13
|
||||
PUSHBUTTON "Cancel", IDCANCEL, 130, 25, 50, 13
|
||||
END
|
||||
|
||||
IDD_VIEW_PLAYLIST DIALOGEX 0, 0, 339, 59
|
||||
STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_SYSMENU
|
||||
EXSTYLE WS_EX_ACCEPTFILES
|
||||
FONT 8, "MS Shell Dlg", 400, 0, 0x1
|
||||
BEGIN
|
||||
CONTROL "", IDC_PLAYLIST_EDITOR, "SysListView32", LVS_REPORT | LVS_SHOWSELALWAYS | LVS_OWNERDATA | LVS_NOSORTHEADER | WS_TABSTOP, 0, 0, 339, 34
|
||||
LTEXT "", IDC_PLSTATUS, 0, 36, 339, 10, SS_CENTERIMAGE | SS_ENDELLIPSIS
|
||||
CONTROL "Play", IDC_PLAY, "Button", BS_OWNERDRAW | WS_TABSTOP, 0, 48, 27, 11
|
||||
CONTROL "Send-To", IDC_BURN, "Button", BS_OWNERDRAW | WS_TABSTOP, 34, 48, 44, 11
|
||||
CONTROL "Add", IDC_ADD, "Button", BS_OWNERDRAW | WS_TABSTOP, 85, 48, 30, 11
|
||||
CONTROL "Rem", IDC_REM, "Button", BS_OWNERDRAW | WS_TABSTOP, 122, 48, 30, 11
|
||||
CONTROL "Sel", IDC_SEL, "Button", BS_OWNERDRAW | WS_TABSTOP, 159, 48, 30, 11
|
||||
CONTROL "Misc", IDC_MISC, "Button", BS_OWNERDRAW | WS_TABSTOP, 196, 48, 30, 11
|
||||
CONTROL "Manage Playlist", IDC_LIST, "Button", BS_OWNERDRAW | WS_TABSTOP, 233, 48, 69, 11
|
||||
CONTROL "Save", IDC_SAVE_PL, "Button", BS_OWNERDRAW | WS_DISABLED | WS_TABSTOP, 309, 48, 30, 11
|
||||
END
|
||||
|
||||
IDD_EDIT_FN DIALOGEX 0, 0, 262, 95
|
||||
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
|
||||
CAPTION "Edit Playlist Entry"
|
||||
FONT 8, "MS Shell Dlg", 400, 0, 0x1
|
||||
BEGIN
|
||||
RTEXT "Old Entry:", IDC_STATIC, 4, 7, 40, 12, SS_CENTERIMAGE
|
||||
EDITTEXT IDC_OLD, 49, 7, 206, 12, ES_AUTOHSCROLL | ES_READONLY | WS_DISABLED
|
||||
RTEXT "Old Title:", IDC_STATIC, 4, 24, 40, 12, SS_CENTERIMAGE
|
||||
EDITTEXT IDC_OLD_TITLE, 49, 24, 206, 12, ES_AUTOHSCROLL | ES_READONLY | WS_DISABLED
|
||||
RTEXT "New Entry:", IDC_STATIC, 4, 41, 40, 12, SS_CENTERIMAGE
|
||||
EDITTEXT IDC_NEW, 49, 41, 188, 12, ES_AUTOHSCROLL
|
||||
PUSHBUTTON "&...", IDC_PLAYLIST_EDIT_ENTRY_BROWSE, 238, 40, 17, 14
|
||||
RTEXT "New Title:", IDC_STATIC, 4, 58, 40, 12, SS_CENTERIMAGE
|
||||
EDITTEXT IDC_NEW_TITLE, 49, 58, 206, 12, ES_AUTOHSCROLL
|
||||
DEFPUSHBUTTON "OK", IDOK, 5, 76, 50, 14
|
||||
PUSHBUTTON "Cancel", IDCANCEL, 61, 76, 50, 14
|
||||
END
|
||||
|
||||
IDD_SELECT_PLAYLIST DIALOGEX 0, 0, 209, 42
|
||||
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
|
||||
CAPTION "Select Playlist"
|
||||
FONT 8, "MS Shell Dlg", 400, 0, 0x1
|
||||
BEGIN
|
||||
COMBOBOX IDC_PLAYLISTS, 4, 7, 200, 158, CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
|
||||
PUSHBUTTON "Cancel", IDCANCEL, 154, 25, 50, 13
|
||||
DEFPUSHBUTTON "OK", IDOK, 100, 25, 50, 13
|
||||
END
|
||||
|
||||
#if defined(APSTUDIO_INVOKED) || defined(DISABLED)
|
||||
#if defined(APSTUDIO_INVOKED)
|
||||
IDD_ADD_CLOUD_PLAYLIST$( DISABLED ) DIALOGEX 0, 0, 186, 42
|
||||
#else
|
||||
IDD_ADD_CLOUD_PLAYLIST DIALOGEX 0, 0, 186, 42
|
||||
#endif
|
||||
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
|
||||
CAPTION "New Playlist"
|
||||
FONT 8, "MS Shell Dlg", 400, 0, 0x1
|
||||
BEGIN
|
||||
LTEXT "Name:", IDC_STATIC, 5, 9, 22, 8
|
||||
EDITTEXT IDC_NAME, 35, 7, 145, 12, ES_AUTOHSCROLL
|
||||
CONTROL "&Available in the Cloud", IDC_CLOUD, "Button", BS_AUTOCHECKBOX | WS_TABSTOP, 6, 26, 88, 11
|
||||
DEFPUSHBUTTON "&OK", IDOK, 98, 25, 36, 13
|
||||
PUSHBUTTON "&Cancel", IDCANCEL, 138, 25, 42, 13
|
||||
END
|
||||
#endif
|
||||
|
||||
IDD_IMPORT_PLFLD DIALOGEX 0, 0, 400, 20
|
||||
STYLE DS_SETFONT | DS_FIXEDSYS | DS_CONTROL | WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN
|
||||
FONT 8, "MS Shell Dlg", 0, 0, 0x0
|
||||
BEGIN
|
||||
CONTROL "Available in the Cloud", IDC_CLOUD, "Button", BS_AUTOCHECKBOX | WS_TABSTOP, 67, 3, 85, 10
|
||||
CONTROL "Use original playlist instead of a Winamp managed copy", IDC_EXTERNAL,
|
||||
"Button", BS_AUTOCHECKBOX | WS_TABSTOP, 167, 3, 193, 10
|
||||
END
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// DESIGNINFO
|
||||
//
|
||||
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
GUIDELINES DESIGNINFO
|
||||
BEGIN
|
||||
IDD_BROWSE_PLFLD, DIALOG
|
||||
BEGIN
|
||||
RIGHTMARGIN, 109
|
||||
BOTTOMMARGIN, 18
|
||||
END
|
||||
|
||||
IDD_RENAME_PLAYLIST, DIALOG
|
||||
BEGIN
|
||||
LEFTMARGIN, 5
|
||||
RIGHTMARGIN, 180
|
||||
TOPMARGIN, 7
|
||||
BOTTOMMARGIN, 38
|
||||
END
|
||||
|
||||
IDD_ADD_PLAYLIST, DIALOG
|
||||
BEGIN
|
||||
LEFTMARGIN, 5
|
||||
RIGHTMARGIN, 180
|
||||
TOPMARGIN, 7
|
||||
BOTTOMMARGIN, 38
|
||||
END
|
||||
|
||||
IDD_VIEW_PLAYLIST, DIALOG
|
||||
BEGIN
|
||||
RIGHTMARGIN, 295
|
||||
END
|
||||
|
||||
IDD_EDIT_FN, DIALOG
|
||||
BEGIN
|
||||
LEFTMARGIN, 5
|
||||
RIGHTMARGIN, 254
|
||||
RIGHTMARGIN, 255
|
||||
TOPMARGIN, 7
|
||||
BOTTOMMARGIN, 90
|
||||
END
|
||||
|
||||
IDD_SELECT_PLAYLIST, DIALOG
|
||||
BEGIN
|
||||
LEFTMARGIN, 4
|
||||
RIGHTMARGIN, 204
|
||||
TOPMARGIN, 7
|
||||
BOTTOMMARGIN, 38
|
||||
END
|
||||
|
||||
"IDD_ADD_CLOUD_PLAYLIST$(DISABLED)", DIALOG
|
||||
BEGIN
|
||||
LEFTMARGIN, 5
|
||||
RIGHTMARGIN, 180
|
||||
TOPMARGIN, 7
|
||||
BOTTOMMARGIN, 38
|
||||
END
|
||||
|
||||
IDD_IMPORT_PLFLD, DIALOG
|
||||
BEGIN
|
||||
RIGHTMARGIN, 227
|
||||
BOTTOMMARGIN, 15
|
||||
END
|
||||
END
|
||||
#endif // APSTUDIO_INVOKED
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Menu
|
||||
//
|
||||
|
||||
IDR_MENU1 MENU
|
||||
BEGIN
|
||||
POPUP "Playlist"
|
||||
BEGIN
|
||||
MENUITEM "Play\tEnter", IDC_PLAY
|
||||
MENUITEM "Enqueue\tShift+Enter", IDC_ENQUEUE
|
||||
POPUP "Send to:"
|
||||
BEGIN
|
||||
MENUITEM "", 40003
|
||||
END
|
||||
MENUITEM SEPARATOR
|
||||
MENUITEM "View Playlist\tCtrl+V", IDC_VIEWLIST
|
||||
MENUITEM SEPARATOR
|
||||
MENUITEM "Rename Playlist...\tF2", IDC_RENAME
|
||||
MENUITEM "New Playlist...\tShift+Insert", IDC_NEWPLAYLIST
|
||||
MENUITEM SEPARATOR
|
||||
MENUITEM "Delete Playlist\tDel", IDC_DELETE
|
||||
END
|
||||
POPUP "Playlistsmenu"
|
||||
BEGIN
|
||||
MENUITEM "New Playlist...", IDC_NEWPLAYLIST
|
||||
MENUITEM SEPARATOR
|
||||
MENUITEM "Import playlist from file...", IDC_IMPORT_PLAYLIST_FROM_FILE
|
||||
MENUITEM "Import active (current) playlist", IDC_IMPORT_WINAMP_PLAYLIST
|
||||
MENUITEM "Import playlist from folder...", 40010
|
||||
MENUITEM SEPARATOR
|
||||
POPUP "Sort playlists by:"
|
||||
BEGIN
|
||||
MENUITEM "Title alphabetically (A->Z)", ID_SORTPLAYLIST_TITLE_A_Z
|
||||
MENUITEM "Title alphabetically (Z->A)", ID_SORTPLAYLIST_TITLE_Z_A
|
||||
MENUITEM "Number of items ascending", ID_SORTPLAYLIST_NUMBEROFITEMSASCENDING
|
||||
MENUITEM "Number of items descending", ID_SORTPLAYLIST_NUMBEROFITEMSDESCENDING
|
||||
END
|
||||
MENUITEM SEPARATOR
|
||||
MENUITEM "Help", ID_PLAYLISTS_HELP
|
||||
END
|
||||
POPUP "PlaylistsImport"
|
||||
BEGIN
|
||||
MENUITEM "Import playlists from folder...", ID_PLAYLISTSIMPORT_IMPORTPLAYLISTSFROMFOLDER
|
||||
MENUITEM "Import (active) current playlist", IDC_IMPORT_WINAMP_PLAYLIST
|
||||
MENUITEM "Import playlist from file...", IDC_IMPORT_PLAYLIST_FROM_FILE
|
||||
END
|
||||
POPUP "PEditorMenus"
|
||||
BEGIN
|
||||
POPUP "RightClick"
|
||||
BEGIN
|
||||
MENUITEM "Play selection\tEnter", IDC_PLAY
|
||||
MENUITEM "Enqueue selection\tShift+Enter", IDC_ENQUEUE
|
||||
POPUP "Send to:"
|
||||
BEGIN
|
||||
MENUITEM "", 40003
|
||||
END
|
||||
MENUITEM SEPARATOR
|
||||
MENUITEM "Remove item(s)\tDelete", IDC_DELETE
|
||||
MENUITEM "Crop item(s)\tCtrl+Delete", IDC_CROP
|
||||
MENUITEM SEPARATOR
|
||||
MENUITEM "Download\t", IDC_PLAYLIST_DOWNLOAD_ENTRY
|
||||
MENUITEM SEPARATOR
|
||||
MENUITEM "View f&ile info...\tAlt+3", IDC_PLAYLIST_VIEW_FILE_INFO
|
||||
MENUITEM "Playlist entry\tCtrl+E", IDC_PLAYLIST_EDIT_ENTRY
|
||||
MENUITEM SEPARATOR
|
||||
MENUITEM "Explore item folder\tCtrl+F", IDC_PLAYLIST_EXPLOREITEMFOLDER
|
||||
END
|
||||
POPUP "Selection"
|
||||
BEGIN
|
||||
MENUITEM "Select &all\tCtrl+A", IDC_PLAYLIST_SELECT_ALL
|
||||
MENUITEM "Select &none", IDC_PLAYLIST_SELECT_NONE
|
||||
MENUITEM "Invert selection\tCtrl+I", IDC_PLAYLIST_INVERT_SELECTION
|
||||
END
|
||||
POPUP "Remove"
|
||||
BEGIN
|
||||
MENUITEM "Remove all &dead files", IDC_PLAYLIST_REMOVE_DEAD
|
||||
MENUITEM SEPARATOR
|
||||
MENUITEM "Remove all items", IDC_PLAYLIST_REMOVE_ALL
|
||||
MENUITEM "Crop selected items\tCtrl+Delete", IDC_CROP
|
||||
MENUITEM "Remove selected items\tDelete", IDC_DELETE
|
||||
MENUITEM "Physically remove selected item(s)", IDC_PLAYLIST_RECYCLE_SELECTED
|
||||
END
|
||||
POPUP "Add"
|
||||
BEGIN
|
||||
MENUITEM "Add file(s)\tL", IDC_ADD_FILES
|
||||
MENUITEM "Add folder\tShift+L", IDC_ADD_DIRECTORY
|
||||
MENUITEM "Add URL\tCtrl+L", IDC_ADD_LOCATION
|
||||
END
|
||||
POPUP "Misc"
|
||||
BEGIN
|
||||
MENUITEM "&Randomize list\tCtrl+Shift+R", IDC_PLAYLIST_RANDOMIZE
|
||||
MENUITEM "R&everse list\tCtrl+R", IDC_PLAYLIST_REVERSE
|
||||
MENUITEM SEPARATOR
|
||||
MENUITEM "Sort list by &path and filename", IDC_PLAYLIST_SORT_PATH
|
||||
MENUITEM "Sort list by &filename", IDC_PLAYLIST_SORT_FILENAME
|
||||
MENUITEM "Sort list by &title", IDC_PLAYLIST_SORT_TITLE
|
||||
MENUITEM SEPARATOR
|
||||
MENUITEM "Generate HTML playlist\tCtrl+Alt+G", ID_PLAYLIST_GENERATE_HTML
|
||||
MENUITEM SEPARATOR
|
||||
MENUITEM "Rebuild titles on selection\tCtrl+Shift+E", IDC_PLAYLIST_RESET_CACHE
|
||||
END
|
||||
POPUP "List"
|
||||
BEGIN
|
||||
MENUITEM "Export playlist...", IDC_EXPORT_PLAYLIST
|
||||
POPUP "Send playlist to"
|
||||
BEGIN
|
||||
MENUITEM "", 40003
|
||||
END
|
||||
MENUITEM SEPARATOR
|
||||
MENUITEM "Import playlist from file...", IDC_IMPORT_PLAYLIST_FROM_FILE
|
||||
MENUITEM "Import active playlist", IDC_IMPORT_WINAMP_PLAYLIST
|
||||
END
|
||||
END
|
||||
END
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Bitmap
|
||||
//
|
||||
|
||||
IDB_TREEITEM_PLAYLIST BITMAP "resources\\ti_playlist_16x16x16.bmp"
|
||||
#if defined(APSTUDIO_INVOKED) || defined(DISABLED)
|
||||
#if defined(APSTUDIO_INVOKED)
|
||||
IDB_TREEITEM_CLOUD_PLAYLIST$( DISABLED ) BITMAP "resources\\ti_cloud_playlist_16x16x16.bmp"
|
||||
#else
|
||||
IDB_TREEITEM_CLOUD_PLAYLIST BITMAP "resources\\ti_cloud_playlist_16x16x16.bmp"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Accelerator
|
||||
//
|
||||
|
||||
IDR_VIEW_PLS_ACCELERATORS ACCELERATORS
|
||||
BEGIN
|
||||
VK_DELETE, IDC_DELETE, VIRTKEY, NOINVERT
|
||||
VK_RETURN, IDC_ENQUEUE, VIRTKEY, SHIFT, NOINVERT
|
||||
VK_INSERT, IDC_NEWPLAYLIST, VIRTKEY, SHIFT, NOINVERT
|
||||
VK_RETURN, IDC_PLAY, VIRTKEY, NOINVERT
|
||||
VK_F2, IDC_RENAME, VIRTKEY, NOINVERT
|
||||
"V", IDC_VIEWLIST, VIRTKEY, CONTROL, NOINVERT
|
||||
VK_RETURN, IDC_CUSTOM, VIRTKEY, SHIFT, CONTROL, NOINVERT
|
||||
END
|
||||
|
||||
IDR_VIEW_PL_ACCELERATORS ACCELERATORS
|
||||
BEGIN
|
||||
"3", IDC_PLAYLIST_VIEW_FILE_INFO, VIRTKEY, ALT, NOINVERT
|
||||
"A", IDC_PLAYLIST_SELECT_ALL, VIRTKEY, CONTROL, NOINVERT
|
||||
"E", IDC_PLAYLIST_EDIT_ENTRY, VIRTKEY, CONTROL, NOINVERT
|
||||
"E", IDC_PLAYLIST_RESET_CACHE, VIRTKEY, CONTROL, ALT, NOINVERT
|
||||
"F", IDC_PLAYLIST_EXPLOREITEMFOLDER, VIRTKEY, CONTROL, NOINVERT
|
||||
"G", ID_PLAYLIST_GENERATE_HTML, VIRTKEY, CONTROL, ALT, NOINVERT
|
||||
"I", IDC_PLAYLIST_INVERT_SELECTION, VIRTKEY, CONTROL, NOINVERT
|
||||
"L", IDC_ADD_FILES, VIRTKEY, NOINVERT
|
||||
"L", IDC_ADD_LOCATION, VIRTKEY, CONTROL, NOINVERT
|
||||
"L", IDC_ADD_DIRECTORY, VIRTKEY, SHIFT, NOINVERT
|
||||
"R", IDC_PLAYLIST_REVERSE, VIRTKEY, CONTROL, NOINVERT
|
||||
"R", IDC_PLAYLIST_RANDOMIZE, VIRTKEY, SHIFT, CONTROL, NOINVERT
|
||||
VK_DELETE, IDC_DELETE, VIRTKEY, NOINVERT
|
||||
VK_DELETE, IDC_CROP, VIRTKEY, CONTROL, NOINVERT
|
||||
VK_F2, IDC_RENAME, VIRTKEY, NOINVERT
|
||||
VK_INSERT, IDC_NEWPLAYLIST, VIRTKEY, SHIFT, NOINVERT
|
||||
VK_RETURN, IDC_PLAY, VIRTKEY, NOINVERT
|
||||
VK_RETURN, IDC_ENQUEUE, VIRTKEY, SHIFT, NOINVERT
|
||||
VK_RETURN, IDC_CUSTOM, VIRTKEY, SHIFT, CONTROL, NOINVERT
|
||||
END
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// String Table
|
||||
//
|
||||
|
||||
STRINGTABLE
|
||||
BEGIN
|
||||
IDS_NULLSOFT_PLAYLISTS "Nullsoft Playlists v%s"
|
||||
65535 "{5E766B4F-818E-4f14-9C42-0902B2C571DC}"
|
||||
END
|
||||
|
||||
STRINGTABLE
|
||||
BEGIN
|
||||
IDS_IMPORT_PLAYLIST "Import playlist"
|
||||
IDS_APPEND_IMPORTED_PLAYLIST
|
||||
"Would you like to append the imported playlist to this playlist?\n\nSelect NO to overwrite this playlist with the imported playlist\nSelect YES to append the imported playlist to this playlist\nSelect CANCEL to not do anything"
|
||||
IDS_LIBRARY_QUESTION "Library Question"
|
||||
IDS_APPEND_ACTIVE_PLAYLIST
|
||||
"Would you like to append the active playlist to this playlist?\n\nSelect NO to overwrite this playlist with the active playlist\nSelect YES to append the active playlist to this playlist\nSelect CANCEL to not do anything"
|
||||
IDS_EXPORT_PLAYLIST "Export playlist"
|
||||
IDS_IMPORTED_PLAYLIST "Imported Playlist"
|
||||
IDS_ITEM "item"
|
||||
IDS_ADD_DIR_TO_PLAYLIST "Add directory to playlist"
|
||||
IDS_ADD_FILES_TO_PLAYLIST "Add file(s) to playlist"
|
||||
IDS_PLAYLISTS "Playlists"
|
||||
IDS_MANAGE_PLAYLISTS "&Manage Playlists..."
|
||||
IDS_NEW_PLAYLIST "New Play&list...\tShift+Insert"
|
||||
IDS_ENTER_A_NAME "You must enter a name!"
|
||||
IDS_ERROR "Error"
|
||||
END
|
||||
|
||||
STRINGTABLE
|
||||
BEGIN
|
||||
IDS_SENDTO_NEW_PLAYLIST "New Playlist"
|
||||
IDS_SENDTO_ML_PLAYLISTS "Library Playlists"
|
||||
IDS_SENDTO_PLAYLIST "Library Playlist"
|
||||
IDS_IMPORT_PLAYLIST_FROM_FOLDER "Import playlist from folder"
|
||||
IDS_CONFIRM_DELETION "Are you sure you want to delete the selected playlist(s)"
|
||||
IDS_CONFIRMATION "Confirmation"
|
||||
IDS_PLAYLIST_TITLE "Playlist Title"
|
||||
IDS_ITEMS "Items"
|
||||
IDS_TIME "Time"
|
||||
IDS_ERROR_DELETING_FILES "Error deleting files"
|
||||
IDS_X_OF_X_SELECTED "%d/%d %s selected (%s/%s)"
|
||||
IDS_X_SELECTED "%d %s (%s)"
|
||||
IDS_ITEMS_LOWER "items"
|
||||
IDS_TITLE "Title"
|
||||
IDS_NO_PLAYLIST_IN_LIBRARY "No Playlist in Library"
|
||||
IDS_OPEN_PLAYLIST_FROM_ML "Open playlist from &Library"
|
||||
END
|
||||
|
||||
STRINGTABLE
|
||||
BEGIN
|
||||
IDS_PLAYLIST_FROM_ML "Playlist from &Library"
|
||||
IDS_PLAYLIST_ERROR "Cannot save playlist: Error writing to file or file is read-only"
|
||||
IDS_PLAYLIST_ERROR_TITLE "Error saving playlist"
|
||||
IDS_DAY "day"
|
||||
IDS_DAYS "days"
|
||||
IDS_PL_FILE_MNGT "Winamp Playlist Management"
|
||||
IDS_EXTERNAL_CHECKED "Checking this will make Winamp use the original playlist file(s) instead of creating a Winamp managed copy which is not synchronized with the original playlist file(s).\n\nIf checked, you need to ensure the playlist file(s) exist and will be accessible always otherwise they will not be useable within Winamp. All actions will be done on the original playlist file e.g. delete will remove the original file instead of just removing the Winamp managed copy."
|
||||
IDS_EXTERNAL_ALREADY_ADDED
|
||||
"The playlist you have selected has already been imported into Winamp and will not be re-added."
|
||||
IDS_SOURCE_PL_MISSING "\n\nThe source playlist file for this playlist view cannot be located.\nThis can happen if the playlist has been physically removed.\n\nThe missing source playlist file is:\n%s"
|
||||
END
|
||||
|
||||
STRINGTABLE
|
||||
BEGIN
|
||||
IDS_BROWSE_FOR_PLEDIT_ENTRY "Browse for playlist entry..."
|
||||
END
|
||||
|
||||
#endif // English (U.S.) resources
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
#ifndef APSTUDIO_INVOKED
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Generated from the TEXTINCLUDE 3 resource.
|
||||
//
|
||||
#include "version.rc2"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
#endif // not APSTUDIO_INVOKED
|
||||
|
81
Src/Plugins/Library/ml_playlists/ml_playlists.sln
Normal file
81
Src/Plugins/Library/ml_playlists/ml_playlists.sln
Normal file
@ -0,0 +1,81 @@
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 16
|
||||
VisualStudioVersion = 16.0.29509.3
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ml_playlists", "ml_playlists.vcxproj", "{71726F38-0625-4E16-BA79-32FE4F83E1E4}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{44AEBB50-1331-4F2E-8AEC-56C82DE16C11} = {44AEBB50-1331-4F2E-8AEC-56C82DE16C11}
|
||||
{F1F5CD60-0D5B-4CEA-9EEB-2F87FF9AA915} = {F1F5CD60-0D5B-4CEA-9EEB-2F87FF9AA915}
|
||||
{E105A0A2-7391-47C5-86AC-718003524C3D} = {E105A0A2-7391-47C5-86AC-718003524C3D}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "nx", "..\replicant\nx\nx.vcxproj", "{57C90706-B25D-4ACA-9B33-95CDB2427C27}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{44AEBB50-1331-4F2E-8AEC-56C82DE16C11} = {44AEBB50-1331-4F2E-8AEC-56C82DE16C11}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "nu", "..\replicant\nu\nu.vcxproj", "{F1F5CD60-0D5B-4CEA-9EEB-2F87FF9AA915}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "jnetlib", "..\replicant\jnetlib\jnetlib.vcxproj", "{E105A0A2-7391-47C5-86AC-718003524C3D}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{44AEBB50-1331-4F2E-8AEC-56C82DE16C11} = {44AEBB50-1331-4F2E-8AEC-56C82DE16C11}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zlib", "..\replicant\zlib\zlib.vcxproj", "{44AEBB50-1331-4F2E-8AEC-56C82DE16C11}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Win32 = Debug|Win32
|
||||
Debug|x64 = Debug|x64
|
||||
Release|Win32 = Release|Win32
|
||||
Release|x64 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{71726F38-0625-4E16-BA79-32FE4F83E1E4}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{71726F38-0625-4E16-BA79-32FE4F83E1E4}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{71726F38-0625-4E16-BA79-32FE4F83E1E4}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{71726F38-0625-4E16-BA79-32FE4F83E1E4}.Debug|x64.Build.0 = Debug|x64
|
||||
{71726F38-0625-4E16-BA79-32FE4F83E1E4}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{71726F38-0625-4E16-BA79-32FE4F83E1E4}.Release|Win32.Build.0 = Release|Win32
|
||||
{71726F38-0625-4E16-BA79-32FE4F83E1E4}.Release|x64.ActiveCfg = Release|x64
|
||||
{71726F38-0625-4E16-BA79-32FE4F83E1E4}.Release|x64.Build.0 = Release|x64
|
||||
{57C90706-B25D-4ACA-9B33-95CDB2427C27}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{57C90706-B25D-4ACA-9B33-95CDB2427C27}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{57C90706-B25D-4ACA-9B33-95CDB2427C27}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{57C90706-B25D-4ACA-9B33-95CDB2427C27}.Debug|x64.Build.0 = Debug|x64
|
||||
{57C90706-B25D-4ACA-9B33-95CDB2427C27}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{57C90706-B25D-4ACA-9B33-95CDB2427C27}.Release|Win32.Build.0 = Release|Win32
|
||||
{57C90706-B25D-4ACA-9B33-95CDB2427C27}.Release|x64.ActiveCfg = Release|x64
|
||||
{57C90706-B25D-4ACA-9B33-95CDB2427C27}.Release|x64.Build.0 = Release|x64
|
||||
{F1F5CD60-0D5B-4CEA-9EEB-2F87FF9AA915}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{F1F5CD60-0D5B-4CEA-9EEB-2F87FF9AA915}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{F1F5CD60-0D5B-4CEA-9EEB-2F87FF9AA915}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{F1F5CD60-0D5B-4CEA-9EEB-2F87FF9AA915}.Debug|x64.Build.0 = Debug|x64
|
||||
{F1F5CD60-0D5B-4CEA-9EEB-2F87FF9AA915}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{F1F5CD60-0D5B-4CEA-9EEB-2F87FF9AA915}.Release|Win32.Build.0 = Release|Win32
|
||||
{F1F5CD60-0D5B-4CEA-9EEB-2F87FF9AA915}.Release|x64.ActiveCfg = Release|x64
|
||||
{F1F5CD60-0D5B-4CEA-9EEB-2F87FF9AA915}.Release|x64.Build.0 = Release|x64
|
||||
{E105A0A2-7391-47C5-86AC-718003524C3D}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{E105A0A2-7391-47C5-86AC-718003524C3D}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{E105A0A2-7391-47C5-86AC-718003524C3D}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{E105A0A2-7391-47C5-86AC-718003524C3D}.Debug|x64.Build.0 = Debug|x64
|
||||
{E105A0A2-7391-47C5-86AC-718003524C3D}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{E105A0A2-7391-47C5-86AC-718003524C3D}.Release|Win32.Build.0 = Release|Win32
|
||||
{E105A0A2-7391-47C5-86AC-718003524C3D}.Release|x64.ActiveCfg = Release|x64
|
||||
{E105A0A2-7391-47C5-86AC-718003524C3D}.Release|x64.Build.0 = Release|x64
|
||||
{44AEBB50-1331-4F2E-8AEC-56C82DE16C11}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{44AEBB50-1331-4F2E-8AEC-56C82DE16C11}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{44AEBB50-1331-4F2E-8AEC-56C82DE16C11}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{44AEBB50-1331-4F2E-8AEC-56C82DE16C11}.Debug|x64.Build.0 = Debug|x64
|
||||
{44AEBB50-1331-4F2E-8AEC-56C82DE16C11}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{44AEBB50-1331-4F2E-8AEC-56C82DE16C11}.Release|Win32.Build.0 = Release|Win32
|
||||
{44AEBB50-1331-4F2E-8AEC-56C82DE16C11}.Release|x64.ActiveCfg = Release|x64
|
||||
{44AEBB50-1331-4F2E-8AEC-56C82DE16C11}.Release|x64.Build.0 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {3815C7C8-CBE1-4F34-B885-16D73AD02A60}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
359
Src/Plugins/Library/ml_playlists/ml_playlists.vcxproj
Normal file
359
Src/Plugins/Library/ml_playlists/ml_playlists.vcxproj
Normal file
@ -0,0 +1,359 @@
|
||||
<?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>{71726F38-0625-4E16-BA79-32FE4F83E1E4}</ProjectGuid>
|
||||
<RootNamespace>ml_playlists</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>10.0.19041.0</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<OutDir>$(PlatformShortName)_$(Configuration)\</OutDir>
|
||||
<IntDir>$(PlatformShortName)_$(Configuration)\</IntDir>
|
||||
<IncludePath>$(IncludePath)</IncludePath>
|
||||
<LibraryPath>$(LibraryPath)</LibraryPath>
|
||||
<EmbedManifest>true</EmbedManifest>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<OutDir>$(PlatformShortName)_$(Configuration)\</OutDir>
|
||||
<IntDir>$(PlatformShortName)_$(Configuration)\</IntDir>
|
||||
<EmbedManifest>true</EmbedManifest>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<OutDir>$(PlatformShortName)_$(Configuration)\</OutDir>
|
||||
<IntDir>$(PlatformShortName)_$(Configuration)\</IntDir>
|
||||
<IncludePath>$(IncludePath)</IncludePath>
|
||||
<LibraryPath>$(LibraryPath)</LibraryPath>
|
||||
<EmbedManifest>true</EmbedManifest>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<OutDir>$(PlatformShortName)_$(Configuration)\</OutDir>
|
||||
<IntDir>$(PlatformShortName)_$(Configuration)\</IntDir>
|
||||
<EmbedManifest>true</EmbedManifest>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Label="Vcpkg">
|
||||
<VcpkgEnableManifest>false</VcpkgEnableManifest>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<VcpkgInstalledDir>
|
||||
</VcpkgInstalledDir>
|
||||
<VcpkgUseStatic>false</VcpkgUseStatic>
|
||||
<VcpkgConfiguration>Debug</VcpkgConfiguration>
|
||||
<VcpkgTriplet>x86-windows-static-md</VcpkgTriplet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<VcpkgInstalledDir>
|
||||
</VcpkgInstalledDir>
|
||||
<VcpkgUseStatic>false</VcpkgUseStatic>
|
||||
<VcpkgTriplet>x86-windows-static-md</VcpkgTriplet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<VcpkgInstalledDir>
|
||||
</VcpkgInstalledDir>
|
||||
<VcpkgUseStatic>false</VcpkgUseStatic>
|
||||
<VcpkgTriplet>x86-windows-static-md</VcpkgTriplet>
|
||||
<VcpkgConfiguration>Debug</VcpkgConfiguration>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<VcpkgInstalledDir>
|
||||
</VcpkgInstalledDir>
|
||||
<VcpkgUseStatic>false</VcpkgUseStatic>
|
||||
<VcpkgTriplet>x86-windows-static-md</VcpkgTriplet>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<AdditionalIncludeDirectories>.;..\..\..\Wasabi;..\..\..\dlmgr;..;..\..\..\;..\..\..\replicant;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>_WIN32_WINNT=0x0601;WINVER=0x0601;WIN32;_DEBUG;_WINDOWS;_USRDLL;ML_PLAYLISTS_EXPORTS;_WIN32_IE=0x0A00;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<MinimalRebuild>false</MinimalRebuild>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
|
||||
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
<DisableSpecificWarnings>4995;%(DisableSpecificWarnings)</DisableSpecificWarnings>
|
||||
<BufferSecurityCheck>true</BufferSecurityCheck>
|
||||
<ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>comctl32.lib;shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<RandomizedBaseAddress>false</RandomizedBaseAddress>
|
||||
<ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
|
||||
<TargetMachine>MachineX86</TargetMachine>
|
||||
<ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
|
||||
<AdditionalLibraryDirectories>..\ml_downloads\$(PlatformShortName)_$(Configuration)\;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
<PostBuildEvent>
|
||||
<Command>xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\
|
||||
xcopy /Y /D $(IntDir)$(TargetName).pdb ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\ </Command>
|
||||
<Message>Post build event: 'xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\'</Message>
|
||||
</PostBuildEvent>
|
||||
<ResourceCompile>
|
||||
<PreprocessorDefinitions>_WIN32_WINNT=0x0601;WINVER=0x0601;_UNICODE;UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ResourceCompile>
|
||||
<Manifest>
|
||||
<OutputManifestFile>$(IntDir)$(TargetName)$(TargetExt).intermediate.manifest</OutputManifestFile>
|
||||
</Manifest>
|
||||
<ProjectReference>
|
||||
<UseLibraryDependencyInputs>false</UseLibraryDependencyInputs>
|
||||
</ProjectReference>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<AdditionalIncludeDirectories>.;..\..\..\Wasabi;..;..\..\..\;..\..\..\replicant;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>_WIN32_WINNT=0x0601;WINVER=0x0601;WIN64;_DEBUG;_WINDOWS;_USRDLL;ML_PLAYLISTS_EXPORTS;_WIN32_IE=0x0A00;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<MinimalRebuild>false</MinimalRebuild>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
|
||||
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
<DisableSpecificWarnings>4244;4267;4838;4477;4090;4995;%(DisableSpecificWarnings)</DisableSpecificWarnings>
|
||||
<BufferSecurityCheck>true</BufferSecurityCheck>
|
||||
<ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>comctl32.lib;shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<RandomizedBaseAddress>false</RandomizedBaseAddress>
|
||||
<ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
|
||||
<ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
|
||||
<AdditionalLibraryDirectories>..\ml_downloads\$(PlatformShortName)_$(Configuration)\;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
<PostBuildEvent>
|
||||
<Command>xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\
|
||||
xcopy /Y /D $(IntDir)$(TargetName).pdb ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\ </Command>
|
||||
<Message>Post build event: 'xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\'</Message>
|
||||
</PostBuildEvent>
|
||||
<ResourceCompile>
|
||||
<PreprocessorDefinitions>_WIN32_WINNT=0x0601;WINVER=0x0601;_UNICODE;UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ResourceCompile>
|
||||
<Manifest>
|
||||
<OutputManifestFile>$(IntDir)$(TargetName)$(TargetExt).intermediate.manifest</OutputManifestFile>
|
||||
</Manifest>
|
||||
<ProjectReference>
|
||||
<UseLibraryDependencyInputs>false</UseLibraryDependencyInputs>
|
||||
</ProjectReference>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<Optimization>MinSpace</Optimization>
|
||||
<FavorSizeOrSpeed>Size</FavorSizeOrSpeed>
|
||||
<AdditionalIncludeDirectories>.;..\..\..\Wasabi;..\..\..\dlmgr;..;..\..\..\;..\..\..\replicant;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>_WIN32_WINNT=0x0601;WINVER=0x0601;WIN32;NDEBUG;_WINDOWS;_USRDLL;ML_PLAYLISTS_EXPORTS;_WIN32_IE=0x0A00;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<StringPooling>true</StringPooling>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
|
||||
<BufferSecurityCheck>true</BufferSecurityCheck>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<DebugInformationFormat>None</DebugInformationFormat>
|
||||
<DisableSpecificWarnings>4995;%(DisableSpecificWarnings)</DisableSpecificWarnings>
|
||||
<ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>comctl32.lib;shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
|
||||
<GenerateDebugInformation>false</GenerateDebugInformation>
|
||||
<ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<RandomizedBaseAddress>false</RandomizedBaseAddress>
|
||||
<ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
|
||||
<TargetMachine>MachineX86</TargetMachine>
|
||||
<AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
|
||||
</Link>
|
||||
<PostBuildEvent>
|
||||
<Command>xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\ </Command>
|
||||
<Message>Post build event: 'xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\'</Message>
|
||||
</PostBuildEvent>
|
||||
<ResourceCompile>
|
||||
<PreprocessorDefinitions>_WIN32_WINNT=0x0601;WINVER=0x0601;_UNICODE;UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ResourceCompile>
|
||||
<Manifest>
|
||||
<OutputManifestFile>$(IntDir)$(TargetName)$(TargetExt).intermediate.manifest</OutputManifestFile>
|
||||
</Manifest>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<Optimization>MinSpace</Optimization>
|
||||
<FavorSizeOrSpeed>Size</FavorSizeOrSpeed>
|
||||
<AdditionalIncludeDirectories>.;..\..\..\Wasabi;..;..\..\..\;..\..\..\replicant;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>_WIN32_WINNT=0x0601;WINVER=0x0601;WIN64;NDEBUG;_WINDOWS;_USRDLL;ML_PLAYLISTS_EXPORTS;_WIN32_IE=0x0A00;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<StringPooling>true</StringPooling>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
|
||||
<BufferSecurityCheck>true</BufferSecurityCheck>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<DebugInformationFormat>None</DebugInformationFormat>
|
||||
<DisableSpecificWarnings>4244;4267;4838;4477;4090;4995;%(DisableSpecificWarnings)</DisableSpecificWarnings>
|
||||
<ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>comctl32.lib;shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
|
||||
<GenerateDebugInformation>false</GenerateDebugInformation>
|
||||
<ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<RandomizedBaseAddress>false</RandomizedBaseAddress>
|
||||
<ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
|
||||
<AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
|
||||
</Link>
|
||||
<PostBuildEvent>
|
||||
<Command>xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\ </Command>
|
||||
<Message>Post build event: 'xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Plugins\'</Message>
|
||||
</PostBuildEvent>
|
||||
<ResourceCompile>
|
||||
<PreprocessorDefinitions>_WIN32_WINNT=0x0601;WINVER=0x0601;_UNICODE;UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
</ResourceCompile>
|
||||
<Manifest>
|
||||
<OutputManifestFile>$(IntDir)$(TargetName)$(TargetExt).intermediate.manifest</OutputManifestFile>
|
||||
</Manifest>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\nde\nde.vcxproj">
|
||||
<Project>{4d25c321-7f8b-424e-9899-d80a364baf1a}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\..\replicant\nx\nx.vcxproj">
|
||||
<Project>{57c90706-b25d-4aca-9b33-95cdb2427c27}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\..\Wasabi\Wasabi.vcxproj">
|
||||
<Project>{3e0bfa8a-b86a-42e9-a33f-ec294f823f7f}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\..\WAT\WAT.vcxproj">
|
||||
<Project>{c5714908-a71f-4644-bd95-aad8ee7914da}</Project>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\..\General\gen_ml\config.h" />
|
||||
<ClInclude Include="..\..\General\gen_ml\menu.h" />
|
||||
<ClInclude Include="..\..\..\nu\DialogSkinner.h" />
|
||||
<ClInclude Include="..\..\..\playlist\plstring.h" />
|
||||
<ClInclude Include="..\..\..\playlist\pl_entry.h" />
|
||||
<ClInclude Include="..\..\..\Winamp\strutil.h" />
|
||||
<ClInclude Include="api__ml_playlists.h" />
|
||||
<ClInclude Include="CurrentPlaylist.h" />
|
||||
<ClInclude Include="main.h" />
|
||||
<ClInclude Include="Playlist.h" />
|
||||
<ClInclude Include="PlaylistDirectoryCallback.h" />
|
||||
<ClInclude Include="PlaylistInfo.h" />
|
||||
<ClInclude Include="playlists.h" />
|
||||
<ClInclude Include="PlaylistsCB.h" />
|
||||
<ClInclude Include="PlaylistsCOM.h" />
|
||||
<ClInclude Include="PlaylistView.h" />
|
||||
<ClInclude Include="resource.h" />
|
||||
<ClInclude Include="SendTo.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\..\General\gen_ml\config.cpp" />
|
||||
<ClCompile Include="..\..\General\gen_ml\menu.cpp" />
|
||||
<ClCompile Include="..\..\General\gen_ml\ml_lib.cpp" />
|
||||
<ClCompile Include="..\..\..\nu\DialogSkinner.cpp" />
|
||||
<ClCompile Include="..\..\..\nu\listview.cpp" />
|
||||
<ClCompile Include="..\..\..\nu\MediaLibraryInterface.cpp" />
|
||||
<ClCompile Include="..\..\..\nu\menushortcuts.cpp" />
|
||||
<ClCompile Include="..\..\..\playlist\plstring.cpp" />
|
||||
<ClCompile Include="..\..\..\playlist\pl_entry.cpp" />
|
||||
<ClCompile Include="..\..\..\Winamp\strutil.cpp" />
|
||||
<ClCompile Include="AddPlaylist.cpp" />
|
||||
<ClCompile Include="CurrentPlaylist.cpp" />
|
||||
<ClCompile Include="ml_playlists.cpp" />
|
||||
<ClCompile Include="ml_subclass.cpp" />
|
||||
<ClCompile Include="pe_subclass.cpp" />
|
||||
<ClCompile Include="Playlist.cpp" />
|
||||
<ClCompile Include="PlaylistDirectoryCallback.cpp" />
|
||||
<ClCompile Include="PlaylistInfo.cpp" />
|
||||
<ClCompile Include="playlists.cpp" />
|
||||
<ClCompile Include="PlaylistsCB.cpp" />
|
||||
<ClCompile Include="PlaylistsCOM.cpp" />
|
||||
<ClCompile Include="PlaylistView.cpp" />
|
||||
<ClCompile Include="pluginproc.cpp" />
|
||||
<ClCompile Include="RenamePlaylist.cpp" />
|
||||
<ClCompile Include="SendTo.cpp" />
|
||||
<ClCompile Include="view_pl.cpp" />
|
||||
<ClCompile Include="view_playlists.cpp" />
|
||||
<ClCompile Include="wa_subclass.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Text Include="Design.txt" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="ml_playlists.rc" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Image Include="resources\ti_cloud_playlist_16x16x16.bmp" />
|
||||
<Image Include="resources\ti_playlist_16x16x16.bmp" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
199
Src/Plugins/Library/ml_playlists/ml_playlists.vcxproj.filters
Normal file
199
Src/Plugins/Library/ml_playlists/ml_playlists.vcxproj.filters
Normal file
@ -0,0 +1,199 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<ClCompile Include="AddPlaylist.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="CurrentPlaylist.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ml_playlists.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ml_subclass.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="pe_subclass.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Playlist.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="PlaylistDirectoryCallback.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="PlaylistInfo.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="playlists.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="PlaylistsCB.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="PlaylistsCOM.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="PlaylistView.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="wa_subclass.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="view_playlists.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="view_pl.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="SendTo.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="RenamePlaylist.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="pluginproc.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\General\gen_ml\config.cpp">
|
||||
<Filter>Source Files\gen_ml</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\nu\DialogSkinner.cpp">
|
||||
<Filter>Source Files\nu</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\nu\listview.cpp">
|
||||
<Filter>Source Files\nu</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\nu\MediaLibraryInterface.cpp">
|
||||
<Filter>Source Files\nu</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\General\gen_ml\menu.cpp">
|
||||
<Filter>Source Files\gen_ml</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\nu\menushortcuts.cpp">
|
||||
<Filter>Source Files\nu</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\General\gen_ml\ml_lib.cpp">
|
||||
<Filter>Source Files\gen_ml</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\playlist\pl_entry.cpp">
|
||||
<Filter>Source Files\playlist</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\playlist\plstring.cpp">
|
||||
<Filter>Source Files\playlist</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\Winamp\strutil.cpp">
|
||||
<Filter>Source Files\Winamp</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="api__ml_playlists.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="CurrentPlaylist.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="main.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Playlist.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="PlaylistDirectoryCallback.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="PlaylistInfo.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="playlists.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="PlaylistsCB.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="PlaylistsCOM.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="PlaylistView.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="resource.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="SendTo.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\General\gen_ml\config.h">
|
||||
<Filter>Header Files\gen_ml</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\..\nu\DialogSkinner.h">
|
||||
<Filter>Header Files\nu</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\General\gen_ml\menu.h">
|
||||
<Filter>Header Files\gen_ml</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\..\playlist\pl_entry.h">
|
||||
<Filter>Header Files\playlist</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\..\playlist\plstring.h">
|
||||
<Filter>Header Files\playlist</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\..\Winamp\strutil.h">
|
||||
<Filter>Header Files\Winamp</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Image Include="resources\ti_cloud_playlist_16x16x16.bmp">
|
||||
<Filter>Image Files</Filter>
|
||||
</Image>
|
||||
<Image Include="resources\ti_playlist_16x16x16.bmp">
|
||||
<Filter>Image Files</Filter>
|
||||
</Image>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Text Include="Design.txt" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{510f3e24-3519-4357-a412-31ca9ea4e679}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Ressource Files">
|
||||
<UniqueIdentifier>{bd3dfff8-2c37-43e7-8cb2-1d701dcaadaa}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{d90e2a08-7da5-425c-97e7-eb41aa99ab8f}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Image Files">
|
||||
<UniqueIdentifier>{b45d999a-7960-4fef-b55a-90b9530879f2}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Source Files\gen_ml">
|
||||
<UniqueIdentifier>{f4f89e40-7fa7-4faa-bdc9-bd6428e5132c}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Source Files\nu">
|
||||
<UniqueIdentifier>{0ee115a9-708c-4311-859e-2aee4ffb1971}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Source Files\playlist">
|
||||
<UniqueIdentifier>{2be30a31-bc6a-4220-9c58-832fd397d80a}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Source Files\Winamp">
|
||||
<UniqueIdentifier>{dd4f54cd-8631-41f9-92a8-1b4c37afa4ce}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Header Files\gen_ml">
|
||||
<UniqueIdentifier>{21b175b4-e364-44c4-96f0-e67663b09ada}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Header Files\nu">
|
||||
<UniqueIdentifier>{973fb9f8-4c13-41dd-aa80-c87c5664b559}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Header Files\playlist">
|
||||
<UniqueIdentifier>{fd06d71f-c851-433d-a4bb-6458c5452422}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Header Files\Winamp">
|
||||
<UniqueIdentifier>{0df480a4-437b-429d-860f-7110e7d6c78d}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="ml_playlists.rc">
|
||||
<Filter>Ressource Files</Filter>
|
||||
</ResourceCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
271
Src/Plugins/Library/ml_playlists/ml_subclass.cpp
Normal file
271
Src/Plugins/Library/ml_playlists/ml_subclass.cpp
Normal file
@ -0,0 +1,271 @@
|
||||
#include <shlwapi.h>
|
||||
|
||||
#include "main.h"
|
||||
#include "../winamp/wa_ipc.h"
|
||||
#include "CurrentPlaylist.h"
|
||||
#include "SendTo.h"
|
||||
#include "Playlist.h"
|
||||
#include "api__ml_playlists.h"
|
||||
|
||||
using namespace Nullsoft::Utility;
|
||||
WNDPROC ml_wndProc = 0;
|
||||
|
||||
static INT_PTR CALLBACK AddPlaylistDialogProc_sc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
static wchar_t *title;
|
||||
switch (uMsg)
|
||||
{
|
||||
case WM_INITDIALOG:
|
||||
title = (wchar_t*)lParam;
|
||||
PostMessage(hwndDlg, WM_NEXTDLGCTL, (WPARAM)GetDlgItem(hwndDlg, IDC_NAME), TRUE);
|
||||
break;
|
||||
case WM_COMMAND:
|
||||
switch (LOWORD(wParam))
|
||||
{
|
||||
case IDOK:
|
||||
{
|
||||
wchar_t name[256] = {0};
|
||||
GetDlgItemText(hwndDlg, IDC_NAME, name, 255);
|
||||
name[255] = 0;
|
||||
if (!name[0])
|
||||
{
|
||||
wchar_t titleStr[32] = {0};
|
||||
MessageBox(hwndDlg, WASABI_API_LNGSTRINGW(IDS_ENTER_A_NAME),
|
||||
WASABI_API_LNGSTRINGW_BUF(IDS_ERROR,titleStr,32), MB_OK);
|
||||
break;
|
||||
}
|
||||
lstrcpyn(title,name,256);
|
||||
EndDialog(hwndDlg,1);
|
||||
}
|
||||
break;
|
||||
case IDCANCEL:
|
||||
EndDialog(hwndDlg,0);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void AddPlaylist(mlAddPlaylist *addPlaylist)
|
||||
{
|
||||
PlaylistInfo pl;
|
||||
wchar_t filename[1024+256] = {0}; // use a longer buffer than MAX_PATH here because createPlayListDBFileName needs it
|
||||
if (addPlaylist->flags & PL_FLAGS_IMPORT)
|
||||
{
|
||||
createPlayListDBFileName(filename);
|
||||
CopyFileW(addPlaylist->filename, filename, FALSE);
|
||||
}
|
||||
else
|
||||
lstrcpynW(filename, addPlaylist->filename, MAX_PATH);
|
||||
|
||||
int numItems = 0;
|
||||
int length = 0;
|
||||
|
||||
wchar_t title[256] = {0};
|
||||
|
||||
if(addPlaylist->playlistName)
|
||||
lstrcpynW(title, addPlaylist->playlistName, 256);
|
||||
else // prompt for name
|
||||
{
|
||||
if(WASABI_API_DIALOGBOXPARAMW((playlists_CloudAvailable() ? IDD_ADD_CLOUD_PLAYLIST : IDD_ADD_PLAYLIST),
|
||||
plugin.hwndLibraryParent, AddPlaylistDialogProc_sc, (LPARAM)title) == 0)
|
||||
{ // the user hit cancel
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (addPlaylist->numItems == -1 || addPlaylist->length == -1)
|
||||
{
|
||||
Playlist temp;
|
||||
AGAVE_API_PLAYLISTMANAGER->Load(filename, &temp);
|
||||
numItems = temp.GetNumItems();
|
||||
for (size_t i = 0;i != numItems;i++)
|
||||
{
|
||||
int len = temp.GetItemLengthMilliseconds(i) / 1000;
|
||||
if (len>=0)
|
||||
length += len;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
length = addPlaylist->length;
|
||||
numItems = addPlaylist->numItems;
|
||||
}
|
||||
|
||||
AddPlaylist(true, title, filename, !!(addPlaylist->flags & PL_FLAG_SHOW), g_config->ReadInt(L"cloud", 1), numItems, length);
|
||||
}
|
||||
|
||||
static void MakePlaylist(mlMakePlaylistV2 *makePlaylist)
|
||||
{
|
||||
AutoLockT<api_playlists> lock (AGAVE_API_PLAYLISTS);
|
||||
switch (makePlaylist->type)
|
||||
{
|
||||
case ML_TYPE_FILENAMES:
|
||||
case ML_TYPE_STREAMNAMES:
|
||||
AddPlaylistFromFilenames((const char *)makePlaylist->data, makePlaylist->playlistName, makePlaylist->flags);
|
||||
if (makePlaylist->flags & PL_FLAG_FILL_FILENAME && makePlaylist->size == sizeof(mlMakePlaylistV2))
|
||||
{
|
||||
// TODO: not guaranteed to be at the end
|
||||
size_t last_index = AGAVE_API_PLAYLISTS->GetCount() - 1;
|
||||
lstrcpynW(makePlaylist->filename, AGAVE_API_PLAYLISTS->GetFilename(last_index), MAX_PATH);
|
||||
}
|
||||
return ;
|
||||
|
||||
case ML_TYPE_FILENAMESW:
|
||||
case ML_TYPE_STREAMNAMESW:
|
||||
AddPlaylistFromFilenamesW((const wchar_t *)makePlaylist->data, makePlaylist->playlistName, makePlaylist->flags);
|
||||
if (makePlaylist->flags & PL_FLAG_FILL_FILENAME && makePlaylist->size == sizeof(mlMakePlaylistV2))
|
||||
{
|
||||
// TODO: not guaranteed to be at the end
|
||||
size_t last_index = AGAVE_API_PLAYLISTS->GetCount() - 1;
|
||||
lstrcpynW(makePlaylist->filename, AGAVE_API_PLAYLISTS->GetFilename(last_index), MAX_PATH);
|
||||
}
|
||||
return ;
|
||||
|
||||
case ML_TYPE_ITEMRECORDLIST:
|
||||
case ML_TYPE_CDTRACKS:
|
||||
AddPlaylistFromItemRecordList((itemRecordList *)makePlaylist->data, makePlaylist->playlistName, makePlaylist->flags);
|
||||
if (makePlaylist->flags & PL_FLAG_FILL_FILENAME && makePlaylist->size == sizeof(mlMakePlaylistV2))
|
||||
{
|
||||
// TODO: not guaranteed to be at the end
|
||||
size_t last_index = AGAVE_API_PLAYLISTS->GetCount() - 1;
|
||||
lstrcpynW(makePlaylist->filename, AGAVE_API_PLAYLISTS->GetFilename(last_index), MAX_PATH);
|
||||
}
|
||||
return ;
|
||||
|
||||
case ML_TYPE_ITEMRECORDLISTW:
|
||||
AddPlaylistFromItemRecordListW((itemRecordListW *)makePlaylist->data, makePlaylist->playlistName, makePlaylist->flags);
|
||||
if (makePlaylist->flags & PL_FLAG_FILL_FILENAME && makePlaylist->size == sizeof(mlMakePlaylistV2))
|
||||
{
|
||||
// TODO: not guaranteed to be at the end
|
||||
size_t last_index = AGAVE_API_PLAYLISTS->GetCount() - 1;
|
||||
lstrcpynW(makePlaylist->filename, AGAVE_API_PLAYLISTS->GetFilename(last_index), MAX_PATH);
|
||||
}
|
||||
return ;
|
||||
}
|
||||
}
|
||||
|
||||
static int GetPlaylistInfo(mlPlaylistInfo *info)
|
||||
{
|
||||
AutoLockT<api_playlists> lock (AGAVE_API_PLAYLISTS);
|
||||
|
||||
size_t num = info->playlistNum;
|
||||
if (num >= AGAVE_API_PLAYLISTS->GetCount())
|
||||
return 0;
|
||||
|
||||
PlaylistInfo playlist(num);
|
||||
lstrcpynW(info->filename, playlist.GetFilename(), MAX_PATH);
|
||||
lstrcpynW(info->playlistName, playlist.GetName(), 128);
|
||||
info->length = playlist.GetLength();
|
||||
info->numItems = playlist.GetSize();
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static INT_PTR PlaylistIPC(int msg, INT_PTR param)
|
||||
{
|
||||
switch (msg)
|
||||
{
|
||||
case ML_IPC_NEWPLAYLIST: playlists_Add((HWND)param); return 1;
|
||||
case ML_IPC_IMPORTPLAYLIST: Playlist_importFromFile((HWND)param); return 1;
|
||||
case ML_IPC_SAVEPLAYLIST: CurrentPlaylist_Export((HWND)param); return 1; // TODO: can we guarantee a currently active playlist?
|
||||
case ML_IPC_IMPORTCURRENTPLAYLIST: Playlist_importFromWinamp(); return 1;
|
||||
// play/load the playlist passed as param
|
||||
case ML_IPC_PLAY_PLAYLIST: PlayPlaylist(param); return 1;
|
||||
case ML_IPC_LOAD_PLAYLIST: LoadPlaylist(param); return 1;
|
||||
case ML_IPC_GETPLAYLISTWND: return(INT_PTR)activeHWND;
|
||||
case ML_IPC_PLAYLIST_ADD: AddPlaylist((mlAddPlaylist *)param); return 1;
|
||||
case ML_IPC_PLAYLIST_MAKE: MakePlaylist((mlMakePlaylistV2 *)param); return 1;
|
||||
case ML_IPC_PLAYLIST_COUNT: return AGAVE_API_PLAYLISTS->GetCount();
|
||||
case ML_IPC_PLAYLIST_INFO: return GetPlaylistInfo((mlPlaylistInfo *)param);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern SendToMenu treeViewSendTo;
|
||||
INT_PTR CALLBACK MediaLibraryProcedure(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
switch (uMsg)
|
||||
{
|
||||
case WM_INITMENUPOPUP:
|
||||
if (treeViewSendTo.InitPopupMenu(wParam))
|
||||
return 0;
|
||||
|
||||
case WM_COMMAND:
|
||||
{
|
||||
switch (LOWORD(wParam))
|
||||
{
|
||||
case WINAMP_MANAGEPLAYLISTS:
|
||||
mediaLibrary.SelectTreeItem(playlistsTreeId);
|
||||
return 1;
|
||||
case ID_DOSHITMENU_ADDNEWPLAYLIST:
|
||||
playlists_Add(hwndDlg);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case WM_ML_IPC:
|
||||
{
|
||||
INT_PTR res = PlaylistIPC(lParam, wParam);
|
||||
if (res)
|
||||
{
|
||||
SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, res);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
return CallWindowProc(ml_wndProc, hwndDlg, uMsg, wParam, lParam);
|
||||
}
|
||||
|
||||
void HookMediaLibrary()
|
||||
{
|
||||
ml_wndProc = (WNDPROC)SetWindowLongPtr(plugin.hwndLibraryParent, DWLP_DLGPROC, (LONG_PTR)MediaLibraryProcedure);
|
||||
}
|
||||
|
||||
void UnhookMediaLibrary()
|
||||
{
|
||||
SetWindowLongPtr(plugin.hwndLibraryParent, DWLP_DLGPROC, (LONG_PTR)ml_wndProc);
|
||||
}
|
||||
|
||||
#define TREE_PLAYLIST_ID_START 3002
|
||||
|
||||
INT_PTR LoadPlaylist(INT_PTR treeId)
|
||||
{
|
||||
if (!FindTreeItem(treeId))
|
||||
return 0;
|
||||
|
||||
wchar_t wstr[MAX_PATH+1] = {0};
|
||||
{ // scope for lock
|
||||
AutoLockT<api_playlists> lock (AGAVE_API_PLAYLISTS);
|
||||
|
||||
PlaylistInfo info;
|
||||
info.Associate(treeId);
|
||||
|
||||
playlist_SaveGUID(info.playlist_guid);
|
||||
|
||||
memset(wstr, 0, sizeof(wstr)); // easy (but slow) double null terminate
|
||||
PathCombineW(wstr, g_path, info.GetFilename());
|
||||
}
|
||||
|
||||
SendMessage(plugin.hwndWinampParent, WM_WA_IPC, 0, IPC_DELETE);
|
||||
enqueueFileWithMetaStructW s;
|
||||
s.filename = wstr;
|
||||
s.title = 0;
|
||||
s.ext = NULL;
|
||||
s.length = -1;
|
||||
SendMessage(plugin.hwndWinampParent, WM_WA_IPC, (WPARAM)&s, IPC_PLAYFILEW);
|
||||
return 1;
|
||||
}
|
||||
|
||||
INT_PTR PlayPlaylist(INT_PTR treeId)
|
||||
{
|
||||
if (LoadPlaylist(treeId))
|
||||
{
|
||||
SendMessage(plugin.hwndWinampParent, WM_WA_IPC, 0, IPC_STARTPLAY);
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
63
Src/Plugins/Library/ml_playlists/pe_subclass.cpp
Normal file
63
Src/Plugins/Library/ml_playlists/pe_subclass.cpp
Normal file
@ -0,0 +1,63 @@
|
||||
#include "main.h"
|
||||
|
||||
static HMENU last_playlistscmdmenu = NULL;
|
||||
static WNDPROC PE_oldWndProc;
|
||||
static WORD waCmdMenuID;
|
||||
|
||||
static BOOL CALLBACK PE_newWndProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
if (uMsg == WM_COMMAND && wParam > 45000 && wParam < 55000)
|
||||
{
|
||||
if (LoadPlaylist(wParam - 45000))
|
||||
return 0;
|
||||
}
|
||||
else if (uMsg == WM_INITMENUPOPUP)
|
||||
{
|
||||
HMENU hmenuPopup = (HMENU) wParam;
|
||||
if (hmenuPopup == wa_playlists_cmdmenu)
|
||||
{
|
||||
if (!waCmdMenuID)
|
||||
{
|
||||
waCmdMenuID = (WORD)SendMessage(plugin.hwndWinampParent,WM_WA_IPC,0,IPC_REGISTER_LOWORD_COMMAND);
|
||||
}
|
||||
if (last_playlistscmdmenu)
|
||||
{
|
||||
RemoveMenu(wa_playlists_cmdmenu, waCmdMenuID, MF_BYCOMMAND);
|
||||
DestroyMenu(last_playlistscmdmenu);
|
||||
last_playlistscmdmenu = NULL;
|
||||
}
|
||||
mlGetTreeStruct mgts = { 3001, 45000, -1};
|
||||
last_playlistscmdmenu = (HMENU)SendMessage(plugin.hwndLibraryParent, WM_ML_IPC, (WPARAM) &mgts, ML_IPC_GETTREE);
|
||||
if (last_playlistscmdmenu)
|
||||
{
|
||||
MENUITEMINFOW menuItem = {sizeof(MENUITEMINFOW), MIIM_SUBMENU | MIIM_ID | MIIM_TYPE, MFT_STRING,
|
||||
MFS_ENABLED, waCmdMenuID, last_playlistscmdmenu, NULL, NULL, NULL,
|
||||
WASABI_API_LNGSTRINGW(IDS_OPEN_PLAYLIST_FROM_ML), 0};
|
||||
// if there's no playlists then let the user know this
|
||||
if(!AGAVE_API_PLAYLISTS->GetCount())
|
||||
{
|
||||
wchar_t buf[64] = {0};
|
||||
DestroyMenu(last_playlistscmdmenu);
|
||||
menuItem.hSubMenu = last_playlistscmdmenu = CreateMenu();
|
||||
InsertMenuW(menuItem.hSubMenu, 0, MF_BYPOSITION | MF_STRING | MF_GRAYED, 0, WASABI_API_LNGSTRINGW_BUF(IDS_NO_PLAYLIST_IN_LIBRARY,buf,64));
|
||||
}
|
||||
InsertMenuItemW(wa_playlists_cmdmenu, 1, TRUE, &menuItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
return CallWindowProc(PE_oldWndProc, hwndDlg, uMsg, wParam, lParam);
|
||||
}
|
||||
|
||||
static HWND hwnd_pe = NULL;
|
||||
void HookPlaylistEditor()
|
||||
{
|
||||
hwnd_pe =(HWND)SendMessage(plugin.hwndWinampParent,WM_WA_IPC,IPC_GETWND_PE,IPC_GETWND);
|
||||
|
||||
if (hwnd_pe)
|
||||
PE_oldWndProc=(WNDPROC) SetWindowLongPtr(hwnd_pe,GWLP_WNDPROC,(LONG_PTR)PE_newWndProc);
|
||||
}
|
||||
|
||||
void UnhookPlaylistEditor()
|
||||
{
|
||||
SetWindowLongPtr(hwnd_pe,GWLP_WNDPROC,(LONG_PTR)PE_oldWndProc);
|
||||
}
|
185
Src/Plugins/Library/ml_playlists/playlists.cpp
Normal file
185
Src/Plugins/Library/ml_playlists/playlists.cpp
Normal file
@ -0,0 +1,185 @@
|
||||
#include "main.h"
|
||||
#include "replicant/nu/AutoWide.h"
|
||||
#include "replicant/nu/AutoLock.h"
|
||||
#include <algorithm>
|
||||
#include <strsafe.h>
|
||||
|
||||
using namespace Nullsoft::Utility;
|
||||
|
||||
TREE_TO_GUID_MAP tree_to_guid_map;
|
||||
|
||||
bool FindTreeItem( INT_PTR treeId )
|
||||
{
|
||||
TREE_TO_GUID_MAP::iterator itr = tree_to_guid_map.find( treeId );
|
||||
|
||||
return itr != tree_to_guid_map.end();
|
||||
}
|
||||
|
||||
void MakeTree( PlaylistInfo &playlist )
|
||||
{
|
||||
NAVINSERTSTRUCT nis = { 0 };
|
||||
nis.item.cbSize = sizeof( NAVITEM );
|
||||
nis.item.pszText = const_cast<wchar_t *>( AGAVE_API_PLAYLISTS->GetName( playlist.GetIndex() ) );
|
||||
nis.item.mask = NIMF_TEXT | NIMF_IMAGE | NIMF_IMAGESEL | NIMF_ITEMID;
|
||||
nis.item.id = playlist.treeId = 3002 + playlist.GetIndex();
|
||||
nis.hParent = playlistItem;
|
||||
|
||||
if ( playlists_CloudInstalled() )
|
||||
nis.item.iImage = nis.item.iSelectedImage = ( !playlist.GetCloud() ? normalimage : cloudImage );
|
||||
else
|
||||
nis.item.iImage = nis.item.iSelectedImage = normalimage;
|
||||
|
||||
if ( MLNavCtrl_InsertItem( plugin.hwndLibraryParent, &nis ) )
|
||||
tree_to_guid_map[ playlist.treeId ] = playlist.playlist_guid;
|
||||
}
|
||||
|
||||
void UpdateTree( PlaylistInfo &playlist, int tree_id )
|
||||
{
|
||||
AutoLockT<api_playlists> lock( AGAVE_API_PLAYLISTS );
|
||||
size_t index = playlist.GetIndex();
|
||||
|
||||
MLTREEITEMW updatedItem = { NULL,MLTI_TEXT,NULL };
|
||||
updatedItem.id = tree_id;
|
||||
updatedItem.title = const_cast<wchar_t *>( AGAVE_API_PLAYLISTS->GetName( index ) );
|
||||
updatedItem.imageIndex = ( !playlist.GetCloud() ? imgPL : imgCloudPL );
|
||||
|
||||
mediaLibrary.SetTreeItem( updatedItem );
|
||||
|
||||
tree_to_guid_map[ tree_id ] = playlist.playlist_guid;
|
||||
}
|
||||
|
||||
void AddPlaylist( int callback, const wchar_t *title, const wchar_t *filename, bool makeTree, int cloud, size_t numItems, uint64_t length )
|
||||
{
|
||||
AutoLockT<api_playlists> lock( AGAVE_API_PLAYLISTS );
|
||||
wchar_t fullFilename[ MAX_PATH ] = { 0 };
|
||||
|
||||
if ( PathIsFileSpecW( filename ) )
|
||||
PathCombineW( fullFilename, g_path, filename );
|
||||
else
|
||||
lstrcpynW( fullFilename, filename, MAX_PATH );
|
||||
|
||||
size_t newIndex = AGAVE_API_PLAYLISTS->AddPlaylist_NoCallback( fullFilename, title );
|
||||
|
||||
// try to get a valid length of the playlist time
|
||||
// (important for the playlists view otherwise looks silly with just the number shown)
|
||||
if ( !length )
|
||||
{
|
||||
length = AGAVE_API_PLAYLISTMANAGER->GetLongLengthMilliseconds( fullFilename );
|
||||
if ( length > 0 ) length /= 1000;
|
||||
else length = 0;
|
||||
}
|
||||
|
||||
if ( cloud )
|
||||
AGAVE_API_PLAYLISTS->SetInfo( newIndex, api_playlists_cloud, &cloud, sizeof( cloud ) );
|
||||
|
||||
if ( numItems > 0 )
|
||||
AGAVE_API_PLAYLISTS->SetInfo( newIndex, api_playlists_itemCount, &numItems, sizeof( numItems ) );
|
||||
|
||||
if ( length > 0 )
|
||||
AGAVE_API_PLAYLISTS->SetInfo( newIndex, api_playlists_totalTime, &length, sizeof( length ) );
|
||||
|
||||
if ( callback )
|
||||
WASABI_API_SYSCB->syscb_issueCallback( api_playlists::SYSCALLBACK, api_playlists::PLAYLIST_ADDED, newIndex, ( callback - 1 ) );
|
||||
}
|
||||
|
||||
bool LoadOldPlaylists()
|
||||
{
|
||||
bool erased = false;
|
||||
int nb = g_config->ReadInt( L"query_num", 0 );
|
||||
for ( int i = 0; i < nb; i++ )
|
||||
{
|
||||
wchar_t qn[ 128 ] = { 0 }, qv[ 128 ] = { 0 }, qm[ 128 ] = { 0 }, qmet[ 128 ] = { 0 };
|
||||
StringCchPrintfW( qn, 128, L"query%i_name", i + 1 );
|
||||
StringCchPrintfW( qv, 128, L"query%i_val", i + 1 );
|
||||
StringCchPrintfW( qm, 128, L"query%i_mode", i + 1 );
|
||||
StringCchPrintfW( qmet, 128, L"query%i_meta", i + 1 );
|
||||
|
||||
int queryMode = g_config->ReadInt( qm, 0 );
|
||||
if ( queryMode == 32 )
|
||||
{
|
||||
wchar_t *name = g_config->ReadString( qn, NULL );
|
||||
if ( !name )
|
||||
continue;
|
||||
|
||||
name = _wcsdup( name );
|
||||
|
||||
wchar_t *val = g_config->ReadString( qv, NULL );
|
||||
if ( val )
|
||||
val = _wcsdup( val );
|
||||
|
||||
wchar_t filename[ MAX_PATH ] = { 0 };
|
||||
PathCombineW( filename, g_path, val );
|
||||
|
||||
size_t numItems = AGAVE_API_PLAYLISTMANAGER->CountItems( filename );
|
||||
AddPlaylist( true, name, filename, ADD_TO_TREE, AddToCloud(), numItems );
|
||||
|
||||
g_config->WriteString( qn, NULL );
|
||||
g_config->WriteString( qv, NULL );
|
||||
g_config->WriteString( qm, NULL );
|
||||
g_config->WriteString( qmet, NULL );
|
||||
|
||||
erased = true;
|
||||
|
||||
free( name );
|
||||
free( val );
|
||||
}
|
||||
}
|
||||
|
||||
return erased;
|
||||
}
|
||||
|
||||
void LoadPlaylists()
|
||||
{
|
||||
bool loadedOld = LoadOldPlaylists();
|
||||
|
||||
AutoLockT<api_playlists> lock( AGAVE_API_PLAYLISTS );
|
||||
size_t count = AGAVE_API_PLAYLISTS->GetCount();
|
||||
normalimage = mediaLibrary.AddTreeImageBmp( IDB_TREEITEM_PLAYLIST );
|
||||
cloudImage = mediaLibrary.AddTreeImageBmp( IDB_TREEITEM_CLOUD_PLAYLIST );
|
||||
|
||||
for ( size_t i = 0; i != count; i++ )
|
||||
{
|
||||
PlaylistInfo info( i );
|
||||
if ( info.Valid() )
|
||||
MakeTree( info );
|
||||
}
|
||||
|
||||
if ( loadedOld )
|
||||
AGAVE_API_PLAYLISTS->Flush();
|
||||
}
|
||||
|
||||
void UpdatePlaylists()
|
||||
{
|
||||
AutoLockT<api_playlists> lock( AGAVE_API_PLAYLISTS );
|
||||
size_t count = AGAVE_API_PLAYLISTS->GetCount();
|
||||
normalimage = mediaLibrary.AddTreeImageBmp( IDB_TREEITEM_PLAYLIST );
|
||||
cloudImage = mediaLibrary.AddTreeImageBmp( IDB_TREEITEM_CLOUD_PLAYLIST );
|
||||
|
||||
for ( size_t i = 0; i != count; i++ )
|
||||
{
|
||||
PlaylistInfo info( i );
|
||||
if ( info.Valid() )
|
||||
UpdateTree( info, info.treeId );
|
||||
}
|
||||
|
||||
if ( IsWindow( currentView ) )
|
||||
PostMessage( currentView, WM_APP + 101, 0, 0 );
|
||||
}
|
||||
|
||||
void Playlist_importFromWinamp()
|
||||
{
|
||||
SendMessage( plugin.hwndWinampParent, WM_WA_IPC, 0, IPC_WRITEPLAYLIST );
|
||||
const wchar_t *m3udir = (const wchar_t *)SendMessage( plugin.hwndWinampParent, WM_WA_IPC, 0, IPC_GETM3UDIRECTORYW );
|
||||
wchar_t s[ MAX_PATH ] = { 0 };
|
||||
PathCombineW( s, m3udir, L"winamp.m3u8" );
|
||||
|
||||
wchar_t filename[ 1024 + 256 ] = { 0 };
|
||||
wchar_t *filenameptr = createPlayListDBFileName( filename );
|
||||
|
||||
wchar_t gs[ MAX_PATH ] = { 0 };
|
||||
PathCombineW( gs, g_path, filenameptr );
|
||||
size_t numItems = AGAVE_API_PLAYLISTMANAGER->Copy( gs, s );
|
||||
|
||||
AddPlaylist( true, WASABI_API_LNGSTRINGW( IDS_IMPORTED_PLAYLIST ), gs, ADD_TO_TREE, ( !( GetAsyncKeyState( VK_SHIFT ) & 0x8000 ) ? AddToCloud() : 0 ), numItems );
|
||||
AGAVE_API_PLAYLISTS->Flush();
|
||||
}
|
6
Src/Plugins/Library/ml_playlists/playlists.h
Normal file
6
Src/Plugins/Library/ml_playlists/playlists.h
Normal file
@ -0,0 +1,6 @@
|
||||
#ifndef NULLSOFT_ML_PLAYLISTS_PLAYLISTS_H
|
||||
#define NULLSOFT_ML_PLAYLISTS_PLAYLISTS_H
|
||||
|
||||
#include "PlaylistInfo.h"
|
||||
|
||||
#endif
|
88
Src/Plugins/Library/ml_playlists/playlistsXML.cpp
Normal file
88
Src/Plugins/Library/ml_playlists/playlistsXML.cpp
Normal file
@ -0,0 +1,88 @@
|
||||
#include "Main.h"
|
||||
#include "playlistsXML.h"
|
||||
#include "../nu/AutoChar.h"
|
||||
|
||||
void PlaylistsXML::StartTag(const wchar_t *xmlpath, const wchar_t *xmltag, api_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");
|
||||
|
||||
int numItems = 0;
|
||||
if (countString && *countString)
|
||||
numItems = _wtoi(countString);
|
||||
|
||||
const wchar_t *lengthString = params->getItemValue(L"seconds");
|
||||
int length = -1000;
|
||||
if (lengthString && *lengthString)
|
||||
length = _wtoi(lengthString);
|
||||
|
||||
AddPlaylist(title, filename, true, numItems, length);
|
||||
}
|
||||
|
||||
void PlaylistsXML::LoadFile(const wchar_t *filename)
|
||||
{
|
||||
if (!parser)
|
||||
return ; // 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 ;
|
||||
|
||||
char data[1024] = {0};
|
||||
DWORD bytesRead;
|
||||
while (true)
|
||||
{
|
||||
if (ReadFile(file, data, 1024, &bytesRead, NULL) && bytesRead)
|
||||
{
|
||||
if (parser->xmlreader_feed(data, bytesRead) != API_XML_SUCCESS)
|
||||
{
|
||||
CloseHandle(file);
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
CloseHandle(file);
|
||||
parser->xmlreader_feed(0, 0);
|
||||
}
|
||||
|
||||
PlaylistsXML::PlaylistsXML(): parser(0), parserFactory(0)
|
||||
{
|
||||
parserFactory = WASABI_API_SVC->service_getServiceByGuid(api_xmlGUID);
|
||||
if (parserFactory)
|
||||
parser = (api_xml *)parserFactory->getInterface();
|
||||
|
||||
if (parser)
|
||||
{
|
||||
parser->xmlreader_registerCallback(L"Winamp:Playlists\fplaylist", this);
|
||||
parser->xmlreader_registerCallback(L"playlists\fplaylist", this);
|
||||
parser->xmlreader_open();
|
||||
}
|
||||
}
|
||||
|
||||
PlaylistsXML::~PlaylistsXML()
|
||||
{
|
||||
if (parser)
|
||||
{
|
||||
parser->xmlreader_unregisterCallback(this);
|
||||
parser->xmlreader_close();
|
||||
}
|
||||
|
||||
if (parserFactory && parser)
|
||||
parserFactory->releaseInterface(parser);
|
||||
|
||||
parserFactory = 0;
|
||||
parser = 0;
|
||||
}
|
||||
|
||||
#ifdef CBCLASS
|
||||
#undef CBCLASS
|
||||
#endif
|
||||
|
||||
#define CBCLASS PlaylistsXML
|
||||
START_DISPATCH;
|
||||
VCB(ONSTARTELEMENT, StartTag)
|
||||
END_DISPATCH;
|
27
Src/Plugins/Library/ml_playlists/playlistsXML.h
Normal file
27
Src/Plugins/Library/ml_playlists/playlistsXML.h
Normal file
@ -0,0 +1,27 @@
|
||||
#ifndef NULLSOFT_ML_PLAYLISTS_PLAYLISTSXML_H
|
||||
#define NULLSOFT_ML_PLAYLISTS_PLAYLISTSXML_H
|
||||
|
||||
#include "../xml/api_xml.h"
|
||||
#include "../xml/api_xmlreadercallback.h"
|
||||
#include "api.h"
|
||||
#include <api/service/waServiceFactory.h>
|
||||
|
||||
class PlaylistsXML : public api_xmlreadercallback
|
||||
{
|
||||
public:
|
||||
PlaylistsXML();
|
||||
~PlaylistsXML();
|
||||
void LoadFile(const wchar_t *filename);
|
||||
|
||||
private:
|
||||
RECVS_DISPATCH;
|
||||
/* XML callbacks */
|
||||
void StartTag(const wchar_t *xmlpath, const wchar_t *xmltag, api_xmlreaderparams *params);
|
||||
|
||||
|
||||
api_xml *parser;
|
||||
waServiceFactory *parserFactory;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
527
Src/Plugins/Library/ml_playlists/pluginproc.cpp
Normal file
527
Src/Plugins/Library/ml_playlists/pluginproc.cpp
Normal file
@ -0,0 +1,527 @@
|
||||
#include "main.h"
|
||||
#include "resource.h"
|
||||
#include <windows.h>
|
||||
#include <commctrl.h>
|
||||
#include "SendTo.h"
|
||||
#include "ml_local/api_mldb.h"
|
||||
#include "ml_pmp/pmp.h"
|
||||
#include "replicant/nswasabi/ReferenceCounted.h"
|
||||
#include "replicant/nx/win/nxstring.h"
|
||||
#include "replicant/nu/AutoChar.h"
|
||||
#include "nu/AutoCharFn.h"
|
||||
#include "nu/menushortcuts.h"
|
||||
|
||||
#include <api/syscb/callbacks/syscb.h>
|
||||
#include <api/syscb/callbacks/browsercb.h>
|
||||
|
||||
using namespace Nullsoft::Utility;
|
||||
INT_PTR lastActiveID = 0;
|
||||
SendToMenu treeViewSendTo;
|
||||
HWND currentView = 0;
|
||||
int playlists_ContextMenu(INT_PTR param1, HWND hHost, POINTS pts);
|
||||
|
||||
LRESULT pluginHandleIpcMessage(int msg, WPARAM param)
|
||||
{
|
||||
return SendMessage(plugin.hwndLibraryParent, WM_ML_IPC, param, msg);
|
||||
}
|
||||
|
||||
INT_PTR pluginMessageProc(int message_type, INT_PTR param1, INT_PTR param2, INT_PTR param3)
|
||||
{
|
||||
switch (message_type)
|
||||
{
|
||||
case ML_MSG_NO_CONFIG:
|
||||
return TRUE;
|
||||
|
||||
case ML_MSG_TREE_ONCREATEVIEW:
|
||||
if (param1 == playlistsTreeId)
|
||||
{
|
||||
return (INT_PTR)(currentView = WASABI_API_CREATEDIALOGW(IDD_VIEW_PLAYLISTS, (HWND)param2, view_playlistsDialogProc));
|
||||
}
|
||||
else // if param1 is a valid playlist
|
||||
{
|
||||
if (FindTreeItem(param1))
|
||||
{
|
||||
lastActiveID = param1;
|
||||
// TODO: what if it's an ifc_playlist provided from elsewhere instead of just a filename?
|
||||
return (INT_PTR)(currentView = WASABI_API_CREATEDIALOGPARAMW(IDD_VIEW_PLAYLIST, (HWND)param2, view_playlistDialogProc, lastActiveID));
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case ML_MSG_ONSENDTOBUILD:
|
||||
return playlists_BuildSendTo(param1, param2);
|
||||
|
||||
case ML_MSG_ONSENDTOSELECT:
|
||||
return playlists_OnSendTo(param1, param2, param3);
|
||||
|
||||
case ML_MSG_TREE_ONCLICK:
|
||||
return playlists_OnClick(param1, param2, (HWND)param3);
|
||||
|
||||
case ML_MSG_NAVIGATION_CONTEXTMENU:
|
||||
{
|
||||
HNAVITEM hItem = (HNAVITEM)param1;
|
||||
HNAVITEM myItem = MLNavCtrl_FindItemById(plugin.hwndLibraryParent, playlistsTreeId);
|
||||
if (hItem == myItem)
|
||||
{
|
||||
return playlists_ContextMenu(param1, (HWND)param2, MAKEPOINTS(param3));
|
||||
}
|
||||
else
|
||||
{
|
||||
NAVITEM nvItem = {sizeof(NAVITEM),hItem,NIMF_ITEMID,};
|
||||
MLNavItem_GetInfo(plugin.hwndLibraryParent, &nvItem);
|
||||
if (FindTreeItem(nvItem.id))
|
||||
{
|
||||
HWND wnd = (HWND)param2;
|
||||
sendToIgnoreID = nvItem.id;
|
||||
HMENU menu = GetSubMenu(g_context_menus, 0),
|
||||
sendToMenu = GetSubMenu(menu, 2);
|
||||
treeViewSendTo.AddHere(wnd, sendToMenu, ML_TYPE_FILENAMES, 1, (ML_TYPE_PLAYLIST+1)); // we're going to lie about the type for now
|
||||
// make sure that we call init on this otherwise the sendto menu will most likely fail
|
||||
treeViewSendTo.InitPopupMenu((WPARAM)sendToMenu);
|
||||
|
||||
// tweaked to not fudge on the ml tree
|
||||
EnableMenuItem(menu, IDC_PLAY, MF_BYCOMMAND | MF_ENABLED);
|
||||
EnableMenuItem(menu, IDC_ENQUEUE, MF_BYCOMMAND | MF_ENABLED);
|
||||
EnableMenuItem(menu, IDC_DELETE, MF_BYCOMMAND | MF_ENABLED);
|
||||
EnableMenuItem(menu, ID_QUERYMENU_ADDNEWQUERY, MF_BYCOMMAND | MF_ENABLED);
|
||||
EnableMenuItem(menu, IDC_RENAME, MF_BYCOMMAND | MF_ENABLED);
|
||||
EnableMenuItem(menu, IDC_ENQUEUE, MF_BYCOMMAND | MF_ENABLED);
|
||||
EnableMenuItem(menu, 2, MF_BYPOSITION | MF_ENABLED);
|
||||
EnableMenuItem(menu, IDC_VIEWLIST, MF_BYCOMMAND | (nvItem.id != lastActiveID ? MF_ENABLED : MF_DISABLED));
|
||||
|
||||
HMENU cloud_hmenu = (HMENU)0x666;
|
||||
size_t index = 0;
|
||||
if (playlists_CloudAvailable())
|
||||
{
|
||||
AutoLockT<api_playlists> lock (AGAVE_API_PLAYLISTS);
|
||||
PlaylistInfo info;
|
||||
if (info.Associate(nvItem.id))
|
||||
{
|
||||
ReferenceCountedNXString uid;
|
||||
NXStringCreateWithFormatting(&uid, "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X",
|
||||
(int)info.playlist_guid.Data1, (int)info.playlist_guid.Data2,
|
||||
(int)info.playlist_guid.Data3, (int)info.playlist_guid.Data4[0],
|
||||
(int)info.playlist_guid.Data4[1], (int)info.playlist_guid.Data4[2],
|
||||
(int)info.playlist_guid.Data4[3], (int)info.playlist_guid.Data4[4],
|
||||
(int)info.playlist_guid.Data4[5], (int)info.playlist_guid.Data4[6],
|
||||
(int)info.playlist_guid.Data4[7]);
|
||||
|
||||
index = info.GetIndex();
|
||||
|
||||
WASABI_API_SYSCB->syscb_issueCallback(api_mldb::SYSCALLBACK, api_mldb::MLDB_FILE_GET_CLOUD_STATUS, (intptr_t)uid->string, (intptr_t)&cloud_hmenu);
|
||||
|
||||
if (cloud_hmenu && cloud_hmenu != (HMENU)0x666)
|
||||
{
|
||||
MENUITEMINFOW m = {sizeof(m), MIIM_TYPE | MIIM_ID | MIIM_SUBMENU, MFT_SEPARATOR, 0};
|
||||
m.wID = CLOUD_SOURCE_MENUS - 1;
|
||||
InsertMenuItemW(menu, 3, TRUE, &m);
|
||||
|
||||
wchar_t a[100] = {0};
|
||||
m.fType = MFT_STRING;
|
||||
m.dwTypeData = WASABI_API_LNGSTRINGW_BUF(IDS_CLOUD_SOURCES, a, 100);
|
||||
m.wID = CLOUD_SOURCE_MENUS;
|
||||
m.hSubMenu = cloud_hmenu;
|
||||
InsertMenuItemW(menu, 4, TRUE, &m);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool swapPlayEnqueue=false;
|
||||
if (g_config->ReadInt(L"enqueuedef", 0) == 1)
|
||||
{
|
||||
SwapPlayEnqueueInMenu(menu);
|
||||
swapPlayEnqueue=true;
|
||||
}
|
||||
|
||||
{
|
||||
HACCEL accel = WASABI_API_LOADACCELERATORSW(IDR_VIEW_PL_ACCELERATORS);
|
||||
int size = CopyAcceleratorTable(accel,0,0);
|
||||
AppendMenuShortcuts(menu, &accel, size, MSF_REPLACE);
|
||||
}
|
||||
|
||||
if (swapPlayEnqueue)
|
||||
SwapPlayEnqueueInMenu(menu);
|
||||
|
||||
POINT pt;
|
||||
POINTSTOPOINT(pt, MAKEPOINTS(param3));
|
||||
if (-1 == pt.x || -1 == pt.y)
|
||||
{
|
||||
NAVITEMGETRECT itemRect;
|
||||
itemRect.fItem = FALSE;
|
||||
itemRect.hItem = hItem;
|
||||
if (MLNavItem_GetRect(plugin.hwndLibraryParent, &itemRect))
|
||||
{
|
||||
MapWindowPoints(wnd, HWND_DESKTOP, (POINT*)&itemRect.rc, 2);
|
||||
pt.x = itemRect.rc.left + 2;
|
||||
pt.y = itemRect.rc.top + 2;
|
||||
}
|
||||
}
|
||||
|
||||
int r = Menu_TrackPopup(plugin.hwndLibraryParent, menu, TPM_RETURNCMD | TPM_RIGHTBUTTON | TPM_LEFTBUTTON, pt.x, pt.y, wnd, NULL);
|
||||
switch (r)
|
||||
{
|
||||
case IDC_PLAY:
|
||||
{
|
||||
AutoLockT<api_playlists> lock (AGAVE_API_PLAYLISTS);
|
||||
PlaylistInfo info;
|
||||
if (info.Associate(nvItem.id))
|
||||
{
|
||||
playlist_SaveGUID(info.playlist_guid);
|
||||
mediaLibrary.PlayFile(info.GetFilename());
|
||||
}
|
||||
}
|
||||
break;
|
||||
case IDC_ENQUEUE:
|
||||
{
|
||||
AutoLockT<api_playlists> lock (AGAVE_API_PLAYLISTS);
|
||||
PlaylistInfo info;
|
||||
if (info.Associate(nvItem.id))
|
||||
{
|
||||
playlist_SaveGUID(info.playlist_guid);
|
||||
mediaLibrary.EnqueueFile(info.GetFilename());
|
||||
}
|
||||
}
|
||||
break;
|
||||
case IDC_NEWPLAYLIST:
|
||||
playlists_Add(wnd);
|
||||
break;
|
||||
case IDC_DELETE:
|
||||
DeletePlaylist(tree_to_guid_map[nvItem.id], wnd, true);
|
||||
break;
|
||||
case IDC_RENAME:
|
||||
RenamePlaylist(tree_to_guid_map[nvItem.id], wnd);
|
||||
break;
|
||||
case IDC_VIEWLIST:
|
||||
mediaLibrary.SelectTreeItem(nvItem.id);
|
||||
break;
|
||||
default:
|
||||
{
|
||||
if (treeViewSendTo.WasClicked(r))
|
||||
{
|
||||
AutoLockT<api_playlists> lock (AGAVE_API_PLAYLISTS);
|
||||
PlaylistInfo info;
|
||||
if (info.Associate(nvItem.id))
|
||||
{
|
||||
playlist_SaveGUID(info.playlist_guid);
|
||||
|
||||
info.Refresh();
|
||||
|
||||
mlPlaylist sendToPlaylist;
|
||||
sendToPlaylist.filename = info.GetFilename();
|
||||
sendToPlaylist.title = info.GetName();
|
||||
sendToPlaylist.numItems = info.GetSize();
|
||||
sendToPlaylist.length = info.GetLength();
|
||||
|
||||
if (treeViewSendTo.SendPlaylist(&sendToPlaylist) != 1)
|
||||
{
|
||||
// didn't like that
|
||||
// let's try this way
|
||||
wchar_t filenames[MAX_PATH + 1] = {0};
|
||||
lstrcpyn(filenames, info.GetFilename(), MAX_PATH);
|
||||
filenames[lstrlen(filenames) + 1] = 0;
|
||||
treeViewSendTo.SendFilenames(filenames);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (r >= CLOUD_SOURCE_MENUS && r < CLOUD_SOURCE_MENUS_PL_UPPER) // deals with cloud specific menus
|
||||
{
|
||||
// 0 = no change
|
||||
// 1 = adding to cloud
|
||||
// 2 = added locally
|
||||
// 4 = removed
|
||||
int mode = -(int)index;
|
||||
WASABI_API_SYSCB->syscb_issueCallback(api_mldb::SYSCALLBACK, api_mldb::MLDB_FILE_PROCESS_CLOUD_STATUS, (intptr_t)r, (intptr_t)&mode);
|
||||
if (mode > 0)
|
||||
{
|
||||
AutoLockT<api_playlists> lock (AGAVE_API_PLAYLISTS);
|
||||
PlaylistInfo info;
|
||||
if (info.Associate(nvItem.id))
|
||||
{
|
||||
info.SetCloud((mode == 1 ? 1 : 0));
|
||||
AGAVE_API_PLAYLISTS->Flush();
|
||||
UpdatePlaylists();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
treeViewSendTo.Cleanup();
|
||||
sendToIgnoreID = 0;
|
||||
if (cloud_hmenu && cloud_hmenu != (HMENU)0x666)
|
||||
{
|
||||
DeleteMenu(menu, CLOUD_SOURCE_MENUS - 1, MF_BYCOMMAND);
|
||||
DeleteMenu(menu, CLOUD_SOURCE_MENUS, MF_BYCOMMAND);
|
||||
DestroyMenu(cloud_hmenu);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
|
||||
case ML_MSG_TREE_ONKEYDOWN:
|
||||
return playlists_OnKeyDown(param1, (NMTVKEYDOWN *)param2, (HWND)param3);
|
||||
|
||||
case ML_MSG_TREE_ONDRAG:
|
||||
return playlists_OnDrag(param1, (POINT *)param2, (int *)param3);
|
||||
|
||||
case ML_MSG_TREE_ONDROP:
|
||||
return playlists_OnDrop(param1, (POINT *)param2, param3);
|
||||
|
||||
case ML_MSG_TREE_ONDROPTARGET:
|
||||
return playlists_OnDropTarget(param1, param2, param3);
|
||||
|
||||
case ML_MSG_PLAYING_FILE:
|
||||
lstrcpynW(current_playing, (wchar_t*)param1, FILENAME_SIZE);
|
||||
if (IsWindow(currentView)) PostMessage(currentView, WM_APP + 103, (WPARAM)current_playing, 0);
|
||||
return FALSE;
|
||||
|
||||
case ML_MSG_WRITE_CONFIG:
|
||||
if (param1)
|
||||
{
|
||||
// only save the ml playlists if saving winamp.m3u/m3u8
|
||||
// else this will happen everytime the prefs are closed
|
||||
AGAVE_API_PLAYLISTS->Flush();
|
||||
}
|
||||
return FALSE;
|
||||
|
||||
case ML_MSG_VIEW_PLAY_ENQUEUE_CHANGE:
|
||||
{
|
||||
enqueuedef = param1;
|
||||
groupBtn = param2;
|
||||
PostMessage(currentView, WM_APP + 104, param1, param2);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void myOpenURL(HWND hwnd, wchar_t *loc)
|
||||
{
|
||||
if (loc)
|
||||
{
|
||||
bool override=false;
|
||||
WASABI_API_SYSCB->syscb_issueCallback(SysCallback::BROWSER, BrowserCallback::ONOPENURL, reinterpret_cast<intptr_t>(loc), reinterpret_cast<intptr_t>(&override));
|
||||
if (!override)
|
||||
ShellExecuteW(hwnd, L"open", loc, NULL, NULL, SW_SHOWNORMAL);
|
||||
}
|
||||
}
|
||||
|
||||
int playlists_ContextMenu( INT_PTR param1, HWND hHost, POINTS pts )
|
||||
{
|
||||
POINT pt;
|
||||
POINTSTOPOINT( pt, pts );
|
||||
if ( -1 == pt.x || -1 == pt.y )
|
||||
{
|
||||
HNAVITEM hItem = (HNAVITEM)param1;
|
||||
NAVITEMGETRECT itemRect;
|
||||
itemRect.fItem = FALSE;
|
||||
itemRect.hItem = hItem;
|
||||
if ( MLNavItem_GetRect( plugin.hwndLibraryParent, &itemRect ) )
|
||||
{
|
||||
MapWindowPoints( hHost, HWND_DESKTOP, (POINT *)&itemRect.rc, 2 );
|
||||
pt.x = itemRect.rc.left + 2;
|
||||
pt.y = itemRect.rc.top + 2;
|
||||
}
|
||||
}
|
||||
|
||||
HMENU menu = GetSubMenu( g_context_menus, 1 );
|
||||
|
||||
int r = Menu_TrackPopup( plugin.hwndLibraryParent, menu, TPM_RETURNCMD | TPM_RIGHTBUTTON | TPM_LEFTBUTTON | TPM_NONOTIFY, pt.x, pt.y, hHost, NULL );
|
||||
switch ( r )
|
||||
{
|
||||
case IDC_NEWPLAYLIST:
|
||||
playlists_Add( hHost );
|
||||
break;
|
||||
case IDC_IMPORT_PLAYLIST_FROM_FILE:
|
||||
Playlist_importFromFile( hHost );
|
||||
break;
|
||||
case IDC_IMPORT_WINAMP_PLAYLIST:
|
||||
Playlist_importFromWinamp();
|
||||
break;
|
||||
case ID_PLAYLISTSMENU_IMPORTPLAYLISTFROMFOLDERS:
|
||||
Playlist_importFromFolders( hHost );
|
||||
break;
|
||||
case ID_SORTPLAYLIST_TITLE_A_Z:
|
||||
playlists_Sort( SORT_TITLE_ASCENDING );
|
||||
break;
|
||||
case ID_SORTPLAYLIST_TITLE_Z_A:
|
||||
playlists_Sort( SORT_TITLE_DESCENDING );
|
||||
break;
|
||||
case ID_SORTPLAYLIST_NUMBEROFITEMSASCENDING:
|
||||
playlists_Sort( SORT_NUMBER_ASCENDING );
|
||||
break;
|
||||
case ID_SORTPLAYLIST_NUMBEROFITEMSDESCENDING:
|
||||
playlists_Sort( SORT_NUMBER_DESCENDING );
|
||||
break;
|
||||
case ID_PLAYLISTS_HELP:
|
||||
myOpenURL( hHost, L"https://help.winamp.com/hc/articles/8109547717268-Winamp-Playlists" );
|
||||
break;
|
||||
}
|
||||
|
||||
Sleep( 100 );
|
||||
MSG msg;
|
||||
while ( PeekMessage( &msg, NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE ) ); //eat return
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// param1 = param of tree item, param2 = action type (below), param3 = HWND of main window
|
||||
INT_PTR playlists_OnClick(INT_PTR treeId, int clickType, HWND wnd)
|
||||
{
|
||||
switch (clickType)
|
||||
{
|
||||
case ML_ACTION_DBLCLICK:
|
||||
case ML_ACTION_ENTER:
|
||||
{
|
||||
if (FindTreeItem(treeId))
|
||||
{
|
||||
AutoLockT<api_playlists> lock (AGAVE_API_PLAYLISTS);
|
||||
PlaylistInfo info;
|
||||
if (info.Associate(treeId))
|
||||
{
|
||||
playlist_SaveGUID(info.playlist_guid);
|
||||
bool flip = (clickType==ML_ACTION_ENTER) && (GetAsyncKeyState(VK_SHIFT)&0x8000);
|
||||
|
||||
if ((!!(g_config->ReadInt(L"enqueuedef", 0) == 1)) ^ flip)
|
||||
mediaLibrary.EnqueueFile(info.GetFilename());
|
||||
else
|
||||
mediaLibrary.PlayFile(info.GetFilename());
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int playlists_OnKeyDown(int treeId, NMTVKEYDOWN *p, HWND hwndDlg)
|
||||
{
|
||||
int ctrl = (GetAsyncKeyState(VK_CONTROL)&0x8000);
|
||||
int shift = (GetAsyncKeyState(VK_SHIFT)&0x8000);
|
||||
|
||||
if (treeId == playlistsTreeId)
|
||||
{
|
||||
switch (p->wVKey)
|
||||
{
|
||||
case VK_INSERT:
|
||||
{
|
||||
if (shift && !ctrl) playlists_Add(plugin.hwndLibraryParent); return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (FindTreeItem(treeId))
|
||||
{
|
||||
switch (p->wVKey)
|
||||
{
|
||||
case VK_F2: if (!shift && !ctrl) RenamePlaylist(tree_to_guid_map[treeId], plugin.hwndLibraryParent); return 1;
|
||||
case VK_INSERT: if (shift && !ctrl) playlists_Add(plugin.hwndLibraryParent); return 1;
|
||||
case VK_DELETE: if (!shift && !ctrl) DeletePlaylist(tree_to_guid_map[treeId], hwndDlg, true); return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int playlists_OnDrag(int treeId, POINT *pt, int *type)
|
||||
{
|
||||
if (FindTreeItem(treeId))
|
||||
{
|
||||
*type = ML_TYPE_FILENAMES;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int playlists_OnDrop(int treeId, POINT *pt, int destTreeId)
|
||||
{
|
||||
if (FindTreeItem(treeId))
|
||||
{
|
||||
AutoLockT<api_playlists> lock (AGAVE_API_PLAYLISTS);
|
||||
PlaylistInfo info;
|
||||
if (info.Associate(treeId))
|
||||
{
|
||||
if (destTreeId == playlistsTreeId)
|
||||
{
|
||||
mediaLibrary.RemoveTreeItem(info.treeId);
|
||||
tree_to_guid_map.erase(info.treeId);
|
||||
AGAVE_API_PLAYLISTS->MoveBefore(info.GetIndex(), 0);
|
||||
|
||||
// TODO: move most of this to PlaylistsCB
|
||||
// TODO use the more native code like in MakeTree(..)
|
||||
MLTREEITEMW src = {sizeof(MLTREEITEMW), };
|
||||
src.title = const_cast<wchar_t *>(info.GetName());
|
||||
src.hasChildren = 0;
|
||||
src.parentId = playlistsTreeId;
|
||||
src.id = destTreeId;
|
||||
src.imageIndex = (!info.GetCloud() ? imgPL : imgCloudPL);
|
||||
mediaLibrary.InsertTreeItem(src);
|
||||
info.treeId = src.id;
|
||||
tree_to_guid_map[info.treeId] = info.playlist_guid;
|
||||
mediaLibrary.SelectTreeItem(info.treeId);
|
||||
}
|
||||
else if (FindTreeItem(destTreeId))
|
||||
{
|
||||
PlaylistInfo dest;
|
||||
if (dest.Associate(destTreeId))
|
||||
{
|
||||
mediaLibrary.RemoveTreeItem(info.treeId);
|
||||
tree_to_guid_map.erase(info.treeId);
|
||||
AGAVE_API_PLAYLISTS->MoveBefore(info.GetIndex(), dest.GetIndex()+1);
|
||||
|
||||
// TODO: move most of this to PlaylistsCB
|
||||
// TODO use the more native code like in MakeTree(..)
|
||||
MLTREEITEMW src = {sizeof(MLTREEITEMW), };
|
||||
src.title = const_cast<wchar_t *>(info.GetName());
|
||||
src.hasChildren = 0;
|
||||
src.parentId = playlistsTreeId;
|
||||
src.id = destTreeId;
|
||||
src.imageIndex = (!info.GetCloud() ? imgPL : imgCloudPL);
|
||||
mediaLibrary.InsertTreeItem(src);
|
||||
info.treeId = src.id;
|
||||
tree_to_guid_map[info.treeId] = info.playlist_guid;
|
||||
mediaLibrary.SelectTreeItem(info.treeId);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
playlist_SaveGUID(info.playlist_guid);
|
||||
|
||||
info.Refresh();
|
||||
mlPlaylist pl;
|
||||
pl.filename = info.GetFilename();
|
||||
pl.length = info.GetLength();
|
||||
pl.numItems = info.GetSize();
|
||||
pl.title = info.GetName();
|
||||
|
||||
mlDropItemStruct m = {0};
|
||||
m.p = *pt;
|
||||
m.flags = 0;
|
||||
m.type = ML_TYPE_PLAYLIST;
|
||||
m.result = 0;
|
||||
m.data = (void *) & pl;
|
||||
m.name = 0;
|
||||
pluginHandleIpcMessage(ML_IPC_HANDLEDROP, (WPARAM)&m);
|
||||
/* TODO: fall back to this is result fails?
|
||||
mlDropItemStruct m = {0};
|
||||
m.p = *pt;
|
||||
m.flags = ML_HANDLEDRAG_FLAG_NAME;
|
||||
m.type=ML_TYPE_FILENAMES;
|
||||
m.result = 0;
|
||||
char filename[1025] = {0};
|
||||
lstrcpynA(filename, AutoCharFn(playlists[index].filename), 1024);
|
||||
filename[lstrlenA(filename)+1]=0;
|
||||
m.data=(void *)filename;
|
||||
AutoChar charTitle(playlists[index].title);
|
||||
m.name = charTitle;
|
||||
pluginHandleIpcMessage(ML_IPC_HANDLEDROP, (WPARAM)&m);
|
||||
*/
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
177
Src/Plugins/Library/ml_playlists/resource.h
Normal file
177
Src/Plugins/Library/ml_playlists/resource.h
Normal file
@ -0,0 +1,177 @@
|
||||
//{{NO_DEPENDENCIES}}
|
||||
// Microsoft Visual C++ generated include file.
|
||||
// Used by ml_playlists.rc
|
||||
//
|
||||
#define IDS_IMPORT_PLAYLIST 0
|
||||
#define IDS_APPEND_IMPORTED_PLAYLIST 1
|
||||
#define IDS_LIBRARY_QUESTION 2
|
||||
#define IDS_APPEND_ACTIVE_PLAYLIST 3
|
||||
#define IDS_EXPORT_PLAYLIST 4
|
||||
#define IDS_IMPORTED_PLAYLIST 6
|
||||
#define IDS_ITEM 7
|
||||
#define IDS_ADD_DIR_TO_PLAYLIST 8
|
||||
#define IDS_ADD_FILES_TO_PLAYLIST 9
|
||||
#define IDS_PLAYLISTS 11
|
||||
#define IDS_MANAGE_PLAYLISTS 12
|
||||
#define IDS_NEW_PLAYLIST 13
|
||||
#define IDS_ENTER_A_NAME 14
|
||||
#define IDS_ERROR 15
|
||||
#define IDS_SENDTO_NEW_PLAYLIST 16
|
||||
#define IDS_SENDTO_ML_PLAYLISTS 17
|
||||
#define IDS_SENDTO_PLAYLIST 18
|
||||
#define IDS_IMPORT_PLAYLIST_FROM_FOLDER 19
|
||||
#define IDS_CONFIRM_DELETION 20
|
||||
#define IDS_CONFIRMATION 21
|
||||
#define IDS_PLAYLIST_TITLE 22
|
||||
#define IDS_ITEMS 23
|
||||
#define IDS_TIME 24
|
||||
#define IDS_ERROR_DELETING_FILES 25
|
||||
#define IDS_X_OF_X_SELECTED 26
|
||||
#define IDS_X_SELECTED 27
|
||||
#define IDS_ITEMS_LOWER 28
|
||||
#define IDS_TITLE 29
|
||||
#define IDS_NO_PLAYLIST_IN_LIBRARY 30
|
||||
#define IDS_OPEN_PLAYLIST_FROM_ML 31
|
||||
#define IDS_PLAYLIST_FROM_ML 32
|
||||
#define IDS_PLAYLIST_ERROR 34
|
||||
#define IDS_PLAYLIST_ERROR_TITLE 35
|
||||
#define IDS_DAY 36
|
||||
#define IDS_DAYS 37
|
||||
#define IDB_TREEITEM_CLOUD_PLAYLIST 38
|
||||
#define IDS_SENDTO_NEW_CLOUD_PLAYLIST 39
|
||||
#define IDD_ADD_CLOUD_PLAYLIST 40
|
||||
#define IDS_CLOUD_UNCHECKED 40
|
||||
#define IDS_PL_FILE_MNGT 41
|
||||
#define IDS_EXTERNAL_CHECKED 42
|
||||
#define IDS_EXTERNAL_ALREADY_ADDED 43
|
||||
#define IDS_CLOUD_SOURCES 44
|
||||
#define IDS_UPLOAD_TO_CLOUD 45
|
||||
#define IDS_AVAILABLE_IN_CLOUD 46
|
||||
#define IDS_SOURCE_PL_MISSING 47
|
||||
#define IDS_TRACK_AVAILABLE 48
|
||||
#define IDS_UPLOAD_TO_SOURCE 49
|
||||
#define IDS_STRING53 50
|
||||
#define IDS_BROWSE_FOR_PLEDIT_ENTRY 50
|
||||
#define IDD_VIEW_PLAYLISTS 101
|
||||
#define IDR_MENU1 102
|
||||
#define IDD_RENAME_PLAYLIST 103
|
||||
#define IDD_ADD_PLAYLIST 104
|
||||
#define IDD_VIEW_PLAYLIST 105
|
||||
#define IDB_BITMAP1 106
|
||||
#define IDC_CURSOR1 107
|
||||
#define IDD_BROWSE_PLFLD 108
|
||||
#define IDD_SELECT_PLAYLIST 110
|
||||
#define IDD_EDIT_FN 111
|
||||
#define IDR_VIEW_PL_ACCELERATORS 113
|
||||
#define IDR_VIEW_PLS_ACCELERATORS 116
|
||||
#define IDC_CUSTOM 1000
|
||||
#define IDC_PLAYLIST_LIST 1001
|
||||
#define IDC_VIEWLIST 1002
|
||||
#define IDC_PLAY 1003
|
||||
#define IDC_NAME 1003
|
||||
#define IDC_ENQUEUE 1004
|
||||
#define IDC_CREATENEWPL 1005
|
||||
#define IDC_BURN 1005
|
||||
#define IDC_IMPORT 1006
|
||||
#define IDC_PLSTATUS 1006
|
||||
#define IDC_SAVE 1007
|
||||
#define IDC_ADD 1007
|
||||
#define IDB_TREEITEM_PLAYLIST 1007
|
||||
#define IDC_REM 1008
|
||||
#define IDC_SEL 1009
|
||||
#define IDC_MISC 1010
|
||||
#define IDC_LIST 1011
|
||||
#define IDC_PLAYLIST_EDITOR 1012
|
||||
#define IDC_CHECK1 1013
|
||||
#define IDC_SAVE_PL 1013
|
||||
#define IDC_EXTERNAL 1014
|
||||
#define IDC_OLD 1015
|
||||
#define IDD_IMPORT_PLFLD 1015
|
||||
#define IDC_NEW 1016
|
||||
#define IDC_PLAYLISTS 1016
|
||||
#define IDC_CLOUD 1017
|
||||
#define IDC_OLD_TITLE 1017
|
||||
#define IDC_NEW_TITLE 1018
|
||||
#define IDC_PLAYLIST_EDIT_ENTRY_BROWSE 1020
|
||||
#define ID_QUERYWND_PLAYQUERY 40001
|
||||
#define ID_QUERYWND_ENQUEUEQUERY 40002
|
||||
#define ID_MEDIAWND_ADDTOPLAYLIST 40003
|
||||
#define ID_QUERYWND_EDIT 40004
|
||||
#define ID_QUERYMENU_ADDNEWQUERY 40005
|
||||
#define ID_QUERYWND_DELETE 40006
|
||||
#define ID_QUERYMENU_ADDNEWPLAYLIST 40007
|
||||
#define ID_PLAYLISTSMENU_IMPORTPLAYLISTFROMFILE 40008
|
||||
#define ID_PLAYLISTSMENU_IMPORTACTIVECURRENTPLAYLIST 40009
|
||||
#define ID_PLAYLISTSMENU_IMPORTPLAYLISTFROMFOLDERS 40010
|
||||
#define ID_PLAYLISTSIMPORT_IMPORTPLAYLISTSFROMFOLDER 40011
|
||||
#define ID_PLAYLISTSIMPORT_IMPORTACTIVECURRENTPLAYLIST 40012
|
||||
#define ID_PLAYLISTSIMPORT_IMPORTPLAYLISTFROMFILE 40013
|
||||
#define ID_PECONTEXT_PLAYSELECTION 40014
|
||||
#define ID_PECONTEXT_ENQUEUESELECTION 40015
|
||||
#define ID_PECONTEXT_DELETESELECTION 40016
|
||||
#define ID_PEDITORMENUS_CROPSELECTEDITEMS 40017
|
||||
#define ID_PE_ID3 40018
|
||||
#define ID_PECONTEXT_SELECTNONE 40019
|
||||
#define ID_PECONTEXT_INVERTSELECTION 40020
|
||||
#define ID_PECONTEXT_SELECTALL 40021
|
||||
#define ID_PE_NONEXIST 40022
|
||||
#define ID_PE_REMOVEALL 40023
|
||||
#define IDC_PLAYLIST_ADDLOC 40024
|
||||
#define IDC_PLAYLIST_ADDDIR 40025
|
||||
#define IDC_PLAYLIST_ADDMP3 40026
|
||||
#define ID_PECONTEXT_RANDOMIZELIST 40027
|
||||
#define ID_PECONTEXT_REVERSELIST 40028
|
||||
#define ID_PE_S_PATH 40029
|
||||
#define ID_PE_S_FILENAME 40030
|
||||
#define ID_PE_S_TITLE 40031
|
||||
#define ID_PEDITORMENUS_LIST_EXPORTPLAYLIST 40032
|
||||
#define ID_PEDITORMENUS_LIST_IMPORTPLAYLISTFROMDISK 40033
|
||||
#define ID_PEDITORMENUS_LIST_IMPORTACTIVEPLAYLIST 40034
|
||||
#define IDC_EXPORT_PLAYLIST 40035
|
||||
#define IDC_IMPORT_PLAYLIST_FROM_FILE 40036
|
||||
#define IDC_IMPORT_WINAMP_PLAYLIST 40037
|
||||
#define IDC_PLAYLIST_RANDOMIZE 40038
|
||||
#define IDC_PLAYLIST_REVERSE 40039
|
||||
#define IDC_PLAYLIST_SORT_FILENAME 40041
|
||||
#define IDC_PLAYLIST_SORT_PATH 40042
|
||||
#define IDC_PLAYLIST_SORT_TITLE 40043
|
||||
#define IDC_ADD_LOCATION 40044
|
||||
#define IDC_ADD_DIRECTORY 40045
|
||||
#define IDC_ADD_FILES 40046
|
||||
#define IDC_PLAYLIST_REMOVE_DEAD 40047
|
||||
#define IDC_PLAYLIST_REMOVE_ALL 40048
|
||||
#define IDC_PLAYLIST_SELECT_NONE 40051
|
||||
#define IDC_PLAYLIST_INVERT_SELECTION 40052
|
||||
#define IDC_PLAYLIST_SELECT_ALL 40053
|
||||
#define IDC_PLAYLIST_VIEW_FILE_INFO 40054
|
||||
#define IDC_PLAYLIST_DOWNLOAD_ENTRY 40055
|
||||
#define IDC_RENAME 40056
|
||||
#define IDC_DELETE 40057
|
||||
#define IDC_CROP 40058
|
||||
#define IDC_NEWPLAYLIST 40059
|
||||
#define IDC_PLAYLIST_RESET_CACHE 40061
|
||||
#define IDC_PLAYLIST_EDIT_ENTRY 40063
|
||||
#define IDC_PLAYLIST_RECYCLE_SELECTED 40065
|
||||
#define ID_SORTPLAYLIST_NUMBEROFITEMSASCENDING 40081
|
||||
#define ID_SORTPLAYLIST_NUMBEROFITEMSDESCENDING 40082
|
||||
#define ID_SORTPLAYLIST_TITLE_A_Z 40083
|
||||
#define ID_SORTPLAYLIST_TITLE_Z_A 40084
|
||||
#define ID_PLAYLISTSMENU_HELP 40085
|
||||
#define ID_PLAYLISTS_HELP 40089
|
||||
#define ID_RIGHTCLICK_EXPLOREITEM 40092
|
||||
#define IDC_PLAYLIST_EXPLOREITEMFOLDER 40093
|
||||
#define ID_PLAYLIST_EXPLOREITEMFOLD 40096
|
||||
#define ID_PLAYLIST_EXPLOREITEMFOLDER 40097
|
||||
#define ID_PLAYLIST_GENERATE_HTML 40098
|
||||
#define IDS_NULLSOFT_PLAYLISTS 65534
|
||||
|
||||
// Next default values for new objects
|
||||
//
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
#ifndef APSTUDIO_READONLY_SYMBOLS
|
||||
#define _APS_NEXT_RESOURCE_VALUE 54
|
||||
#define _APS_NEXT_COMMAND_VALUE 40102
|
||||
#define _APS_NEXT_CONTROL_VALUE 1021
|
||||
#define _APS_NEXT_SYMED_VALUE 101
|
||||
#endif
|
||||
#endif
|
Binary file not shown.
After Width: | Height: | Size: 578 B |
Binary file not shown.
After Width: | Height: | Size: 568 B |
39
Src/Plugins/Library/ml_playlists/version.rc2
Normal file
39
Src/Plugins/Library/ml_playlists/version.rc2
Normal file
@ -0,0 +1,39 @@
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Version
|
||||
//
|
||||
#include "../../../Winamp/buildType.h"
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 1,78,0,0
|
||||
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 Media Library Plug-in"
|
||||
VALUE "FileVersion", "1,78,0,0"
|
||||
VALUE "InternalName", "Nullsoft Playlists"
|
||||
VALUE "LegalCopyright", "Copyright <20> 2002-2023 Winamp SA"
|
||||
VALUE "LegalTrademarks", "Nullsoft and Winamp are trademarks of Winamp SA"
|
||||
VALUE "OriginalFilename", "ml_playlists.dll"
|
||||
VALUE "ProductName", "Winamp"
|
||||
VALUE "ProductVersion", STR_WINAMP_PRODUCTVER
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
BEGIN
|
||||
VALUE "Translation", 0x409, 1200
|
||||
END
|
||||
END
|
2885
Src/Plugins/Library/ml_playlists/view_pl.cpp
Normal file
2885
Src/Plugins/Library/ml_playlists/view_pl.cpp
Normal file
File diff suppressed because it is too large
Load Diff
1953
Src/Plugins/Library/ml_playlists/view_playlists.cpp
Normal file
1953
Src/Plugins/Library/ml_playlists/view_playlists.cpp
Normal file
File diff suppressed because it is too large
Load Diff
90
Src/Plugins/Library/ml_playlists/wa_subclass.cpp
Normal file
90
Src/Plugins/Library/ml_playlists/wa_subclass.cpp
Normal file
@ -0,0 +1,90 @@
|
||||
#include "main.h"
|
||||
#include "../Winamp/wa_ipc.h"
|
||||
#include "replicant/nu/AutoLock.h"
|
||||
#include <algorithm>
|
||||
|
||||
using namespace Nullsoft::Utility;
|
||||
|
||||
static WNDPROC waProc = 0;
|
||||
extern HMENU wa_play_menu;
|
||||
static HMENU last_playlistsmenu = NULL;
|
||||
WORD waMenuID = 0;
|
||||
extern int IPC_LIBRARY_PLAYLISTS_REFRESH, IPC_CLOUD_ENABLED;
|
||||
|
||||
LRESULT WINAPI WinampProcedure(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
if (msg == WM_COMMAND || msg == WM_SYSCOMMAND)
|
||||
{
|
||||
if (LOWORD(wParam) == WINAMP_MANAGEPLAYLISTS)
|
||||
{
|
||||
mediaLibrary.ShowMediaLibrary();
|
||||
mediaLibrary.SelectTreeItem(playlistsTreeId);
|
||||
return 1;
|
||||
}
|
||||
else if (msg == WM_COMMAND && wParam > 45000 && wParam < 55000)
|
||||
{
|
||||
INT_PTR treeId = wParam - 45000;
|
||||
if (FindTreeItem(treeId))
|
||||
{
|
||||
mediaLibrary.SwitchToPluginView(treeId);
|
||||
}
|
||||
}
|
||||
else if (msg == WM_COMMAND && wParam > 55000 && wParam < 65000)
|
||||
{
|
||||
if (PlayPlaylist(wParam - 55000))
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else if (msg == WM_INITMENUPOPUP)
|
||||
{
|
||||
HMENU hmenuPopup = (HMENU) wParam;
|
||||
if (hmenuPopup == wa_play_menu)
|
||||
{
|
||||
if (last_playlistsmenu)
|
||||
{
|
||||
RemoveMenu(wa_play_menu, waMenuID, MF_BYCOMMAND);
|
||||
DestroyMenu(last_playlistsmenu);
|
||||
last_playlistsmenu = NULL;
|
||||
}
|
||||
mlGetTreeStruct mgts = { 3001, 55000, -1};
|
||||
last_playlistsmenu = (HMENU)SendMessage(plugin.hwndLibraryParent, WM_ML_IPC, (WPARAM) &mgts, ML_IPC_GETTREE);
|
||||
if (last_playlistsmenu)
|
||||
{
|
||||
MENUITEMINFOW menuItem = {sizeof(MENUITEMINFOW), MIIM_SUBMENU | MIIM_ID | MIIM_TYPE, MFT_STRING,
|
||||
MFS_ENABLED, waMenuID, last_playlistsmenu, NULL, NULL, NULL,
|
||||
WASABI_API_LNGSTRINGW(IDS_PLAYLIST_FROM_ML), 0};
|
||||
// if there's no playlists then let the user know this
|
||||
if(!AGAVE_API_PLAYLISTS->GetCount())
|
||||
{
|
||||
wchar_t buf[64] = {0};
|
||||
DestroyMenu(last_playlistsmenu);
|
||||
menuItem.hSubMenu = last_playlistsmenu = CreateMenu();
|
||||
InsertMenuW(menuItem.hSubMenu, 0, MF_BYPOSITION | MF_STRING | MF_GRAYED, 0, WASABI_API_LNGSTRINGW_BUF(IDS_NO_PLAYLIST_IN_LIBRARY,buf,64));
|
||||
}
|
||||
InsertMenuItemW(wa_play_menu, GetMenuItemCount(wa_play_menu), TRUE, &menuItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (msg == WM_WA_IPC && lParam == IPC_LIBRARY_PLAYLISTS_REFRESH)
|
||||
{
|
||||
// refresh the status of the tree items e.g. when made
|
||||
// being made into a cloud playlist or remove from it
|
||||
UpdatePlaylists();
|
||||
}
|
||||
else if (msg == WM_WA_IPC && lParam == IPC_CLOUD_ENABLED)
|
||||
{
|
||||
cloud_avail = 1;
|
||||
if (IsWindow(currentView)) PostMessage(currentView, WM_APP + 102, 0, 0);
|
||||
}
|
||||
|
||||
if (waProc)
|
||||
return CallWindowProcW(waProc, hwnd, msg, wParam, lParam);
|
||||
else
|
||||
return DefWindowProc(hwnd, msg, wParam, lParam);
|
||||
}
|
||||
|
||||
void Hook(HWND winamp)
|
||||
{
|
||||
if (IsWindow(winamp))
|
||||
waProc = (WNDPROC)SetWindowLongPtrW(winamp, GWLP_WNDPROC, (LONG_PTR)WinampProcedure);
|
||||
}
|
Reference in New Issue
Block a user