mirror of
https://github.com/WinampDesktop/winamp.git
synced 2025-06-17 16:45:47 -04:00
Initial community commit
This commit is contained in:
404
Src/Plugins/Library/ml_impex/ImportPlaylists.cpp
Normal file
404
Src/Plugins/Library/ml_impex/ImportPlaylists.cpp
Normal file
@ -0,0 +1,404 @@
|
||||
#include "api__ml_impex.h"
|
||||
#include "../xml/obj_xml.h"
|
||||
#include <map>
|
||||
#include <bfc/string/url.h>
|
||||
#include "importer.h"
|
||||
#include "resource.h"
|
||||
#include "../plist/loader.h"
|
||||
#include "../playlist/ifc_playlist.h"
|
||||
#include "../Winamp/wa_ipc.h"
|
||||
#include <shlwapi.h>
|
||||
|
||||
struct iTunesFileInfo
|
||||
{
|
||||
iTunesFileInfo(const wchar_t *_filename, uint64_t _length)
|
||||
{
|
||||
filename = _wcsdup(_filename);
|
||||
length = _length;
|
||||
}
|
||||
~iTunesFileInfo()
|
||||
{
|
||||
free(filename);
|
||||
}
|
||||
wchar_t *filename;
|
||||
uint64_t length;
|
||||
};
|
||||
typedef std::map<int64_t, iTunesFileInfo*> FilesList;
|
||||
extern winampMediaLibraryPlugin plugin;
|
||||
int Load(const wchar_t *filename, obj_xml *parser);
|
||||
|
||||
class PlistPlaylist : public ifc_playlist
|
||||
{
|
||||
public:
|
||||
PlistPlaylist(const plistArray *_items, FilesList &_files) : items(_items), files(_files)
|
||||
{
|
||||
length_sum = 0;
|
||||
}
|
||||
size_t GetNumItems();
|
||||
size_t GetItem(size_t item, wchar_t *filename, size_t filenameCch);
|
||||
int GetItemLengthMilliseconds(size_t item);
|
||||
uint64_t length_sum;
|
||||
protected:
|
||||
RECVS_DISPATCH;
|
||||
const plistArray *items;
|
||||
FilesList &files;
|
||||
};
|
||||
|
||||
size_t PlistPlaylist::GetNumItems()
|
||||
{
|
||||
return items->getNumItems();
|
||||
}
|
||||
|
||||
size_t PlistPlaylist::GetItem(size_t item, wchar_t *filename, size_t filenameCch)
|
||||
{
|
||||
plistDict *item_dict = (plistDict *)items->enumItem((int)item);
|
||||
if (item_dict)
|
||||
{
|
||||
plistKey *id_key = item_dict->getKey(L"Track ID");
|
||||
if (id_key)
|
||||
{
|
||||
plistInteger *id_data = (plistInteger *)id_key->getData();
|
||||
if (id_data)
|
||||
{
|
||||
int64_t key = id_data->getValue();
|
||||
iTunesFileInfo *info = files[key];
|
||||
if (info)
|
||||
{
|
||||
const wchar_t *track_name = info->filename;
|
||||
if (track_name)
|
||||
{
|
||||
length_sum += info->length;
|
||||
StringCchCopyW(filename, filenameCch, track_name);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int PlistPlaylist::GetItemLengthMilliseconds(size_t item)
|
||||
{
|
||||
plistDict *item_dict = (plistDict *)items->enumItem((int)item);
|
||||
if (item_dict)
|
||||
{
|
||||
plistKey *id_key = item_dict->getKey(L"Track ID");
|
||||
if (id_key)
|
||||
{
|
||||
plistInteger *id_data = (plistInteger *)id_key->getData();
|
||||
if (id_data)
|
||||
{
|
||||
int64_t key = id_data->getValue();
|
||||
iTunesFileInfo *info = files[key];
|
||||
if (info)
|
||||
{
|
||||
return (int)info->length;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define CBCLASS PlistPlaylist
|
||||
START_DISPATCH;
|
||||
CB(IFC_PLAYLIST_GETNUMITEMS, GetNumItems)
|
||||
CB(IFC_PLAYLIST_GETITEM, GetItem)
|
||||
CB(IFC_PLAYLIST_GETITEMLENGTHMILLISECONDS, GetItemLengthMilliseconds)
|
||||
END_DISPATCH;
|
||||
#undef CBCLASS
|
||||
|
||||
static bool GetInteger(const plistDict *dict, const wchar_t *key_name, int64_t *int_val)
|
||||
{
|
||||
plistKey *key = dict->getKey(key_name);
|
||||
if (!key)
|
||||
return false;
|
||||
|
||||
plistData *data = key->getData();
|
||||
if (!data)
|
||||
return false;
|
||||
|
||||
if (data->getType() != PLISTDATA_INTEGER)
|
||||
return false;
|
||||
|
||||
plistInteger *data_int = static_cast<plistInteger *>(data);
|
||||
*int_val = data_int->getValue();
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool GetString(const plistDict *dict, const wchar_t *key_name, const wchar_t **str_val)
|
||||
{
|
||||
plistKey *key = dict->getKey(key_name);
|
||||
if (!key)
|
||||
return false;
|
||||
|
||||
plistData *data = key->getData();
|
||||
if (!data)
|
||||
return false;
|
||||
|
||||
if (data->getType() != PLISTDATA_STRING)
|
||||
return false;
|
||||
|
||||
plistString *data_str = static_cast<plistString *>(data);
|
||||
*str_val = data_str->getString();
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool GetArray(const plistDict *dict, const wchar_t *key_name, plistArray **array_val)
|
||||
{
|
||||
plistKey *key = dict->getKey(key_name);
|
||||
if (!key)
|
||||
return false;
|
||||
|
||||
plistData *data = key->getData();
|
||||
if (!data)
|
||||
return false;
|
||||
|
||||
if (data->getType() != PLISTDATA_ARRAY)
|
||||
return false;
|
||||
|
||||
*array_val = static_cast<plistArray *>(data);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool CheckDuplicatePlaylist(uint64_t playlist_id64, GUID &dup_guid)
|
||||
{
|
||||
AGAVE_API_PLAYLISTS->Lock();
|
||||
size_t numPlaylists = AGAVE_API_PLAYLISTS->GetCount();
|
||||
uint64_t compare_id64=0;
|
||||
for (size_t i=0;i!=numPlaylists;i++)
|
||||
{
|
||||
if (AGAVE_API_PLAYLISTS->GetInfo(i, api_playlists_iTunesID, &compare_id64, sizeof(compare_id64)) == API_PLAYLISTS_SUCCESS)
|
||||
{
|
||||
if (compare_id64 == playlist_id64)
|
||||
{
|
||||
dup_guid = AGAVE_API_PLAYLISTS->GetGUID(i);
|
||||
AGAVE_API_PLAYLISTS->Unlock();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
AGAVE_API_PLAYLISTS->Unlock();
|
||||
return false;
|
||||
}
|
||||
|
||||
enum
|
||||
{
|
||||
DUPLICATE_PLAYLIST_SKIP,
|
||||
DUPLICATE_PLAYLIST_REPLACE,
|
||||
DUPLICATE_PLAYLIST_NEW,
|
||||
};
|
||||
|
||||
static int PromptReplaceSkipNew(GUID &dup_guid)
|
||||
{
|
||||
/* TODO:
|
||||
* get name and stuff from api_playlists
|
||||
* we'll need an HWND for the UI
|
||||
* we'll need some passed-in state variable to remember "do for all" choice
|
||||
*/
|
||||
return DUPLICATE_PLAYLIST_SKIP;
|
||||
}
|
||||
|
||||
HINSTANCE cloud_hinst = 0;
|
||||
int IPC_GET_CLOUD_HINST = -1, IPC_GET_CLOUD_ACTIVE = -1;
|
||||
int 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 (/*0/*/!(!cloud_hinst || cloud_hinst == (HINSTANCE)1 || !SendMessage(plugin.hwndWinampParent, WM_WA_IPC, 0, IPC_GET_CLOUD_ACTIVE))/**/);
|
||||
}
|
||||
|
||||
static void AddPlaylist(plistDict *playlist, FilesList &files)
|
||||
{
|
||||
const wchar_t *name;
|
||||
const wchar_t *playlist_persistent_id;
|
||||
int64_t playlist_id;
|
||||
int64_t visible;
|
||||
plistArray *items;
|
||||
uint64_t playlist_id64;
|
||||
|
||||
if (GetString(playlist, L"Name", &name)
|
||||
&& GetArray(playlist, L"Playlist Items", &items)
|
||||
&& GetInteger(playlist, L"Playlist ID", &playlist_id)
|
||||
&& GetString(playlist, L"Playlist Persistent ID", &playlist_persistent_id)
|
||||
&& (!GetInteger(playlist, L"Visible", &visible) || visible))
|
||||
{
|
||||
playlist_id64 =_wcstoui64(playlist_persistent_id, 0, 16);
|
||||
// see if it's already in the database
|
||||
|
||||
GUID dup_guid; // so we know the GUID we clash with, in case we want to replace it instead of skip it
|
||||
if (playlist_id64 && CheckDuplicatePlaylist(playlist_id64, dup_guid))
|
||||
{
|
||||
switch(PromptReplaceSkipNew(dup_guid))
|
||||
{
|
||||
case DUPLICATE_PLAYLIST_SKIP:
|
||||
break;
|
||||
case DUPLICATE_PLAYLIST_REPLACE:
|
||||
// TODO
|
||||
break;
|
||||
case DUPLICATE_PLAYLIST_NEW:
|
||||
// TODO
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
PlistPlaylist plist_playlist(items, files);
|
||||
|
||||
const wchar_t *user_folder = WASABI_API_APP->path_getUserSettingsPath();
|
||||
wchar_t destination[MAX_PATH] = {0};
|
||||
PathCombineW(destination, user_folder, L"plugins\\ml\\playlists");
|
||||
|
||||
wchar_t playlist_filename[MAX_PATH] = {0};
|
||||
StringCbPrintfW(playlist_filename, sizeof(playlist_filename), L"i_%I64u.m3u8", playlist_id);
|
||||
PathAppendW(destination, playlist_filename);
|
||||
|
||||
static wchar_t ml_ini_file[MAX_PATH] = {0};
|
||||
if (!ml_ini_file[0]) lstrcpynW(ml_ini_file, (const wchar_t*)SendMessage(plugin.hwndWinampParent, WM_WA_IPC, 0, IPC_GETMLINIFILEW), MAX_PATH);
|
||||
size_t cloud = (cloudAvailable() ? GetPrivateProfileIntW(L"gen_ml_config", L"cloud_always", 1, ml_ini_file) : 0);
|
||||
|
||||
AGAVE_API_PLAYLISTMANAGER->Save(destination, &plist_playlist);
|
||||
AGAVE_API_PLAYLISTS->Lock();
|
||||
int new_index = (!cloud ? (int)AGAVE_API_PLAYLISTS->AddPlaylist(destination, name) : (int)AGAVE_API_PLAYLISTS->AddCloudPlaylist(destination, name));
|
||||
if (new_index >= 0)
|
||||
{
|
||||
uint32_t numItems = (uint32_t)plist_playlist.GetNumItems();
|
||||
uint64_t totalLength = plist_playlist.length_sum/1000;
|
||||
AGAVE_API_PLAYLISTS->SetInfo(new_index, api_playlists_totalTime, &totalLength, sizeof(totalLength));
|
||||
AGAVE_API_PLAYLISTS->SetInfo(new_index, api_playlists_itemCount, &numItems, sizeof(numItems));
|
||||
if (cloud) AGAVE_API_PLAYLISTS->SetInfo(new_index, api_playlists_cloud, &cloud, sizeof(cloud));
|
||||
AGAVE_API_PLAYLISTS->SetInfo(new_index, api_playlists_iTunesID, &playlist_id64, sizeof(playlist_id64));
|
||||
}
|
||||
AGAVE_API_PLAYLISTS->Unlock();
|
||||
|
||||
PostMessage(plugin.hwndWinampParent, WM_WA_IPC, 0, SendMessage(plugin.hwndWinampParent, WM_WA_IPC, (WPARAM)&"ml_playlist_refresh", IPC_REGISTER_WINAMP_IPCMESSAGE));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FixPath(const wchar_t *strdata, StringW &f);
|
||||
|
||||
int ImportPlaylists(HWND parent, const wchar_t *library_file)
|
||||
{
|
||||
FilesList files;
|
||||
// create an XML parser
|
||||
obj_xml *parser=0;
|
||||
waServiceFactory *factory = plugin.service->service_getServiceByGuid(obj_xmlGUID);
|
||||
if (factory)
|
||||
parser = (obj_xml *)factory->getInterface();
|
||||
|
||||
if (parser)
|
||||
{
|
||||
// create status window
|
||||
//HWND hwndDlg = WASABI_API_CREATEDIALOGW(IDD_INFODIALOG,plugin.hwndLibraryParent,import_dlgproc);
|
||||
|
||||
// init it
|
||||
//ShowWindow(hwndDlg, SW_NORMAL);
|
||||
//UpdateWindow(hwndDlg);
|
||||
|
||||
// create an iTunes XML library reader
|
||||
plistLoader it;
|
||||
|
||||
// load the XML, this creates an iTunes DB in memory, and returns the root key
|
||||
parser->xmlreader_open();
|
||||
parser->xmlreader_registerCallback(L"plist\f*", &it);
|
||||
Load(library_file, parser);
|
||||
parser->xmlreader_unregisterCallback(&it);
|
||||
parser->xmlreader_close();
|
||||
plistKey *root_key = ⁢
|
||||
|
||||
// show import progress controls
|
||||
//ShowWindow(GetDlgItem(hwndDlg, IDC_PROCESSING_STATE), SW_HIDE);
|
||||
//ShowWindow(GetDlgItem(hwndDlg, IDC_PROGRESS_PERCENT), SW_SHOWNORMAL);
|
||||
//ShowWindow(GetDlgItem(hwndDlg, IDC_TRACKS), SW_SHOWNORMAL);
|
||||
//UpdateWindow(hwndDlg);
|
||||
|
||||
// we start at the root key
|
||||
if (root_key)
|
||||
{
|
||||
// the root key contains a dictionary
|
||||
plistData *root_dict = root_key->getData();
|
||||
if (root_dict && root_dict->getType() == PLISTDATA_DICT)
|
||||
{
|
||||
// that dictionary contains a number of keys, one of which contains a dictionary of tracks
|
||||
plistKey *tracks_key = ((plistDict*)root_dict)->getKey(L"Tracks");
|
||||
plistData *tracks_dict = tracks_key?tracks_key->getData():0;
|
||||
if (tracks_dict && tracks_dict->getType() == PLISTDATA_DICT)
|
||||
{
|
||||
// we have the tracks dictionary ...
|
||||
plistDict *tracks = (plistDict *)tracks_dict;
|
||||
int n =tracks?tracks->getNumKeys():0;
|
||||
// ... now enumerate tracks
|
||||
for (int i=0;i<n;i++)
|
||||
{
|
||||
// each track is a key in the tracks dictionary, and contains a dictionary of properties
|
||||
plistKey *track_key = tracks->enumKey(i);
|
||||
plistData *track_dict = track_key->getData();
|
||||
// prepare an item record
|
||||
|
||||
if (track_dict->getType() == PLISTDATA_DICT)
|
||||
{
|
||||
// we have the track's dictionary of properties...
|
||||
plistDict *track = (plistDict *)track_dict;
|
||||
int64_t id = 0;
|
||||
const wchar_t *location = 0;
|
||||
if (GetInteger(track, L"Track ID", &id) && GetString(track, L"Location", &location))
|
||||
{
|
||||
StringW f;
|
||||
FixPath(location, f);
|
||||
|
||||
int64_t length = 0;
|
||||
GetInteger(track, L"Total Time", &length);
|
||||
// done
|
||||
wchar_t *filename = _wcsdup(f);
|
||||
files[id] = new iTunesFileInfo(filename, length);
|
||||
|
||||
// show progress
|
||||
//SetDlgItemText(hwndDlg, IDC_TRACKS, StringPrintfW(WASABI_API_LNGSTRINGW(IDS_TRACKS_IMPORTED_X), ++count));
|
||||
//SendDlgItemMessage(hwndDlg, IDC_PROGRESS_PERCENT, PBM_SETPOS, (int)((double)count/n*100.0), 0);
|
||||
//if (count % 10 == 0 || count == n)
|
||||
// UpdateWindow(hwndDlg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ok we're done building the track list, now let's enumerate the playlists
|
||||
plistKey *playlists_key = ((plistDict*)root_dict)->getKey(L"Playlists");
|
||||
plistData *playlists_dict = playlists_key?playlists_key->getData():0;
|
||||
if (playlists_dict && playlists_dict->getType() == PLISTDATA_ARRAY)
|
||||
{
|
||||
plistArray *playlists = (plistArray *)playlists_dict;
|
||||
int n =playlists?playlists->getNumItems():0;
|
||||
// ... now enumerate playlists
|
||||
for (int i=0;i<n;i++)
|
||||
{
|
||||
// each playlist is a key in the playlists dictionary, and contains a dictionary of properties
|
||||
plistData *playlist_dict = playlists->enumItem(i);
|
||||
if (playlist_dict->getType() == PLISTDATA_DICT)
|
||||
{
|
||||
// we have the playlist's dictionary of properties...
|
||||
plistDict *playlist = (plistDict *)playlist_dict;
|
||||
AddPlaylist(playlist, files);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//DestroyWindow(hwndDlg);
|
||||
factory->releaseInterface(parser);
|
||||
}
|
||||
else
|
||||
return DISPATCH_FAILURE;
|
||||
|
||||
FilesList::iterator itr;
|
||||
for (itr = files.begin(); itr!= files.end(); itr++)
|
||||
{
|
||||
iTunesFileInfo *info = itr->second;
|
||||
delete info;
|
||||
}
|
||||
return DISPATCH_SUCCESS;
|
||||
}
|
299
Src/Plugins/Library/ml_impex/ImporterAPI.cpp
Normal file
299
Src/Plugins/Library/ml_impex/ImporterAPI.cpp
Normal file
@ -0,0 +1,299 @@
|
||||
#include "ImporterAPI.h"
|
||||
#include "../xml/obj_xml.h"
|
||||
#include "importer.h"
|
||||
#include "resource.h"
|
||||
#include "api__ml_impex.h"
|
||||
#include "../plist/loader.h"
|
||||
#include <api/service/waservicefactory.h>
|
||||
#include <shlobj.h>
|
||||
|
||||
extern winampMediaLibraryPlugin plugin;
|
||||
|
||||
int Load(const wchar_t *filename, obj_xml *parser)
|
||||
{
|
||||
if (!parser)
|
||||
return 1; // 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 1;
|
||||
|
||||
while (true)
|
||||
{
|
||||
char data[1024] = {0};
|
||||
DWORD bytesRead = 0;
|
||||
if (ReadFile(file, data, 1024, &bytesRead, NULL) && bytesRead)
|
||||
{
|
||||
parser->xmlreader_feed(data, bytesRead);
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
CloseHandle(file);
|
||||
parser->xmlreader_feed(0, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool GetiTunesPreferencesPath(wchar_t *path, size_t path_cch)
|
||||
{
|
||||
wchar_t appdata[MAX_PATH] = {0};
|
||||
SHGetSpecialFolderPathW(NULL, appdata, CSIDL_APPDATA, FALSE);
|
||||
StringCchPrintf(path, path_cch, L"%s\\Apple Computer\\iTunes\\iTunesPrefs.xml", appdata);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool GetiTunesLibraryPath(wchar_t *path, size_t path_cch)
|
||||
{
|
||||
wchar_t itunes_pref[MAX_PATH] = {0};
|
||||
if (GetiTunesPreferencesPath(itunes_pref, MAX_PATH))
|
||||
{
|
||||
plistLoader it;
|
||||
|
||||
obj_xml *parser=0;
|
||||
waServiceFactory *factory = plugin.service->service_getServiceByGuid(obj_xmlGUID);
|
||||
if (factory)
|
||||
parser = (obj_xml *)factory->getInterface();
|
||||
|
||||
if (parser)
|
||||
{
|
||||
// load the XML, this creates an iTunes DB in memory, and returns the root key
|
||||
parser->xmlreader_open();
|
||||
parser->xmlreader_registerCallback(L"plist\f*", &it);
|
||||
Load(itunes_pref, parser);
|
||||
parser->xmlreader_unregisterCallback(&it);
|
||||
parser->xmlreader_close();
|
||||
plistKey *root_key = ⁢
|
||||
plistData *root_dict = root_key->getData();
|
||||
if (root_dict)
|
||||
{
|
||||
plistKey *prefs_key = ((plistDict*)root_dict)->getKey(L"User Preferences");
|
||||
if (prefs_key)
|
||||
{
|
||||
plistData *prefs_dict= prefs_key->getData();
|
||||
if (prefs_dict)
|
||||
{
|
||||
plistKey *location_key = ((plistDict*)prefs_dict)->getKey(L"iTunes Library XML Location:1");
|
||||
if (location_key)
|
||||
{
|
||||
plistData *location_data = location_key->getData();
|
||||
if (location_data)
|
||||
{
|
||||
plistRaw *location_data_raw = (plistRaw *)location_data;
|
||||
if (location_data_raw)
|
||||
{
|
||||
int size;
|
||||
const wchar_t *mem = (const wchar_t *)location_data_raw->getMem(&size);
|
||||
if (mem)
|
||||
{
|
||||
memcpy(path, mem, size);
|
||||
path[size/2]=0;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// import status window proc
|
||||
// -----------------------------------------------------------------------
|
||||
static BOOL CALLBACK import_dlgproc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam)
|
||||
{
|
||||
switch (uMsg)
|
||||
{
|
||||
case WM_INITDIALOG:
|
||||
{
|
||||
SetWindowLongPtr(hwndDlg, GWLP_USERDATA, lParam);
|
||||
|
||||
// show import progress controls
|
||||
ShowWindow(GetDlgItem(hwndDlg, IDC_PROCESSING_STATE), SW_HIDE);
|
||||
ShowWindow(GetDlgItem(hwndDlg, IDC_PROGRESS_PERCENT), SW_SHOWNORMAL);
|
||||
ShowWindow(GetDlgItem(hwndDlg, IDC_TRACKS), SW_SHOWNORMAL);
|
||||
|
||||
SetWindowText(hwndDlg,WASABI_API_LNGSTRINGW(IDS_IMPORTING_DATABASE));
|
||||
SetDlgItemText(hwndDlg, IDC_PROCESSING_STATE, WASABI_API_LNGSTRINGW(IDS_LOADING_XML));
|
||||
SendMessage(GetDlgItem(hwndDlg, IDC_PROGRESS_PERCENT), PBM_SETRANGE, 0, MAKELPARAM(0, 100));
|
||||
SendDlgItemMessage(hwndDlg, IDC_PROGRESS_PERCENT, PBM_SETPOS, 0, 0);
|
||||
|
||||
setDialogIcon(hwndDlg);
|
||||
|
||||
SetTimer(hwndDlg, 666, 250, 0);
|
||||
SetForegroundWindow(hwndDlg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
case WM_TIMER:
|
||||
if (wParam == 666)
|
||||
{
|
||||
int *progress = (int *)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
|
||||
if (progress[0] == -666)
|
||||
{
|
||||
KillTimer(hwndDlg, 666);
|
||||
EndDialog(hwndDlg, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
// display progress
|
||||
SetDlgItemText(hwndDlg, IDC_TRACKS, StringPrintfW(WASABI_API_LNGSTRINGW(IDS_TRACKS_IMPORTED_X), progress[0]));
|
||||
SendDlgItemMessage(hwndDlg, IDC_PROGRESS_PERCENT, PBM_SETPOS, (int)((double)progress[0]/progress[1]*100.0), 0);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case WM_COMMAND:
|
||||
{
|
||||
int wID = LOWORD(wParam);
|
||||
switch (wID) {
|
||||
case IDOK:
|
||||
case IDCANCEL:
|
||||
EndDialog(hwndDlg, wID);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static DWORD CALLBACK ImportThread(LPVOID param)
|
||||
{
|
||||
WASABI_API_DIALOGBOXPARAMW(IDD_INFODIALOG, NULL, import_dlgproc, (LPARAM)param);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ImporterAPI::ImportFromFile(HWND parent, const wchar_t *library_file)
|
||||
{
|
||||
// create an XML parser
|
||||
obj_xml *parser=0;
|
||||
waServiceFactory *factory = plugin.service->service_getServiceByGuid(obj_xmlGUID);
|
||||
if (factory)
|
||||
parser = (obj_xml *)factory->getInterface();
|
||||
|
||||
if (parser)
|
||||
{
|
||||
// create status window
|
||||
int progress[2] = {0};
|
||||
DWORD threadId = 0;
|
||||
HANDLE importThread = CreateThread(0, 0, ImportThread, progress, 0, &threadId);
|
||||
|
||||
// create an iTunes XML library reader
|
||||
plistLoader it;
|
||||
|
||||
// load the XML, this creates an iTunes DB in memory, and returns the root key
|
||||
parser->xmlreader_open();
|
||||
parser->xmlreader_registerCallback(L"plist\f*", &it);
|
||||
Load(library_file, parser);
|
||||
parser->xmlreader_unregisterCallback(&it);
|
||||
parser->xmlreader_close();
|
||||
plistKey *root_key = ⁢
|
||||
|
||||
// we start at the root key
|
||||
if (root_key) {
|
||||
// the root key contains a dictionary
|
||||
plistData *root_dict = root_key->getData();
|
||||
if (root_dict && root_dict->getType() == PLISTDATA_DICT) {
|
||||
// that dictionary contains a number of keys, one of which contains a dictionary of tracks
|
||||
plistKey *tracks_key = ((plistDict*)root_dict)->getKey(L"Tracks");
|
||||
plistData *tracks_dict = tracks_key?tracks_key->getData():0;
|
||||
if (tracks_dict && tracks_dict->getType() == PLISTDATA_DICT) {
|
||||
// we have the tracks dictionary ...
|
||||
plistDict *tracks = (plistDict *)tracks_dict;
|
||||
progress[1]=tracks?tracks->getNumKeys():0;
|
||||
// ... now enumerate tracks
|
||||
for (int i=0;i<progress[1];i++) {
|
||||
// each track is a key in the tracks dictionary, and contains a dictionary of properties
|
||||
plistKey *track_key = tracks->enumKey(i);
|
||||
plistData *track_dict = track_key->getData();
|
||||
// prepare an item record
|
||||
itemRecordW ir;
|
||||
MEMZERO(&ir, sizeof(ir));
|
||||
ir.year = ir.track = ir.length = -1;
|
||||
ir.lastplay = -1;
|
||||
ir.type = 0; // this makes it an Audio file (unless otherwise specified
|
||||
if (track_dict->getType() == PLISTDATA_DICT) {
|
||||
// we have the track's dictionary of properties...
|
||||
plistDict *track = (plistDict *)track_dict;
|
||||
int tn = track->getNumKeys();
|
||||
// ... now enumerate the properties
|
||||
for (int j=0;j<tn;j++) {
|
||||
plistKey *prop = track->enumKey(j);
|
||||
Importer_AddKeyToItemRecord(prop, ir);
|
||||
}
|
||||
// add or update the file
|
||||
SendMessage(plugin.hwndLibraryParent, WM_ML_IPC, (WPARAM)&ir, ML_IPC_DB_ADDORUPDATEITEMW);
|
||||
// free the record
|
||||
freeRecord(&ir);
|
||||
// show progress
|
||||
++progress[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//done
|
||||
progress[0]=-666;
|
||||
if (importThread)
|
||||
{
|
||||
WaitForSingleObject(importThread, INFINITE);
|
||||
CloseHandle(importThread);
|
||||
}
|
||||
|
||||
// tell gen_ml we modified the db
|
||||
SendMessage(plugin.hwndLibraryParent, WM_ML_IPC, 0, ML_IPC_DB_SYNCDB);
|
||||
|
||||
factory->releaseInterface(parser);
|
||||
}
|
||||
else
|
||||
return DISPATCH_FAILURE;
|
||||
return DISPATCH_SUCCESS;
|
||||
}
|
||||
|
||||
bool ImporterAPI::iTunesExists()
|
||||
{
|
||||
wchar_t itunes_path[MAX_PATH] = {0};
|
||||
if (GetiTunesPreferencesPath(itunes_path, MAX_PATH))
|
||||
{
|
||||
return GetFileAttributesW(itunes_path) != INVALID_FILE_ATTRIBUTES;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int ImporterAPI::ImportFromiTunes(HWND parent)
|
||||
{
|
||||
wchar_t itunes_path[MAX_PATH] = {0};
|
||||
if (GetiTunesLibraryPath(itunes_path, MAX_PATH))
|
||||
{
|
||||
return ImportFromFile(parent, itunes_path);
|
||||
}
|
||||
return DISPATCH_FAILURE;
|
||||
}
|
||||
|
||||
int ImportPlaylists(HWND parent, const wchar_t *library_file);
|
||||
int ImporterAPI::ImportPlaylistsFromiTunes(HWND parent)
|
||||
{
|
||||
wchar_t itunes_path[MAX_PATH] = {0};
|
||||
if (GetiTunesLibraryPath(itunes_path, MAX_PATH))
|
||||
{
|
||||
return ImportPlaylists(parent, itunes_path);
|
||||
}
|
||||
return DISPATCH_FAILURE;
|
||||
}
|
||||
|
||||
#define CBCLASS ImporterAPI
|
||||
START_DISPATCH;
|
||||
CB(API_ITUNES_IMPORTER_ITUNESEXISTS, iTunesExists)
|
||||
CB(API_ITUNES_IMPORTER_IMPORTFROMFILE, ImportFromFile)
|
||||
CB(API_ITUNES_IMPORTER_IMPORTFROMITUNES, ImportFromiTunes)
|
||||
CB(API_ITUNES_IMPORTER_IMPORTPLAYLISTSFROMITUNES, ImportPlaylistsFromiTunes)
|
||||
END_DISPATCH;
|
||||
#undef CBCLASS
|
13
Src/Plugins/Library/ml_impex/ImporterAPI.h
Normal file
13
Src/Plugins/Library/ml_impex/ImporterAPI.h
Normal file
@ -0,0 +1,13 @@
|
||||
#include "api_importer.h"
|
||||
|
||||
class ImporterAPI : public api_itunes_importer
|
||||
{
|
||||
public:
|
||||
bool iTunesExists();
|
||||
int ImportFromFile(HWND parent, const wchar_t *library_file);
|
||||
int ImportFromiTunes(HWND parent);
|
||||
int ImportPlaylistsFromiTunes(HWND parent);
|
||||
|
||||
protected:
|
||||
RECVS_DISPATCH;
|
||||
};
|
20
Src/Plugins/Library/ml_impex/api__ml_impex.h
Normal file
20
Src/Plugins/Library/ml_impex/api__ml_impex.h
Normal file
@ -0,0 +1,20 @@
|
||||
#ifndef NULLSOFT_ML_IMPEX_API_H
|
||||
#define NULLSOFT_ML_IMPEX_API_H
|
||||
|
||||
#include <api/service/waservicefactory.h>
|
||||
|
||||
#include "../Agave/Language/api_language.h"
|
||||
|
||||
#include <api/application/api_application.h>
|
||||
extern api_application *applicationApi;
|
||||
#define WASABI_API_APP applicationApi
|
||||
|
||||
#include "../playlist/api_playlistmanager.h"
|
||||
extern api_playlistmanager *playlistManager;
|
||||
#define AGAVE_API_PLAYLISTMANAGER playlistManager
|
||||
|
||||
#include "../playlist/api_playlists.h"
|
||||
extern api_playlists *playlistsApi;
|
||||
#define AGAVE_API_PLAYLISTS playlistsApi
|
||||
|
||||
#endif // !NULLSOFT_ML_IMPEX_API_H
|
52
Src/Plugins/Library/ml_impex/api_importer.h
Normal file
52
Src/Plugins/Library/ml_impex/api_importer.h
Normal file
@ -0,0 +1,52 @@
|
||||
#pragma once
|
||||
|
||||
#include <bfc/dispatch.h>
|
||||
#include <api/service/services.h>
|
||||
|
||||
// {A32C39BC-CDF7-4c9b-9EA2-9DF7E0D651D2}
|
||||
static const GUID iTunesImporterGUID =
|
||||
{ 0xa32c39bc, 0xcdf7, 0x4c9b, { 0x9e, 0xa2, 0x9d, 0xf7, 0xe0, 0xd6, 0x51, 0xd2 } };
|
||||
|
||||
class api_itunes_importer : public Dispatchable
|
||||
{
|
||||
protected:
|
||||
api_itunes_importer() {}
|
||||
~api_itunes_importer() {}
|
||||
public:
|
||||
static FOURCC getServiceType() { return WaSvc::UNIQUE; }
|
||||
static const char *getServiceName() { return "iTunes Importer Service"; }
|
||||
static GUID getServiceGuid() { return iTunesImporterGUID; }
|
||||
|
||||
bool iTunesExists();
|
||||
int ImportFromFile(HWND parent, const wchar_t *library_file);
|
||||
int ImportFromiTunes(HWND parent);
|
||||
int ImportPlaylistsFromiTunes(HWND parent);
|
||||
|
||||
enum
|
||||
{
|
||||
API_ITUNES_IMPORTER_ITUNESEXISTS = 0,
|
||||
API_ITUNES_IMPORTER_IMPORTFROMFILE = 1,
|
||||
API_ITUNES_IMPORTER_IMPORTFROMITUNES = 2,
|
||||
API_ITUNES_IMPORTER_IMPORTPLAYLISTSFROMITUNES = 3,
|
||||
};
|
||||
};
|
||||
|
||||
inline bool api_itunes_importer::iTunesExists()
|
||||
{
|
||||
return _call(API_ITUNES_IMPORTER_ITUNESEXISTS, (bool)false);
|
||||
}
|
||||
|
||||
inline int api_itunes_importer::ImportFromFile(HWND parent, const wchar_t *library_file)
|
||||
{
|
||||
return _call(API_ITUNES_IMPORTER_IMPORTFROMFILE, (int)DISPATCH_FAILURE, parent, library_file);
|
||||
}
|
||||
|
||||
inline int api_itunes_importer::ImportFromiTunes(HWND parent)
|
||||
{
|
||||
return _call(API_ITUNES_IMPORTER_IMPORTFROMITUNES, (int)DISPATCH_FAILURE, parent);
|
||||
}
|
||||
|
||||
inline int api_itunes_importer::ImportPlaylistsFromiTunes(HWND parent)
|
||||
{
|
||||
return _call(API_ITUNES_IMPORTER_IMPORTPLAYLISTSFROMITUNES, (int)DISPATCH_FAILURE, parent);
|
||||
}
|
625
Src/Plugins/Library/ml_impex/impex.cpp
Normal file
625
Src/Plugins/Library/ml_impex/impex.cpp
Normal file
@ -0,0 +1,625 @@
|
||||
//------------------------------------------------------------------------
|
||||
//
|
||||
// iTunes XML Import/Export Plugin
|
||||
// Copyright <20> 2003-2014 Winamp SA
|
||||
//
|
||||
//------------------------------------------------------------------------
|
||||
//#define PLUGIN_NAME "Nullsoft Database Import/Export"
|
||||
#define PLUGIN_VERSION L"2.65"
|
||||
|
||||
#include <windows.h>
|
||||
#include <commdlg.h>
|
||||
#include <commctrl.h>
|
||||
#include <stdio.h>
|
||||
#include "api__ml_impex.h"
|
||||
#include "../../General/gen_ml/ml.h"
|
||||
#include "../winamp/wa_ipc.h"
|
||||
#include "resource.h"
|
||||
#include <bfc/string/url.h>
|
||||
#include "itunesxmlwrite.h"
|
||||
#include "importer.h"
|
||||
#include "ImporterAPI.h"
|
||||
#include "../nu/Singleton.h"
|
||||
#include "../nu/AutoChar.h"
|
||||
#include "../nu/AutoWide.h"
|
||||
|
||||
static ImporterAPI importAPI;
|
||||
static SingletonServiceFactory<api_itunes_importer, ImporterAPI> importerFactory;
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
#define ID_IMPORT 35443
|
||||
#define ID_EXPORT 35444
|
||||
#define ID_CVTPLAYLISTS 35445
|
||||
#define ID_IMPORT_ITUNES 35446
|
||||
|
||||
#define ID_FILE_ADDTOLIBRARY 40344
|
||||
#define ID_DOSHITMENU_ADDNEWVIEW 40030
|
||||
#define IDM_LIBRARY_CONFIG 40050
|
||||
#define ID_DOSHITMENU_ADDNEWPLAYLIST 40031
|
||||
#define WINAMP_MANAGEPLAYLISTS 40385
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
api_application *WASABI_API_APP = 0;
|
||||
api_playlistmanager *AGAVE_API_PLAYLISTMANAGER = 0;
|
||||
api_playlists *AGAVE_API_PLAYLISTS = 0;
|
||||
|
||||
// wasabi based services for localisation support
|
||||
api_language *WASABI_API_LNG = 0;
|
||||
HINSTANCE WASABI_API_LNG_HINST = 0, WASABI_API_ORIG_HINST = 0;
|
||||
|
||||
wchar_t* GetFilterListString(void) { // "iTunes XML Library\0*.xml\0\0"
|
||||
static wchar_t filterString[128] = {0};
|
||||
wchar_t* end = 0;
|
||||
StringCchCopyEx(filterString, 128, WASABI_API_LNGSTRINGW(IDS_ITUNES_XML_LIBRARY), &end, 0, 0);
|
||||
StringCchCopyEx(end+1, 128, L"*.xml", 0, 0, 0);
|
||||
return filterString;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
static LRESULT WINAPI ml_newParentWndProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam);
|
||||
static LRESULT WINAPI ml_newMlWndProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam);
|
||||
|
||||
static WNDPROC ml_oldParentWndProc;
|
||||
static WNDPROC ml_oldMlWndProc;
|
||||
static HWND export_wnd, hwnd_winamp, mlWnd;
|
||||
extern winampMediaLibraryPlugin plugin;
|
||||
HMENU mlMenu=NULL;
|
||||
void exportDatabase();
|
||||
void importDatabase();
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// dummy plugin message procs, we just ignore everything
|
||||
// -----------------------------------------------------------------------
|
||||
static INT_PTR PluginMessageProc(int message_type, INT_PTR param1, INT_PTR param2, INT_PTR param3)
|
||||
{
|
||||
if (message_type == ML_MSG_NO_CONFIG)
|
||||
return TRUE;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// plugin, exported to gen_ml
|
||||
// -----------------------------------------------------------------------
|
||||
static int init();
|
||||
static void quit();
|
||||
|
||||
extern "C" winampMediaLibraryPlugin plugin =
|
||||
{
|
||||
MLHDR_VER,
|
||||
"nullsoft(ml_impex.dll)",
|
||||
init,
|
||||
quit,
|
||||
PluginMessageProc,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
};
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// export
|
||||
// -----------------------------------------------------------------------
|
||||
extern "C" {
|
||||
__declspec( dllexport ) winampMediaLibraryPlugin * winampGetMediaLibraryPlugin()
|
||||
{
|
||||
return &plugin;
|
||||
}
|
||||
};
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// returns the position of a command within an HMENU
|
||||
// -----------------------------------------------------------------------
|
||||
int getMenuItemPos(HMENU menu, UINT command) {
|
||||
for (int i=0;i<256;i++) {
|
||||
MENUITEMINFO mii={sizeof(mii),MIIM_ID,};
|
||||
if (!GetMenuItemInfo(menu, i, TRUE, &mii)) break;
|
||||
if (mii.wID == command) return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// entry point, gen_ml is starting up and we've just been loaded
|
||||
// -----------------------------------------------------------------------
|
||||
int init()
|
||||
{
|
||||
waServiceFactory *sf = plugin.service->service_getServiceByGuid(languageApiGUID);
|
||||
if (sf) WASABI_API_LNG = reinterpret_cast<api_language*>(sf->getInterface());
|
||||
|
||||
sf = plugin.service->service_getServiceByGuid(applicationApiServiceGuid);
|
||||
if (sf) WASABI_API_APP = reinterpret_cast<api_application*>(sf->getInterface());
|
||||
|
||||
sf = plugin.service->service_getServiceByGuid(api_playlistmanagerGUID);
|
||||
if (sf) AGAVE_API_PLAYLISTMANAGER = reinterpret_cast<api_playlistmanager*>(sf->getInterface());
|
||||
|
||||
sf = plugin.service->service_getServiceByGuid(api_playlistsGUID);
|
||||
if (sf) AGAVE_API_PLAYLISTS = reinterpret_cast<api_playlists*>(sf->getInterface());
|
||||
|
||||
// need to have this initialised before we try to do anything with localisation features
|
||||
WASABI_API_START_LANG(plugin.hDllInstance,MlImpexLangGUID);
|
||||
|
||||
importerFactory.Register(plugin.service, &importAPI);
|
||||
|
||||
static wchar_t szDescription[256];
|
||||
StringCchPrintf(szDescription, ARRAYSIZE(szDescription),
|
||||
WASABI_API_LNGSTRINGW(IDS_ML_IMPEX_DESC), PLUGIN_VERSION);
|
||||
plugin.description = (char*)szDescription;
|
||||
|
||||
HWND w = plugin.hwndWinampParent;
|
||||
while (GetParent(w) != NULL) w = GetParent(w);
|
||||
hwnd_winamp = w;
|
||||
|
||||
ml_oldParentWndProc = (WNDPROC)SetWindowLongPtrW(plugin.hwndWinampParent, GWLP_WNDPROC, (LONG_PTR)ml_newParentWndProc);
|
||||
|
||||
mlMenu = (HMENU)SendMessage(hwnd_winamp, WM_WA_IPC, 9, IPC_GET_HMENU);
|
||||
int IPC_GETMLWINDOW=(int)SendMessage(hwnd_winamp,WM_WA_IPC,(WPARAM)&"LibraryGetWnd",IPC_REGISTER_WINAMP_IPCMESSAGE);
|
||||
mlWnd = (HWND)SendMessage(hwnd_winamp, WM_WA_IPC, -1, IPC_GETMLWINDOW);
|
||||
|
||||
ml_oldMlWndProc = (WNDPROC)SetWindowLongPtrW(mlWnd, GWLP_WNDPROC, (LONG_PTR)ml_newMlWndProc);
|
||||
|
||||
int p = getMenuItemPos(mlMenu, ID_FILE_ADDTOLIBRARY);
|
||||
MENUITEMINFO mii={sizeof(mii),MIIM_ID|MIIM_TYPE, MFT_SEPARATOR, };
|
||||
InsertMenuItem(mlMenu, ++p, TRUE, &mii);
|
||||
|
||||
if (importAPI.iTunesExists())
|
||||
{
|
||||
MENUITEMINFO mii2={sizeof(mii2),MIIM_ID|MIIM_STATE|MIIM_TYPE, MFT_STRING, MFS_ENABLED, ID_IMPORT_ITUNES, NULL, NULL, NULL, NULL, WASABI_API_LNGSTRINGW(IDS_IMPORT_ITUNES_DB), 0};
|
||||
InsertMenuItem(mlMenu, ++p, TRUE, &mii2);
|
||||
MENUITEMINFO mii5={sizeof(mii5),MIIM_ID|MIIM_STATE|MIIM_TYPE, MFT_STRING, MFS_ENABLED, ID_CVTPLAYLISTS, NULL, NULL, NULL, NULL, WASABI_API_LNGSTRINGW(IDS_IMPORT_ITUNES_PL), 0};
|
||||
InsertMenuItem(mlMenu, ++p, TRUE, &mii5);
|
||||
}
|
||||
MENUITEMINFO mii3={sizeof(mii),MIIM_ID|MIIM_STATE|MIIM_TYPE, MFT_STRING, MFS_ENABLED, ID_IMPORT, NULL, NULL, NULL, NULL, WASABI_API_LNGSTRINGW(IDS_IMPORT_DATABASE), 0};
|
||||
InsertMenuItem(mlMenu, ++p, TRUE, &mii3);
|
||||
MENUITEMINFO mii4={sizeof(mii),MIIM_ID|MIIM_STATE|MIIM_TYPE, MFT_STRING, MFS_ENABLED, ID_EXPORT, NULL, NULL, NULL, NULL, WASABI_API_LNGSTRINGW(IDS_EXPORT_DATABASE), 0};
|
||||
InsertMenuItem(mlMenu, ++p, TRUE, &mii4);
|
||||
|
||||
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 hmenuPopup = GetSubMenu(context_menu, 0);
|
||||
if (hmenuPopup)
|
||||
{
|
||||
int p = getMenuItemPos(hmenuPopup, WINAMP_MANAGEPLAYLISTS);
|
||||
if (getMenuItemPos(hmenuPopup, IDM_LIBRARY_CONFIG) != -1) // sanity check
|
||||
{
|
||||
bool end_separator=true;
|
||||
if (p != -1)
|
||||
{
|
||||
MENUITEMINFO mii={sizeof(mii),MIIM_ID|MIIM_TYPE, MFT_SEPARATOR, };
|
||||
InsertMenuItem(hmenuPopup, ++p, TRUE, &mii);
|
||||
end_separator=false;
|
||||
}
|
||||
if (importAPI.iTunesExists())
|
||||
{
|
||||
MENUITEMINFO mii2={sizeof(mii2),MIIM_ID|MIIM_STATE|MIIM_TYPE, MFT_STRING, MFS_ENABLED, ID_IMPORT_ITUNES, NULL, NULL, NULL, NULL, WASABI_API_LNGSTRINGW(IDS_IMPORT_ITUNES_DB), 0};
|
||||
InsertMenuItem(hmenuPopup, ++p, TRUE, &mii2);
|
||||
MENUITEMINFO mii5={sizeof(mii5),MIIM_ID|MIIM_STATE|MIIM_TYPE, MFT_STRING, MFS_ENABLED, ID_CVTPLAYLISTS, NULL, NULL, NULL, NULL, WASABI_API_LNGSTRINGW(IDS_IMPORT_ITUNES_PL), 0};
|
||||
InsertMenuItem(hmenuPopup, ++p, TRUE, &mii5);
|
||||
}
|
||||
MENUITEMINFO mii3={sizeof(mii3),MIIM_ID|MIIM_STATE|MIIM_TYPE, MFT_STRING, MFS_ENABLED, ID_IMPORT, NULL, NULL, NULL, NULL, WASABI_API_LNGSTRINGW(IDS_IMPORT_DATABASE), 0};
|
||||
InsertMenuItem(hmenuPopup, ++p, TRUE, &mii3);
|
||||
MENUITEMINFO mii4={sizeof(mii4),MIIM_ID|MIIM_STATE|MIIM_TYPE, MFT_STRING, MFS_ENABLED, ID_EXPORT, NULL, NULL, NULL, NULL, WASABI_API_LNGSTRINGW(IDS_EXPORT_DATABASE), 0};
|
||||
InsertMenuItem(hmenuPopup, ++p, TRUE, &mii4);
|
||||
if (end_separator)
|
||||
{
|
||||
MENUITEMINFO mii={sizeof(mii),MIIM_ID|MIIM_TYPE, MFT_SEPARATOR, };
|
||||
InsertMenuItem(hmenuPopup, ++p, TRUE, &mii);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ML_INIT_SUCCESS;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// entry point, gen_ml is shutting down and we are being unloaded
|
||||
// -----------------------------------------------------------------------
|
||||
void quit() {
|
||||
if (IsWindow(plugin.hwndWinampParent)) SetWindowLongPtrW(plugin.hwndWinampParent, GWLP_WNDPROC, (LONG_PTR)ml_oldParentWndProc);
|
||||
if (IsWindow(mlWnd)) SetWindowLongPtrW(mlWnd, GWLP_WNDPROC, (LONG_PTR)ml_oldMlWndProc);
|
||||
importerFactory.Deregister(plugin.service);
|
||||
}
|
||||
|
||||
void handleMenuItem(int wID) {
|
||||
switch (wID) {
|
||||
case ID_EXPORT:
|
||||
exportDatabase();
|
||||
break;
|
||||
case ID_IMPORT:
|
||||
importDatabase();
|
||||
break;
|
||||
case ID_IMPORT_ITUNES:
|
||||
{
|
||||
importAPI.ImportFromiTunes(plugin.hwndLibraryParent);
|
||||
}
|
||||
break;
|
||||
case ID_CVTPLAYLISTS:
|
||||
{
|
||||
importAPI.ImportPlaylistsFromiTunes(plugin.hwndLibraryParent);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void setDialogIcon(HWND hwndDlg)
|
||||
{
|
||||
static HICON wa_icy;
|
||||
if (wa_icy)
|
||||
{
|
||||
wa_icy = (HICON)LoadImage(GetModuleHandle(L"winamp.exe"),
|
||||
MAKEINTRESOURCE(102), IMAGE_ICON,
|
||||
GetSystemMetrics(SM_CXSMICON),
|
||||
GetSystemMetrics(SM_CYSMICON),
|
||||
LR_SHARED | LR_LOADTRANSPARENT | LR_CREATEDIBSECTION);
|
||||
}
|
||||
SendMessage(hwndDlg, WM_SETICON, ICON_SMALL, (LPARAM)wa_icy);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// library HWND subclass
|
||||
// -----------------------------------------------------------------------
|
||||
static LRESULT WINAPI ml_newParentWndProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam)
|
||||
{
|
||||
switch (uMsg)
|
||||
{
|
||||
case WM_COMMAND:
|
||||
{
|
||||
int wID = LOWORD(wParam);
|
||||
handleMenuItem(wID);
|
||||
}
|
||||
break;
|
||||
}
|
||||
return CallWindowProcW(ml_oldParentWndProc,hwndDlg,uMsg,wParam,lParam);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
static LRESULT WINAPI ml_newMlWndProc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam)
|
||||
{
|
||||
switch (uMsg)
|
||||
{
|
||||
case WM_COMMAND:
|
||||
{
|
||||
int wID = LOWORD(wParam);
|
||||
handleMenuItem(wID);
|
||||
}
|
||||
break;
|
||||
}
|
||||
return CallWindowProcW(ml_oldMlWndProc,hwndDlg,uMsg,wParam,lParam);
|
||||
}
|
||||
|
||||
// {55334B63-68D5-4389-A209-797F123E207F}
|
||||
static const GUID ML_IMPEX =
|
||||
{ 0x55334b63, 0x68d5, 0x4389, { 0xa2, 0x9, 0x79, 0x7f, 0x12, 0x3e, 0x20, 0x7f } };
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// pick an input file
|
||||
//------------------------------------------------------------------------
|
||||
static int pickFile(HWND hwndDlg, StringW *file)
|
||||
{
|
||||
wchar_t oldCurPath[MAX_PATH] = {0};
|
||||
GetCurrentDirectoryW(MAX_PATH, oldCurPath);
|
||||
|
||||
OPENFILENAME l={sizeof(l),};
|
||||
wchar_t *temp;
|
||||
const int len=256*1024-128;
|
||||
|
||||
temp = (wchar_t *)GlobalAlloc(GPTR,len*sizeof(*temp));
|
||||
l.hwndOwner = hwndDlg;
|
||||
extern wchar_t* GetFilterListString(void);
|
||||
l.lpstrFilter = GetFilterListString();//L"iTunes XML Library\0*.xml\0\0"; // IDS_ITUNES_XML_LIBRARY
|
||||
l.lpstrFile = temp;
|
||||
l.nMaxFile = len-1;
|
||||
l.lpstrTitle = WASABI_API_LNGSTRINGW(IDS_IMPORT_DATABASE);
|
||||
l.lpstrDefExt = L"";
|
||||
l.lpstrInitialDir = WASABI_API_APP->path_getWorkingPath();;
|
||||
l.Flags = OFN_HIDEREADONLY|OFN_EXPLORER;
|
||||
if(GetOpenFileName(&l))
|
||||
{
|
||||
wchar_t newCurPath[MAX_PATH] = {0};
|
||||
GetCurrentDirectoryW(MAX_PATH, newCurPath);
|
||||
WASABI_API_APP->path_setWorkingPath(newCurPath);
|
||||
SetCurrentDirectoryW(oldCurPath);
|
||||
*file = temp;
|
||||
return 1;
|
||||
}
|
||||
SetCurrentDirectoryW(oldCurPath);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// import an iTunes XML library into gen_ml
|
||||
// -----------------------------------------------------------------------
|
||||
void importDatabase()
|
||||
{
|
||||
StringW file;
|
||||
// pick an inputfile
|
||||
if (pickFile(plugin.hwndLibraryParent, &file))
|
||||
{
|
||||
importAPI.ImportFromFile(plugin.hwndLibraryParent, file.getValue());
|
||||
// TODO ideally should only do this if the current view is from ml_local
|
||||
PostMessage(plugin.hwndLibraryParent, WM_USER + 30, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
int only_itunes = -1; // ask
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// ask the user if we should also write files unsupported by iTunes
|
||||
// -----------------------------------------------------------------------
|
||||
static BOOL CALLBACK exporttype_dlgproc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam)
|
||||
{
|
||||
switch (uMsg)
|
||||
{
|
||||
case WM_INITDIALOG:
|
||||
{
|
||||
only_itunes = 0;
|
||||
setDialogIcon(hwndDlg);
|
||||
|
||||
CheckDlgButton(hwndDlg, IDC_RADIO_ALLFILES, TRUE);
|
||||
CheckDlgButton(hwndDlg, IDC_RADIO_ONLYSUPPORTED, FALSE);
|
||||
SetForegroundWindow(hwndDlg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
case WM_COMMAND: {
|
||||
int wID = LOWORD(wParam);
|
||||
switch (wID) {
|
||||
case IDOK:
|
||||
case IDCANCEL:
|
||||
EndDialog(hwndDlg, wID);
|
||||
SetForegroundWindow(export_wnd);
|
||||
break;
|
||||
case IDC_RADIO_ONLYSUPPORTED:
|
||||
only_itunes = 1;
|
||||
break;
|
||||
case IDC_RADIO_ALLFILES:
|
||||
only_itunes = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// export status window proc
|
||||
// -----------------------------------------------------------------------
|
||||
static BOOL CALLBACK export_dlgproc(HWND hwndDlg, UINT uMsg, WPARAM wParam,LPARAM lParam)
|
||||
{
|
||||
switch (uMsg)
|
||||
{
|
||||
case WM_INITDIALOG:
|
||||
{
|
||||
export_wnd = hwndDlg;
|
||||
SetWindowLongPtr(hwndDlg, GWLP_USERDATA, lParam);
|
||||
|
||||
// init it
|
||||
ShowWindow(GetDlgItem(hwndDlg, IDC_PROGRESS_PERCENT), SW_SHOWNORMAL);
|
||||
ShowWindow(GetDlgItem(hwndDlg, IDC_TRACKS), SW_SHOWNORMAL);
|
||||
|
||||
SetWindowText(hwndDlg,WASABI_API_LNGSTRINGW(IDS_EXPORTING_DATABASE));
|
||||
SendMessage(GetDlgItem(hwndDlg, IDC_PROGRESS_PERCENT), PBM_SETRANGE, 0, MAKELPARAM(0, 100));
|
||||
SendDlgItemMessage(hwndDlg, IDC_PROGRESS_PERCENT, PBM_SETPOS, 0, 0);
|
||||
|
||||
setDialogIcon(hwndDlg);
|
||||
|
||||
SetTimer(hwndDlg, 666, 250, 0);
|
||||
SetForegroundWindow(hwndDlg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
case WM_TIMER:
|
||||
if (wParam == 666)
|
||||
{
|
||||
int *progress = (int *)GetWindowLongPtr(hwndDlg, GWLP_USERDATA);
|
||||
if (progress[0] == -333)
|
||||
{
|
||||
// show "saving xml"
|
||||
ShowWindow(GetDlgItem(hwndDlg, IDC_PROGRESS_PERCENT), SW_HIDE);
|
||||
ShowWindow(GetDlgItem(hwndDlg, IDC_TRACKS), SW_HIDE);
|
||||
SetDlgItemText(hwndDlg,IDC_PROCESSING_STATE,WASABI_API_LNGSTRINGW(IDS_WRITINGING_XML));
|
||||
ShowWindow(GetDlgItem(hwndDlg, IDC_PROCESSING_STATE), SW_SHOWNORMAL);
|
||||
}
|
||||
else if (progress[0] == -666)
|
||||
{
|
||||
KillTimer(hwndDlg, 666);
|
||||
EndDialog(hwndDlg, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
// display progress
|
||||
SendDlgItemMessage(hwndDlg, IDC_PROGRESS_PERCENT, PBM_SETPOS, (int)((double)progress[0] / progress[1] * 100.0), 0);
|
||||
SetDlgItemText(hwndDlg, IDC_TRACKS, StringPrintfW(WASABI_API_LNGSTRINGW(IDS_TRACKS_EXPORTED_X), progress[0]));
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case WM_COMMAND: {
|
||||
int wID = LOWORD(wParam);
|
||||
switch (wID) {
|
||||
case IDOK:
|
||||
case IDCANCEL:
|
||||
EndDialog(hwndDlg, wID);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// returns 1 if str ends with e
|
||||
// -----------------------------------------------------------------------
|
||||
int endsIn(const wchar_t *str, const wchar_t *e) {
|
||||
return !_wcsicmp(str+wcslen(str)-wcslen(e), e);
|
||||
}
|
||||
|
||||
static DWORD CALLBACK ExportThread(LPVOID param)
|
||||
{
|
||||
WASABI_API_DIALOGBOXPARAMW(IDD_INFODIALOG, NULL, export_dlgproc, (LPARAM)param);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// exports an iTunes XML library from gen_ml's database
|
||||
// -----------------------------------------------------------------------
|
||||
void exportDatabase() {
|
||||
// create an iTunes XML library writer
|
||||
iTunesXmlWrite w;
|
||||
|
||||
// pick an output file
|
||||
if (w.pickFile(plugin.hwndLibraryParent)) {
|
||||
// if a file unsupported by iTunes is about to be exported, ask confirmation
|
||||
only_itunes = -1;
|
||||
|
||||
// create status window
|
||||
int progress[2] = {0};
|
||||
DWORD threadId = 0;
|
||||
HANDLE exportThread = CreateThread(0, 0, ExportThread, progress, 0, &threadId);
|
||||
|
||||
// create an iTunes DB in memory, start with a root key
|
||||
plistKey *rootKey = new plistKey(L"root");
|
||||
// add a dictionary to it
|
||||
plistDict *rootDict = new plistDict();
|
||||
rootKey->setData(rootDict);
|
||||
|
||||
// add a few useless fields
|
||||
rootDict->addKey(new plistKey(L"Major Version", new plistInteger(1)));
|
||||
rootDict->addKey(new plistKey(L"Minor Version", new plistInteger(1)));
|
||||
rootDict->addKey(new plistKey(L"Application Version", new plistString(L"7.6.1"))); // we pretend to be iTunes 7.6.1
|
||||
|
||||
// create the Tracks key and its dictionary of tracks
|
||||
plistDict *dict_tracks = new plistDict();
|
||||
rootDict->addKey(new plistKey(L"Tracks", dict_tracks));
|
||||
|
||||
// run an empty query, so we get all items in the db
|
||||
mlQueryStructW query;
|
||||
query.query = L"";
|
||||
query.max_results = 0;
|
||||
query.results.Size = 0;
|
||||
query.results.Items = NULL;
|
||||
query.results.Alloc = 0;
|
||||
|
||||
SendMessage(plugin.hwndLibraryParent, WM_ML_IPC, (WPARAM)&query, ML_IPC_DB_RUNQUERYW);
|
||||
|
||||
// my, what a big number of items...
|
||||
progress[1] = query.results.Size;
|
||||
|
||||
// ... enumerate them
|
||||
for (int x = 0; x < progress[1]; x ++) {
|
||||
// take the xth item
|
||||
itemRecordW ir = query.results.Items[x];
|
||||
|
||||
// check if it's supported by iTunes, if we've already answered the question, use last answer
|
||||
if ((only_itunes > 0 || only_itunes < 0) && (!endsIn(ir.filename, L".mp3") && !endsIn(ir.filename, L".m4a") && !endsIn(ir.filename, L".wav") && !endsIn(ir.filename, L".aiff"))) {
|
||||
if (only_itunes < 0) {
|
||||
// prompt user, should we export files unsupported by iTunes ?
|
||||
WASABI_API_DIALOGBOXW(IDD_EXPORTTYPE, plugin.hwndLibraryParent, exporttype_dlgproc);
|
||||
}
|
||||
// if not, continue with the next item
|
||||
if (only_itunes) continue;
|
||||
}
|
||||
|
||||
// create a track key, its name is the number of the track (not counting skipped tracks)
|
||||
plistKey *key_track = new plistKey(StringPrintfW(L"%d", progress[0]));
|
||||
dict_tracks->addKey(key_track);
|
||||
|
||||
// give it a dictionary to hold its properties
|
||||
plistDict *dict_track = new plistDict();
|
||||
key_track->setData(dict_track);
|
||||
|
||||
// create the properties as needed
|
||||
dict_track->addKey(new plistKey(L"Track ID", new plistInteger(progress[0])));
|
||||
if (ir.title) dict_track->addKey(new plistKey(L"Name", new plistString(ir.title)));
|
||||
if (ir.artist) dict_track->addKey(new plistKey(L"Artist", new plistString(ir.artist)));
|
||||
if (ir.albumartist) dict_track->addKey(new plistKey(L"Album Artist", new plistString(ir.albumartist)));
|
||||
if (ir.album) dict_track->addKey(new plistKey(L"Album", new plistString(ir.album)));
|
||||
if (ir.genre) dict_track->addKey(new plistKey(L"Genre", new plistString(ir.genre)));
|
||||
if (ir.comment) dict_track->addKey(new plistKey(L"Comments", new plistString(ir.comment)));
|
||||
dict_track->addKey(new plistKey(L"Kind", new plistString(L"MPEG audio file")));
|
||||
|
||||
// changed in 5.64 to use the 'realsize' if it's available, otherwise map to filesize scaled to bytes (stored as kb otherwise)
|
||||
const wchar_t *realsize = getRecordExtendedItem(&ir, L"realsize");
|
||||
if (realsize) dict_track->addKey(new plistKey(L"Size", new plistInteger(_wtoi64(realsize))));
|
||||
else if (ir.filesize > 0) dict_track->addKey(new plistKey(L"Size", new plistInteger(ir.filesize * 1024)));
|
||||
|
||||
if (ir.length >= 0) dict_track->addKey(new plistKey(L"Total Time", new plistInteger(ir.length * 1000)));
|
||||
if (ir.track >= 0) dict_track->addKey(new plistKey(L"Track Number", new plistInteger(ir.track)));
|
||||
if (ir.year >= 0) dict_track->addKey(new plistKey(L"Year", new plistInteger(ir.year)));
|
||||
if (ir.filetime> 0) dict_track->addKey(new plistKey(L"Date Modified", new plistDate((time_t)ir.filetime)));
|
||||
if (ir.lastupd> 0) dict_track->addKey(new plistKey(L"Date Added", new plistDate((time_t)ir.lastupd)));
|
||||
//if (ir.lastplay> 0) dict_track->addKey(new plistKey(L"Play Date", new plistInteger((time_t)ir.lastplay)));
|
||||
if (ir.lastplay > 0) dict_track->addKey(new plistKey(L"Play Date UTC", new plistDate((time_t)ir.lastplay)));
|
||||
if (ir.bitrate> 0) dict_track->addKey(new plistKey(L"Bit Rate", new plistInteger(ir.bitrate)));
|
||||
if (ir.playcount> 0) dict_track->addKey(new plistKey(L"Play Count", new plistInteger(ir.playcount)));
|
||||
if (ir.rating> 0) dict_track->addKey(new plistKey(L"Rating", new plistInteger(ir.rating * 20)));
|
||||
if (ir.composer) dict_track->addKey(new plistKey(L"Composer", new plistString(ir.composer)));
|
||||
if (ir.publisher) dict_track->addKey(new plistKey(L"Publisher", new plistString(ir.publisher)));
|
||||
if (ir.type == 1) dict_track->addKey(new plistKey(L"Has Video", new plistInteger(1)));
|
||||
if (ir.disc> 0) dict_track->addKey(new plistKey(L"Disc Number", new plistInteger(ir.disc)));
|
||||
if (ir.discs> 0) dict_track->addKey(new plistKey(L"Disc Count", new plistInteger(ir.discs)));
|
||||
if (ir.tracks > 0) dict_track->addKey(new plistKey(L"Track Count", new plistInteger(ir.tracks)));
|
||||
if (ir.bpm > 0) dict_track->addKey(new plistKey(L"BPM", new plistInteger(ir.bpm)));
|
||||
const wchar_t *category = getRecordExtendedItem(&ir, L"category");
|
||||
if (category) dict_track->addKey(new plistKey(L"Grouping", new plistString(category)));
|
||||
const wchar_t *producer = getRecordExtendedItem(&ir, L"producer");
|
||||
if (producer) dict_track->addKey(new plistKey(L"Producer", new plistString(producer)));
|
||||
const wchar_t *director = getRecordExtendedItem(&ir, L"director");
|
||||
if (director) dict_track->addKey(new plistKey(L"Director", new plistString(director)));
|
||||
const wchar_t *width = getRecordExtendedItem(&ir, L"width");
|
||||
if (width) dict_track->addKey(new plistKey(L"Video Width", new plistInteger(_wtoi64(width))));
|
||||
const wchar_t *height = getRecordExtendedItem(&ir, L"height");
|
||||
if (height) dict_track->addKey(new plistKey(L"Video Height", new plistInteger(_wtoi64(height))));
|
||||
// convert the filename's backslashes to slashes
|
||||
StringW s = ir.filename;
|
||||
|
||||
if (WCSNICMP(s, L"http://", 7))
|
||||
{
|
||||
wchar_t *val = s.getNonConstVal();
|
||||
// TODO: we could do this with less malloc usage
|
||||
AutoChar utf8(val, CP_UTF8);
|
||||
String encoded = (const char *)utf8;
|
||||
Url::encode(encoded, 0, URLENCODE_EXCLUDEALPHANUM|URLENCODE_EXCLUDESLASH, Url::URLENCODE_STYLE_PERCENT);
|
||||
|
||||
s = StringPrintfW(L"%s%s", ITUNES_FILENAME_HEADER, AutoWide(encoded, CP_UTF8));
|
||||
}
|
||||
|
||||
// done
|
||||
dict_track->addKey(new plistKey(L"Location", new plistString(s)));
|
||||
dict_track->addKey(new plistKey(L"File Folder Count", new plistInteger(-1)));
|
||||
dict_track->addKey(new plistKey(L"Library Folder Count", new plistInteger(-1)));
|
||||
|
||||
// we have one more item in our exported db
|
||||
progress[0]++;
|
||||
}
|
||||
|
||||
// show "saving xml"
|
||||
progress[0]=-333;
|
||||
|
||||
// free query results
|
||||
SendMessage(plugin.hwndLibraryParent, WM_ML_IPC, (WPARAM)&query, ML_IPC_DB_FREEQUERYRESULTSW);
|
||||
|
||||
// save the xml
|
||||
w.saveXml(rootKey);
|
||||
|
||||
// done
|
||||
progress[0]=-666;
|
||||
if (exportThread)
|
||||
{
|
||||
WaitForSingleObject(exportThread, INFINITE);
|
||||
CloseHandle(exportThread);
|
||||
}
|
||||
|
||||
// destroy the db, this deletes all the children too
|
||||
delete rootKey;
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
327
Src/Plugins/Library/ml_impex/importer.cpp
Normal file
327
Src/Plugins/Library/ml_impex/importer.cpp
Normal file
@ -0,0 +1,327 @@
|
||||
#include "../plist/types.h"
|
||||
#include "importer.h"
|
||||
#include "../../General/gen_ml/ml.h"
|
||||
#include <bfc/string/stringdict.h>
|
||||
#include <bfc/string/url.h>
|
||||
|
||||
BEGIN_STRINGDICTIONARY(_itunesprops)
|
||||
SDI(L"Track ID", IT_TRACKID);
|
||||
SDI(L"Name", IT_NAME);
|
||||
SDI(L"Artist", IT_ARTIST);
|
||||
SDI(L"Album Artist", IT_ALBUMARTIST);
|
||||
SDI(L"Album", IT_ALBUM);
|
||||
SDI(L"Genre", IT_GENRE);
|
||||
SDI(L"Comments", IT_COMMENTS);
|
||||
SDI(L"Kind", IT_KIND);
|
||||
SDI(L"Size", IT_SIZE);
|
||||
SDI(L"Total Time", IT_TOTALTIME);
|
||||
SDI(L"Track Number", IT_TRACKNUM);
|
||||
SDI(L"Track Count", IT_TRACKCOUNT);
|
||||
SDI(L"Year", IT_YEAR);
|
||||
SDI(L"Date Modified", IT_DATEMODIFIED);
|
||||
SDI(L"Date Added", IT_DATEADDED);
|
||||
SDI(L"Bit Rate", IT_BITRATE);
|
||||
SDI(L"Bitrate", IT_BITRATE);
|
||||
SDI(L"Sample Rate", IT_SAMPLERATE);
|
||||
SDI(L"Rating", IT_RATING);
|
||||
SDI(L"Location", IT_LOCATION);
|
||||
SDI(L"File Folder Count", IT_FOLDERCOUNT);
|
||||
SDI(L"Library Folder Count", IT_LIBFOLDERCOUNT);
|
||||
SDI(L"Play Count", IT_PLAYCOUNT);
|
||||
SDI(L"Play Date", IT_PLAYDATE);
|
||||
SDI(L"Play Date UTC", IT_PLAYDATE_UTC);
|
||||
SDI(L"Composer", IT_COMPOSER);
|
||||
SDI(L"Publisher", IT_PUBLISHER);
|
||||
SDI(L"Disc Number", IT_DISCNUMBER);
|
||||
SDI(L"Disc Count", IT_DISCCOUNT);
|
||||
SDI(L"BPM", IT_BPM);
|
||||
SDI(L"Has Video", IT_HAS_VIDEO);
|
||||
SDI(L"Grouping", IT_GROUPING);
|
||||
SDI(L"Producer", IT_PRODUCER);
|
||||
SDI(L"Director", IT_DIRECTOR);
|
||||
SDI(L"Artwork Count", IT_ARTWORK_COUNT);
|
||||
SDI(L"Persistent ID", IT_PERSISTENT_ID);
|
||||
SDI(L"Track Type", IT_TRACK_TYPE);
|
||||
SDI(L"HD", IT_HD);
|
||||
SDI(L"Video Width", IT_VIDEO_WIDTH);
|
||||
SDI(L"Video Height", IT_VIDEO_HEIGHT);
|
||||
SDI(L"Movie", IT_MOVIE);
|
||||
SDI(L"Release Date", IT_RELEASE_DATE);
|
||||
SDI(L"Normalization", IT_NORMALIZATION);
|
||||
SDI(L"Sort Name", IT_SORTNAME);
|
||||
SDI(L"Purchased", IT_PURCHASED);
|
||||
SDI(L"iTunesU", IT_ITUNESU);
|
||||
SDI(L"Skip Count", IT_SKIPCOUNT);
|
||||
SDI(L"Skip Date", IT_SKIPDATE);
|
||||
SDI(L"Sort Album", IT_SORTALBUM);
|
||||
SDI(L"Sort Composer", IT_SORTCOMPOSER);
|
||||
SDI(L"Part Of Gapless Album", IT_PART_OF_GAPLESS_ALBUM);
|
||||
SDI(L"Compilation", IT_COMPILATION);
|
||||
SDI(L"Sort Album Artist", IT_SORT_ALBUM_ARTIST);
|
||||
SDI(L"Sort Artist", IT_SORT_ARTIST);
|
||||
END_STRINGDICTIONARY(_itunesprops, itunesprops)
|
||||
|
||||
void FixPath(const wchar_t *strdata, StringW &f)
|
||||
{
|
||||
f = strdata;
|
||||
// if the file starts with the local filename header, strip it
|
||||
if (!_wcsnicmp(f, ITUNES_FILENAME_HEADER, wcslen(ITUNES_FILENAME_HEADER))) {
|
||||
if (f[wcslen(ITUNES_FILENAME_HEADER)] == '/')
|
||||
f = StringW(f.getValue()+wcslen(ITUNES_FILENAME_HEADER)-1);
|
||||
else
|
||||
f = StringW(f.getValue()+wcslen(ITUNES_FILENAME_HEADER));
|
||||
// and then convert the slashes to backslashes
|
||||
wchar_t *p = f.getNonConstVal();
|
||||
while (p && *p) { if (*p == '/') *p = '\\'; p++; }
|
||||
}
|
||||
// oddly enough, iTunes XML library filenames have a trailing slash, go figure... and strip it!
|
||||
if (f.lastChar() == '\\') f.trunc((int)f.len()-1);
|
||||
else if (f.lastChar() == '/') f.trunc((int)f.len()-1); // if this is a url, there was no / to \ conversion
|
||||
// decode %XX
|
||||
Url::decode(f);
|
||||
}
|
||||
|
||||
static void Importer_AddKeyToItemRecord(int t, const plistString *data, itemRecordW &ir)
|
||||
{
|
||||
const wchar_t *strdata = data->getString();
|
||||
|
||||
// load this property into the appropriate gen_ml field
|
||||
switch (t)
|
||||
{
|
||||
case IT_TRACKID:
|
||||
// ignored
|
||||
break;
|
||||
case IT_NAME:
|
||||
ir.title = _wcsdup(strdata);
|
||||
break;
|
||||
case IT_ARTIST:
|
||||
ir.artist = _wcsdup(strdata);
|
||||
break;
|
||||
case IT_ALBUMARTIST:
|
||||
ir.albumartist = _wcsdup(strdata);
|
||||
break;
|
||||
case IT_ALBUM:
|
||||
ir.album = _wcsdup(strdata);
|
||||
break;
|
||||
case IT_GENRE:
|
||||
ir.genre = _wcsdup(strdata);
|
||||
break;
|
||||
case IT_COMMENTS:
|
||||
ir.comment = _wcsdup(strdata);
|
||||
break;
|
||||
case IT_KIND:
|
||||
// ignored
|
||||
break;
|
||||
case IT_LOCATION:
|
||||
{
|
||||
StringW f;
|
||||
FixPath(strdata, f);
|
||||
// done
|
||||
ir.filename = _wcsdup(f);
|
||||
break;
|
||||
}
|
||||
case IT_COMPOSER:
|
||||
ir.composer = _wcsdup(strdata);
|
||||
break;
|
||||
case IT_PUBLISHER:
|
||||
ir.publisher = _wcsdup(strdata);
|
||||
break;
|
||||
case IT_GROUPING:
|
||||
setRecordExtendedItem(&ir, L"category", strdata);
|
||||
break;
|
||||
case IT_PRODUCER:
|
||||
setRecordExtendedItem(&ir, L"producer", strdata);
|
||||
break;
|
||||
case IT_DIRECTOR:
|
||||
setRecordExtendedItem(&ir, L"director", strdata);
|
||||
break;
|
||||
case IT_PERSISTENT_ID:
|
||||
break;
|
||||
case IT_TRACK_TYPE:
|
||||
break;
|
||||
case IT_SORTNAME:
|
||||
break;
|
||||
case IT_SORTALBUM:
|
||||
break;
|
||||
case IT_SORTCOMPOSER:
|
||||
break;
|
||||
case IT_SORT_ALBUM_ARTIST:
|
||||
break;
|
||||
case IT_SORT_ARTIST:
|
||||
break;
|
||||
default:
|
||||
//DebugStringW(L"Unknown property: %s\n", prop->getName());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void Importer_AddKeyToItemRecord(int t, const plistInteger *data, itemRecordW &ir)
|
||||
{
|
||||
int64_t value = data->getValue();
|
||||
|
||||
/* benski> we need to keep the ones that were changed to plistBoolean,
|
||||
because old exported libraries will still be written with integers */
|
||||
|
||||
// load this property into the appropriate gen_ml field
|
||||
switch (t)
|
||||
{
|
||||
case IT_TRACKID:
|
||||
// ignore
|
||||
break;
|
||||
case IT_SIZE:
|
||||
ir.filesize = (int)(value >> 10);
|
||||
setRecordExtendedItem(&ir, L"realsize", data->getString());
|
||||
break;
|
||||
case IT_TOTALTIME:
|
||||
if (value)
|
||||
ir.length = (int)(value / 1000);
|
||||
break;
|
||||
case IT_TRACKNUM:
|
||||
ir.track = (int)value;
|
||||
break;
|
||||
case IT_TRACKCOUNT:
|
||||
if (value)
|
||||
ir.tracks = (int)value;
|
||||
break;
|
||||
case IT_YEAR:
|
||||
if (value)
|
||||
ir.year = (int)value;
|
||||
break;
|
||||
case IT_BITRATE:
|
||||
ir.bitrate = (int)value;
|
||||
break;
|
||||
case IT_SAMPLERATE:
|
||||
// ignored
|
||||
break;
|
||||
case IT_RATING:
|
||||
ir.rating = (int)(((double)value / 100.0) * 5.0);
|
||||
break;
|
||||
case IT_FOLDERCOUNT:
|
||||
// ignored
|
||||
break;
|
||||
case IT_LIBFOLDERCOUNT:
|
||||
// ignored
|
||||
break;
|
||||
case IT_PLAYCOUNT:
|
||||
if (value > 0)
|
||||
ir.playcount = (int)value;
|
||||
break;
|
||||
case IT_PLAYDATE:
|
||||
if (value)
|
||||
ir.lastplay = value;
|
||||
break;
|
||||
case IT_DISCNUMBER:
|
||||
if (value)
|
||||
ir.disc = (int)value;
|
||||
break;
|
||||
case IT_DISCCOUNT:
|
||||
if (value)
|
||||
ir.discs = (int)value;
|
||||
break;
|
||||
case IT_BPM:
|
||||
if (value)
|
||||
ir.bpm = (int)value;
|
||||
break;
|
||||
case IT_HAS_VIDEO:
|
||||
if (value == 1)
|
||||
ir.type = 1;
|
||||
break;
|
||||
case IT_ARTWORK_COUNT:
|
||||
break;
|
||||
case IT_VIDEO_WIDTH:
|
||||
setRecordExtendedItem(&ir, L"width", data->getString());
|
||||
break;
|
||||
case IT_VIDEO_HEIGHT:
|
||||
setRecordExtendedItem(&ir, L"height", data->getString());
|
||||
break;
|
||||
case IT_NORMALIZATION:
|
||||
// TODO: can we convert this to replay gain?
|
||||
break;
|
||||
case IT_SKIPCOUNT:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void Importer_AddKeyToItemRecord(int t, const plistBoolean *data, itemRecordW &ir)
|
||||
{
|
||||
int value = !!data->getValue();
|
||||
|
||||
// load this property into the appropriate gen_ml field
|
||||
switch (t)
|
||||
{
|
||||
case IT_HAS_VIDEO:
|
||||
ir.type = value;
|
||||
break;
|
||||
case IT_HD:
|
||||
break;
|
||||
case IT_MOVIE:
|
||||
break;
|
||||
case IT_PURCHASED:
|
||||
break;
|
||||
case IT_ITUNESU:
|
||||
break;
|
||||
case IT_PART_OF_GAPLESS_ALBUM:
|
||||
break;
|
||||
case IT_COMPILATION:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void Importer_AddKeyToItemRecord(int t, const plistDate *data, itemRecordW &ir)
|
||||
{
|
||||
time_t date_value= data->getDate();
|
||||
|
||||
// load this property into the appropriate gen_ml field
|
||||
switch (t)
|
||||
{
|
||||
case IT_DATEMODIFIED:
|
||||
if (date_value != -1)
|
||||
ir.filetime = date_value;
|
||||
break;
|
||||
case IT_DATEADDED:
|
||||
if (date_value != -1)
|
||||
ir.lastupd = date_value;
|
||||
break;
|
||||
case IT_PLAYDATE_UTC:
|
||||
if (date_value != -1)
|
||||
ir.lastplay = date_value;
|
||||
break;
|
||||
case IT_RELEASE_DATE:
|
||||
break;
|
||||
case IT_SKIPDATE:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Importer_AddKeyToItemRecord(const plistKey *prop, itemRecordW &ir)
|
||||
{
|
||||
const plistData *data = prop->getData();
|
||||
|
||||
if (data)
|
||||
{
|
||||
int t = itunesprops.getId(prop->getName());
|
||||
switch(data->getType())
|
||||
{
|
||||
case PLISTDATA_STRING:
|
||||
Importer_AddKeyToItemRecord(t, (const plistString *)data, ir);
|
||||
break;
|
||||
case PLISTDATA_INTEGER:
|
||||
Importer_AddKeyToItemRecord(t, (const plistInteger *)data, ir);
|
||||
break;
|
||||
case PLISTDATA_DATE:
|
||||
Importer_AddKeyToItemRecord(t, (const plistDate *)data, ir);
|
||||
break;
|
||||
case PLISTDATA_BOOLEAN:
|
||||
Importer_AddKeyToItemRecord(t, (const plistBoolean *)data, ir);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
66
Src/Plugins/Library/ml_impex/importer.h
Normal file
66
Src/Plugins/Library/ml_impex/importer.h
Normal file
@ -0,0 +1,66 @@
|
||||
#pragma once
|
||||
#include "../plist/types.h"
|
||||
#include "../../General/gen_ml/ml.h"
|
||||
|
||||
// header for local filenames
|
||||
#define ITUNES_FILENAME_HEADER L"file://localhost/"
|
||||
|
||||
enum
|
||||
{
|
||||
IT_TRACKID=0,
|
||||
IT_NAME,
|
||||
IT_ARTIST,
|
||||
IT_ALBUMARTIST,
|
||||
IT_ALBUM,
|
||||
IT_GENRE,
|
||||
IT_COMMENTS,
|
||||
IT_KIND,
|
||||
IT_SIZE,
|
||||
IT_TOTALTIME,
|
||||
IT_TRACKNUM,
|
||||
IT_TRACKCOUNT,
|
||||
IT_YEAR,
|
||||
IT_DATEMODIFIED,
|
||||
IT_DATEADDED,
|
||||
IT_BITRATE,
|
||||
IT_RATING,
|
||||
IT_SAMPLERATE,
|
||||
IT_LOCATION,
|
||||
IT_FOLDERCOUNT,
|
||||
IT_LIBFOLDERCOUNT,
|
||||
IT_PLAYCOUNT,
|
||||
IT_PLAYDATE,
|
||||
IT_PLAYDATE_UTC,
|
||||
IT_COMPOSER,
|
||||
IT_PUBLISHER,
|
||||
IT_DISCNUMBER,
|
||||
IT_DISCCOUNT,
|
||||
IT_BPM,
|
||||
IT_HAS_VIDEO,
|
||||
IT_GROUPING,
|
||||
IT_PRODUCER,
|
||||
IT_DIRECTOR,
|
||||
IT_ARTWORK_COUNT,
|
||||
IT_PERSISTENT_ID,
|
||||
IT_TRACK_TYPE,
|
||||
IT_HD,
|
||||
IT_VIDEO_WIDTH,
|
||||
IT_VIDEO_HEIGHT,
|
||||
IT_MOVIE,
|
||||
IT_RELEASE_DATE,
|
||||
IT_NORMALIZATION,
|
||||
IT_SORTNAME,
|
||||
IT_PURCHASED,
|
||||
IT_ITUNESU,
|
||||
IT_SKIPCOUNT,
|
||||
IT_SKIPDATE,
|
||||
IT_SORTALBUM,
|
||||
IT_SORTCOMPOSER,
|
||||
IT_PART_OF_GAPLESS_ALBUM,
|
||||
IT_COMPILATION,
|
||||
IT_SORT_ALBUM_ARTIST,
|
||||
IT_SORT_ARTIST,
|
||||
};
|
||||
void Importer_AddKeyToItemRecord(const plistKey *prop, itemRecordW &ir);
|
||||
int ImportPlaylists(HWND parent, const wchar_t *library_file);
|
||||
void setDialogIcon(HWND hwndDlg);
|
152
Src/Plugins/Library/ml_impex/itunesxmlwrite.cpp
Normal file
152
Src/Plugins/Library/ml_impex/itunesxmlwrite.cpp
Normal file
@ -0,0 +1,152 @@
|
||||
//------------------------------------------------------------------------
|
||||
//
|
||||
// iTunes XML Library Writer
|
||||
// Copyright <20> 2003-2014 Winamp SA
|
||||
//
|
||||
//------------------------------------------------------------------------
|
||||
|
||||
#include <windows.h>
|
||||
#include <commdlg.h>
|
||||
#include <api/xml/xmlwrite.h>
|
||||
#include <bfc/string/url.h>
|
||||
#include "itunesxmlwrite.h"
|
||||
#include "../plist/types.h"
|
||||
#include "api__ml_impex.h"
|
||||
#include "resource.h"
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
iTunesXmlWrite::iTunesXmlWrite() {
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
iTunesXmlWrite::~iTunesXmlWrite() {
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
int iTunesXmlWrite::pickFile(HWND hwndDlg, const wchar_t *title)
|
||||
{
|
||||
wchar_t oldCurPath[MAX_PATH] = {0};
|
||||
GetCurrentDirectoryW(MAX_PATH, oldCurPath);
|
||||
|
||||
OPENFILENAME l={sizeof(l),};
|
||||
wchar_t *temp;
|
||||
const int len=256*1024-128;
|
||||
|
||||
temp = (wchar_t *)GlobalAlloc(GPTR,len*sizeof(*temp));
|
||||
l.hwndOwner = hwndDlg;
|
||||
//l.lpstrFilter = L"iTunes XML Library\0*.xml\0\0"; // IDS_ITUNES_XML_LIBRARY
|
||||
extern wchar_t* GetFilterListString(void);
|
||||
l.lpstrFilter = GetFilterListString();//L"iTunes XML Library\0*.xml\0\0"; // IDS_ITUNES_XML_LIBRARY
|
||||
l.lpstrFile = temp;
|
||||
l.nMaxFile = len-1;
|
||||
l.lpstrTitle = title ? title : WASABI_API_LNGSTRINGW(IDS_EXPORT_DATABASE);
|
||||
l.lpstrDefExt = L"xml";
|
||||
l.lpstrInitialDir = WASABI_API_APP->path_getWorkingPath();
|
||||
l.Flags = OFN_HIDEREADONLY|OFN_EXPLORER|OFN_OVERWRITEPROMPT;
|
||||
if (GetSaveFileName(&l))
|
||||
{
|
||||
wchar_t newCurPath[MAX_PATH] = {0};
|
||||
GetCurrentDirectoryW(MAX_PATH, newCurPath);
|
||||
WASABI_API_APP->path_setWorkingPath(newCurPath);
|
||||
SetCurrentDirectoryW(oldCurPath);
|
||||
file = temp;
|
||||
return 1;
|
||||
}
|
||||
SetCurrentDirectoryW(oldCurPath);
|
||||
return 0;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void iTunesXmlWrite::saveXml(plistKey *rootkey) {
|
||||
if (file.isempty()) return;
|
||||
XMLWrite w(file, L"plist version=\"1.0\"", L"plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\"", 1);
|
||||
writeData(&w, rootkey->getData());
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void iTunesXmlWrite::writeData(XMLWrite *writer, plistData *data)
|
||||
{
|
||||
switch (data->getType())
|
||||
{
|
||||
case PLISTDATA_KEY:
|
||||
{
|
||||
plistKey *key = (plistKey *)data;
|
||||
writer->writeAttrib(data->getTypeString(), data->getString(), key->getData()->getType() == PLISTDATA_DICT || key->getData()->getType() == PLISTDATA_ARRAY || key->getData()->getType() == PLISTDATA_RAW);
|
||||
writeData(writer, key->getData());
|
||||
break;
|
||||
}
|
||||
case PLISTDATA_DICT:
|
||||
{
|
||||
plistDict *dict = (plistDict *)data;
|
||||
writer->pushCategory(data->getTypeString());
|
||||
for (int i=0;i<dict->getNumKeys();i++)
|
||||
{
|
||||
writeData(writer, dict->enumKey(i));
|
||||
}
|
||||
writer->popCategory();
|
||||
break;
|
||||
}
|
||||
case PLISTDATA_ARRAY:
|
||||
{
|
||||
plistArray *array = (plistArray *)data;
|
||||
writer->pushCategory(data->getTypeString());
|
||||
for (int i=0;i<array->getNumItems();i++) {
|
||||
writeData(writer, array->enumItem(i));
|
||||
}
|
||||
writer->popCategory();
|
||||
break;
|
||||
}
|
||||
case PLISTDATA_INTEGER:
|
||||
case PLISTDATA_DATE:
|
||||
case PLISTDATA_RAW:
|
||||
{
|
||||
const wchar_t *str = data->getString();
|
||||
if (str && *str)
|
||||
{
|
||||
writer->writeAttrib(data->getTypeString(), str, 1, 0);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case PLISTDATA_STRING:
|
||||
{
|
||||
const wchar_t *str = data->getString();
|
||||
if (str && *str)
|
||||
{
|
||||
// not pretty but it'll strip out control characters
|
||||
// in the 0 - 31 range that will cause import issues
|
||||
wchar_t *temp = 0;
|
||||
int len = (int)wcslen(str) + 1;
|
||||
temp = (wchar_t*)calloc(len, sizeof(wchar_t));
|
||||
wchar_t *ptr = temp;
|
||||
while(str && *str)
|
||||
{
|
||||
int chr = *str;
|
||||
if (chr >= 0 && chr <= 31)
|
||||
{
|
||||
if(chr == 9 || chr == 10 || chr == 13)
|
||||
{
|
||||
*ptr = *str;
|
||||
ptr++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
*ptr = *str;
|
||||
ptr++;
|
||||
}
|
||||
str = CharNextW(str);
|
||||
}
|
||||
*ptr=0;
|
||||
writer->writeAttrib(data->getTypeString(), (temp ? temp : str), 1, 0);
|
||||
if (temp) free(temp);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case PLISTDATA_BOOLEAN:
|
||||
{
|
||||
//plistBoolean *booldata = (plistBoolean *)data;
|
||||
writer->writeAttribEmpty(data->getString(), 1, 0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
33
Src/Plugins/Library/ml_impex/itunesxmlwrite.h
Normal file
33
Src/Plugins/Library/ml_impex/itunesxmlwrite.h
Normal file
@ -0,0 +1,33 @@
|
||||
//------------------------------------------------------------------------
|
||||
//
|
||||
// iTunes XML Library Writer
|
||||
// Copyright <20> 2003-2014 Winamp SA
|
||||
//
|
||||
//------------------------------------------------------------------------
|
||||
|
||||
#ifndef _ITUNESXMLWRITE_H
|
||||
#define _ITUNESXMLWRITE_H
|
||||
|
||||
class plistKey;
|
||||
class XMLWrite;
|
||||
class plistData;
|
||||
#include <bfc/string/stringw.h>
|
||||
//------------------------------------------------------------------------
|
||||
|
||||
class iTunesXmlWrite {
|
||||
public:
|
||||
iTunesXmlWrite();
|
||||
virtual ~iTunesXmlWrite();
|
||||
|
||||
int pickFile(HWND hwndDlg, const wchar_t *title=NULL);
|
||||
void saveXml(plistKey *rootkey);
|
||||
|
||||
void writeData(XMLWrite *writer, plistData *data);
|
||||
|
||||
private:
|
||||
StringW file;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------------------------
|
144
Src/Plugins/Library/ml_impex/ml_impex.rc
Normal file
144
Src/Plugins/Library/ml_impex/ml_impex.rc
Normal file
@ -0,0 +1,144 @@
|
||||
// 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
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Dialog
|
||||
//
|
||||
|
||||
IDD_INFODIALOG DIALOGEX 0, 0, 188, 47
|
||||
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
|
||||
FONT 8, "MS Shell Dlg", 0, 0, 0x0
|
||||
BEGIN
|
||||
CONTROL "Progress1",IDC_PROGRESS_PERCENT,"msctls_progress32",PBS_SMOOTH | NOT WS_VISIBLE | WS_BORDER,7,7,174,12
|
||||
CTEXT "",IDC_TRACKS,7,27,174,8,NOT WS_VISIBLE
|
||||
CTEXT "",IDC_PROCESSING_STATE,35,19,117,8
|
||||
END
|
||||
|
||||
IDD_EXPORTTYPE DIALOGEX 0, 0, 229, 71
|
||||
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
|
||||
CAPTION "Unsupported File Formats"
|
||||
FONT 8, "MS Shell Dlg", 0, 0, 0x0
|
||||
BEGIN
|
||||
LTEXT "Some files in your database are not supported by iTunes.",IDC_STATIC,9,11,184,8
|
||||
CONTROL "Export all files anyway.",IDC_RADIO_ALLFILES,"Button",BS_AUTORADIOBUTTON | WS_GROUP | WS_TABSTOP,15,24,91,10
|
||||
CONTROL "Export only files supported by iTunes (mp3/aac/wav/aiff).",IDC_RADIO_ONLYSUPPORTED,
|
||||
"Button",BS_AUTORADIOBUTTON | WS_TABSTOP,15,35,201,10
|
||||
DEFPUSHBUTTON "OK",IDOK,172,50,50,14
|
||||
END
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// DESIGNINFO
|
||||
//
|
||||
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
GUIDELINES DESIGNINFO
|
||||
BEGIN
|
||||
IDD_INFODIALOG, DIALOG
|
||||
BEGIN
|
||||
LEFTMARGIN, 7
|
||||
RIGHTMARGIN, 181
|
||||
TOPMARGIN, 7
|
||||
BOTTOMMARGIN, 40
|
||||
END
|
||||
|
||||
IDD_EXPORTTYPE, DIALOG
|
||||
BEGIN
|
||||
LEFTMARGIN, 7
|
||||
RIGHTMARGIN, 222
|
||||
TOPMARGIN, 7
|
||||
BOTTOMMARGIN, 64
|
||||
END
|
||||
END
|
||||
#endif // APSTUDIO_INVOKED
|
||||
|
||||
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// TEXTINCLUDE
|
||||
//
|
||||
|
||||
1 TEXTINCLUDE
|
||||
BEGIN
|
||||
"resource.h\0"
|
||||
END
|
||||
|
||||
2 TEXTINCLUDE
|
||||
BEGIN
|
||||
"#include ""afxres.h""\r\n"
|
||||
"\0"
|
||||
END
|
||||
|
||||
3 TEXTINCLUDE
|
||||
BEGIN
|
||||
"#include ""version.rc2""\r\n"
|
||||
"\0"
|
||||
END
|
||||
|
||||
#endif // APSTUDIO_INVOKED
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// String Table
|
||||
//
|
||||
|
||||
STRINGTABLE
|
||||
BEGIN
|
||||
IDS_ML_IMPEX_DESC "Nullsoft Database Import / Export v%s"
|
||||
65535 "{22661553-8D22-4012-8D3B-0FF8FE57A9ED}"
|
||||
END
|
||||
|
||||
STRINGTABLE
|
||||
BEGIN
|
||||
IDS_IMPORT_DATABASE "Import Media Database..."
|
||||
IDS_EXPORT_DATABASE "Export Media Database..."
|
||||
IDS_TRACKS_IMPORTED_X "Tracks imported : %d"
|
||||
IDS_TRACKS_EXPORTED_X "Tracks exported : %d"
|
||||
IDS_ITUNES_XML_LIBRARY "iTunes XML Library"
|
||||
IDS_LOADING_XML "Loading XML..."
|
||||
IDS_WRITINGING_XML "Writing XML..."
|
||||
IDS_IMPORTING_DATABASE "Importing Database"
|
||||
IDS_EXPORTING_DATABASE "Exporting Database"
|
||||
IDS_IMPORT_ITUNES_DB "Import iTunes Library"
|
||||
IDS_IMPORT_ITUNES_PL "Import iTunes Playlists"
|
||||
END
|
||||
|
||||
#endif // English (U.S.) resources
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
#ifndef APSTUDIO_INVOKED
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Generated from the TEXTINCLUDE 3 resource.
|
||||
//
|
||||
#include "version.rc2"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
#endif // not APSTUDIO_INVOKED
|
||||
|
50
Src/Plugins/Library/ml_impex/ml_impex.sln
Normal file
50
Src/Plugins/Library/ml_impex/ml_impex.sln
Normal file
@ -0,0 +1,50 @@
|
||||
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_impex", "ml_impex.vcxproj", "{DDD08D55-B0E6-4070-9C67-39B495A0B4ED}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bfc", "..\Wasabi\bfc\bfc.vcxproj", "{D0EC862E-DDDD-4F4F-934F-B75DC9062DC1}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "plist", "..\plist\plist.vcxproj", "{5ED1729B-EA41-4163-9506-741A8B76F625}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Win32 = Debug|Win32
|
||||
Release|Win32 = Release|Win32
|
||||
Debug|x64 = Debug|x64
|
||||
Release|x64 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{DDD08D55-B0E6-4070-9C67-39B495A0B4ED}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{DDD08D55-B0E6-4070-9C67-39B495A0B4ED}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{DDD08D55-B0E6-4070-9C67-39B495A0B4ED}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{DDD08D55-B0E6-4070-9C67-39B495A0B4ED}.Debug|x64.Build.0 = Debug|x64
|
||||
{DDD08D55-B0E6-4070-9C67-39B495A0B4ED}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{DDD08D55-B0E6-4070-9C67-39B495A0B4ED}.Release|Win32.Build.0 = Release|Win32
|
||||
{DDD08D55-B0E6-4070-9C67-39B495A0B4ED}.Release|x64.ActiveCfg = Release|x64
|
||||
{DDD08D55-B0E6-4070-9C67-39B495A0B4ED}.Release|x64.Build.0 = Release|x64
|
||||
{D0EC862E-DDDD-4F4F-934F-B75DC9062DC1}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{D0EC862E-DDDD-4F4F-934F-B75DC9062DC1}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{D0EC862E-DDDD-4F4F-934F-B75DC9062DC1}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{D0EC862E-DDDD-4F4F-934F-B75DC9062DC1}.Debug|x64.Build.0 = Debug|x64
|
||||
{D0EC862E-DDDD-4F4F-934F-B75DC9062DC1}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{D0EC862E-DDDD-4F4F-934F-B75DC9062DC1}.Release|Win32.Build.0 = Release|Win32
|
||||
{D0EC862E-DDDD-4F4F-934F-B75DC9062DC1}.Release|x64.ActiveCfg = Release|x64
|
||||
{D0EC862E-DDDD-4F4F-934F-B75DC9062DC1}.Release|x64.Build.0 = Release|x64
|
||||
{5ED1729B-EA41-4163-9506-741A8B76F625}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{5ED1729B-EA41-4163-9506-741A8B76F625}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{5ED1729B-EA41-4163-9506-741A8B76F625}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{5ED1729B-EA41-4163-9506-741A8B76F625}.Debug|x64.Build.0 = Debug|x64
|
||||
{5ED1729B-EA41-4163-9506-741A8B76F625}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{5ED1729B-EA41-4163-9506-741A8B76F625}.Release|Win32.Build.0 = Release|Win32
|
||||
{5ED1729B-EA41-4163-9506-741A8B76F625}.Release|x64.ActiveCfg = Release|x64
|
||||
{5ED1729B-EA41-4163-9506-741A8B76F625}.Release|x64.Build.0 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {1C93F5AD-DB79-444D-A5CE-58652C31D19F}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
317
Src/Plugins/Library/ml_impex/ml_impex.vcxproj
Normal file
317
Src/Plugins/Library/ml_impex/ml_impex.vcxproj
Normal file
@ -0,0 +1,317 @@
|
||||
<?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>{DDD08D55-B0E6-4070-9C67-39B495A0B4ED}</ProjectGuid>
|
||||
<RootNamespace>ml_impex</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>10.0.19041.0</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|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>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|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;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>_WIN32_WINNT=0x0601;WINVER=0x0601;WIN32;_DEBUG;_WINDOWS;_USRDLL;ML_IMPEX_EXPORTS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<MinimalRebuild>false</MinimalRebuild>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
|
||||
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
|
||||
<TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
|
||||
<ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
<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>%(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>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<AdditionalIncludeDirectories>..\..\..\Wasabi;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>_WIN32_WINNT=0x0601;WINVER=0x0601;WIN64;_DEBUG;_WINDOWS;_USRDLL;ML_IMPEX_EXPORTS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<MinimalRebuild>false</MinimalRebuild>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
|
||||
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
|
||||
<TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
|
||||
<ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
<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>%(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>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<Optimization>MinSpace</Optimization>
|
||||
<FavorSizeOrSpeed>Size</FavorSizeOrSpeed>
|
||||
<AdditionalIncludeDirectories>..\..\..\Wasabi;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>_WIN32_WINNT=0x0601;WINVER=0x0601;WIN32;NDEBUG;_WINDOWS;_USRDLL;ML_IMPEX_EXPORTS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<StringPooling>true</StringPooling>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
|
||||
<BufferSecurityCheck>true</BufferSecurityCheck>
|
||||
<TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
|
||||
<ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<DebugInformationFormat>None</DebugInformationFormat>
|
||||
<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>
|
||||
<ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
|
||||
<AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
</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;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>_WIN32_WINNT=0x0601;WINVER=0x0601;WIN64;NDEBUG;_WINDOWS;_USRDLL;ML_IMPEX_EXPORTS;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<StringPooling>true</StringPooling>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
|
||||
<BufferSecurityCheck>true</BufferSecurityCheck>
|
||||
<TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
|
||||
<ForceConformanceInForLoopScope>true</ForceConformanceInForLoopScope>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<DebugInformationFormat>None</DebugInformationFormat>
|
||||
<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>
|
||||
<ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
|
||||
<AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
</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="..\..\..\plist\plist.vcxproj">
|
||||
<Project>{5ed1729b-ea41-4163-9506-741a8b76f625}</Project>
|
||||
<CopyLocalSatelliteAssemblies>true</CopyLocalSatelliteAssemblies>
|
||||
<ReferenceOutputAssembly>true</ReferenceOutputAssembly>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\..\Wasabi\bfc\bfc.vcxproj">
|
||||
<Project>{d0ec862e-dddd-4f4f-934f-b75dc9062dc1}</Project>
|
||||
<CopyLocalSatelliteAssemblies>true</CopyLocalSatelliteAssemblies>
|
||||
<ReferenceOutputAssembly>true</ReferenceOutputAssembly>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\..\..\Wasabi\Wasabi.vcxproj">
|
||||
<Project>{3e0bfa8a-b86a-42e9-a33f-ec294f823f7f}</Project>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\..\General\gen_ml\ml_lib.cpp" />
|
||||
<ClCompile Include="impex.cpp" />
|
||||
<ClCompile Include="importer.cpp" />
|
||||
<ClCompile Include="ImporterAPI.cpp" />
|
||||
<ClCompile Include="ImportPlaylists.cpp" />
|
||||
<ClCompile Include="itunesxmlwrite.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="api__ml_impex.h" />
|
||||
<ClInclude Include="api_importer.h" />
|
||||
<ClInclude Include="importer.h" />
|
||||
<ClInclude Include="ImporterAPI.h" />
|
||||
<ClInclude Include="itunesxmlwrite.h" />
|
||||
<ClInclude Include="resource.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="ml_impex.rc" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
62
Src/Plugins/Library/ml_impex/ml_impex.vcxproj.filters
Normal file
62
Src/Plugins/Library/ml_impex/ml_impex.vcxproj.filters
Normal file
@ -0,0 +1,62 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<ClCompile Include="impex.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="importer.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ImporterAPI.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ImportPlaylists.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="itunesxmlwrite.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\General\gen_ml\ml_lib.cpp">
|
||||
<Filter>Source Files\gen_ml</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="api__ml_impex.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="api_importer.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="importer.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="ImporterAPI.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="itunesxmlwrite.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="resource.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{367262fe-81b8-41c9-a013-150093098f81}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Ressource Files">
|
||||
<UniqueIdentifier>{91f9aff7-f6fc-45c6-9c44-88bf5ec938ce}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{a20e93fc-10cf-4f90-b11f-2e91d427b1b1}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Source Files\gen_ml">
|
||||
<UniqueIdentifier>{5957e24d-fc45-47d0-8c55-b6a758580b36}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="ml_impex.rc">
|
||||
<Filter>Ressource Files</Filter>
|
||||
</ResourceCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
37
Src/Plugins/Library/ml_impex/resource.h
Normal file
37
Src/Plugins/Library/ml_impex/resource.h
Normal file
@ -0,0 +1,37 @@
|
||||
//{{NO_DEPENDENCIES}}
|
||||
// Microsoft Visual C++ generated include file.
|
||||
// Used by ml_impex.rc
|
||||
//
|
||||
#define IDS_IMPORT_DATABASE 1
|
||||
#define IDS_EXPORT_DATABASE 2
|
||||
#define IDS_TRACKS_IMPORTED_X 3
|
||||
#define IDS_TRACKS_EXPORTED_X 4
|
||||
#define IDS_ITUNES_XML_LIBRARY 5
|
||||
#define IDS_LOADING_XML 6
|
||||
#define IDS_WRITINGING_XML 7
|
||||
#define IDS_IMPORTING_DATABASE 8
|
||||
#define IDS_EXPORTING_DATABASE 9
|
||||
#define IDS_IMPORT_ITUNES_DB 10
|
||||
#define IDS_IMPORT_ITUNES_PL 11
|
||||
#define IDD_IMPORT 102
|
||||
#define IDD_INFODIALOG 102
|
||||
#define IDD_EXPORTTYPE 104
|
||||
#define IDC_TRACKS 1000
|
||||
#define IDC_PROGRESS_PERCENT 1001
|
||||
#define IDC_LOADING 1002
|
||||
#define IDC_PROCESSING_STATE 1002
|
||||
#define IDC_WRITING 1003
|
||||
#define IDC_RADIO_ONLYSUPPORTED 1004
|
||||
#define IDC_RADIO_ALLFILES 1005
|
||||
#define IDS_ML_IMPEX_DESC 65534
|
||||
|
||||
// Next default values for new objects
|
||||
//
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
#ifndef APSTUDIO_READONLY_SYMBOLS
|
||||
#define _APS_NEXT_RESOURCE_VALUE 109
|
||||
#define _APS_NEXT_COMMAND_VALUE 40001
|
||||
#define _APS_NEXT_CONTROL_VALUE 1007
|
||||
#define _APS_NEXT_SYMED_VALUE 101
|
||||
#endif
|
||||
#endif
|
39
Src/Plugins/Library/ml_impex/version.rc2
Normal file
39
Src/Plugins/Library/ml_impex/version.rc2
Normal file
@ -0,0 +1,39 @@
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Version
|
||||
//
|
||||
#include "../../../Winamp/buildType.h"
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 2,65,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", "2,65,0,0"
|
||||
VALUE "InternalName", "Nullsoft Database Import / Export"
|
||||
VALUE "LegalCopyright", "Copyright <20> 2009-2023 Winamp SA"
|
||||
VALUE "LegalTrademarks", "Nullsoft and Winamp are trademarks of Winamp SA"
|
||||
VALUE "OriginalFilename", "ml_impex.dll"
|
||||
VALUE "ProductName", "Winamp"
|
||||
VALUE "ProductVersion", STR_WINAMP_PRODUCTVER
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
BEGIN
|
||||
VALUE "Translation", 0x409, 1200
|
||||
END
|
||||
END
|
Reference in New Issue
Block a user