winamp/Src/Plugins/Library/ml_history/Main.cpp

349 lines
9.5 KiB
C++

#include "api__ml_history.h"
#include "main.h"
#include "..\..\General\gen_ml/config.h"
#include "HistoryAPIFactory.h"
#include "JSAPI2_Creator.h"
#include "..\..\General\gen_ml/ml_ipc_0313.h"
#include "../nu/AutoCharFn.h"
#include <strsafe.h>
#define LOCAL_WRITE_VER L"2.03"
// wasabi based services for localisation support
api_language *WASABI_API_LNG = 0;
api_explorerfindfile *WASABI_API_EXPLORERFINDFILE = 0;
JSAPI2::api_security *AGAVE_API_JSAPI2_SECURITY = 0;
api_application *WASABI_API_APP=0;
HINSTANCE WASABI_API_LNG_HINST = 0, WASABI_API_ORIG_HINST = 0;
static HistoryAPIFactory historyAPIFactory;
static JSAPI2Factory jsapi2Factory;
static int Init();
static void Quit();
static INT_PTR MessageProc(int message_type, INT_PTR param1, INT_PTR param2, INT_PTR param3);
prefsDlgRecW preferences = {0};
wchar_t g_tableDir[MAX_PATH] = {0};
extern "C" winampMediaLibraryPlugin plugin =
{
MLHDR_VER,
"nullsoft(ml_history.dll)",
Init,
Quit,
MessageProc,
0,
0,
0,
};
// Delay load library control << begin >>
#include <delayimp.h>
#pragma comment(lib, "delayimp")
bool nde_error = false;
FARPROC WINAPI FailHook(unsigned dliNotify, PDelayLoadInfo pdli)
{
nde_error = true;
return 0;
}
/*
extern "C"
{
PfnDliHook __pfnDliFailureHook2 = FailHook;
}
*/
// Delay load library control << end >>
int Init()
{
InitializeCriticalSection(&g_db_cs);
g_db = NULL;
g_table = NULL;
mediaLibrary.library = plugin.hwndLibraryParent;
mediaLibrary.winamp = plugin.hwndWinampParent;
mediaLibrary.instance = plugin.hDllInstance;
wchar_t configName[ MAX_PATH ] = { 0 };
const wchar_t *dir = mediaLibrary.GetIniDirectoryW();
if ( (INT_PTR)( dir ) < 65536 )
return ML_INIT_FAILURE;
PathCombineW( g_tableDir, dir, L"Plugins" );
PathCombineW( configName, g_tableDir, L"gen_ml.ini" );
g_config = new C_Config( configName );
CreateDirectoryW( g_tableDir, NULL );
PathCombineW( g_tableDir, g_tableDir, L"ml" );
CreateDirectoryW( g_tableDir, NULL );
// loader so that we can get the localisation service api for use
waServiceFactory *sf = plugin.service->service_getServiceByGuid( languageApiGUID );
if ( sf )
WASABI_API_LNG = reinterpret_cast<api_language *>( sf->getInterface() );
sf = plugin.service->service_getServiceByGuid( JSAPI2::api_securityGUID );
if ( sf )
AGAVE_API_JSAPI2_SECURITY = reinterpret_cast<JSAPI2::api_security *>( sf->getInterface() );
sf = plugin.service->service_getServiceByGuid( applicationApiServiceGuid );
if ( sf )
WASABI_API_APP = reinterpret_cast<api_application *>( sf->getInterface() );
sf = plugin.service->service_getServiceByGuid( ExplorerFindFileApiGUID );
if ( sf )
WASABI_API_EXPLORERFINDFILE = reinterpret_cast<api_explorerfindfile *>( sf->getInterface() );
plugin.service->service_register( &historyAPIFactory );
plugin.service->service_register( &jsapi2Factory );
// need to have this initialised before we try to do anything with localisation features
WASABI_API_START_LANG( plugin.hDllInstance, MlHistoryLangGUID );
g_context_menus2 = WASABI_API_LOADMENUW(IDR_CONTEXTMENUS);
static wchar_t szDescription[256];
StringCchPrintfW( szDescription, ARRAYSIZE( szDescription ), WASABI_API_LNGSTRINGW( IDS_NULLSOFT_HISTORY ), LOCAL_WRITE_VER );
plugin.description = (char*)szDescription;
static wchar_t preferencesName[64] = {0};
preferences.hInst = WASABI_API_LNG_HINST;
preferences.dlgID = IDD_PREFS;
preferences.proc = (void *)PrefsProc;
preferences.name = WASABI_API_LNGSTRINGW_BUF( IDS_HISTORY, preferencesName, 64 );
preferences.where = 6; // media library
SENDWAIPC( plugin.hwndWinampParent, IPC_ADD_PREFS_DLGW, &preferences );
if ( !history_init() )
return ML_INIT_FAILURE;
return ML_INIT_SUCCESS;
}
void Quit()
{
plugin.service->service_deregister(&historyAPIFactory);
plugin.service->service_deregister(&jsapi2Factory);
history_quit();
delete g_config;
DeleteCriticalSection(&g_db_cs);
waServiceFactory *sf = plugin.service->service_getServiceByGuid(languageApiGUID);
if (sf) sf->releaseInterface(WASABI_API_LNG);
sf = plugin.service->service_getServiceByGuid(JSAPI2::api_securityGUID);
if (sf) sf->releaseInterface(AGAVE_API_JSAPI2_SECURITY);
}
static INT_PTR History_OnContextMenu(INT_PTR param1, HWND hHost, POINTS pts)
{
HNAVITEM hItem = (HNAVITEM)param1;
HNAVITEM myItem = MLNavCtrl_FindItemById(plugin.hwndLibraryParent, ml_history_tree);
if (hItem != myItem)
return FALSE;
POINT pt;
POINTSTOPOINT(pt, pts);
if (-1 == pt.x || -1 == pt.y)
{
NAVITEMGETRECT itemRect;
itemRect.fItem = FALSE;
itemRect.hItem = hItem;
if (MLNavItem_GetRect(plugin.hwndLibraryParent, &itemRect))
{
MapWindowPoints(hHost, HWND_DESKTOP, (POINT*)&itemRect.rc, 2);
pt.x = itemRect.rc.left + 2;
pt.y = itemRect.rc.top + 2;
}
}
HMENU hMenu = WASABI_API_LOADMENUW(IDR_CONTEXTMENUS);
HMENU subMenu = (NULL != hMenu) ? GetSubMenu(hMenu, 1) : NULL;
if (NULL != subMenu)
{
INT r = Menu_TrackPopup(plugin.hwndLibraryParent, subMenu,
TPM_LEFTALIGN | TPM_TOPALIGN | TPM_NONOTIFY |
TPM_RETURNCMD | TPM_RIGHTBUTTON | TPM_LEFTBUTTON,
pt.x, pt.y, hHost, NULL);
switch(r)
{
case ID_NAVIGATION_PREFERENCES:
SENDWAIPC(plugin.hwndWinampParent, IPC_OPENPREFSTOPAGE, &preferences);
break;
case ID_NAVIGATION_HELP:
SENDWAIPC(plugin.hwndWinampParent, IPC_OPEN_URL, L"https://help.winamp.com/hc/articles/8105304048660-The-Winamp-Media-Library");
break;
}
}
if (NULL != hMenu)
DestroyMenu(hMenu);
return TRUE;
}
void History_StartTracking(const wchar_t *filename, bool resume)
{
KillTimer(plugin.hwndWinampParent, 8082);
if (!resume)
{
free(history_fn);
history_fn = 0;
history_fn_mode = 0;
if (wcsstr(filename, L"://") && _wcsnicmp(filename, L"cda://", 6) && _wcsnicmp(filename, L"file://", 7))
{
history_fn_mode = 1;
}
history_fn = _wcsdup(filename);
}
int timer1 = -1, timer2 = -1, timer3 = -1;
// wait for x seconds
if(g_config->ReadInt(L"recent_wait_secs",0))
{
timer1 = g_config->ReadInt(L"recent_wait_secs_lim",5)*1000;
}
// wait for x percent of the song (approx to a second)
if(g_config->ReadInt(L"recent_wait_percent",0))
{
basicFileInfoStructW bfiW = {0};
bfiW.filename = history_fn;
SendMessage(plugin.hwndWinampParent, WM_WA_IPC, (WPARAM)&bfiW, IPC_GET_BASIC_FILE_INFOW);
if(bfiW.length > 0)
{
bfiW.length=bfiW.length*1000;
timer2 = (bfiW.length*g_config->ReadInt(L"recent_wait_percent_lim",50))/100;
}
}
// wait for the end of the item (within the last second of the track hopefully)
if(g_config->ReadInt(L"recent_wait_end",0))
{
basicFileInfoStructW bfiW = {0};
bfiW.filename = history_fn;
SendMessage(plugin.hwndWinampParent, WM_WA_IPC, (WPARAM)&bfiW, IPC_GET_BASIC_FILE_INFOW);
if(bfiW.length > 0)
{
timer3=(bfiW.length-1)*1000;
}
}
// decide on which playback option will be the prefered duration (smallest wins)
if(timer1 != -1 && timer2 != -1)
{
if(timer1 > timer2)
{
timer = timer2;
}
if(timer2 > timer1)
{
timer = timer1;
}
}
else if(timer1 == -1 && timer2 != -1)
{
timer = timer2;
}
else if(timer2 == -1 && timer1 != -1)
{
timer = timer1;
}
// only track on end of file as very last method
if((timer <= 0) && (timer3 > 0)){ timer = timer3; }
// if no match or something went wrong then try to ensure the default timer value is used
SetTimer(plugin.hwndWinampParent, 8082, ((timer > 0)? timer : 350), NULL);
}
INT_PTR MessageProc(int message_type, INT_PTR param1, INT_PTR param2, INT_PTR param3)
{
switch (message_type)
{
case ML_MSG_TREE_ONCREATEVIEW: // param1 = param of tree item, param2 is HWND of parent. return HWND if it is us
return (param1 == ml_history_tree) ? (INT_PTR)onTreeViewSelectChange((HWND)param2) : 0;
case ML_MSG_CONFIG:
mediaLibrary.GoToPreferences((int)preferences._id);
return TRUE;
case ML_MSG_VIEW_PLAY_ENQUEUE_CHANGE:
enqueuedef = (int)param1;
groupBtn = (int)param2;
PostMessage(m_curview_hwnd, WM_APP + 104, param1, param2);
return 0;
case ML_MSG_NAVIGATION_CONTEXTMENU:
return History_OnContextMenu(param1, (HWND)param2, MAKEPOINTS(param3));
case ML_MSG_PLAYING_FILE:
if (param1)
{
int resume = g_config->ReadInt(L"resumeplayback",0);
if(resume)
{
int is_playing = (int)SendMessage(plugin.hwndWinampParent, WM_WA_IPC, 0, IPC_ISPLAYING);
//int play_pos = SendMessage(plugin.hwndWinampParent,WM_WA_IPC,0,IPC_GETOUTPUTTIME);
if(is_playing == 1/* && !(play_pos/1000 > 0)*/) //playing, look up last play offset and send seek message
{
wchar_t genre[256]={0};
extendedFileInfoStructW efis={
(wchar_t*)param1,
L"genre",
genre,
ARRAYSIZE(genre),
};
SendMessage(plugin.hwndWinampParent,WM_WA_IPC,(WPARAM)&efis,IPC_GET_EXTENDED_FILE_INFOW);
wchar_t ispodcast[8]={0};
extendedFileInfoStructW efis1={
(wchar_t*)param1,
L"ispodcast",
ispodcast,
ARRAYSIZE(ispodcast),
};
SendMessage(plugin.hwndWinampParent,WM_WA_IPC,(WPARAM)&efis1,IPC_GET_EXTENDED_FILE_INFOW_HOOKABLE);
if (resume == 2 || (ispodcast[0] && _wtoi(ispodcast) > 0) || (genre[0] && !_wcsicmp(genre, L"podcast")))
{
int offset = retrieve_offset((wchar_t*)param1);
if (offset > 0 && (offset/1000 > 0)) PostMessage(plugin.hwndWinampParent,WM_WA_IPC,offset,IPC_JUMPTOTIME);
}
}
}
History_StartTracking((const wchar_t *)param1, false);
}
break;
case ML_MSG_WRITE_CONFIG:
if(param1)
{
closeDb();
openDb();
}
break;
}
return 0;
}
extern "C" __declspec(dllexport) winampMediaLibraryPlugin *winampGetMediaLibraryPlugin()
{
return &plugin;
}