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:
Birunthan Mohanathas 2011-06-19 14:58:48 +00:00
parent 6aa004eb22
commit d633f4b586
29 changed files with 1181 additions and 329 deletions

View File

@ -19,76 +19,25 @@
#include "StdAfx.h" #include "StdAfx.h"
#include "Cover.h" #include "Cover.h"
extern std::wstring g_CachePath;
/* /*
** GetCover ** GetCached
**
** 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
** **
** Checks if cover art is in cache. ** 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; path += L".art";
if (artist.empty() || title.empty()) return (_waccess(path.c_str(), 0) == 0) ? true : false;
{
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;
} }
/* /*
** GetLocalArt ** GetLocal
** **
** Attemps to find local cover art in various formats. ** 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; std::wstring testPath = folder;
testPath += filename; 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. ** 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; bool found = false;

View File

@ -19,6 +19,8 @@
#ifndef __COVER_H__ #ifndef __COVER_H__
#define __COVER_H__ #define __COVER_H__
// TagLib
#include "fileref.h"
#include "apefile.h" #include "apefile.h"
#include "apetag.h" #include "apetag.h"
#include "asffile.h" #include "asffile.h"
@ -40,10 +42,9 @@
class CCover class CCover
{ {
public: public:
static void GetCover(const std::wstring& artist, const std::wstring& title, const std::wstring& file, std::wstring& target); static bool GetCached(std::wstring& path);
static bool GetCachedCover(const std::wstring& artist, const std::wstring& title, std::wstring& target); static bool GetLocal(std::wstring filename, const std::wstring& folder, std::wstring& target);
static bool GetLocalCover(std::wstring filename, const std::wstring& folder, std::wstring& target); static bool GetEmbedded(const TagLib::FileRef& fr, std::wstring& target);
static bool GetEmbeddedCover(const TagLib::FileRef& fr, std::wstring& target);
static std::wstring GetFileFolder(const std::wstring& file); static std::wstring GetFileFolder(const std::wstring& file);
private: private:

View 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;
}

View 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

View 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;
}

View 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

View File

@ -19,6 +19,7 @@
#include "StdAfx.h" #include "StdAfx.h"
#include "../../Library/DisableThreadLibraryCalls.h" // contains DllMain entry point #include "../../Library/DisableThreadLibraryCalls.h" // contains DllMain entry point
#include "NowPlaying.h" #include "NowPlaying.h"
#include "Internet.h"
#include "PlayerAIMP.h" #include "PlayerAIMP.h"
#include "PlayerCAD.h" #include "PlayerCAD.h"
#include "PlayerFoobar.h" #include "PlayerFoobar.h"
@ -28,17 +29,7 @@
#include "PlayerWLM.h" #include "PlayerWLM.h"
#include "PlayerWMP.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 std::map<UINT, ChildMeasure*> g_Measures;
static bool g_DisableLeazingZero = false;
std::wstring g_CachePath; std::wstring g_CachePath;
std::wstring g_SettingsFile; 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."); 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 // 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 (_wcsicmp(L"AIMP", str) == 0)
{ {
if (!g_AIMP) parent->player = CPlayerAIMP::Create();
{
g_AIMP = new CPlayerAIMP();
}
parent->player = g_AIMP;
} }
else if (_wcsicmp(L"CAD", str) == 0) else if (_wcsicmp(L"CAD", str) == 0)
{ {
if (!g_CAD) parent->player = CPlayerCAD::Create();
{
g_CAD = new CPlayerCAD();
}
parent->player = g_CAD;
} }
else if (_wcsicmp(L"foobar2000", str) == 0) else if (_wcsicmp(L"foobar2000", str) == 0)
{ {
if (!g_Foobar) parent->player = CPlayerFoobar::Create();
{
g_Foobar = new CPlayerFoobar();
}
parent->player = g_Foobar;
} }
else if (_wcsicmp(L"iTunes", str) == 0) else if (_wcsicmp(L"iTunes", str) == 0)
{ {
if (!g_iTunes) parent->player = CPlayerITunes::Create();
{
g_iTunes = new CPlayerITunes();
}
parent->player = g_iTunes;
} }
else if (_wcsicmp(L"MediaMonkey", str) == 0) else if (_wcsicmp(L"MediaMonkey", str) == 0)
{ {
if (!g_Winamp) parent->player = CPlayerWinamp::Create(WA_MEDIAMONKEY);
{
g_Winamp = new CPlayerWinamp(WA_MEDIAMONKEY);
}
parent->player = g_Winamp;
} }
else if (_wcsicmp(L"Spotify", str) == 0) else if (_wcsicmp(L"Spotify", str) == 0)
{ {
if (!g_Spotify) parent->player = CPlayerSpotify::Create();
{
g_Spotify = new CPlayerSpotify();
}
parent->player = g_Spotify;
} }
else if (_wcsicmp(L"WinAmp", str) == 0) else if (_wcsicmp(L"WinAmp", str) == 0)
{ {
if (!g_Winamp) parent->player = CPlayerWinamp::Create(WA_WINAMP);
{
g_Winamp = new CPlayerWinamp(WA_WINAMP);
}
parent->player = g_Winamp;
} }
else if (_wcsicmp(L"WLM", str) == 0) else if (_wcsicmp(L"WLM", str) == 0)
{ {
if (!g_WLM) parent->player = CPlayerWLM::Create();
{
g_WLM = new CPlayerWLM();
}
parent->player = g_WLM;
} }
else if (_wcsicmp(L"WMP", str) == 0) else if (_wcsicmp(L"WMP", str) == 0)
{ {
if (!g_WMP) parent->player = CPlayerWMP::Create();
{
g_WMP = new CPlayerWMP();
}
parent->player = g_WMP;
} }
else else
{ {
@ -331,6 +288,11 @@ void Finalize(HMODULE instance, UINT id)
delete child; delete child;
g_Measures.erase(i); g_Measures.erase(i);
if (g_Measures.empty())
{
CInternet::Finalize();
}
} }
} }
@ -359,8 +321,6 @@ UINT Update(UINT id)
parent->trackCount != player->GetTrackCount()) parent->trackCount != player->GetTrackCount())
{ {
ExecuteCommand(parent->trackChangeAction, parent->window); ExecuteCommand(parent->trackChangeAction, parent->window);
// TODO: First is true..
parent->trackCount = player->GetTrackCount(); parent->trackCount = player->GetTrackCount();
} }
} }
@ -423,6 +383,9 @@ LPCTSTR GetString(UINT id, UINT flags)
case MEASURE_ALBUM: case MEASURE_ALBUM:
return player->GetAlbum(); return player->GetAlbum();
case MEASURE_LYRICS:
return player->GetLyrics();
case MEASURE_COVER: case MEASURE_COVER:
return player->GetCoverPath(); return player->GetCoverPath();

View File

@ -27,7 +27,6 @@ struct ParentMeasure
UINT childCount; UINT childCount;
UINT trackCount; UINT trackCount;
CPlayer* player; CPlayer* player;
HANDLE thread;
HWND window; HWND window;
std::wstring name; std::wstring name;
std::wstring iniFile; std::wstring iniFile;
@ -35,7 +34,7 @@ struct ParentMeasure
std::wstring playerPath; std::wstring playerPath;
bool disableLeadingZero; bool disableLeadingZero;
ParentMeasure() : player(NULL), thread(NULL) {} ParentMeasure() : player(NULL) {}
}; };
struct ChildMeasure struct ChildMeasure

View File

@ -19,6 +19,8 @@
#include "StdAfx.h" #include "StdAfx.h"
#include "Player.h" #include "Player.h"
extern std::wstring g_CachePath;
/* /*
** CPlayer ** CPlayer
** **
@ -36,8 +38,11 @@ CPlayer::CPlayer() :
m_Duration(), m_Duration(),
m_Position(), m_Position(),
m_Rating(), m_Rating(),
m_Volume() m_Volume(),
m_CriticalSection(),
m_InternetThread()
{ {
InitializeCriticalSection(&m_CriticalSection);
} }
/* /*
@ -48,6 +53,7 @@ CPlayer::CPlayer() :
*/ */
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 ** ClearData
** **
@ -125,6 +256,7 @@ void CPlayer::ClearData()
m_Artist.clear(); m_Artist.clear();
m_Album.clear(); m_Album.clear();
m_Title.clear(); m_Title.clear();
m_Lyrics.clear();
m_FilePath.clear(); m_FilePath.clear();
m_CoverPath.clear(); m_CoverPath.clear();
} }

