315 lines
8.6 KiB
C++
315 lines
8.6 KiB
C++
|
#include "main.h"
|
||
|
#include "Metadata.h"
|
||
|
#include "../Winamp/wa_ipc.h"
|
||
|
#include "../nu/ns_wc.h"
|
||
|
#include "uvox_3901.h"
|
||
|
#include "uvox_3902.h"
|
||
|
#include "Stopper.h"
|
||
|
#include <shlwapi.h>
|
||
|
#include "../Agave/Language/api_language.h"
|
||
|
#include <strsafe.h>
|
||
|
|
||
|
extern CGioFile *g_playing_file;
|
||
|
static FILETIME ftLastWriteTime;
|
||
|
|
||
|
// is used to determine if the last write time of the file has changed when
|
||
|
// asked to get the metadata for the same cached file so we can update things
|
||
|
BOOL HasFileTimeChanged(const wchar_t *fn)
|
||
|
{
|
||
|
WIN32_FILE_ATTRIBUTE_DATA fileData = {0};
|
||
|
if (GetFileAttributesExW(fn, GetFileExInfoStandard, &fileData) == TRUE)
|
||
|
{
|
||
|
if(CompareFileTime(&ftLastWriteTime, &fileData.ftLastWriteTime))
|
||
|
{
|
||
|
ftLastWriteTime = fileData.ftLastWriteTime;
|
||
|
return TRUE;
|
||
|
}
|
||
|
}
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
void UpdateFileTimeChanged(const wchar_t *fn)
|
||
|
{
|
||
|
WIN32_FILE_ATTRIBUTE_DATA fileData;
|
||
|
if (GetFileAttributesExW(fn, GetFileExInfoStandard, &fileData) == TRUE)
|
||
|
{
|
||
|
ftLastWriteTime = fileData.ftLastWriteTime;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Metadata *m_ext_set_mp3info = NULL;
|
||
|
Metadata *m_ext_get_mp3info = NULL;
|
||
|
extern "C" __declspec(dllexport)
|
||
|
int winampGetExtendedFileInfoW(const wchar_t *fn, const char *data, wchar_t *dest, size_t destlen)
|
||
|
{
|
||
|
if (!_stricmp(data, "type"))
|
||
|
{
|
||
|
dest[0] = '0';
|
||
|
dest[1] = 0;
|
||
|
return 1;
|
||
|
}
|
||
|
if (!_stricmp(data, "rateable"))
|
||
|
{
|
||
|
dest[0] = '1';
|
||
|
dest[1] = 0;
|
||
|
return 1;
|
||
|
}
|
||
|
else if (!_stricmp(data, "family"))
|
||
|
{
|
||
|
if (!fn || !fn[0]) return 0;
|
||
|
int len = lstrlenW(fn);
|
||
|
if (len < 4 || L'.' != fn[len - 4]) return 0;
|
||
|
const wchar_t *p = &fn[len - 3];
|
||
|
if (!_wcsicmp(p, L"MP3")) { WASABI_API_LNGSTRINGW_BUF(IDS_FAMILY_STRING_MP3, dest, destlen); return 1; }
|
||
|
if (!_wcsicmp(p, L"MP2")) { WASABI_API_LNGSTRINGW_BUF(IDS_FAMILY_STRING_MP2, dest, destlen); return 1; }
|
||
|
if (!_wcsicmp(p, L"MP1")) { WASABI_API_LNGSTRINGW_BUF(IDS_FAMILY_STRING_MP1, dest, destlen); return 1; }
|
||
|
if (!_wcsicmp(p, L"AAC")) { WASABI_API_LNGSTRINGW_BUF(IDS_FAMILY_STRING_MPEG2_AAC, dest, destlen); return 1; }
|
||
|
if (!_wcsicmp(p, L"VLB")) { WASABI_API_LNGSTRINGW_BUF(IDS_FAMILY_STRING_DOLBY, dest, destlen); return 1; }
|
||
|
return 0;
|
||
|
}
|
||
|
else if (!_stricmp(data, "mime"))
|
||
|
{
|
||
|
if (!fn || !fn[0]) return 0;
|
||
|
int len = lstrlenW(fn);
|
||
|
if (len < 4 || L'.' != fn[len - 4]) return 0;
|
||
|
const wchar_t *p = &fn[len - 3];
|
||
|
if (!_wcsicmp(p, L"MP3")) { StringCchCopyW(dest, destlen, L"audio/mpeg"); return 1; }
|
||
|
if (!_wcsicmp(p, L"MP2")) { StringCchCopyW(dest, destlen, L"audio/mpeg"); return 1; }
|
||
|
if (!_wcsicmp(p, L"MP1")) { StringCchCopyW(dest, destlen, L"audio/mpeg"); return 1; }
|
||
|
if (!_wcsicmp(p, L"AAC")) { StringCchCopyW(dest, destlen, L"audio/aac"); return 1; }
|
||
|
if (!_wcsicmp(p, L"VLB")) { StringCchCopyW(dest, destlen, L"audio/vlb"); return 1; }
|
||
|
return 0;
|
||
|
}
|
||
|
else if (!_strnicmp(data, "uvox/", 5))
|
||
|
{
|
||
|
EnterCriticalSection(&streamInfoLock);
|
||
|
if (g_playing_file)
|
||
|
{
|
||
|
if (g_playing_file->uvox_3901) // check again now that we've acquired the lock
|
||
|
{
|
||
|
Ultravox3901 uvox_metadata;
|
||
|
if (uvox_metadata.Parse(g_playing_file->uvox_3901) != API_XML_FAILURE)
|
||
|
{
|
||
|
LeaveCriticalSection(&streamInfoLock);
|
||
|
return uvox_metadata.GetExtendedData(data, dest, (int)destlen);
|
||
|
}
|
||
|
}
|
||
|
else if (g_playing_file->uvox_3902)
|
||
|
{
|
||
|
Ultravox3902 uvox_metadata;
|
||
|
if (uvox_metadata.Parse(g_playing_file->uvox_3902) != API_XML_FAILURE)
|
||
|
{
|
||
|
LeaveCriticalSection(&streamInfoLock);
|
||
|
return uvox_metadata.GetExtendedData(data, dest, (int)destlen);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
LeaveCriticalSection(&streamInfoLock);
|
||
|
return 0;
|
||
|
}
|
||
|
else if (_stricmp(data, "0x3901") == 0)
|
||
|
{
|
||
|
EnterCriticalSection(&streamInfoLock);
|
||
|
if (g_playing_file && g_playing_file->uvox_3901) // check again now that we've acquired the lock
|
||
|
{
|
||
|
if (dest == NULL) // It's empty, he's looking for the size of the 0x3901
|
||
|
{
|
||
|
int size = MultiByteToWideChar(CP_UTF8, 0, g_playing_file->uvox_3901, -1, 0, 0);
|
||
|
LeaveCriticalSection(&streamInfoLock);
|
||
|
return size;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
MultiByteToWideCharSZ(CP_UTF8, 0, g_playing_file->uvox_3901, -1, dest, (int)destlen);
|
||
|
LeaveCriticalSection(&streamInfoLock);
|
||
|
return 1;
|
||
|
}
|
||
|
}
|
||
|
LeaveCriticalSection(&streamInfoLock);
|
||
|
return 0;
|
||
|
}
|
||
|
else if (!_stricmp(data, "streamtype"))
|
||
|
{
|
||
|
if (lstrcmpW(lastfn, fn))
|
||
|
return 0;
|
||
|
|
||
|
if (g_playing_file)
|
||
|
{
|
||
|
EnterCriticalSection(&streamInfoLock);
|
||
|
if (g_playing_file) // check again now that we've acquired the lock
|
||
|
{
|
||
|
StringCchPrintfW(dest, destlen, L"%d", g_playing_file->IsStream());
|
||
|
LeaveCriticalSection(&streamInfoLock);
|
||
|
return 1;
|
||
|
}
|
||
|
LeaveCriticalSection(&streamInfoLock);
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
else if (!_stricmp(data, "streammetadata"))
|
||
|
{
|
||
|
if (lstrcmpW(lastfn, fn))
|
||
|
return 0;
|
||
|
|
||
|
if (g_playing_file)
|
||
|
{
|
||
|
uint32_t len=0;
|
||
|
EnterCriticalSection(&streamInfoLock);
|
||
|
if (g_playing_file && g_playing_file->GetID3v2(&len) && len > 0) // check again now that we've acquired the lock
|
||
|
{
|
||
|
lstrcpynW(dest, L"1", (int)destlen);
|
||
|
LeaveCriticalSection(&streamInfoLock);
|
||
|
return 1; // always return 1 to ensure we can do title lookups
|
||
|
}
|
||
|
LeaveCriticalSection(&streamInfoLock);
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
else if (!_stricmp(data, "streamtitle"))
|
||
|
{
|
||
|
EnterCriticalSection(&streamInfoLock);
|
||
|
if (g_playing_file) // check again now that we've acquired the lock
|
||
|
ConvertTryUTF8(g_playing_file->stream_current_title, dest, destlen);
|
||
|
else
|
||
|
dest[0]=0;
|
||
|
LeaveCriticalSection(&streamInfoLock);
|
||
|
return 1;
|
||
|
}
|
||
|
else if (!_stricmp(data, "streamname"))
|
||
|
{
|
||
|
EnterCriticalSection(&streamInfoLock);
|
||
|
if (g_playing_file) // check again now that we've acquired the lock
|
||
|
ConvertTryUTF8(g_playing_file->stream_name, dest, destlen);
|
||
|
else
|
||
|
dest[0]=0;
|
||
|
LeaveCriticalSection(&streamInfoLock);
|
||
|
return 1;
|
||
|
}
|
||
|
else if (!_stricmp(data, "streamurl"))
|
||
|
{
|
||
|
EnterCriticalSection(&streamInfoLock);
|
||
|
if (g_playing_file) // check again now that we've acquired the lock
|
||
|
ConvertTryUTF8(g_playing_file->stream_url, dest, destlen);
|
||
|
else
|
||
|
dest[0]=0;
|
||
|
LeaveCriticalSection(&streamInfoLock);
|
||
|
return 1;
|
||
|
}
|
||
|
else if (!_stricmp(data, "streamgenre"))
|
||
|
{
|
||
|
EnterCriticalSection(&streamInfoLock);
|
||
|
if (g_playing_file) // check again now that we've acquired the lock
|
||
|
ConvertTryUTF8(g_playing_file->stream_genre, dest, destlen);
|
||
|
else
|
||
|
dest[0]=0;
|
||
|
LeaveCriticalSection(&streamInfoLock);
|
||
|
return 1;
|
||
|
}
|
||
|
else if (!_stricmp(data, "streaminformation"))
|
||
|
{
|
||
|
EnterCriticalSection(&streamInfoLock);
|
||
|
if (g_playing_file)
|
||
|
g_playing_file->GetStreamInfo(dest, destlen);
|
||
|
else
|
||
|
dest[0]=0;
|
||
|
LeaveCriticalSection(&streamInfoLock);
|
||
|
return 1;
|
||
|
}
|
||
|
|
||
|
if (!fn || !fn[0]) return 0;
|
||
|
|
||
|
if (!_wcsnicmp(fn, L"uvox://", 7))
|
||
|
return 0;
|
||
|
|
||
|
if (g_playing_file && PathIsURL(fn) && !lstrcmpW(lastfn, fn))
|
||
|
{
|
||
|
EnterCriticalSection(&streamInfoLock);
|
||
|
uint32_t len = 0;
|
||
|
if (g_playing_file && g_playing_file->GetID3v2(&len) && len > 0) // check again now that we've acquired the lock
|
||
|
{
|
||
|
Metadata meta(g_playing_file, fn);
|
||
|
int ret = meta.GetExtendedData(data, dest, (int)destlen);
|
||
|
LeaveCriticalSection(&streamInfoLock);
|
||
|
return ret;
|
||
|
}
|
||
|
LeaveCriticalSection(&streamInfoLock);
|
||
|
}
|
||
|
|
||
|
if (PathIsURL(fn))
|
||
|
return 0;
|
||
|
|
||
|
if (m_ext_get_mp3info && (!m_ext_get_mp3info->IsMe(fn) || HasFileTimeChanged(fn)))
|
||
|
{
|
||
|
m_ext_get_mp3info->Release();
|
||
|
m_ext_get_mp3info=0;
|
||
|
}
|
||
|
|
||
|
if (!m_ext_get_mp3info)
|
||
|
{
|
||
|
m_ext_get_mp3info = new Metadata;
|
||
|
m_ext_get_mp3info->Open(fn);
|
||
|
}
|
||
|
|
||
|
return m_ext_get_mp3info->GetExtendedData(data, dest, (int)destlen);
|
||
|
}
|
||
|
|
||
|
extern "C"
|
||
|
__declspec(dllexport) int winampSetExtendedFileInfoW(const wchar_t *fn, const char *data, const wchar_t *val)
|
||
|
{
|
||
|
if (!m_ext_set_mp3info || (m_ext_set_mp3info && !m_ext_set_mp3info->IsMe(fn)))
|
||
|
{
|
||
|
if(m_ext_set_mp3info) m_ext_set_mp3info->Release();
|
||
|
m_ext_set_mp3info = new Metadata;
|
||
|
m_ext_set_mp3info->Open(fn);
|
||
|
}
|
||
|
return m_ext_set_mp3info->SetExtendedData(data, val);
|
||
|
}
|
||
|
|
||
|
extern "C"
|
||
|
__declspec(dllexport) int winampWriteExtendedFileInfo()
|
||
|
{
|
||
|
// flush our read cache too :)
|
||
|
if(m_ext_get_mp3info) m_ext_get_mp3info->Release();
|
||
|
m_ext_get_mp3info = NULL;
|
||
|
|
||
|
if (!m_ext_set_mp3info) return 0;
|
||
|
|
||
|
Stopper stopper;
|
||
|
if (m_ext_set_mp3info->IsMe(lastfn))
|
||
|
stopper.Stop();
|
||
|
|
||
|
// just in-case something changed
|
||
|
if (!m_ext_set_mp3info) return 0;
|
||
|
|
||
|
int ret = m_ext_set_mp3info->Save();
|
||
|
stopper.Play();
|
||
|
m_ext_set_mp3info->Release();
|
||
|
m_ext_set_mp3info = NULL;
|
||
|
|
||
|
// update last modified so we're not re-queried on our own updates
|
||
|
UpdateFileTimeChanged(lastfn);
|
||
|
|
||
|
return !ret;
|
||
|
}
|
||
|
|
||
|
extern "C" __declspec(dllexport)
|
||
|
int winampClearExtendedFileInfoW(const wchar_t *fn)
|
||
|
{
|
||
|
Metadata meta;
|
||
|
if (meta.Open(fn)==METADATA_SUCCESS)
|
||
|
{
|
||
|
meta.id3v2.Clear();
|
||
|
Stopper stopper;
|
||
|
if (meta.IsMe(lastfn))
|
||
|
stopper.Stop();
|
||
|
meta.Save();
|
||
|
stopper.Play();
|
||
|
|
||
|
// update last modified so we're not re-queried on our own updates
|
||
|
UpdateFileTimeChanged(fn);
|
||
|
|
||
|
return 1;
|
||
|
}
|
||
|
return 0;
|
||
|
}
|