mirror of
https://github.com/chibicitiberiu/rainmeter-studio.git
synced 2024-02-24 04:33:31 +00:00
NowPlayingPlugin:
- Added preliminary support to display lyrics (PlayerType=LYRICS) - Applied r825 fix on TrackChangeAction= (sends bang to correct window without the need of #CURRENTCONFIG#) - Some refactoring
This commit is contained in:
parent
6aa004eb22
commit
d633f4b586
@ -19,76 +19,25 @@
|
||||
#include "StdAfx.h"
|
||||
#include "Cover.h"
|
||||
|
||||
extern std::wstring g_CachePath;
|
||||
|
||||
/*
|
||||
** GetCover
|
||||
**
|
||||
** Default implementation for getting cover.
|
||||
**
|
||||
*/
|
||||
void CCover::GetCover(const std::wstring& artist, const std::wstring& title, const std::wstring& file, std::wstring& target)
|
||||
{
|
||||
if (!GetCachedCover(artist, title, target))
|
||||
{
|
||||
TagLib::FileRef fr(file.c_str());
|
||||
if (fr.isNull() || !fr.tag() || !GetEmbeddedCover(fr, target))
|
||||
{
|
||||
std::wstring trackFolder = GetFileFolder(file);
|
||||
|
||||
if (!GetLocalCover(L"cover", trackFolder, target) &&
|
||||
!GetLocalCover(L"folder", trackFolder, target))
|
||||
{
|
||||
// Nothing found
|
||||
target.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** GetCachedArt
|
||||
** GetCached
|
||||
**
|
||||
** Checks if cover art is in cache.
|
||||
**
|
||||
*/
|
||||
bool CCover::GetCachedCover(const std::wstring& artist, const std::wstring& title, std::wstring& target)
|
||||
bool CCover::GetCached(std::wstring& path)
|
||||
{
|
||||
target = g_CachePath;
|
||||
if (artist.empty() || title.empty())
|
||||
{
|
||||
target += L"temp.art";
|
||||
}
|
||||
else
|
||||
{
|
||||
// Otherwise, save it as "Artist - Title.art"
|
||||
std::wstring name = artist;
|
||||
name += L" - ";
|
||||
name += title;
|
||||
|
||||
// Replace reserved chars with _
|
||||
std::wstring::size_type pos = 0;
|
||||
while ((pos = name.find_first_of(L"\\/:*?\"<>|", pos)) != std::wstring::npos) name[pos] = L'_';
|
||||
|
||||
target += name;
|
||||
target += L".art";
|
||||
if (_waccess(target.c_str(), 0) == 0)
|
||||
{
|
||||
// Art found in cache
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
path += L".art";
|
||||
return (_waccess(path.c_str(), 0) == 0) ? true : false;
|
||||
}
|
||||
|
||||
/*
|
||||
** GetLocalArt
|
||||
** GetLocal
|
||||
**
|
||||
** Attemps to find local cover art in various formats.
|
||||
**
|
||||
*/
|
||||
bool CCover::GetLocalCover(std::wstring filename, const std::wstring& folder, std::wstring& target)
|
||||
bool CCover::GetLocal(std::wstring filename, const std::wstring& folder, std::wstring& target)
|
||||
{
|
||||
std::wstring testPath = folder;
|
||||
testPath += filename;
|
||||
@ -117,12 +66,12 @@ bool CCover::GetLocalCover(std::wstring filename, const std::wstring& folder, st
|
||||
}
|
||||
|
||||
/*
|
||||
** GetEmbeddedArt
|
||||
** GetEmbedded
|
||||
**
|
||||
** Attempts to extract cover art from audio files.
|
||||
**
|
||||
*/
|
||||
bool CCover::GetEmbeddedCover(const TagLib::FileRef& fr, std::wstring& target)
|
||||
bool CCover::GetEmbedded(const TagLib::FileRef& fr, std::wstring& target)
|
||||
{
|
||||
bool found = false;
|
||||
|
||||
|
@ -19,6 +19,8 @@
|
||||
#ifndef __COVER_H__
|
||||
#define __COVER_H__
|
||||
|
||||
// TagLib
|
||||
#include "fileref.h"
|
||||
#include "apefile.h"
|
||||
#include "apetag.h"
|
||||
#include "asffile.h"
|
||||
@ -40,10 +42,9 @@
|
||||
class CCover
|
||||
{
|
||||
public:
|
||||
static void GetCover(const std::wstring& artist, const std::wstring& title, const std::wstring& file, std::wstring& target);
|
||||
static bool GetCachedCover(const std::wstring& artist, const std::wstring& title, std::wstring& target);
|
||||
static bool GetLocalCover(std::wstring filename, const std::wstring& folder, std::wstring& target);
|
||||
static bool GetEmbeddedCover(const TagLib::FileRef& fr, std::wstring& target);
|
||||
static bool GetCached(std::wstring& path);
|
||||
static bool GetLocal(std::wstring filename, const std::wstring& folder, std::wstring& target);
|
||||
static bool GetEmbedded(const TagLib::FileRef& fr, std::wstring& target);
|
||||
static std::wstring GetFileFolder(const std::wstring& file);
|
||||
|
||||
private:
|
||||
|
281
Plugins/PluginNowPlaying/Internet.cpp
Normal file
281
Plugins/PluginNowPlaying/Internet.cpp
Normal file
@ -0,0 +1,281 @@
|
||||
/*
|
||||
Copyright (C) 2011 Birunthan Mohanathas (www.poiru.net)
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "StdAfx.h"
|
||||
#include "Internet.h"
|
||||
|
||||
HINTERNET CInternet::c_NetHandle = NULL;
|
||||
|
||||
/*
|
||||
** Initialize
|
||||
**
|
||||
** Initialize internet handle and crtical section.
|
||||
**
|
||||
*/
|
||||
void CInternet::Initialize()
|
||||
{
|
||||
c_NetHandle = InternetOpen(L"Rainmeter NowPlaying.dll",
|
||||
INTERNET_OPEN_TYPE_PRECONFIG,
|
||||
NULL,
|
||||
NULL,
|
||||
0);
|
||||
|
||||
if (!c_NetHandle)
|
||||
{
|
||||
LSLog(LOG_ERROR, L"Rainmeter", L"NowPlayingPlugin: Unable to open net handle.");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Finalize
|
||||
**
|
||||
** Close handles and delete critical section.
|
||||
**
|
||||
*/
|
||||
void CInternet::Finalize()
|
||||
{
|
||||
if (c_NetHandle) InternetCloseHandle(c_NetHandle);
|
||||
}
|
||||
|
||||
/*
|
||||
** DownloadUrl
|
||||
**
|
||||
** Downloads given url and returns it as a string.
|
||||
**
|
||||
*/
|
||||
std::wstring CInternet::DownloadUrl(const std::wstring& url, int codepage)
|
||||
{
|
||||
std::wstring result;
|
||||
DWORD flags = INTERNET_FLAG_RESYNCHRONIZE;
|
||||
HINTERNET hUrlDump = InternetOpenUrl(c_NetHandle, url.c_str(), NULL, NULL, flags, 0);
|
||||
|
||||
if (!hUrlDump)
|
||||
{
|
||||
LSLog(LOG_DEBUG, L"Rainmeter", L"NowPlayingPlguin: Unable to open internet file.");
|
||||
return result;
|
||||
}
|
||||
|
||||
// Allocate the buffer.
|
||||
const int CHUNK_SIZE = 8192;
|
||||
BYTE* lpData = new BYTE[CHUNK_SIZE];
|
||||
BYTE* lpOutPut;
|
||||
BYTE* lpHolding = NULL;
|
||||
int nCounter = 1;
|
||||
int nBufferSize;
|
||||
DWORD dwDataSize = 0;
|
||||
DWORD dwSize = 0;
|
||||
|
||||
do
|
||||
{
|
||||
// Read the data.
|
||||
if (!InternetReadFile(hUrlDump, (LPVOID)lpData, CHUNK_SIZE, &dwSize))
|
||||
{
|
||||
LSLog(LOG_DEBUG, L"Rainmeter", L"NowPlayingPlguin: Unable to read internet file.");
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Check if all of the data has been read. This should
|
||||
// never get called on the first time through the loop.
|
||||
if (dwSize == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// Determine the buffer size to hold the new data and the data
|
||||
// already written (if any).
|
||||
nBufferSize = dwDataSize + dwSize;
|
||||
|
||||
// Allocate the output buffer.
|
||||
lpOutPut = new BYTE[nBufferSize + 2];
|
||||
|
||||
// Make sure the buffer is not the initial buffer.
|
||||
if (lpHolding != NULL)
|
||||
{
|
||||
// Copy the data in the holding buffer.
|
||||
memcpy(lpOutPut, lpHolding, dwDataSize);
|
||||
|
||||
// Delete the old buffer
|
||||
delete [] lpHolding;
|
||||
|
||||
lpHolding = lpOutPut;
|
||||
lpOutPut = lpOutPut + dwDataSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
lpHolding = lpOutPut;
|
||||
}
|
||||
|
||||
// Copy the data buffer.
|
||||
memcpy(lpOutPut, lpData, dwSize);
|
||||
|
||||
dwDataSize += dwSize;
|
||||
|
||||
// End with double null
|
||||
lpOutPut[dwSize] = 0;
|
||||
lpOutPut[dwSize + 1] = 0;
|
||||
|
||||
// Increment the number of buffers read.
|
||||
++nCounter;
|
||||
|
||||
// Clear the buffer
|
||||
memset(lpData, 0, CHUNK_SIZE);
|
||||
}
|
||||
} while (true);
|
||||
|
||||
InternetCloseHandle(hUrlDump);
|
||||
|
||||
delete [] lpData;
|
||||
|
||||
if (lpHolding)
|
||||
{
|
||||
result = ConvertToWide((LPCSTR)lpHolding, codepage);
|
||||
delete [] lpHolding;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
** EncodeUrl
|
||||
**
|
||||
** Encode reserved characters.
|
||||
**
|
||||
*/
|
||||
std::wstring CInternet::EncodeUrl(const std::wstring& url)
|
||||
{
|
||||
// Based on http://www.zedwood.com/article/111/cpp-urlencode-function
|
||||
static const std::wstring url_chars = L" !*'();:@&=+$,/?#[]";
|
||||
std::wstring ret;
|
||||
|
||||
for (size_t i = 0, max = url.length(); i < max; ++i)
|
||||
{
|
||||
if (url_chars.find_first_of(url[i]) != std::string::npos)
|
||||
{
|
||||
// If reserved character
|
||||
ret.append(L"%");
|
||||
WCHAR buffer[3];
|
||||
_snwprintf_s(buffer, 3, L"%.2X", url[i]);
|
||||
ret.append(buffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
ret.push_back(url[i]);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
** DecodeReferences
|
||||
**
|
||||
** Decodes numeric references.
|
||||
**
|
||||
*/
|
||||
void CInternet::DecodeReferences(std::wstring& str)
|
||||
{
|
||||
// From WebParser.cpp
|
||||
std::wstring::size_type start = 0;
|
||||
|
||||
while ((start = str.find(L'&', start)) != std::wstring::npos)
|
||||
{
|
||||
std::wstring::size_type end, pos;
|
||||
|
||||
if ((end = str.find(L';', start)) == std::wstring::npos) break;
|
||||
pos = start + 1;
|
||||
|
||||
if (pos == end) // &; - skip
|
||||
{
|
||||
start = end + 1;
|
||||
continue;
|
||||
}
|
||||
else if ((end - pos) > 10) // name (or number) is too long
|
||||
{
|
||||
++start;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (str[pos] == L'#') // Numeric character reference
|
||||
{
|
||||
if (++pos == end) // &#; - skip
|
||||
{
|
||||
start = end + 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
int base;
|
||||
if (str[pos] == L'x' || str[pos] == L'X')
|
||||
{
|
||||
if (++pos == end) // &#x; or &#X; - skip
|
||||
{
|
||||
start = end + 1;
|
||||
continue;
|
||||
}
|
||||
base = 16;
|
||||
}
|
||||
else
|
||||
{
|
||||
base = 10;
|
||||
}
|
||||
|
||||
std::wstring num(str, pos, end - pos);
|
||||
WCHAR* pch = NULL;
|
||||
errno = 0;
|
||||
long ch = wcstol(num.c_str(), &pch, base);
|
||||
if (pch == NULL || *pch != L'\0' || errno == ERANGE || ch <= 0 || ch >= 0xFFFE) // invalid character
|
||||
{
|
||||
start = pos;
|
||||
continue;
|
||||
}
|
||||
str.replace(start, end - start + 1, 1, (WCHAR)ch);
|
||||
++start;
|
||||
}
|
||||
else // Character entity reference
|
||||
{
|
||||
start = end + 1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** ConvertToWide
|
||||
**
|
||||
** Convert from multibyte ti wide string.
|
||||
**
|
||||
*/
|
||||
std::wstring CInternet::ConvertToWide(LPCSTR str, int codepage)
|
||||
{
|
||||
std::wstring szWide;
|
||||
|
||||
if (str && *str)
|
||||
{
|
||||
int strLen = (int)strlen(str) + 1;
|
||||
int bufLen = MultiByteToWideChar(codepage, 0, str, strLen, NULL, 0);
|
||||
if (bufLen > 0)
|
||||
{
|
||||
WCHAR* wideSz = new WCHAR[bufLen];
|
||||
wideSz[0] = 0;
|
||||
MultiByteToWideChar(codepage, 0, str, strLen, wideSz, bufLen);
|
||||
szWide = wideSz;
|
||||
delete [] wideSz;
|
||||
}
|
||||
}
|
||||
|
||||
return szWide;
|
||||
}
|
37
Plugins/PluginNowPlaying/Internet.h
Normal file
37
Plugins/PluginNowPlaying/Internet.h
Normal file
@ -0,0 +1,37 @@
|
||||
/*
|
||||
Copyright (C) 2011 Birunthan Mohanathas (www.poiru.net)
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef __INTERNET_H__
|
||||
#define __INTERNET_H__
|
||||
|
||||
class CInternet
|
||||
{
|
||||
public:
|
||||
static void Initialize();
|
||||
static void Finalize();
|
||||
|
||||
static std::wstring DownloadUrl(const std::wstring& url, int codepage);
|
||||
static std::wstring EncodeUrl(const std::wstring& url);
|
||||
static void DecodeReferences(std::wstring& str);
|
||||
static std::wstring ConvertToWide(LPCSTR str, int codepage);
|
||||
|
||||
private:
|
||||
static HINTERNET c_NetHandle;
|
||||
};
|
||||
|
||||
#endif
|
204
Plugins/PluginNowPlaying/Lyrics.cpp
Normal file
204
Plugins/PluginNowPlaying/Lyrics.cpp
Normal file
@ -0,0 +1,204 @@
|
||||
/*
|
||||
Copyright (C) 2011 Birunthan Mohanathas (www.poiru.net)
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#include "StdAfx.h"
|
||||
#include "Player.h"
|
||||
#include "Internet.h"
|
||||
#include "Lyrics.h"
|
||||
|
||||
/*
|
||||
** GetFromInternet
|
||||
**
|
||||
** Download lyrics from various serivces.
|
||||
**
|
||||
*/
|
||||
bool CLyrics::GetFromInternet(const std::wstring& artist, const std::wstring& title, std::wstring& out)
|
||||
{
|
||||
std::wstring encArtist = CInternet::EncodeUrl(artist);
|
||||
std::wstring encTitle = CInternet::EncodeUrl(title);
|
||||
|
||||
bool found = GetFromWikia(encArtist, encTitle, out) ||
|
||||
GetFromLYRDB(encArtist, encTitle, out) ||
|
||||
GetFromLetras(encArtist, encTitle, out);
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
/*
|
||||
** GetFromWikia
|
||||
**
|
||||
** Download lyrics from LyricWiki.
|
||||
**
|
||||
*/
|
||||
bool CLyrics::GetFromWikia(const std::wstring& artist, const std::wstring& title, std::wstring& data)
|
||||
{
|
||||
bool ret = false;
|
||||
|
||||
std::wstring url = L"http://lyrics.wikia.com/api.php?func=getSong&fmt=json&artist=";
|
||||
url += artist;
|
||||
url += L"&song=";
|
||||
url += title;
|
||||
|
||||
data = CInternet::DownloadUrl(url, CP_UTF8);
|
||||
if (!data.empty())
|
||||
{
|
||||
// First we get the URL to the actual wiki page
|
||||
std::wstring::size_type pos = data.find(L"http://");
|
||||
if (pos != std::wstring::npos)
|
||||
{
|
||||
data.erase(0, pos);
|
||||
pos = data.find(L"'");
|
||||
url = data.substr(0, pos);
|
||||
|
||||
// Fetch the wiki page
|
||||
data = CInternet::DownloadUrl(url, CP_UTF8);
|
||||
if (!data.empty())
|
||||
{
|
||||
pos = data.find(L"'lyricbox'");
|
||||
pos = data.find(L"&#", pos);
|
||||
if (pos != std::wstring::npos)
|
||||
{
|
||||
// Get and decode lyrics
|
||||
data.erase(0, pos);
|
||||
pos = data.find(L"<!");
|
||||
data.resize(pos);
|
||||
CInternet::DecodeReferences(data);
|
||||
|
||||
pos = data.find(L"[...]");
|
||||
if (pos != std::wstring::npos)
|
||||
{
|
||||
// Skip incomplete lyrics
|
||||
return ret;
|
||||
}
|
||||
|
||||
pos = data.find(L"<p>");
|
||||
if (pos != std::wstring::npos)
|
||||
{
|
||||
// Skip unavailable lyrics
|
||||
return ret;
|
||||
}
|
||||
|
||||
while ((pos = data.find(L"<br />"), pos) != std::wstring::npos)
|
||||
{
|
||||
data.replace(pos, 6, L"\n");
|
||||
}
|
||||
|
||||
// Get rid of all HTML tags
|
||||
std::wstring::size_type len = 0;
|
||||
while ((pos = data.find_first_of(L'<'), pos) != std::wstring::npos)
|
||||
{
|
||||
len = data.find_first_of(L'>', pos);
|
||||
len -= pos;
|
||||
data.erase(pos, ++len);
|
||||
}
|
||||
|
||||
ret = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
** GetFromLYRDB
|
||||
**
|
||||
** Download lyrics from LYRDB.
|
||||
**
|
||||
*/
|
||||
bool CLyrics::GetFromLYRDB(const std::wstring& artist, const std::wstring& title, std::wstring& data)
|
||||
{
|
||||
bool ret = false;
|
||||
|
||||
std::wstring query = artist;
|
||||
query += L"|";
|
||||
query += title;
|
||||
|
||||
// LYRDB doesn't like apostrophes
|
||||
std::wstring::size_type pos = 0;
|
||||
while ((pos = query.find(L"%27", pos)) != std::wstring::npos)
|
||||
{
|
||||
query.erase(pos, 3);
|
||||
}
|
||||
|
||||
std::wstring url = L"http://webservices.lyrdb.com/lookup.php?q=";
|
||||
url += query;
|
||||
url += L"&for=match&agent=RainmeterNowPlaying";
|
||||
|
||||
data = CInternet::DownloadUrl(url, CP_ACP);
|
||||
if (!data.empty())
|
||||
{
|
||||
pos = data.find(L"\\");
|
||||
if (pos != std::wstring::npos)
|
||||
{
|
||||
// Grab the first match
|
||||
url = L"http://webservices.lyrdb.com/getlyr.php?q=";
|
||||
url += data.substr(0, pos);
|
||||
|
||||
data = CInternet::DownloadUrl(url, CP_ACP);
|
||||
if (!data.empty())
|
||||
{
|
||||
ret = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
** GetFromLetras
|
||||
**
|
||||
** Download lyrics from Letras.
|
||||
**
|
||||
*/
|
||||
bool CLyrics::GetFromLetras(const std::wstring& artist, const std::wstring& title, std::wstring& data)
|
||||
{
|
||||
bool ret = false;
|
||||
|
||||
std::wstring url = L"http://letras.terra.com.br/winamp.php?musica=";
|
||||
url += title;
|
||||
url += L"&artista=";
|
||||
url += artist;
|
||||
data = CInternet::DownloadUrl(url, CP_ACP);
|
||||
if (!data.empty())
|
||||
{
|
||||
std::wstring::size_type pos = data.find(L"\"letra\"");
|
||||
pos = data.find(L"<p>", pos);
|
||||
if (pos != std::wstring::npos)
|
||||
{
|
||||
pos += 3;
|
||||
data.erase(0, pos);
|
||||
|
||||
pos = data.find(L"</p>");
|
||||
data.resize(pos);
|
||||
|
||||
CInternet::DecodeReferences(data);
|
||||
|
||||
while ((pos = data.find(L"<br/>"), pos) != std::wstring::npos)
|
||||
{
|
||||
data.erase(pos, 5);
|
||||
}
|
||||
|
||||
ret = true;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
33
Plugins/PluginNowPlaying/Lyrics.h
Normal file
33
Plugins/PluginNowPlaying/Lyrics.h
Normal file
@ -0,0 +1,33 @@
|
||||
/*
|
||||
Copyright (C) 2011 Birunthan Mohanathas (www.poiru.net)
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
as published by the Free Software Foundation; either version 2
|
||||
of the License, or (at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef __LYRICS_H__
|
||||
#define __LYRICS_H__
|
||||
|
||||
class CLyrics
|
||||
{
|
||||
public:
|
||||
static bool GetFromInternet(const std::wstring& artist, const std::wstring& title, std::wstring& out);
|
||||
|
||||
private:
|
||||
static bool GetFromLetras(const std::wstring& artist, const std::wstring& title, std::wstring& data);
|
||||
static bool GetFromLYRDB(const std::wstring& artist, const std::wstring& title, std::wstring& data);
|
||||
static bool GetFromWikia(const std::wstring& artist, const std::wstring& title, std::wstring& data);
|
||||
};
|
||||
|
||||
#endif
|
@ -19,6 +19,7 @@
|
||||
#include "StdAfx.h"
|
||||
#include "../../Library/DisableThreadLibraryCalls.h" // contains DllMain entry point
|
||||
#include "NowPlaying.h"
|
||||
#include "Internet.h"
|
||||
#include "PlayerAIMP.h"
|
||||
#include "PlayerCAD.h"
|
||||
#include "PlayerFoobar.h"
|
||||
@ -28,17 +29,7 @@
|
||||
#include "PlayerWLM.h"
|
||||
#include "PlayerWMP.h"
|
||||
|
||||
CPlayer* g_AIMP = NULL;
|
||||
CPlayer* g_CAD = NULL;
|
||||
CPlayer* g_Foobar = NULL;
|
||||
CPlayer* g_iTunes = NULL;
|
||||
CPlayer* g_Spotify = NULL;
|
||||
CPlayer* g_Winamp = NULL;
|
||||
CPlayer* g_WLM = NULL;
|
||||
CPlayer* g_WMP = NULL;
|
||||
|
||||
static std::map<UINT, ChildMeasure*> g_Measures;
|
||||
static bool g_DisableLeazingZero = false;
|
||||
std::wstring g_CachePath;
|
||||
std::wstring g_SettingsFile;
|
||||
|
||||
@ -71,6 +62,8 @@ UINT Initialize(HMODULE instance, LPCTSTR iniFile, LPCTSTR section, UINT id)
|
||||
{
|
||||
LSLog(LOG_ERROR, L"Rainmeter", L"NowPlayingPlugin: Unable to get path to Plugins.ini.");
|
||||
}
|
||||
|
||||
CInternet::Initialize();
|
||||
}
|
||||
|
||||
// Data is stored in two structs: ChildMeasure and ParentMeasure. ParentMeasure is created for measures
|
||||
@ -125,75 +118,39 @@ UINT Initialize(HMODULE instance, LPCTSTR iniFile, LPCTSTR section, UINT id)
|
||||
|
||||
if (_wcsicmp(L"AIMP", str) == 0)
|
||||
{
|
||||
if (!g_AIMP)
|
||||
{
|
||||
g_AIMP = new CPlayerAIMP();
|
||||
}
|
||||
parent->player = g_AIMP;
|
||||
parent->player = CPlayerAIMP::Create();
|
||||
}
|
||||
else if (_wcsicmp(L"CAD", str) == 0)
|
||||
{
|
||||
if (!g_CAD)
|
||||
{
|
||||
g_CAD = new CPlayerCAD();
|
||||
}
|
||||
parent->player = g_CAD;
|
||||
parent->player = CPlayerCAD::Create();
|
||||
}
|
||||
else if (_wcsicmp(L"foobar2000", str) == 0)
|
||||
{
|
||||
if (!g_Foobar)
|
||||
{
|
||||
g_Foobar = new CPlayerFoobar();
|
||||
}
|
||||
parent->player = g_Foobar;
|
||||
parent->player = CPlayerFoobar::Create();
|
||||
}
|
||||
else if (_wcsicmp(L"iTunes", str) == 0)
|
||||
{
|
||||
if (!g_iTunes)
|
||||
{
|
||||
g_iTunes = new CPlayerITunes();
|
||||
}
|
||||
parent->player = g_iTunes;
|
||||
parent->player = CPlayerITunes::Create();
|
||||
}
|
||||
else if (_wcsicmp(L"MediaMonkey", str) == 0)
|
||||
{
|
||||
if (!g_Winamp)
|
||||
{
|
||||
g_Winamp = new CPlayerWinamp(WA_MEDIAMONKEY);
|
||||
}
|
||||
parent->player = g_Winamp;
|
||||
parent->player = CPlayerWinamp::Create(WA_MEDIAMONKEY);
|
||||
}
|
||||
else if (_wcsicmp(L"Spotify", str) == 0)
|
||||
{
|
||||
if (!g_Spotify)
|
||||
{
|
||||
g_Spotify = new CPlayerSpotify();
|
||||
}
|
||||
parent->player = g_Spotify;
|
||||
parent->player = CPlayerSpotify::Create();
|
||||
}
|
||||
else if (_wcsicmp(L"WinAmp", str) == 0)
|
||||
{
|
||||
if (!g_Winamp)
|
||||
{
|
||||
g_Winamp = new CPlayerWinamp(WA_WINAMP);
|
||||
}
|
||||
parent->player = g_Winamp;
|
||||
parent->player = CPlayerWinamp::Create(WA_WINAMP);
|
||||
}
|
||||
else if (_wcsicmp(L"WLM", str) == 0)
|
||||
{
|
||||
if (!g_WLM)
|
||||
{
|
||||
g_WLM = new CPlayerWLM();
|
||||
}
|
||||
parent->player = g_WLM;
|
||||
parent->player = CPlayerWLM::Create();
|
||||
}
|
||||
else if (_wcsicmp(L"WMP", str) == 0)
|
||||
{
|
||||
if (!g_WMP)
|
||||
{
|
||||
g_WMP = new CPlayerWMP();
|
||||
}
|
||||
parent->player = g_WMP;
|
||||
parent->player = CPlayerWMP::Create();
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -331,6 +288,11 @@ void Finalize(HMODULE instance, UINT id)
|
||||
|
||||
delete child;
|
||||
g_Measures.erase(i);
|
||||
|
||||
if (g_Measures.empty())
|
||||
{
|
||||
CInternet::Finalize();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -359,8 +321,6 @@ UINT Update(UINT id)
|
||||
parent->trackCount != player->GetTrackCount())
|
||||
{
|
||||
ExecuteCommand(parent->trackChangeAction, parent->window);
|
||||
|
||||
// TODO: First is true..
|
||||
parent->trackCount = player->GetTrackCount();
|
||||
}
|
||||
}
|
||||
@ -423,6 +383,9 @@ LPCTSTR GetString(UINT id, UINT flags)
|
||||
case MEASURE_ALBUM:
|
||||
return player->GetAlbum();
|
||||
|
||||
case MEASURE_LYRICS:
|
||||
return player->GetLyrics();
|
||||
|
||||
case MEASURE_COVER:
|
||||
return player->GetCoverPath();
|
||||
|
||||
|
@ -27,7 +27,6 @@ struct ParentMeasure
|
||||
UINT childCount;
|
||||
UINT trackCount;
|
||||
CPlayer* player;
|
||||
HANDLE thread;
|
||||
HWND window;
|
||||
std::wstring name;
|
||||
std::wstring iniFile;
|
||||
@ -35,7 +34,7 @@ struct ParentMeasure
|
||||
std::wstring playerPath;
|
||||
bool disableLeadingZero;
|
||||
|
||||
ParentMeasure() : player(NULL), thread(NULL) {}
|
||||
ParentMeasure() : player(NULL) {}
|
||||
};
|
||||
|
||||
struct ChildMeasure
|
||||
|
@ -19,6 +19,8 @@
|
||||
#include "StdAfx.h"
|
||||
#include "Player.h"
|
||||
|
||||
extern std::wstring g_CachePath;
|
||||
|
||||
/*
|
||||
** CPlayer
|
||||
**
|
||||
@ -36,8 +38,11 @@ CPlayer::CPlayer() :
|
||||
m_Duration(),
|
||||
m_Position(),
|
||||
m_Rating(),
|
||||
m_Volume()
|
||||
m_Volume(),
|
||||
m_CriticalSection(),
|
||||
m_InternetThread()
|
||||
{
|
||||
InitializeCriticalSection(&m_CriticalSection);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -48,6 +53,7 @@ CPlayer::CPlayer() :
|
||||
*/
|
||||
CPlayer::~CPlayer()
|
||||
{
|
||||
DeleteCriticalSection(&m_CriticalSection);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -110,6 +116,131 @@ void CPlayer::UpdateMeasure()
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** GetCacheFile
|
||||
**
|
||||
** Creates escaped path to cache file (without extension)
|
||||
**
|
||||
*/
|
||||
std::wstring CPlayer::GetCacheFile()
|
||||
{
|
||||
std::wstring path = g_CachePath;
|
||||
|
||||
if (m_Artist.empty() || m_Title.empty())
|
||||
{
|
||||
path += L"temp";
|
||||
}
|
||||
else
|
||||
{
|
||||
std::wstring name = m_Artist;
|
||||
name += L" - ";
|
||||
name += m_Title;
|
||||
|
||||
// Replace reserved chars with _
|
||||
std::wstring::size_type pos = 0;
|
||||
while ((pos = name.find_first_of(L"\\/:*?\"<>|", pos)) != std::wstring::npos) name[pos] = L'_';
|
||||
|
||||
path += name;
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
/*
|
||||
** FindCover
|
||||
**
|
||||
** Default implementation for getting cover.
|
||||
**
|
||||
*/
|
||||
void CPlayer::FindCover()
|
||||
{
|
||||
m_CoverPath = GetCacheFile();
|
||||
|
||||
if (!CCover::GetCached(m_CoverPath))
|
||||
{
|
||||
TagLib::FileRef fr(m_FilePath.c_str());
|
||||
if (fr.isNull() || !fr.tag() || !CCover::GetEmbedded(fr, m_CoverPath))
|
||||
{
|
||||
std::wstring trackFolder = CCover::GetFileFolder(m_FilePath);
|
||||
|
||||
if (!CCover::GetLocal(L"cover", trackFolder, m_CoverPath) &&
|
||||
!CCover::GetLocal(L"folder", trackFolder, m_CoverPath))
|
||||
{
|
||||
// Nothing found
|
||||
m_CoverPath.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** FindLyrics
|
||||
**
|
||||
** Default implementation for getting lyrics.
|
||||
**
|
||||
*/
|
||||
void CPlayer::FindLyrics()
|
||||
{
|
||||
if (TryEnterCriticalSection(&m_CriticalSection))
|
||||
{
|
||||
m_Lyrics.clear();
|
||||
|
||||
unsigned int id;
|
||||
HANDLE thread = (HANDLE)_beginthreadex(NULL, 0, LyricsThreadProc, this, 0, &id);
|
||||
if (thread)
|
||||
{
|
||||
m_InternetThread = thread;
|
||||
}
|
||||
else
|
||||
{
|
||||
LSLog(LOG_DEBUG, L"Rainmeter", L"NowPlayingPlugin: Failed to start lyrics thread.");
|
||||
}
|
||||
|
||||
LeaveCriticalSection(&m_CriticalSection);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** LyricsThreadProc
|
||||
**
|
||||
** Thread to download lyrics.
|
||||
**
|
||||
*/
|
||||
unsigned __stdcall CPlayer::LyricsThreadProc(void* pParam)
|
||||
{
|
||||
CPlayer* player = (CPlayer*)pParam;
|
||||
|
||||
EnterCriticalSection(&player->m_CriticalSection);
|
||||
std::wstring lyrics;
|
||||
bool found;
|
||||
|
||||
while (true)
|
||||
{
|
||||
UINT beforeCount = player->GetTrackCount();
|
||||
found = CLyrics::GetFromInternet(player->m_Artist, player->m_Title, lyrics);
|
||||
UINT afterCount = player->GetTrackCount();
|
||||
|
||||
if (beforeCount == afterCount)
|
||||
{
|
||||
// We're on the same track
|
||||
break;
|
||||
}
|
||||
|
||||
// Track changed, fetch lyrics for it
|
||||
}
|
||||
|
||||
if (found)
|
||||
{
|
||||
player->m_Lyrics = lyrics;
|
||||
}
|
||||
|
||||
CloseHandle(player->m_InternetThread);
|
||||
player->m_InternetThread = NULL;
|
||||
LeaveCriticalSection(&player->m_CriticalSection);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
** ClearData
|
||||
**
|
||||
@ -125,6 +256,7 @@ void CPlayer::ClearData()
|
||||
m_Artist.clear();
|
||||
m_Album.clear();
|
||||
m_Title.clear();
|
||||
m_Lyrics.clear();
|
||||
m_FilePath.clear();
|
||||
m_CoverPath.clear();
|
||||
}
|
||||
|
@ -19,8 +19,11 @@
|
||||
#ifndef __PLAYER_H__
|
||||
#define __PLAYER_H__
|
||||
|
||||
#include "fileref.h"
|
||||
#include "tag.h"
|
||||
#include "Cover.h"
|
||||
#include "Internet.h"
|
||||
#include "Lyrics.h"
|
||||
|
||||
enum PLAYSTATE
|
||||
{
|
||||
@ -45,8 +48,7 @@ enum MEASURETYPE
|
||||
MEASURE_FILE
|
||||
};
|
||||
|
||||
class CPlayer :
|
||||
public CCover
|
||||
class CPlayer
|
||||
{
|
||||
public:
|
||||
CPlayer();
|
||||
@ -60,6 +62,10 @@ public:
|
||||
|
||||
bool IsInitialized() { return m_Initialized; }
|
||||
UINT GetTrackCount() { return m_TrackCount; }
|
||||
|
||||
std::wstring GetCacheFile();
|
||||
void FindCover();
|
||||
void FindLyrics();
|
||||
|
||||
virtual void Pause() {}
|
||||
virtual void Play() {}
|
||||
@ -105,6 +111,12 @@ protected:
|
||||
UINT m_Position; // Current position in seconds
|
||||
UINT m_Rating; // Track rating from 0 to 100
|
||||
UINT m_Volume; // Volume from 0 to 100
|
||||
|
||||
private:
|
||||
static unsigned __stdcall LyricsThreadProc(void* pParam);
|
||||
|
||||
HANDLE m_InternetThread;
|
||||
CRITICAL_SECTION m_CriticalSection;
|
||||
};
|
||||
|
||||
#endif
|
@ -21,8 +21,9 @@
|
||||
#include "AIMP/aimp2_sdk.h"
|
||||
#include "Winamp/wa_ipc.h"
|
||||
|
||||
extern CPlayer* g_AIMP;
|
||||
CPlayer* CPlayerAIMP::c_Player = NULL;
|
||||
|
||||
// TODO
|
||||
/*
|
||||
** CPlayerAIMP
|
||||
**
|
||||
@ -30,10 +31,10 @@ extern CPlayer* g_AIMP;
|
||||
**
|
||||
*/
|
||||
CPlayerAIMP::CPlayerAIMP() : CPlayer(),
|
||||
m_FileMap(),
|
||||
m_FileMapHandle(),
|
||||
m_Window(),
|
||||
m_WinampWindow()
|
||||
m_WinampWindow(),
|
||||
m_FileMap(),
|
||||
m_FileMapHandle()
|
||||
{
|
||||
}
|
||||
|
||||
@ -45,74 +46,69 @@ CPlayerAIMP::CPlayerAIMP() : CPlayer(),
|
||||
*/
|
||||
CPlayerAIMP::~CPlayerAIMP()
|
||||
{
|
||||
g_AIMP = NULL;
|
||||
c_Player = NULL;
|
||||
if (m_FileMap) UnmapViewOfFile(m_FileMap);
|
||||
if (m_FileMapHandle) CloseHandle(m_FileMapHandle);
|
||||
}
|
||||
|
||||
/*
|
||||
** Initialize
|
||||
** Create
|
||||
**
|
||||
** Find AIMP window and mapped object.
|
||||
** Creates a shared class object.
|
||||
**
|
||||
*/
|
||||
bool CPlayerAIMP::Initialize()
|
||||
CPlayer* CPlayerAIMP::Create()
|
||||
{
|
||||
m_Window = FindWindow(L"AIMP2_RemoteInfo", L"AIMP2_RemoteInfo");
|
||||
m_WinampWindow = FindWindow(L"Winamp v1.x", NULL);
|
||||
|
||||
if (m_Window)
|
||||
if (!c_Player)
|
||||
{
|
||||
m_FileMapHandle = OpenFileMapping(FILE_MAP_READ, FALSE, L"AIMP2_RemoteInfo");
|
||||
if (!m_FileMapHandle)
|
||||
{
|
||||
LSLog(LOG_ERROR, L"Rainmeter", L"NowPlayingPlugin: AIMP - Unable to access mapping.");
|
||||
return false;
|
||||
}
|
||||
|
||||
m_FileMap = (LPVOID)MapViewOfFile(m_FileMapHandle, FILE_MAP_READ, 0, 0, 2048);
|
||||
if (!m_FileMap)
|
||||
{
|
||||
LSLog(LOG_ERROR, L"Rainmeter", L"NowPlayingPlugin: AIMP - Unable to view mapping.");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
c_Player = new CPlayerAIMP();
|
||||
}
|
||||
|
||||
return false;
|
||||
return c_Player;
|
||||
}
|
||||
|
||||
bool CPlayerAIMP::CheckActive()
|
||||
/*
|
||||
** CheckWindow
|
||||
**
|
||||
** Try to find AIMP periodically.
|
||||
**
|
||||
*/
|
||||
bool CPlayerAIMP::CheckWindow()
|
||||
{
|
||||
if (m_Window)
|
||||
{
|
||||
if (!IsWindow(m_Window))
|
||||
{
|
||||
m_Window = NULL;
|
||||
m_WinampWindow = NULL;
|
||||
if (m_FileMap) UnmapViewOfFile(m_FileMap);
|
||||
if (m_FileMapHandle) CloseHandle(m_FileMapHandle);
|
||||
ClearData();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
static DWORD oldTime = 0;
|
||||
DWORD time = GetTickCount();
|
||||
static DWORD oldTime = 0;
|
||||
DWORD time = GetTickCount();
|
||||
|
||||
// Try to find AIMP every 5 seconds
|
||||
if (time - oldTime > 5000)
|
||||
{
|
||||
oldTime = time;
|
||||
return Initialize();
|
||||
}
|
||||
// Try to find AIMP every 5 seconds
|
||||
if (time - oldTime > 5000)
|
||||
{
|
||||
oldTime = time;
|
||||
m_Window = FindWindow(L"AIMP2_RemoteInfo", L"AIMP2_RemoteInfo");
|
||||
|
||||
return false;
|
||||
if (m_Window)
|
||||
{
|
||||
m_WinampWindow = FindWindow(L"Winamp v1.x", NULL);
|
||||
|
||||
m_FileMapHandle = OpenFileMapping(FILE_MAP_READ, FALSE, L"AIMP2_RemoteInfo");
|
||||
if (m_FileMapHandle)
|
||||
{
|
||||
m_FileMap = (LPVOID)MapViewOfFile(m_FileMapHandle, FILE_MAP_READ, 0, 0, 2048);
|
||||
if (m_FileMap)
|
||||
{
|
||||
m_Initialized = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
LSLog(LOG_ERROR, L"Rainmeter", L"NowPlayingPlugin: Unable to view AIMP file mapping.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LSLog(LOG_ERROR, L"Rainmeter", L"NowPlayingPlugin: AIMP - Unable to access AIMP file mapping.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return m_Initialized;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -123,29 +119,43 @@ bool CPlayerAIMP::CheckActive()
|
||||
*/
|
||||
void CPlayerAIMP::UpdateData()
|
||||
{
|
||||
static long oldFileSize;
|
||||
static UINT oldTitleLen;
|
||||
|
||||
if (!CheckActive())
|
||||
static long oldFileSize = 0;
|
||||
static UINT oldTitleLen = 0;
|
||||
|
||||
if (!m_Initialized)
|
||||
{
|
||||
// Make sure AIMP is running
|
||||
if (oldFileSize != 0)
|
||||
if (oldTitleLen != 0)
|
||||
{
|
||||
oldFileSize = 0;
|
||||
oldTitleLen = 0;
|
||||
}
|
||||
return;
|
||||
|
||||
if (!CheckWindow())
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// If initialized
|
||||
m_State = (PLAYSTATE)SendMessage(m_Window, WM_AIMP_COMMAND, WM_AIMP_STATUS_GET, AIMP_STS_Player);
|
||||
if (m_State == PLAYER_STOPPED)
|
||||
{
|
||||
if (oldFileSize != 0)
|
||||
// Make sure AIMP is still active
|
||||
if (!IsWindow(m_Window))
|
||||
{
|
||||
m_Initialized = false;
|
||||
if (m_FileMap) UnmapViewOfFile(m_FileMap);
|
||||
if (m_FileMapHandle) CloseHandle(m_FileMapHandle);
|
||||
}
|
||||
|
||||
if (oldTitleLen != 0)
|
||||
{
|
||||
oldFileSize = 0;
|
||||
oldTitleLen = 0;
|
||||
ClearData();
|
||||
}
|
||||
|
||||
// Don't continue if AIMP has quit or is stopped
|
||||
return;
|
||||
}
|
||||
|
||||
@ -154,7 +164,7 @@ void CPlayerAIMP::UpdateData()
|
||||
|
||||
AIMP2FileInfo* info = (AIMP2FileInfo*)m_FileMap;
|
||||
if (info->cbSizeOf > 0 &&
|
||||
info->nFileSize != oldFileSize || // FileSize and TitleLen are probably unique enough
|
||||
info->nFileSize != oldFileSize || // Avoid reading the same file
|
||||
info->nTitleLen != oldTitleLen)
|
||||
{
|
||||
oldFileSize = info->nFileSize;
|
||||
@ -191,7 +201,12 @@ void CPlayerAIMP::UpdateData()
|
||||
// Find cover if needed
|
||||
if (m_HasCoverMeasure)
|
||||
{
|
||||
GetCover(m_Artist, m_Title, m_FilePath, m_CoverPath);
|
||||
FindCover();
|
||||
}
|
||||
|
||||
if (m_HasLyricsMeasure)
|
||||
{
|
||||
FindLyrics();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -24,8 +24,9 @@
|
||||
class CPlayerAIMP : public CPlayer
|
||||
{
|
||||
public:
|
||||
CPlayerAIMP();
|
||||
~CPlayerAIMP();
|
||||
virtual ~CPlayerAIMP();
|
||||
|
||||
static CPlayer* Create();
|
||||
|
||||
virtual void UpdateData();
|
||||
|
||||
@ -40,14 +41,19 @@ public:
|
||||
virtual void ClosePlayer();
|
||||
virtual void OpenPlayer(std::wstring& path);
|
||||
|
||||
protected:
|
||||
CPlayerAIMP();
|
||||
|
||||
private:
|
||||
bool Initialize();
|
||||
bool CheckActive();
|
||||
bool CheckWindow();
|
||||
|
||||
LPVOID m_FileMap;
|
||||
HANDLE m_FileMapHandle;
|
||||
static CPlayer* c_Player;
|
||||
|
||||
HWND m_Window; // AIMP window
|
||||
HWND m_WinampWindow; // AIMP Winamp API window
|
||||
LPVOID m_FileMap;
|
||||
HANDLE m_FileMapHandle;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -20,7 +20,7 @@
|
||||
#include "PlayerCAD.h"
|
||||
#include "CAD/cad_sdk.h"
|
||||
|
||||
extern CPlayer* g_CAD;
|
||||
CPlayer* CPlayerCAD::c_Player = NULL;
|
||||
extern std::wstring g_SettingsFile;
|
||||
|
||||
// This player emulates the CD Art Display IPC interface, which is supported by
|
||||
@ -47,10 +47,26 @@ CPlayerCAD::CPlayerCAD() : CPlayer(),
|
||||
*/
|
||||
CPlayerCAD::~CPlayerCAD()
|
||||
{
|
||||
g_CAD = NULL;
|
||||
c_Player = NULL;
|
||||
Uninitialize();
|
||||
}
|
||||
|
||||
/*
|
||||
** Create
|
||||
**
|
||||
** Creates a shared class object.
|
||||
**
|
||||
*/
|
||||
CPlayer* CPlayerCAD::Create()
|
||||
{
|
||||
if (!c_Player)
|
||||
{
|
||||
c_Player = new CPlayerCAD();
|
||||
}
|
||||
|
||||
return c_Player;
|
||||
}
|
||||
|
||||
/*
|
||||
** Initialize
|
||||
**
|
||||
@ -113,6 +129,7 @@ void CPlayerCAD::Initialize()
|
||||
|
||||
if (m_PlayerWindow)
|
||||
{
|
||||
m_Initialized = true;
|
||||
SendMessage(m_PlayerWindow, WM_USER, (WPARAM)m_Window, IPC_SET_CALLBACK_HWND);
|
||||
m_State = (PLAYSTATE)SendMessage(m_PlayerWindow, WM_USER, 0, IPC_GET_PLAYER_STATE);
|
||||
|
||||
@ -143,37 +160,37 @@ void CPlayerCAD::Uninitialize()
|
||||
*/
|
||||
LRESULT CALLBACK CPlayerCAD::WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
static CPlayerCAD* p;
|
||||
static CPlayerCAD* player;
|
||||
|
||||
switch (msg)
|
||||
{
|
||||
case WM_CREATE:
|
||||
// Get pointer to the CPlayerCAD class from the CreateWindow call
|
||||
p = (CPlayerCAD*)((CREATESTRUCT*)lParam)->lpCreateParams;
|
||||
player = (CPlayerCAD*)((CREATESTRUCT*)lParam)->lpCreateParams;
|
||||
return 0;
|
||||
|
||||
case WM_DESTROY:
|
||||
SendMessage(p->m_PlayerWindow, WM_USER, 0, IPC_SHUTDOWN_NOTIFICATION);
|
||||
SendMessage(player->m_PlayerWindow, WM_USER, 0, IPC_SHUTDOWN_NOTIFICATION);
|
||||
return 0;
|
||||
|
||||
case WM_USER:
|
||||
switch (lParam)
|
||||
{
|
||||
case IPC_TRACK_CHANGED_NOTIFICATION:
|
||||
SendMessage(p->m_PlayerWindow, WM_USER, 0, IPC_GET_CURRENT_TRACK);
|
||||
SendMessage(player->m_PlayerWindow, WM_USER, 0, IPC_GET_CURRENT_TRACK);
|
||||
break;
|
||||
|
||||
case IPC_PLAYER_STATE_CHANGED_NOTIFICATION:
|
||||
p->m_State = (PLAYSTATE)wParam;
|
||||
if (p->m_State == PLAYER_STOPPED)
|
||||
player->m_State = (PLAYSTATE)wParam;
|
||||
if (player->m_State == PLAYER_STOPPED)
|
||||
{
|
||||
p->ClearData();
|
||||
player->ClearData();
|
||||
}
|
||||
break;
|
||||
|
||||
case IPC_SHUTDOWN_NOTIFICATION:
|
||||
p->m_PlayerWindow = NULL;
|
||||
p->ClearData();
|
||||
player->m_Initialized = false;
|
||||
player->ClearData();
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
@ -184,19 +201,19 @@ LRESULT CALLBACK CPlayerCAD::WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM
|
||||
if (cds->dwData == IPC_CURRENT_TRACK_INFO)
|
||||
{
|
||||
// TODO: Sent on track update?
|
||||
++p->m_TrackCount;
|
||||
++player->m_TrackCount;
|
||||
|
||||
std::wstring data = (WCHAR*)cds->lpData;
|
||||
std::wstring::size_type len = data.find_first_of(L'\t');
|
||||
p->m_Title.assign(data, 0, len);
|
||||
player->m_Title.assign(data, 0, len);
|
||||
data.erase(0, ++len);
|
||||
|
||||
len = data.find_first_of(L'\t');
|
||||
p->m_Artist.assign(data, 0, len);
|
||||
player->m_Artist.assign(data, 0, len);
|
||||
data.erase(0, ++len);
|
||||
|
||||
len = data.find_first_of(L'\t');
|
||||
p->m_Album.assign(data, 0, len);
|
||||
player->m_Album.assign(data, 0, len);
|
||||
data.erase(0, ++len);
|
||||
|
||||
len = data.find_first_of(L'\t'); // Skip genre
|
||||
@ -206,23 +223,28 @@ LRESULT CALLBACK CPlayerCAD::WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM
|
||||
data.erase(0, ++len);
|
||||
|
||||
len = data.find_first_of(L'\t');
|
||||
p->m_Duration = _wtoi(data.substr(0, len).c_str());
|
||||
player->m_Duration = _wtoi(data.substr(0, len).c_str());
|
||||
data.erase(0, ++len);
|
||||
|
||||
len = data.find_first_of(L'\t');
|
||||
p->m_FilePath.assign(data, 0, len);
|
||||
player->m_FilePath.assign(data, 0, len);
|
||||
data.erase(0, ++len);
|
||||
|
||||
len = data.find_first_of(L'\t');
|
||||
UINT rating = (_wtoi(data.substr(0, len).c_str()) + 1) / 2; // From 0 - 10 to 0 - 5
|
||||
p->m_Rating = rating;
|
||||
player->m_Rating = rating;
|
||||
data.erase(0, ++len);
|
||||
|
||||
len = data.find_first_of(L'\t');
|
||||
p->m_CoverPath.assign(data, 0, len);
|
||||
player->m_CoverPath.assign(data, 0, len);
|
||||
data.erase(0, ++len);
|
||||
|
||||
if (player->m_HasLyricsMeasure)
|
||||
{
|
||||
player->FindLyrics();
|
||||
}
|
||||
}
|
||||
else if (cds->dwData == IPC_REGISTER_PLAYER && !p->m_PlayerWindow)
|
||||
else if (cds->dwData == IPC_REGISTER_PLAYER && !player->m_Initialized)
|
||||
{
|
||||
std::wstring data = (WCHAR*)cds->lpData;
|
||||
if (data[0] == L'1')
|
||||
@ -238,7 +260,7 @@ LRESULT CALLBACK CPlayerCAD::WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM
|
||||
data.erase(0, ++len);
|
||||
|
||||
len = data.find_first_of(L'\t');
|
||||
p->m_PlayerPath.assign(data, 0, len);
|
||||
player->m_PlayerPath.assign(data, 0, len);
|
||||
data.erase(0, ++len);
|
||||
|
||||
LPCTSTR classSz = className.empty() ? NULL : className.c_str();
|
||||
@ -247,17 +269,18 @@ LRESULT CALLBACK CPlayerCAD::WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM
|
||||
|
||||
WritePrivateProfileString(L"NowPlaying.dll", L"ClassName", classSz, file);
|
||||
WritePrivateProfileString(L"NowPlaying.dll", L"WindowName", windowSz, file);
|
||||
WritePrivateProfileString(L"NowPlaying.dll", L"PlayerPath", p->m_PlayerPath.c_str(), file);
|
||||
WritePrivateProfileString(L"NowPlaying.dll", L"PlayerPath", player->m_PlayerPath.c_str(), file);
|
||||
|
||||
p->m_PlayerWindow = FindWindow(classSz, windowSz);
|
||||
player->m_PlayerWindow = FindWindow(classSz, windowSz);
|
||||
|
||||
if (p->m_PlayerWindow)
|
||||
if (player->m_PlayerWindow)
|
||||
{
|
||||
p->m_State = (PLAYSTATE)SendMessage(p->m_PlayerWindow, WM_USER, 0, IPC_GET_PLAYER_STATE);
|
||||
player->m_Initialized = true;
|
||||
player->m_State = (PLAYSTATE)SendMessage(player->m_PlayerWindow, WM_USER, 0, IPC_GET_PLAYER_STATE);
|
||||
|
||||
if (p->m_State != PLAYER_STOPPED)
|
||||
if (player->m_State != PLAYER_STOPPED)
|
||||
{
|
||||
SendMessage(p->m_PlayerWindow, WM_USER, 0, IPC_GET_CURRENT_TRACK);
|
||||
SendMessage(player->m_PlayerWindow, WM_USER, 0, IPC_GET_CURRENT_TRACK);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -392,7 +415,8 @@ void CPlayerCAD::SetVolume(int volume)
|
||||
void CPlayerCAD::ClosePlayer()
|
||||
{
|
||||
SendMessage(m_PlayerWindow, WM_USER, 0, IPC_CLOSE_PLAYER);
|
||||
m_PlayerWindow = NULL;
|
||||
// TODO
|
||||
m_Initialized = false;
|
||||
ClearData();
|
||||
}
|
||||
|
||||
|
@ -24,8 +24,9 @@
|
||||
class CPlayerCAD : public CPlayer
|
||||
{
|
||||
public:
|
||||
CPlayerCAD();
|
||||
~CPlayerCAD();
|
||||
virtual ~CPlayerCAD();
|
||||
|
||||
static CPlayer* Create();
|
||||
|
||||
virtual void UpdateData();
|
||||
|
||||
@ -40,11 +41,16 @@ public:
|
||||
virtual void ClosePlayer();
|
||||
virtual void OpenPlayer(std::wstring& path);
|
||||
|
||||
protected:
|
||||
CPlayerCAD();
|
||||
|
||||
private:
|
||||
void Initialize();
|
||||
void Uninitialize();
|
||||
static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
|
||||
|
||||
static CPlayer* c_Player;
|
||||
|
||||
HWND m_Window;
|
||||
HWND m_PlayerWindow;
|
||||
std::wstring m_PlayerPath;
|
||||
|
@ -19,7 +19,7 @@
|
||||
#include "StdAfx.h"
|
||||
#include "PlayerFoobar.h"
|
||||
|
||||
extern CPlayer* g_Foobar;
|
||||
CPlayer* CPlayerFoobar::c_Player = NULL;
|
||||
|
||||
/*
|
||||
** CPlayerFoobar
|
||||
@ -42,10 +42,26 @@ CPlayerFoobar::CPlayerFoobar() : CPlayer(),
|
||||
*/
|
||||
CPlayerFoobar::~CPlayerFoobar()
|
||||
{
|
||||
g_Foobar = NULL;
|
||||
c_Player = NULL;
|
||||
Uninitialize();
|
||||
}
|
||||
|
||||
/*
|
||||
** Create
|
||||
**
|
||||
** Creates a shared class object.
|
||||
**
|
||||
*/
|
||||
CPlayer* CPlayerFoobar::Create()
|
||||
{
|
||||
if (!c_Player)
|
||||
{
|
||||
c_Player = new CPlayerFoobar();
|
||||
}
|
||||
|
||||
return c_Player;
|
||||
}
|
||||
|
||||
/*
|
||||
** Initialize
|
||||
**
|
||||
@ -89,6 +105,7 @@ void CPlayerFoobar::Initialize()
|
||||
}
|
||||
else
|
||||
{
|
||||
m_Initialized = true;
|
||||
SendMessage(m_FooWindow, WM_USER, (WPARAM)m_Window, FOO_SETCALLBACK);
|
||||
}
|
||||
}
|
||||
@ -164,7 +181,7 @@ LRESULT CALLBACK CPlayerFoobar::WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPAR
|
||||
break;
|
||||
|
||||
case FOO_PLAYERQUIT:
|
||||
player->m_FooWindow = NULL;
|
||||
player->m_Initialized = false;
|
||||
player->ClearData();
|
||||
break;
|
||||
}
|
||||
@ -221,7 +238,12 @@ LRESULT CALLBACK CPlayerFoobar::WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPAR
|
||||
|
||||
if (player->m_HasCoverMeasure || player->m_InstanceCount == 0)
|
||||
{
|
||||
GetCover(player->m_Artist, player->m_Title, player->m_FilePath, player->m_CoverPath);
|
||||
player->FindCover();
|
||||
}
|
||||
|
||||
if (player->m_HasLyricsMeasure)
|
||||
{
|
||||
player->FindLyrics();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -339,7 +361,7 @@ void CPlayerFoobar::ClosePlayer()
|
||||
*/
|
||||
void CPlayerFoobar::OpenPlayer(std::wstring& path)
|
||||
{
|
||||
if (!m_FooWindow)
|
||||
if (!m_Initialized)
|
||||
{
|
||||
if (path.empty())
|
||||
{
|
||||
|
@ -24,8 +24,9 @@
|
||||
class CPlayerFoobar : public CPlayer
|
||||
{
|
||||
public:
|
||||
CPlayerFoobar();
|
||||
~CPlayerFoobar();
|
||||
virtual ~CPlayerFoobar();
|
||||
|
||||
static CPlayer* Create();
|
||||
|
||||
virtual void UpdateData();
|
||||
|
||||
@ -40,6 +41,9 @@ public:
|
||||
virtual void ClosePlayer();
|
||||
virtual void OpenPlayer(std::wstring& path);
|
||||
|
||||
protected:
|
||||
CPlayerFoobar();
|
||||
|
||||
private:
|
||||
enum FOOMESSAGE
|
||||
{
|
||||
@ -73,6 +77,8 @@ private:
|
||||
void Uninitialize();
|
||||
static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
|
||||
|
||||
static CPlayer* c_Player;
|
||||
|
||||
HWND m_Window; // Our reciever window
|
||||
HWND m_FooWindow; // Foobar receiver window
|
||||
};
|
||||
|
@ -19,7 +19,7 @@
|
||||
#include "StdAfx.h"
|
||||
#include "PlayerITunes.h"
|
||||
|
||||
extern CPlayer* g_iTunes;
|
||||
CPlayer* CPlayerITunes::c_Player = NULL;
|
||||
|
||||
/*
|
||||
** CEventHandler
|
||||
@ -129,11 +129,27 @@ CPlayerITunes::CPlayerITunes() : CPlayer(),
|
||||
*/
|
||||
CPlayerITunes::~CPlayerITunes()
|
||||
{
|
||||
g_iTunes = NULL;
|
||||
c_Player = NULL;
|
||||
Uninitialize();
|
||||
CoUninitialize();
|
||||
}
|
||||
|
||||
/*
|
||||
** Create
|
||||
**
|
||||
** Creates a shared class object.
|
||||
**
|
||||
*/
|
||||
CPlayer* CPlayerITunes::Create()
|
||||
{
|
||||
if (!c_Player)
|
||||
{
|
||||
c_Player = new CPlayerITunes();
|
||||
}
|
||||
|
||||
return c_Player;
|
||||
}
|
||||
|
||||
/*
|
||||
** Initialize
|
||||
**
|
||||
@ -216,7 +232,6 @@ void CPlayerITunes::Uninitialize()
|
||||
if (m_Initialized)
|
||||
{
|
||||
m_Initialized = false;
|
||||
m_UserQuitPrompt = true;
|
||||
if (m_iTunes)
|
||||
{
|
||||
m_iTunes->Release();
|
||||
@ -304,6 +319,7 @@ void CPlayerITunes::OnTrackChange()
|
||||
track->get_Duration(&tmpVal);
|
||||
m_Duration = (UINT)tmpVal;
|
||||
|
||||
// Rating is 0 - 100, divide to 0 - 5
|
||||
track->get_Rating(&tmpVal);
|
||||
tmpVal /= 20L;
|
||||
m_Rating = (UINT)tmpVal;
|
||||
@ -319,45 +335,54 @@ void CPlayerITunes::OnTrackChange()
|
||||
++m_TrackCount;
|
||||
m_FilePath = tmpStr;
|
||||
|
||||
if (m_HasCoverMeasure && !GetCachedCover(m_Artist, m_Title, m_CoverPath))
|
||||
if (m_HasCoverMeasure)
|
||||
{
|
||||
// Art not in cache, check for embedded art
|
||||
IITArtworkCollection* artworkCollection;
|
||||
hr = track->get_Artwork(&artworkCollection);
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
m_CoverPath = GetCacheFile();
|
||||
if (!CCover::GetCached(m_CoverPath))
|
||||
{
|
||||
long count;
|
||||
artworkCollection->get_Count(&count);
|
||||
// Art not in cache, check for embedded art through iTunes interface
|
||||
IITArtworkCollection* artworkCollection;
|
||||
hr = track->get_Artwork(&artworkCollection);
|
||||
|
||||
if (count > 0)
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
IITArtwork* artwork;
|
||||
hr = artworkCollection->get_Item(1, &artwork);
|
||||
long count;
|
||||
artworkCollection->get_Count(&count);
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
if (count > 0)
|
||||
{
|
||||
tmpStr = m_CoverPath.c_str();
|
||||
hr = artwork->SaveArtworkToFile(tmpStr);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
m_CoverPath.clear();
|
||||
}
|
||||
IITArtwork* artwork;
|
||||
hr = artworkCollection->get_Item(1, &artwork);
|
||||
|
||||
artwork->Release();
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
tmpStr = m_CoverPath.c_str();
|
||||
hr = artwork->SaveArtworkToFile(tmpStr);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
m_CoverPath.clear();
|
||||
}
|
||||
|
||||
artwork->Release();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_CoverPath.clear();
|
||||
}
|
||||
|
||||
artworkCollection->Release();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_CoverPath.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
artworkCollection->Release();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_CoverPath.clear();
|
||||
}
|
||||
if (m_HasLyricsMeasure)
|
||||
{
|
||||
FindLyrics();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -35,8 +35,9 @@
|
||||
class CPlayerITunes : public CPlayer
|
||||
{
|
||||
public:
|
||||
CPlayerITunes();
|
||||
~CPlayerITunes();
|
||||
virtual ~CPlayerITunes();
|
||||
|
||||
static CPlayer* Create();
|
||||
|
||||
virtual void UpdateData();
|
||||
|
||||
@ -51,6 +52,9 @@ public:
|
||||
virtual void ClosePlayer();
|
||||
virtual void OpenPlayer(std::wstring& path);
|
||||
|
||||
protected:
|
||||
CPlayerITunes();
|
||||
|
||||
private:
|
||||
class CEventHandler : public _IiTunesEvents
|
||||
{
|
||||
@ -83,6 +87,8 @@ private:
|
||||
void OnVolumeChange(int volume);
|
||||
bool CheckWindow();
|
||||
|
||||
static CPlayer* c_Player;
|
||||
|
||||
bool m_UserQuitPrompt;
|
||||
IiTunes* m_iTunes;
|
||||
CEventHandler* m_iTunesEvent;
|
||||
|
@ -19,7 +19,7 @@
|
||||
#include "StdAfx.h"
|
||||
#include "PlayerSpotify.h"
|
||||
|
||||
extern CPlayer* g_Spotify;
|
||||
CPlayer* CPlayerSpotify::c_Player = NULL;
|
||||
|
||||
/*
|
||||
** CPlayerSpotify
|
||||
@ -40,7 +40,23 @@ CPlayerSpotify::CPlayerSpotify() : CPlayer(),
|
||||
*/
|
||||
CPlayerSpotify::~CPlayerSpotify()
|
||||
{
|
||||
g_Spotify = NULL;
|
||||
c_Player = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
** Create
|
||||
**
|
||||
** Creates a shared class object.
|
||||
**
|
||||
*/
|
||||
CPlayer* CPlayerSpotify::Create()
|
||||
{
|
||||
if (!c_Player)
|
||||
{
|
||||
c_Player = new CPlayerSpotify();
|
||||
}
|
||||
|
||||
return c_Player;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -98,6 +114,11 @@ void CPlayerSpotify::UpdateData()
|
||||
m_Title = track;
|
||||
m_Artist = artist;
|
||||
++m_TrackCount;
|
||||
|
||||
if (m_HasLyricsMeasure)
|
||||
{
|
||||
FindLyrics();
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -24,8 +24,9 @@
|
||||
class CPlayerSpotify : public CPlayer
|
||||
{
|
||||
public:
|
||||
CPlayerSpotify();
|
||||
~CPlayerSpotify();
|
||||
virtual ~CPlayerSpotify();
|
||||
|
||||
static CPlayer* Create();
|
||||
|
||||
virtual void Pause() { return Play(); }
|
||||
virtual void Play();
|
||||
@ -36,6 +37,9 @@ public:
|
||||
virtual void OpenPlayer(std::wstring& path);
|
||||
virtual void UpdateData();
|
||||
|
||||
protected:
|
||||
CPlayerSpotify();
|
||||
|
||||
private:
|
||||
enum SPOTIFYCOMMAND
|
||||
{
|
||||
@ -50,6 +54,8 @@ private:
|
||||
|
||||
bool CheckWindow();
|
||||
|
||||
static CPlayer* c_Player;
|
||||
|
||||
HWND m_Window;
|
||||
};
|
||||
|
||||
|
@ -19,7 +19,7 @@
|
||||
#include "StdAfx.h"
|
||||
#include "PlayerWLM.h"
|
||||
|
||||
extern CPlayer* g_WLM;
|
||||
CPlayer* CPlayerWLM::c_Player = NULL;
|
||||
|
||||
// This player emulates the MSN/WLM Messenger 'Listening to' interface, which is
|
||||
// supported by OpenPandora, Last.fm, Media Player Classic, TTPlayer, Zune, etc.
|
||||
@ -54,6 +54,8 @@ CPlayerWLM::CPlayerWLM() : CPlayer(),
|
||||
NULL,
|
||||
hInstance,
|
||||
this);
|
||||
|
||||
m_Initialized = true;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -64,11 +66,27 @@ CPlayerWLM::CPlayerWLM() : CPlayer(),
|
||||
*/
|
||||
CPlayerWLM::~CPlayerWLM()
|
||||
{
|
||||
g_WLM = NULL;
|
||||
c_Player = NULL;
|
||||
DestroyWindow(m_Window);
|
||||
UnregisterClass(L"MsnMsgrUIManager", GetModuleHandle(NULL));
|
||||
}
|
||||
|
||||
/*
|
||||
** Create
|
||||
**
|
||||
** Creates a shared class object.
|
||||
**
|
||||
*/
|
||||
CPlayer* CPlayerWLM::Create()
|
||||
{
|
||||
if (!c_Player)
|
||||
{
|
||||
c_Player = new CPlayerWLM();
|
||||
}
|
||||
|
||||
return c_Player;
|
||||
}
|
||||
|
||||
LRESULT CALLBACK CPlayerWLM::WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
static CPlayerWLM* player;
|
||||
@ -99,6 +117,7 @@ LRESULT CALLBACK CPlayerWLM::WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM
|
||||
|
||||
if (playing)
|
||||
{
|
||||
++player->m_TrackCount;
|
||||
player->m_State = PLAYER_PLAYING;
|
||||
data.erase(0, 3); // Get rid of the status
|
||||
|
||||
@ -119,6 +138,11 @@ LRESULT CALLBACK CPlayerWLM::WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM
|
||||
|
||||
len = data.find_first_of(L'\\');
|
||||
player->m_Album = data.substr(0, len);
|
||||
|
||||
if (player->m_HasLyricsMeasure)
|
||||
{
|
||||
player->FindLyrics();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -24,8 +24,9 @@
|
||||
class CPlayerWLM : public CPlayer
|
||||
{
|
||||
public:
|
||||
CPlayerWLM();
|
||||
~CPlayerWLM();
|
||||
virtual ~CPlayerWLM();
|
||||
|
||||
static CPlayer* Create();
|
||||
|
||||
virtual void UpdateData();
|
||||
|
||||
@ -35,10 +36,15 @@ public:
|
||||
virtual void Next();
|
||||
virtual void Previous();
|
||||
|
||||
protected:
|
||||
CPlayerWLM();
|
||||
|
||||
private:
|
||||
static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
|
||||
void SendKeyInput(WORD key);
|
||||
|
||||
static CPlayer* c_Player;
|
||||
|
||||
HWND m_Window;
|
||||
};
|
||||
|
||||
|
@ -19,7 +19,7 @@
|
||||
#include "StdAfx.h"
|
||||
#include "PlayerWMP.h"
|
||||
|
||||
extern CPlayer* g_WMP;
|
||||
CPlayer* CPlayerWMP::c_Player = NULL;
|
||||
|
||||
/*
|
||||
** CRemoteHost
|
||||
@ -170,11 +170,27 @@ CPlayerWMP::CPlayerWMP() : CPlayer(),
|
||||
*/
|
||||
CPlayerWMP::~CPlayerWMP()
|
||||
{
|
||||
g_WMP = NULL;
|
||||
c_Player = NULL;
|
||||
Uninitialize();
|
||||
m_ComModule.Term();
|
||||
}
|
||||
|
||||
/*
|
||||
** Create
|
||||
**
|
||||
** Creates a shared class object.
|
||||
**
|
||||
*/
|
||||
CPlayer* CPlayerWMP::Create()
|
||||
{
|
||||
if (!c_Player)
|
||||
{
|
||||
c_Player = new CPlayerWMP();
|
||||
}
|
||||
|
||||
return c_Player;
|
||||
}
|
||||
|
||||
/*
|
||||
** Initialize
|
||||
**
|
||||
@ -450,9 +466,14 @@ void CPlayerWMP::UpdateData()
|
||||
}
|
||||
else
|
||||
{
|
||||
GetCover(m_Artist, m_Title, m_FilePath, m_CoverPath);
|
||||
FindCover();
|
||||
}
|
||||
}
|
||||
|
||||
if (m_HasLyricsMeasure)
|
||||
{
|
||||
FindLyrics();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -34,8 +34,9 @@
|
||||
class CPlayerWMP : public CPlayer
|
||||
{
|
||||
public:
|
||||
CPlayerWMP();
|
||||
~CPlayerWMP();
|
||||
virtual ~CPlayerWMP();
|
||||
|
||||
static CPlayer* Create();
|
||||
|
||||
virtual void UpdateData();
|
||||
|
||||
@ -50,6 +51,9 @@ public:
|
||||
virtual void OpenPlayer(std::wstring& path);
|
||||
virtual void ClosePlayer();
|
||||
|
||||
protected:
|
||||
CPlayerWMP();
|
||||
|
||||
private:
|
||||
class CRemoteHost :
|
||||
public CComObjectRootEx<CComSingleThreadModel>,
|
||||
@ -129,6 +133,8 @@ private:
|
||||
void Initialize();
|
||||
void Uninitialize();
|
||||
|
||||
static CPlayer* c_Player;
|
||||
|
||||
bool m_TrackChanged;
|
||||
HWND m_Window;
|
||||
CAxWindow* m_AxWindow;
|
||||
|
@ -21,7 +21,7 @@
|
||||
#include "Winamp/wa_ipc.h"
|
||||
#include "Winamp/wa_cmd.h"
|
||||
|
||||
extern CPlayer* g_Winamp;
|
||||
CPlayer* CPlayerWinamp::c_Player = NULL;
|
||||
|
||||
// This player retrieves data through the Winamp IPC interface.
|
||||
|
||||
@ -32,9 +32,11 @@ extern CPlayer* g_Winamp;
|
||||
**
|
||||
*/
|
||||
CPlayerWinamp::CPlayerWinamp(WINAMPTYPE type) : CPlayer(),
|
||||
m_WinampType(type),
|
||||
m_Window(),
|
||||
m_UseUnicodeAPI(false),
|
||||
m_Window()
|
||||
m_WinampType(type),
|
||||
m_WinampHandle(),
|
||||
m_WinampAddress()
|
||||
{
|
||||
}
|
||||
|
||||
@ -46,10 +48,26 @@ CPlayerWinamp::CPlayerWinamp(WINAMPTYPE type) : CPlayer(),
|
||||
*/
|
||||
CPlayerWinamp::~CPlayerWinamp()
|
||||
{
|
||||
g_Winamp = NULL;
|
||||
c_Player = NULL;
|
||||
if (m_WinampHandle) CloseHandle(m_WinampHandle);
|
||||
}
|
||||
|
||||
/*
|
||||
** Create
|
||||
**
|
||||
** Creates a shared class object.
|
||||
**
|
||||
*/
|
||||
CPlayer* CPlayerWinamp::Create(WINAMPTYPE type)
|
||||
{
|
||||
if (!c_Player)
|
||||
{
|
||||
c_Player = new CPlayerWinamp(type);
|
||||
}
|
||||
|
||||
return c_Player;
|
||||
}
|
||||
|
||||
/*
|
||||
** CheckWindow
|
||||
**
|
||||
@ -204,63 +222,70 @@ void CPlayerWinamp::UpdateData()
|
||||
}
|
||||
}
|
||||
|
||||
// Find cover if needed
|
||||
if (m_HasCoverMeasure &&
|
||||
!GetCachedCover(m_Artist, m_Title, m_CoverPath) &&
|
||||
!GetEmbeddedCover(fr, m_CoverPath))
|
||||
if (m_HasLyricsMeasure)
|
||||
{
|
||||
std::wstring trackFolder = GetFileFolder(m_FilePath);
|
||||
FindLyrics();
|
||||
}
|
||||
|
||||
if (!m_Album.empty())
|
||||
// Find cover if needed
|
||||
if (m_HasCoverMeasure)
|
||||
{
|
||||
m_CoverPath = GetCacheFile();
|
||||
if (!CCover::GetCached(m_CoverPath) &&
|
||||
!CCover::GetEmbedded(fr, m_CoverPath))
|
||||
{
|
||||
// Winamp stores covers usually as %album%.jpg
|
||||
std::wstring file = m_Album;
|
||||
std::wstring::size_type end = file.length();
|
||||
for (std::wstring::size_type pos = 0; pos < end; ++pos)
|
||||
std::wstring trackFolder = CCover::GetFileFolder(m_FilePath);
|
||||
|
||||
if (!m_Album.empty())
|
||||
{
|
||||
// Replace reserved chars according to Winamp specs
|
||||
switch (file[pos])
|
||||
// Winamp stores covers usually as %album%.jpg
|
||||
std::wstring file = m_Album;
|
||||
std::wstring::size_type end = file.length();
|
||||
for (std::wstring::size_type pos = 0; pos < end; ++pos)
|
||||
{
|
||||
case L'?':
|
||||
case L'*':
|
||||
case L'|':
|
||||
file[pos] = L'_';
|
||||
break;
|
||||
// Replace reserved chars according to Winamp specs
|
||||
switch (file[pos])
|
||||
{
|
||||
case L'?':
|
||||
case L'*':
|
||||
case L'|':
|
||||
file[pos] = L'_';
|
||||
break;
|
||||
|
||||
case L'/':
|
||||
case L'\\':
|
||||
case L':':
|
||||
file[pos] = L'-';
|
||||
break;
|
||||
case L'/':
|
||||
case L'\\':
|
||||
case L':':
|
||||
file[pos] = L'-';
|
||||
break;
|
||||
|
||||
case L'\"':
|
||||
file[pos] = L'\'';
|
||||
break;
|
||||
case L'\"':
|
||||
file[pos] = L'\'';
|
||||
break;
|
||||
|
||||
case L'<':
|
||||
file[pos] = L'(';
|
||||
break;
|
||||
case L'<':
|
||||
file[pos] = L'(';
|
||||
break;
|
||||
|
||||
case L'>':
|
||||
file[pos] = L')';
|
||||
break;
|
||||
case L'>':
|
||||
file[pos] = L')';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (CCover::GetLocal(file, trackFolder, m_CoverPath))
|
||||
{
|
||||
// %album% art file found
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (GetLocalCover(file, trackFolder, m_CoverPath))
|
||||
if (!CCover::GetLocal(L"cover", trackFolder, m_CoverPath) &&
|
||||
!CCover::GetLocal(L"folder", trackFolder, m_CoverPath))
|
||||
{
|
||||
// %album% art file found
|
||||
return;
|
||||
// Nothing found
|
||||
m_CoverPath.clear();
|
||||
}
|
||||
}
|
||||
|
||||
if (!GetLocalCover(L"cover", trackFolder, m_CoverPath) &&
|
||||
!GetLocalCover(L"folder", trackFolder, m_CoverPath))
|
||||
{
|
||||
// Nothing found
|
||||
m_CoverPath.clear();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -30,8 +30,9 @@ enum WINAMPTYPE
|
||||
class CPlayerWinamp : public CPlayer
|
||||
{
|
||||
public:
|
||||
CPlayerWinamp(WINAMPTYPE type);
|
||||
~CPlayerWinamp();
|
||||
virtual ~CPlayerWinamp();
|
||||
|
||||
static CPlayer* Create(WINAMPTYPE type);
|
||||
|
||||
virtual void UpdateData();
|
||||
|
||||
@ -46,12 +47,17 @@ public:
|
||||
virtual void ClosePlayer();
|
||||
virtual void OpenPlayer(std::wstring& path);
|
||||
|
||||
protected:
|
||||
CPlayerWinamp(WINAMPTYPE type);
|
||||
|
||||
private:
|
||||
bool CheckWindow();
|
||||
|
||||
static CPlayer* c_Player;
|
||||
|
||||
HWND m_Window; // Winamp window
|
||||
bool m_UseUnicodeAPI;
|
||||
WINAMPTYPE m_WinampType;
|
||||
HWND m_Window; // Winamp window
|
||||
HANDLE m_WinampHandle; // Handle to Winamp process
|
||||
LPCVOID m_WinampAddress;
|
||||
};
|
||||
|
@ -122,6 +122,7 @@
|
||||
<ProgramDatabaseFile>.\x32/Debug/NowPlaying.pdb</ProgramDatabaseFile>
|
||||
<ImportLibrary>.\x32/Debug/NowPlaying.lib</ImportLibrary>
|
||||
<TargetMachine>MachineX86</TargetMachine>
|
||||
<AdditionalDependencies>WinInet.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
@ -162,6 +163,7 @@
|
||||
<ProgramDatabaseFile>.\x64/Debug/NowPlaying.pdb</ProgramDatabaseFile>
|
||||
<ImportLibrary>.\x64/Debug/NowPlaying.lib</ImportLibrary>
|
||||
<TargetMachine>MachineX64</TargetMachine>
|
||||
<AdditionalDependencies>WinInet.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
@ -198,7 +200,7 @@
|
||||
<Culture>0x0409</Culture>
|
||||
</ResourceCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>Rainmeter.lib;Wininet.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>Rainmeter.lib;WinInet.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<OutputFile>../../TestBench/x32/Release/Plugins/NowPlaying.dll</OutputFile>
|
||||
<SuppressStartupBanner>true</SuppressStartupBanner>
|
||||
<AdditionalLibraryDirectories>..\..\Library\x32\Release;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
@ -243,7 +245,7 @@
|
||||
</ResourceCompile>
|
||||
<Link>
|
||||
<AdditionalOptions>/LTCG %(AdditionalOptions)</AdditionalOptions>
|
||||
<AdditionalDependencies>Rainmeter.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>Rainmeter.lib;WinInet.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<OutputFile>../../TestBench/x64/Release/Plugins/NowPlaying.dll</OutputFile>
|
||||
<SuppressStartupBanner>true</SuppressStartupBanner>
|
||||
<AdditionalLibraryDirectories>..\..\Library\x64\Release;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
@ -256,6 +258,8 @@
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="Cover.cpp" />
|
||||
<ClCompile Include="Internet.cpp" />
|
||||
<ClCompile Include="Lyrics.cpp" />
|
||||
<ClCompile Include="NowPlaying.cpp" />
|
||||
<ClCompile Include="Player.cpp" />
|
||||
<ClCompile Include="PlayerAIMP.cpp" />
|
||||
@ -344,6 +348,8 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="Cover.h" />
|
||||
<ClInclude Include="Internet.h" />
|
||||
<ClInclude Include="Lyrics.h" />
|
||||
<ClInclude Include="NowPlaying.h" />
|
||||
<ClInclude Include="Player.h" />
|
||||
<ClInclude Include="PlayerAIMP.h" />
|
||||
|
@ -267,6 +267,12 @@
|
||||
<ClCompile Include="Cover.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Lyrics.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Internet.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="SDKs\AIMP\aimp2_sdk.h">
|
||||
@ -326,6 +332,12 @@
|
||||
<ClInclude Include="Cover.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Lyrics.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Internet.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="PluginNowPlaying.rc">
|
||||
|
@ -20,7 +20,8 @@
|
||||
#define __STDAFX_H__
|
||||
|
||||
// WinAPI
|
||||
#include <windows.h>
|
||||
#include <Windows.h>
|
||||
#include <WinInet.h>
|
||||
|
||||
// STL
|
||||
#include <string>
|
||||
@ -32,7 +33,4 @@
|
||||
// Rainmeter's exported functions
|
||||
#include "../../Library/Export.h"
|
||||
|
||||
// TagLib
|
||||
#include "fileref.h"
|
||||
|
||||
#endif
|
||||
|
Loading…
x
Reference in New Issue
Block a user