View File

@ -19,8 +19,11 @@
#ifndef __PLAYER_H__ #ifndef __PLAYER_H__
#define __PLAYER_H__ #define __PLAYER_H__
#include "fileref.h"
#include "tag.h" #include "tag.h"
#include "Cover.h" #include "Cover.h"
#include "Internet.h"
#include "Lyrics.h"
enum PLAYSTATE enum PLAYSTATE
{ {
@ -45,8 +48,7 @@ enum MEASURETYPE
MEASURE_FILE MEASURE_FILE
}; };
class CPlayer : class CPlayer
public CCover
{ {
public: public:
CPlayer(); CPlayer();
@ -61,6 +63,10 @@ public:
bool IsInitialized() { return m_Initialized; } bool IsInitialized() { return m_Initialized; }
UINT GetTrackCount() { return m_TrackCount; } UINT GetTrackCount() { return m_TrackCount; }
std::wstring GetCacheFile();
void FindCover();
void FindLyrics();
virtual void Pause() {} virtual void Pause() {}
virtual void Play() {} virtual void Play() {}
virtual void Stop() {} virtual void Stop() {}
@ -105,6 +111,12 @@ protected:
UINT m_Position; // Current position in seconds UINT m_Position; // Current position in seconds
UINT m_Rating; // Track rating from 0 to 100 UINT m_Rating; // Track rating from 0 to 100
UINT m_Volume; // Volume 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 #endif

View File

@ -21,8 +21,9 @@
#include "AIMP/aimp2_sdk.h" #include "AIMP/aimp2_sdk.h"
#include "Winamp/wa_ipc.h" #include "Winamp/wa_ipc.h"
extern CPlayer* g_AIMP; CPlayer* CPlayerAIMP::c_Player = NULL;
// TODO
/* /*
** CPlayerAIMP ** CPlayerAIMP
** **
@ -30,10 +31,10 @@ extern CPlayer* g_AIMP;
** **
*/ */
CPlayerAIMP::CPlayerAIMP() : CPlayer(), CPlayerAIMP::CPlayerAIMP() : CPlayer(),
m_FileMap(),
m_FileMapHandle(),
m_Window(), m_Window(),
m_WinampWindow() m_WinampWindow(),
m_FileMap(),
m_FileMapHandle()
{ {
} }
@ -45,62 +46,35 @@ CPlayerAIMP::CPlayerAIMP() : CPlayer(),
*/ */
CPlayerAIMP::~CPlayerAIMP() CPlayerAIMP::~CPlayerAIMP()
{ {
g_AIMP = NULL; c_Player = NULL;
if (m_FileMap) UnmapViewOfFile(m_FileMap); if (m_FileMap) UnmapViewOfFile(m_FileMap);
if (m_FileMapHandle) CloseHandle(m_FileMapHandle); 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"); if (!c_Player)
m_WinampWindow = FindWindow(L"Winamp v1.x", NULL);
if (m_Window)
{ {
m_FileMapHandle = OpenFileMapping(FILE_MAP_READ, FALSE, L"AIMP2_RemoteInfo"); c_Player = new CPlayerAIMP();
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); return c_Player;
if (!m_FileMap)
{
LSLog(LOG_ERROR, L"Rainmeter", L"NowPlayingPlugin: AIMP - Unable to view mapping.");
return false;
}
return true;
}
return false;
} }
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; static DWORD oldTime = 0;
DWORD time = GetTickCount(); DWORD time = GetTickCount();
@ -108,11 +82,33 @@ bool CPlayerAIMP::CheckActive()
if (time - oldTime > 5000) if (time - oldTime > 5000)
{ {
oldTime = time; oldTime = time;
return Initialize(); m_Window = FindWindow(L"AIMP2_RemoteInfo", L"AIMP2_RemoteInfo");
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 false; return m_Initialized;
}
} }
/* /*
@ -123,29 +119,43 @@ bool CPlayerAIMP::CheckActive()
*/ */
void CPlayerAIMP::UpdateData() void CPlayerAIMP::UpdateData()
{ {
static long oldFileSize; static long oldFileSize = 0;
static UINT oldTitleLen; static UINT oldTitleLen = 0;
if (!CheckActive()) if (!m_Initialized)
{ {
// Make sure AIMP is running if (oldTitleLen != 0)
if (oldFileSize != 0)
{ {
oldFileSize = 0; oldFileSize = 0;
oldTitleLen = 0; oldTitleLen = 0;
} }
if (!CheckWindow())
{
return; return;
} }
}
// If initialized
m_State = (PLAYSTATE)SendMessage(m_Window, WM_AIMP_COMMAND, WM_AIMP_STATUS_GET, AIMP_STS_Player); m_State = (PLAYSTATE)SendMessage(m_Window, WM_AIMP_COMMAND, WM_AIMP_STATUS_GET, AIMP_STS_Player);
if (m_State == PLAYER_STOPPED) 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; oldFileSize = 0;
oldTitleLen = 0; oldTitleLen = 0;
ClearData(); ClearData();
} }
// Don't continue if AIMP has quit or is stopped
return; return;
} }
@ -154,7 +164,7 @@ void CPlayerAIMP::UpdateData()
AIMP2FileInfo* info = (AIMP2FileInfo*)m_FileMap; AIMP2FileInfo* info = (AIMP2FileInfo*)m_FileMap;
if (info->cbSizeOf > 0 && 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) info->nTitleLen != oldTitleLen)
{ {
oldFileSize = info->nFileSize; oldFileSize = info->nFileSize;
@ -191,7 +201,12 @@ void CPlayerAIMP::UpdateData()
// Find cover if needed // Find cover if needed
if (m_HasCoverMeasure) if (m_HasCoverMeasure)
{ {
GetCover(m_Artist, m_Title, m_FilePath, m_CoverPath); FindCover();
}
if (m_HasLyricsMeasure)
{
FindLyrics();
} }
} }
} }

View File

@ -24,8 +24,9 @@
class CPlayerAIMP : public CPlayer class CPlayerAIMP : public CPlayer
{ {
public: public:
CPlayerAIMP(); virtual ~CPlayerAIMP();
~CPlayerAIMP();
static CPlayer* Create();
virtual void UpdateData(); virtual void UpdateData();
@ -40,14 +41,19 @@ public:
virtual void ClosePlayer(); virtual void ClosePlayer();
virtual void OpenPlayer(std::wstring& path); virtual void OpenPlayer(std::wstring& path);
protected:
CPlayerAIMP();
private: private:
bool Initialize(); bool Initialize();
bool CheckActive(); bool CheckWindow();
static CPlayer* c_Player;
LPVOID m_FileMap;
HANDLE m_FileMapHandle;
HWND m_Window; // AIMP window HWND m_Window; // AIMP window
HWND m_WinampWindow; // AIMP Winamp API window HWND m_WinampWindow; // AIMP Winamp API window
LPVOID m_FileMap;
HANDLE m_FileMapHandle;
}; };
#endif #endif

View File

@ -20,7 +20,7 @@
#include "PlayerCAD.h" #include "PlayerCAD.h"
#include "CAD/cad_sdk.h" #include "CAD/cad_sdk.h"
extern CPlayer* g_CAD; CPlayer* CPlayerCAD::c_Player = NULL;
extern std::wstring g_SettingsFile; extern std::wstring g_SettingsFile;
// This player emulates the CD Art Display IPC interface, which is supported by // This player emulates the CD Art Display IPC interface, which is supported by
@ -47,10 +47,26 @@ CPlayerCAD::CPlayerCAD() : CPlayer(),
*/ */
CPlayerCAD::~CPlayerCAD() CPlayerCAD::~CPlayerCAD()
{ {
g_CAD = NULL; c_Player = NULL;
Uninitialize(); Uninitialize();
} }
/*
** Create
**
** Creates a shared class object.
**
*/
CPlayer* CPlayerCAD::Create()
{
if (!c_Player)
{
c_Player = new CPlayerCAD();
}
return c_Player;
}
/* /*
** Initialize ** Initialize
** **
@ -113,6 +129,7 @@ void CPlayerCAD::Initialize()
if (m_PlayerWindow) if (m_PlayerWindow)
{ {
m_Initialized = true;
SendMessage(m_PlayerWindow, WM_USER, (WPARAM)m_Window, IPC_SET_CALLBACK_HWND); 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); 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) LRESULT CALLBACK CPlayerCAD::WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{ {
static CPlayerCAD* p; static CPlayerCAD* player;
switch (msg) switch (msg)
{ {
case WM_CREATE: case WM_CREATE:
// Get pointer to the CPlayerCAD class from the CreateWindow call // Get pointer to the CPlayerCAD class from the CreateWindow call
p = (CPlayerCAD*)((CREATESTRUCT*)lParam)->lpCreateParams; player = (CPlayerCAD*)((CREATESTRUCT*)lParam)->lpCreateParams;
return 0; return 0;
case WM_DESTROY: 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; return 0;
case WM_USER: case WM_USER:
switch (lParam) switch (lParam)
{ {
case IPC_TRACK_CHANGED_NOTIFICATION: 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; break;
case IPC_PLAYER_STATE_CHANGED_NOTIFICATION: case IPC_PLAYER_STATE_CHANGED_NOTIFICATION:
p->m_State = (PLAYSTATE)wParam; player->m_State = (PLAYSTATE)wParam;
if (p->m_State == PLAYER_STOPPED) if (player->m_State == PLAYER_STOPPED)
{ {
p->ClearData(); player->ClearData();
} }
break; break;
case IPC_SHUTDOWN_NOTIFICATION: case IPC_SHUTDOWN_NOTIFICATION:
p->m_PlayerWindow = NULL; player->m_Initialized = false;
p->ClearData(); player->ClearData();
break; break;
} }
return 0; return 0;
@ -184,19 +201,19 @@ LRESULT CALLBACK CPlayerCAD::WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM
if (cds->dwData == IPC_CURRENT_TRACK_INFO) if (cds->dwData == IPC_CURRENT_TRACK_INFO)
{ {
// TODO: Sent on track update? // TODO: Sent on track update?
++p->m_TrackCount; ++player->m_TrackCount;
std::wstring data = (WCHAR*)cds->lpData; std::wstring data = (WCHAR*)cds->lpData;
std::wstring::size_type len = data.find_first_of(L'\t'); 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); data.erase(0, ++len);
len = data.find_first_of(L'\t'); 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); data.erase(0, ++len);
len = data.find_first_of(L'\t'); 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); data.erase(0, ++len);
len = data.find_first_of(L'\t'); // Skip genre 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); data.erase(0, ++len);
len = data.find_first_of(L'\t'); 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); data.erase(0, ++len);
len = data.find_first_of(L'\t'); 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); data.erase(0, ++len);
len = data.find_first_of(L'\t'); len = data.find_first_of(L'\t');
UINT rating = (_wtoi(data.substr(0, len).c_str()) + 1) / 2; // From 0 - 10 to 0 - 5 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); data.erase(0, ++len);
len = data.find_first_of(L'\t'); 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); 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; std::wstring data = (WCHAR*)cds->lpData;
if (data[0] == L'1') if (data[0] == L'1')
@ -238,7 +260,7 @@ LRESULT CALLBACK CPlayerCAD::WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM
data.erase(0, ++len); data.erase(0, ++len);
len = data.find_first_of(L'\t'); 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); data.erase(0, ++len);
LPCTSTR classSz = className.empty() ? NULL : className.c_str(); 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"ClassName", classSz, file);
WritePrivateProfileString(L"NowPlaying.dll", L"WindowName", windowSz, 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() void CPlayerCAD::ClosePlayer()
{ {
SendMessage(m_PlayerWindow, WM_USER, 0, IPC_CLOSE_PLAYER); SendMessage(m_PlayerWindow, WM_USER, 0, IPC_CLOSE_PLAYER);
m_PlayerWindow = NULL; // TODO
m_Initialized = false;
ClearData(); ClearData();
} }

View File

@ -24,8 +24,9 @@
class CPlayerCAD : public CPlayer class CPlayerCAD : public CPlayer
{ {
public: public:
CPlayerCAD(); virtual ~CPlayerCAD();
~CPlayerCAD();
static CPlayer* Create();
virtual void UpdateData(); virtual void UpdateData();
@ -40,11 +41,16 @@ public:
virtual void ClosePlayer(); virtual void ClosePlayer();
virtual void OpenPlayer(std::wstring& path); virtual void OpenPlayer(std::wstring& path);
protected:
CPlayerCAD();
private: private:
void Initialize(); void Initialize();
void Uninitialize(); void Uninitialize();
static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
static CPlayer* c_Player;
HWND m_Window; HWND m_Window;
HWND m_PlayerWindow; HWND m_PlayerWindow;
std::wstring m_PlayerPath; std::wstring m_PlayerPath;

View File

@ -19,7 +19,7 @@
#include "StdAfx.h" #include "StdAfx.h"
#include "PlayerFoobar.h" #include "PlayerFoobar.h"
extern CPlayer* g_Foobar; CPlayer* CPlayerFoobar::c_Player = NULL;
/* /*
** CPlayerFoobar ** CPlayerFoobar
@ -42,10 +42,26 @@ CPlayerFoobar::CPlayerFoobar() : CPlayer(),
*/ */
CPlayerFoobar::~CPlayerFoobar() CPlayerFoobar::~CPlayerFoobar()
{ {
g_Foobar = NULL; c_Player = NULL;
Uninitialize(); Uninitialize();
} }
/*
** Create
**
** Creates a shared class object.
**
*/
CPlayer* CPlayerFoobar::Create()
{
if (!c_Player)
{
c_Player = new CPlayerFoobar();
}
return c_Player;
}
/* /*
** Initialize ** Initialize
** **
@ -89,6 +105,7 @@ void CPlayerFoobar::Initialize()
} }
else else
{ {
m_Initialized = true;
SendMessage(m_FooWindow, WM_USER, (WPARAM)m_Window, FOO_SETCALLBACK); 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; break;
case FOO_PLAYERQUIT: case FOO_PLAYERQUIT:
player->m_FooWindow = NULL; player->m_Initialized = false;
player->ClearData(); player->ClearData();
break; break;
} }
@ -221,7 +238,12 @@ LRESULT CALLBACK CPlayerFoobar::WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPAR
if (player->m_HasCoverMeasure || player->m_InstanceCount == 0) 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) void CPlayerFoobar::OpenPlayer(std::wstring& path)
{ {
if (!m_FooWindow) if (!m_Initialized)
{ {
if (path.empty()) if (path.empty())
{ {

View File

@ -24,8 +24,9 @@
class CPlayerFoobar : public CPlayer class CPlayerFoobar : public CPlayer
{ {
public: public:
CPlayerFoobar(); virtual ~CPlayerFoobar();
~CPlayerFoobar();
static CPlayer* Create();
virtual void UpdateData(); virtual void UpdateData();
@ -40,6 +41,9 @@ public:
virtual void ClosePlayer(); virtual void ClosePlayer();
virtual void OpenPlayer(std::wstring& path); virtual void OpenPlayer(std::wstring& path);
protected:
CPlayerFoobar();
private: private:
enum FOOMESSAGE enum FOOMESSAGE
{ {
@ -73,6 +77,8 @@ private:
void Uninitialize(); void Uninitialize();
static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
static CPlayer* c_Player;
HWND m_Window; // Our reciever window HWND m_Window; // Our reciever window
HWND m_FooWindow; // Foobar receiver window HWND m_FooWindow; // Foobar receiver window
}; };

View File

@ -19,7 +19,7 @@
#include "StdAfx.h" #include "StdAfx.h"
#include "PlayerITunes.h" #include "PlayerITunes.h"
extern CPlayer* g_iTunes; CPlayer* CPlayerITunes::c_Player = NULL;
/* /*
** CEventHandler ** CEventHandler
@ -129,11 +129,27 @@ CPlayerITunes::CPlayerITunes() : CPlayer(),
*/ */
CPlayerITunes::~CPlayerITunes() CPlayerITunes::~CPlayerITunes()
{ {
g_iTunes = NULL; c_Player = NULL;
Uninitialize(); Uninitialize();
CoUninitialize(); CoUninitialize();
} }
/*
** Create
**
** Creates a shared class object.
**
*/
CPlayer* CPlayerITunes::Create()
{
if (!c_Player)
{
c_Player = new CPlayerITunes();
}
return c_Player;
}
/* /*
** Initialize ** Initialize
** **
@ -216,7 +232,6 @@ void CPlayerITunes::Uninitialize()
if (m_Initialized) if (m_Initialized)
{ {
m_Initialized = false; m_Initialized = false;
m_UserQuitPrompt = true;
if (m_iTunes) if (m_iTunes)
{ {
m_iTunes->Release(); m_iTunes->Release();
@ -304,6 +319,7 @@ void CPlayerITunes::OnTrackChange()
track->get_Duration(&tmpVal); track->get_Duration(&tmpVal);
m_Duration = (UINT)tmpVal; m_Duration = (UINT)tmpVal;
// Rating is 0 - 100, divide to 0 - 5
track->get_Rating(&tmpVal); track->get_Rating(&tmpVal);
tmpVal /= 20L; tmpVal /= 20L;
m_Rating = (UINT)tmpVal; m_Rating = (UINT)tmpVal;
@ -319,9 +335,12 @@ void CPlayerITunes::OnTrackChange()
++m_TrackCount; ++m_TrackCount;
m_FilePath = tmpStr; m_FilePath = tmpStr;
if (m_HasCoverMeasure && !GetCachedCover(m_Artist, m_Title, m_CoverPath)) if (m_HasCoverMeasure)
{ {
// Art not in cache, check for embedded art m_CoverPath = GetCacheFile();
if (!CCover::GetCached(m_CoverPath))
{
// Art not in cache, check for embedded art through iTunes interface
IITArtworkCollection* artworkCollection; IITArtworkCollection* artworkCollection;
hr = track->get_Artwork(&artworkCollection); hr = track->get_Artwork(&artworkCollection);
@ -360,6 +379,12 @@ void CPlayerITunes::OnTrackChange()
} }
} }
} }
if (m_HasLyricsMeasure)
{
FindLyrics();
}
}
} }
track->Release(); track->Release();

View File

@ -35,8 +35,9 @@
class CPlayerITunes : public CPlayer class CPlayerITunes : public CPlayer
{ {
public: public:
CPlayerITunes(); virtual ~CPlayerITunes();
~CPlayerITunes();
static CPlayer* Create();
virtual void UpdateData(); virtual void UpdateData();
@ -51,6 +52,9 @@ public:
virtual void ClosePlayer(); virtual void ClosePlayer();
virtual void OpenPlayer(std::wstring& path); virtual void OpenPlayer(std::wstring& path);
protected:
CPlayerITunes();
private: private:
class CEventHandler : public _IiTunesEvents class CEventHandler : public _IiTunesEvents
{ {
@ -83,6 +87,8 @@ private:
void OnVolumeChange(int volume); void OnVolumeChange(int volume);
bool CheckWindow(); bool CheckWindow();
static CPlayer* c_Player;
bool m_UserQuitPrompt; bool m_UserQuitPrompt;
IiTunes* m_iTunes; IiTunes* m_iTunes;
CEventHandler* m_iTunesEvent; CEventHandler* m_iTunesEvent;

View File

@ -19,7 +19,7 @@
#include "StdAfx.h" #include "StdAfx.h"
#include "PlayerSpotify.h" #include "PlayerSpotify.h"
extern CPlayer* g_Spotify; CPlayer* CPlayerSpotify::c_Player = NULL;
/* /*
** CPlayerSpotify ** CPlayerSpotify
@ -40,7 +40,23 @@ CPlayerSpotify::CPlayerSpotify() : CPlayer(),
*/ */
CPlayerSpotify::~CPlayerSpotify() 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_Title = track;
m_Artist = artist; m_Artist = artist;
++m_TrackCount; ++m_TrackCount;
if (m_HasLyricsMeasure)
{
FindLyrics();
}
} }
return; return;
} }

View File

@ -24,8 +24,9 @@
class CPlayerSpotify : public CPlayer class CPlayerSpotify : public CPlayer
{ {
public: public:
CPlayerSpotify(); virtual ~CPlayerSpotify();
~CPlayerSpotify();
static CPlayer* Create();
virtual void Pause() { return Play(); } virtual void Pause() { return Play(); }
virtual void Play(); virtual void Play();
@ -36,6 +37,9 @@ public:
virtual void OpenPlayer(std::wstring& path); virtual void OpenPlayer(std::wstring& path);
virtual void UpdateData(); virtual void UpdateData();
protected:
CPlayerSpotify();
private: private:
enum SPOTIFYCOMMAND enum SPOTIFYCOMMAND
{ {
@ -50,6 +54,8 @@ private:
bool CheckWindow(); bool CheckWindow();
static CPlayer* c_Player;
HWND m_Window; HWND m_Window;
}; };

View File

@ -19,7 +19,7 @@
#include "StdAfx.h" #include "StdAfx.h"
#include "PlayerWLM.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 // This player emulates the MSN/WLM Messenger 'Listening to' interface, which is
// supported by OpenPandora, Last.fm, Media Player Classic, TTPlayer, Zune, etc. // supported by OpenPandora, Last.fm, Media Player Classic, TTPlayer, Zune, etc.
@ -54,6 +54,8 @@ CPlayerWLM::CPlayerWLM() : CPlayer(),
NULL, NULL,
hInstance, hInstance,
this); this);
m_Initialized = true;
} }
/* /*
@ -64,11 +66,27 @@ CPlayerWLM::CPlayerWLM() : CPlayer(),
*/ */
CPlayerWLM::~CPlayerWLM() CPlayerWLM::~CPlayerWLM()
{ {
g_WLM = NULL; c_Player = NULL;
DestroyWindow(m_Window); DestroyWindow(m_Window);
UnregisterClass(L"MsnMsgrUIManager", GetModuleHandle(NULL)); 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) LRESULT CALLBACK CPlayerWLM::WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{ {
static CPlayerWLM* player; static CPlayerWLM* player;
@ -99,6 +117,7 @@ LRESULT CALLBACK CPlayerWLM::WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM
if (playing) if (playing)
{ {
++player->m_TrackCount;
player->m_State = PLAYER_PLAYING; player->m_State = PLAYER_PLAYING;
data.erase(0, 3); // Get rid of the status 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'\\'); len = data.find_first_of(L'\\');
player->m_Album = data.substr(0, len); player->m_Album = data.substr(0, len);
if (player->m_HasLyricsMeasure)
{
player->FindLyrics();
}
} }
else else
{ {

View File

@ -24,8 +24,9 @@
class CPlayerWLM : public CPlayer class CPlayerWLM : public CPlayer
{ {
public: public:
CPlayerWLM(); virtual ~CPlayerWLM();
~CPlayerWLM();
static CPlayer* Create();
virtual void UpdateData(); virtual void UpdateData();
@ -35,10 +36,15 @@ public:
virtual void Next(); virtual void Next();
virtual void Previous(); virtual void Previous();
protected:
CPlayerWLM();
private: private:
static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
void SendKeyInput(WORD key); void SendKeyInput(WORD key);
static CPlayer* c_Player;
HWND m_Window; HWND m_Window;
}; };

View File

@ -19,7 +19,7 @@
#include "StdAfx.h" #include "StdAfx.h"
#include "PlayerWMP.h" #include "PlayerWMP.h"
extern CPlayer* g_WMP; CPlayer* CPlayerWMP::c_Player = NULL;
/* /*
** CRemoteHost ** CRemoteHost
@ -170,11 +170,27 @@ CPlayerWMP::CPlayerWMP() : CPlayer(),
*/ */
CPlayerWMP::~CPlayerWMP() CPlayerWMP::~CPlayerWMP()
{ {
g_WMP = NULL; c_Player = NULL;
Uninitialize(); Uninitialize();
m_ComModule.Term(); m_ComModule.Term();
} }
/*
** Create
**
** Creates a shared class object.
**
*/
CPlayer* CPlayerWMP::Create()
{
if (!c_Player)
{
c_Player = new CPlayerWMP();
}
return c_Player;
}
/* /*
** Initialize ** Initialize
** **
@ -450,9 +466,14 @@ void CPlayerWMP::UpdateData()
} }
else else
{ {
GetCover(m_Artist, m_Title, m_FilePath, m_CoverPath); FindCover();
} }
} }
if (m_HasLyricsMeasure)
{
FindLyrics();
}
} }
} }
} }

View File

@ -34,8 +34,9 @@
class CPlayerWMP : public CPlayer class CPlayerWMP : public CPlayer
{ {
public: public:
CPlayerWMP(); virtual ~CPlayerWMP();
~CPlayerWMP();
static CPlayer* Create();
virtual void UpdateData(); virtual void UpdateData();
@ -50,6 +51,9 @@ public:
virtual void OpenPlayer(std::wstring& path); virtual void OpenPlayer(std::wstring& path);
virtual void ClosePlayer(); virtual void ClosePlayer();
protected:
CPlayerWMP();
private: private:
class CRemoteHost : class CRemoteHost :
public CComObjectRootEx<CComSingleThreadModel>, public CComObjectRootEx<CComSingleThreadModel>,
@ -129,6 +133,8 @@ private:
void Initialize(); void Initialize();
void Uninitialize(); void Uninitialize();
static CPlayer* c_Player;
bool m_TrackChanged; bool m_TrackChanged;
HWND m_Window; HWND m_Window;
CAxWindow* m_AxWindow; CAxWindow* m_AxWindow;

View File

@ -21,7 +21,7 @@
#include "Winamp/wa_ipc.h" #include "Winamp/wa_ipc.h"
#include "Winamp/wa_cmd.h" #include "Winamp/wa_cmd.h"
extern CPlayer* g_Winamp; CPlayer* CPlayerWinamp::c_Player = NULL;
// This player retrieves data through the Winamp IPC interface. // This player retrieves data through the Winamp IPC interface.
@ -32,9 +32,11 @@ extern CPlayer* g_Winamp;
** **
*/ */
CPlayerWinamp::CPlayerWinamp(WINAMPTYPE type) : CPlayer(), CPlayerWinamp::CPlayerWinamp(WINAMPTYPE type) : CPlayer(),
m_WinampType(type), m_Window(),
m_UseUnicodeAPI(false), m_UseUnicodeAPI(false),
m_Window() m_WinampType(type),
m_WinampHandle(),
m_WinampAddress()
{ {
} }
@ -46,10 +48,26 @@ CPlayerWinamp::CPlayerWinamp(WINAMPTYPE type) : CPlayer(),
*/ */
CPlayerWinamp::~CPlayerWinamp() CPlayerWinamp::~CPlayerWinamp()
{ {
g_Winamp = NULL; c_Player = NULL;
if (m_WinampHandle) CloseHandle(m_WinampHandle); 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 ** CheckWindow
** **
@ -204,12 +222,19 @@ void CPlayerWinamp::UpdateData()
} }
} }
// Find cover if needed if (m_HasLyricsMeasure)
if (m_HasCoverMeasure &&
!GetCachedCover(m_Artist, m_Title, m_CoverPath) &&
!GetEmbeddedCover(fr, m_CoverPath))
{ {
std::wstring trackFolder = GetFileFolder(m_FilePath); FindLyrics();
}
// Find cover if needed
if (m_HasCoverMeasure)
{
m_CoverPath = GetCacheFile();
if (!CCover::GetCached(m_CoverPath) &&
!CCover::GetEmbedded(fr, m_CoverPath))
{
std::wstring trackFolder = CCover::GetFileFolder(m_FilePath);
if (!m_Album.empty()) if (!m_Album.empty())
{ {
@ -247,20 +272,20 @@ void CPlayerWinamp::UpdateData()
} }
} }
if (GetLocalCover(file, trackFolder, m_CoverPath)) if (CCover::GetLocal(file, trackFolder, m_CoverPath))
{ {
// %album% art file found // %album% art file found
return; return;
} }
} }
if (!GetLocalCover(L"cover", trackFolder, m_CoverPath) && if (!CCover::GetLocal(L"cover", trackFolder, m_CoverPath) &&
!GetLocalCover(L"folder", trackFolder, m_CoverPath)) !CCover::GetLocal(L"folder", trackFolder, m_CoverPath))
{ {
// Nothing found // Nothing found
m_CoverPath.clear(); m_CoverPath.clear();
} }
}
} }
} }
} }

View File

@ -30,8 +30,9 @@ enum WINAMPTYPE
class CPlayerWinamp : public CPlayer class CPlayerWinamp : public CPlayer
{ {
public: public:
CPlayerWinamp(WINAMPTYPE type); virtual ~CPlayerWinamp();
~CPlayerWinamp();
static CPlayer* Create(WINAMPTYPE type);
virtual void UpdateData(); virtual void UpdateData();
@ -46,12 +47,17 @@ public:
virtual void ClosePlayer(); virtual void ClosePlayer();
virtual void OpenPlayer(std::wstring& path); virtual void OpenPlayer(std::wstring& path);
protected:
CPlayerWinamp(WINAMPTYPE type);
private: private:
bool CheckWindow(); bool CheckWindow();
static CPlayer* c_Player;
HWND m_Window; // Winamp window
bool m_UseUnicodeAPI; bool m_UseUnicodeAPI;
WINAMPTYPE m_WinampType; WINAMPTYPE m_WinampType;
HWND m_Window; // Winamp window
HANDLE m_WinampHandle; // Handle to Winamp process HANDLE m_WinampHandle; // Handle to Winamp process
LPCVOID m_WinampAddress; LPCVOID m_WinampAddress;
}; };

View File

@ -122,6 +122,7 @@
<ProgramDatabaseFile>.\x32/Debug/NowPlaying.pdb</ProgramDatabaseFile> <ProgramDatabaseFile>.\x32/Debug/NowPlaying.pdb</ProgramDatabaseFile>
<ImportLibrary>.\x32/Debug/NowPlaying.lib</ImportLibrary> <ImportLibrary>.\x32/Debug/NowPlaying.lib</ImportLibrary>
<TargetMachine>MachineX86</TargetMachine> <TargetMachine>MachineX86</TargetMachine>
<AdditionalDependencies>WinInet.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
@ -162,6 +163,7 @@
<ProgramDatabaseFile>.\x64/Debug/NowPlaying.pdb</ProgramDatabaseFile> <ProgramDatabaseFile>.\x64/Debug/NowPlaying.pdb</ProgramDatabaseFile>
<ImportLibrary>.\x64/Debug/NowPlaying.lib</ImportLibrary> <ImportLibrary>.\x64/Debug/NowPlaying.lib</ImportLibrary>
<TargetMachine>MachineX64</TargetMachine> <TargetMachine>MachineX64</TargetMachine>
<AdditionalDependencies>WinInet.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
@ -198,7 +200,7 @@
<Culture>0x0409</Culture> <Culture>0x0409</Culture>
</ResourceCompile> </ResourceCompile>
<Link> <Link>
<AdditionalDependencies>Rainmeter.lib;Wininet.lib;%(AdditionalDependencies)</AdditionalDependencies> <AdditionalDependencies>Rainmeter.lib;WinInet.lib;%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>../../TestBench/x32/Release/Plugins/NowPlaying.dll</OutputFile> <OutputFile>../../TestBench/x32/Release/Plugins/NowPlaying.dll</OutputFile>
<SuppressStartupBanner>true</SuppressStartupBanner> <SuppressStartupBanner>true</SuppressStartupBanner>
<AdditionalLibraryDirectories>..\..\Library\x32\Release;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> <AdditionalLibraryDirectories>..\..\Library\x32\Release;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
@ -243,7 +245,7 @@
</ResourceCompile> </ResourceCompile>
<Link> <Link>
<AdditionalOptions>/LTCG %(AdditionalOptions)</AdditionalOptions> <AdditionalOptions>/LTCG %(AdditionalOptions)</AdditionalOptions>
<AdditionalDependencies>Rainmeter.lib;%(AdditionalDependencies)</AdditionalDependencies> <AdditionalDependencies>Rainmeter.lib;WinInet.lib;%(AdditionalDependencies)</AdditionalDependencies>
<OutputFile>../../TestBench/x64/Release/Plugins/NowPlaying.dll</OutputFile> <OutputFile>../../TestBench/x64/Release/Plugins/NowPlaying.dll</OutputFile>
<SuppressStartupBanner>true</SuppressStartupBanner> <SuppressStartupBanner>true</SuppressStartupBanner>
<AdditionalLibraryDirectories>..\..\Library\x64\Release;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> <AdditionalLibraryDirectories>..\..\Library\x64\Release;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
@ -256,6 +258,8 @@
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="Cover.cpp" /> <ClCompile Include="Cover.cpp" />
<ClCompile Include="Internet.cpp" />
<ClCompile Include="Lyrics.cpp" />
<ClCompile Include="NowPlaying.cpp" /> <ClCompile Include="NowPlaying.cpp" />
<ClCompile Include="Player.cpp" /> <ClCompile Include="Player.cpp" />
<ClCompile Include="PlayerAIMP.cpp" /> <ClCompile Include="PlayerAIMP.cpp" />
@ -344,6 +348,8 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="Cover.h" /> <ClInclude Include="Cover.h" />
<ClInclude Include="Internet.h" />
<ClInclude Include="Lyrics.h" />
<ClInclude Include="NowPlaying.h" /> <ClInclude Include="NowPlaying.h" />
<ClInclude Include="Player.h" /> <ClInclude Include="Player.h" />
<ClInclude Include="PlayerAIMP.h" /> <ClInclude Include="PlayerAIMP.h" />

View File

@ -267,6 +267,12 @@
<ClCompile Include="Cover.cpp"> <ClCompile Include="Cover.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="Lyrics.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="Internet.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="SDKs\AIMP\aimp2_sdk.h"> <ClInclude Include="SDKs\AIMP\aimp2_sdk.h">
@ -326,6 +332,12 @@
<ClInclude Include="Cover.h"> <ClInclude Include="Cover.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="Lyrics.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="Internet.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ResourceCompile Include="PluginNowPlaying.rc"> <ResourceCompile Include="PluginNowPlaying.rc">

View File

@ -20,7 +20,8 @@
#define __STDAFX_H__ #define __STDAFX_H__
// WinAPI // WinAPI
#include <windows.h> #include <Windows.h>
#include <WinInet.h>
// STL // STL
#include <string> #include <string>
@ -32,7 +33,4 @@
// Rainmeter's exported functions // Rainmeter's exported functions
#include "../../Library/Export.h" #include "../../Library/Export.h"
// TagLib
#include "fileref.h"
#endif #endif