123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789 |
- #include "main.h"
- #include "./fileview.h"
- #include "./fileview_internal.h"
- #include <vector>
- #include <deque>
- #include "../nu/threadname.h"
- #include <api/service/waServiceFactory.h>
- #include "../playlist/api_playlistmanager.h"
- #include "../playlist/ifc_playlistloadercallback.h"
- #include "../Agave/Metadata/api_metadata.h"
- #include <shlwapi.h>
- #include <strsafe.h>
- #include <algorithm>
- typedef struct _METASEARCHKEY
- {
- INT pathId;
- LPCWSTR pszFileName;
- } METASEARCHKEY;
- typedef struct _PATHID
- {
- INT id;
- LPWSTR pszPath;
- } PATHID;
- typedef struct _METAINFO
- {
- INT pathId;
- LPWSTR pszFileName;
- FILETIME lastWriteTime;
- DWORD fileSizeLow;
- DWORD fileSizeHigh;
- BOOL bBusy;
- FILEMETARECORD *pFileMeta;
- } METAINFO;
- typedef std::vector<PATHID> PATHLIST;
- typedef std::vector<METAINFO*> METARECORS;
- typedef struct _METADB
- {
- UINT ref;
- PATHLIST pPath;
- METARECORS pRec;
- size_t lastPathIndex;
- INT maxPathId;
- HANDLE hDiscoverThread;
- HANDLE hDiscoverWake;
- HANDLE hDiscoverKill;
- } METADB;
- #define METATHREAD_KILL 0
- #define METATHREAD_WAKE 1
- typedef void (CALLBACK *DISCOVERCALLBACK)(LPCWSTR /*pszFileName*/, ULONG_PTR /*param*/);
- typedef struct _DISCOVERJOB
- {
- METAINFO *pMeta;
- HANDLE hCaller;
- DISCOVERCALLBACK fnCallback;
- ULONG_PTR param;
- UINT fileType;
- WCHAR szFileName[2*MAX_PATH];
- } DISCOVERJOB;
- typedef std::deque<DISCOVERJOB*> DISCOVERDEQUE;
- static DISCOVERDEQUE discoverJobs;
- static api_metadata *apiMetaData = NULL;
- static api_playlistmanager *apiPlaylistManager = NULL;
- static METADB metaDb = { 0, };
- static CRITICAL_SECTION g_cs_discover;
- static BOOL MetaDiscovery_InitializeThread(METADB *pMetaDb);
- static void MetaDiscovery_KillThread(METADB *pMetaDb);
- static BOOL MetaDiscovery_ScheduleJob(HANDLE hWakeEvent, LPCWSTR pszPath, METAINFO *pMeta, UINT fileType, DISCOVERCALLBACK fnCallback, ULONG_PTR param);
- class PlMetaLoader : public ifc_playlistloadercallback
- {
- public:
- PlMetaLoader( PLAYLISTMETA *plm )
- {
- this->plm = plm; plm->nCount = 0; plm->nLength = 0;
- }
- ~PlMetaLoader()
- {};
- void OnFile( const wchar_t *filename, const wchar_t *title, int lengthInMS, ifc_plentryinfo *info )
- {
- if ( plm->nCount < sizeof( plm->szEntries ) / sizeof( plm->szEntries[ 0 ] ) )
- {
- PLENTRY *pe = &plm->szEntries[ plm->nCount ];
- if ( title && *title )
- pe->pszTitle = _wcsdup( title );
- else if ( filename && *filename )
- {
- pe->pszTitle = _wcsdup( filename );
- }
- else
- pe->pszTitle = NULL;
- pe->nLength = lengthInMS / 1000;
- }
- plm->nCount++;
- plm->nLength += lengthInMS;
- }
- void OnPlaylistInfo( const wchar_t *playlistName, size_t numEntries, ifc_plentryinfo *info )
- {
- plm->pszTitle = ( playlistName && *playlistName ) ? _wcsdup( playlistName ) : NULL;
- }
- const wchar_t *GetBasePath()
- {
- return L".";
- }
- protected:
- RECVS_DISPATCH;
- private:
- PLAYLISTMETA *plm;
- };
- #define CBCLASS PlMetaLoader
- START_DISPATCH;
- VCB( IFC_PLAYLISTLOADERCALLBACK_ONFILE, OnFile )
- VCB( IFC_PLAYLISTLOADERCALLBACK_ONPLAYLISTINFO, OnPlaylistInfo )
- CB( IFC_PLAYLISTLOADERCALLBACK_GETBASEPATH, GetBasePath )
- END_DISPATCH;
- void FileViewMeta_InitializeStorage(HWND hView)
- {
- if (0 == metaDb.ref)
- {
- InitializeCriticalSection(&g_cs_discover);
- if (WASABI_API_SVC)
- {
- waServiceFactory *factory;
- factory = WASABI_API_SVC->service_getServiceByGuid(api_metadataGUID);
- if (factory) apiMetaData = (api_metadata*) factory->getInterface();
- else apiMetaData = NULL;
- factory = WASABI_API_SVC->service_getServiceByGuid(api_playlistmanagerGUID);
- if (factory) apiPlaylistManager = (api_playlistmanager*) factory->getInterface();
- else apiPlaylistManager = NULL;
- }
-
- }
- metaDb.ref++;
- }
- static void FileViewMeta_FreeAudioMeta(AUDIOMETA *pMeta)
- {
- if (pMeta->pszAlbum) { free(pMeta->pszAlbum); pMeta->pszAlbum = NULL; }
- if (pMeta->pszArtist) { free(pMeta->pszArtist); pMeta->pszArtist = NULL; }
- if (pMeta->pszTitle) { free(pMeta->pszTitle); pMeta->pszTitle = NULL; }
- if (pMeta->pszAlbumArtist) { free(pMeta->pszAlbumArtist); pMeta->pszAlbumArtist = NULL; }
- if (pMeta->pszComment) { free(pMeta->pszComment); pMeta->pszComment = NULL; }
- if (pMeta->pszComposer) { free(pMeta->pszComposer); pMeta->pszComposer = NULL; }
- if (pMeta->pszGenre) { free(pMeta->pszGenre); pMeta->pszGenre = NULL; }
- if (pMeta->pszPublisher) { free(pMeta->pszPublisher); pMeta->pszPublisher = NULL; }
- }
- static void FileViewMeta_FreeVideoMeta(VIDEOMETA *pMeta)
- {
- if (pMeta->pszAlbum) { free(pMeta->pszAlbum); pMeta->pszAlbum = NULL; }
- if (pMeta->pszArtist) { free(pMeta->pszArtist); pMeta->pszArtist = NULL; }
- if (pMeta->pszTitle) { free(pMeta->pszTitle); pMeta->pszTitle = NULL; }
- if (pMeta->pszAlbumArtist) { free(pMeta->pszAlbumArtist); pMeta->pszAlbumArtist = NULL; }
- if (pMeta->pszComment) { free(pMeta->pszComment); pMeta->pszComment = NULL; }
- if (pMeta->pszComposer) { free(pMeta->pszComposer); pMeta->pszComposer = NULL; }
- if (pMeta->pszGenre) { free(pMeta->pszGenre); pMeta->pszGenre = NULL; }
- if (pMeta->pszPublisher) { free(pMeta->pszPublisher); pMeta->pszPublisher = NULL; }
- }
- static void FileViewMeta_FreePlaylistMeta(PLAYLISTMETA *pMeta)
- {
- if (!pMeta) return;
- if (pMeta->pszTitle) { free(pMeta->pszTitle); pMeta->pszTitle = NULL; }
- for (int i = 0; i < sizeof(pMeta->szEntries)/sizeof(pMeta->szEntries[0]); i++)
- {
- if (pMeta->szEntries[i].pszTitle) { free(pMeta->szEntries[i].pszTitle); pMeta->szEntries[i].pszTitle = NULL; }
- }
- if (pMeta->pszTitle) { free(pMeta->pszTitle); pMeta->pszTitle = NULL; }
- }
- static void FileViewMeta_FreeFileMeta(FILEMETARECORD *pFileMeta)
- {
- if (pFileMeta)
- {
- switch(pFileMeta->type)
- {
- case METATYPE_AUDIO:
- FileViewMeta_FreeAudioMeta(&pFileMeta->audio); break;
- case METATYPE_VIDEO:
- FileViewMeta_FreeVideoMeta(&pFileMeta->video); break;
- case METATYPE_PLAYLIST:
- FileViewMeta_FreePlaylistMeta(&pFileMeta->playlist); break;
- }
-
- free(pFileMeta);
- }
- }
- static void FileViewMeta_FreeMetaInfo(METAINFO *pMeta)
- {
- if (pMeta)
- {
- if (pMeta->pszFileName) { free(pMeta->pszFileName); pMeta->pszFileName = NULL; }
- FileViewMeta_FreeFileMeta(pMeta->pFileMeta);
- }
- }
- void FileViewMeta_TruncateQueue(size_t max)
- {
- EnterCriticalSection(&g_cs_discover);
- while(discoverJobs.size() > max)
- {
- DISCOVERJOB *pdj = discoverJobs.front();
- if (pdj)
- {
- if (pdj->pMeta)
- {
- ZeroMemory(&pdj->pMeta->lastWriteTime, sizeof(FILETIME));
- pdj->pMeta->fileSizeLow = 0;
- pdj->pMeta->bBusy = FALSE;
- if (pdj->hCaller) CloseHandle(pdj->hCaller);
- }
- free(pdj);
- }
-
- discoverJobs.pop_front();
- }
- LeaveCriticalSection(&g_cs_discover);
- }
- void FileViewMeta_ReleaseStorage(HWND hView)
- {
- if (0 == metaDb.ref) return;
-
- metaDb.ref--;
- if (0 == metaDb.ref)
- {
- FileViewMeta_TruncateQueue(0);
- MetaDiscovery_KillThread(&metaDb);
- if (WASABI_API_SVC)
- {
- if(apiMetaData)
- {
- waServiceFactory *factory = WASABI_API_SVC->service_getServiceByGuid(api_metadataGUID);
- if (factory) factory->releaseInterface(apiMetaData);
- }
- if(apiPlaylistManager)
- {
- waServiceFactory *factory = WASABI_API_SVC->service_getServiceByGuid(api_playlistmanagerGUID);
- if (factory) factory->releaseInterface(apiPlaylistManager);
- }
- }
- while(metaDb.pPath.size() > 0)
- {
- if (metaDb.pPath.back().pszPath) free(metaDb.pPath.back().pszPath);
- metaDb.pPath.pop_back();
- }
- while(metaDb.pRec.size() > 0)
- {
- FileViewMeta_FreeMetaInfo(metaDb.pRec.back());
- metaDb.pRec.pop_back();
- }
- metaDb.maxPathId = 0;
- metaDb.lastPathIndex = 0;
- DeleteCriticalSection(&g_cs_discover);
- }
- }
- __inline static int __cdecl FileViewMeta_SortPathId(const void *elem1, const void *elem2)
- {
- return (CompareStringW(CSTR_INVARIANT, NORM_IGNORECASE,
- ((PATHID*)elem1)->pszPath, -1, ((PATHID*)elem2)->pszPath, -1) - 2);
- }
- __inline static int __cdecl FileViewMeta_SearhPath(const void *elem1, const void *elem2)
- {
- return (CompareStringW(CSTR_INVARIANT, NORM_IGNORECASE,
- (LPCWSTR)elem1, -1, ((PATHID*)elem2)->pszPath, -1) - 2);
- }
- __inline static int __cdecl FileViewMeta_SortMetaInfo(const void *elem1, const void *elem2)
- {
- METAINFO *pmi1 = ((METAINFO*)elem1);
- METAINFO *pmi2 = ((METAINFO*)elem2);
- if (pmi1->pathId != pmi2->pathId) return (pmi1->pathId - pmi2->pathId);
- return (CompareStringW(CSTR_INVARIANT, NORM_IGNORECASE, pmi1->pszFileName, -1, pmi2->pszFileName, -1) - 2);
- }
- __inline static int __cdecl FileViewMeta_SortMetaInfo_V2(const void* elem1, const void* elem2)
- {
- return FileViewMeta_SortMetaInfo(elem1, elem2) < 0;
- }
- __inline static int __cdecl FileViewMeta_SearhMetaInfo(const void *elem1, const void *elem2)
- {
- METASEARCHKEY *pKey = (METASEARCHKEY*)elem1;
- if (pKey->pathId != (((METAINFO*)elem2))->pathId)
- return (pKey->pathId - (((METAINFO*)elem2))->pathId);
- return (CompareStringW(CSTR_INVARIANT, NORM_IGNORECASE,
- pKey->pszFileName, -1, (((METAINFO*)elem2))->pszFileName, -1) - 2);
- }
- static INT FileViewMeta_GetPathId(LPCWSTR pszPath)
- {
- if (!pszPath || L'\0' == pszPath) return 0;
- //PATHID *psr;
- PATHLIST::iterator psr;
- if (metaDb.lastPathIndex < metaDb.pPath.size() &&
- CSTR_EQUAL == CompareStringW(CSTR_INVARIANT, NORM_IGNORECASE, pszPath, -1,
- metaDb.pPath.at(metaDb.lastPathIndex).pszPath, -1))
- {
- //psr = &metaDb.pPath.at(metaDb.lastPathIndex);
- psr = metaDb.pPath.begin() + metaDb.lastPathIndex;
- }
- else
- {
- //psr = (PATHID*)bsearch(pszPath, metaDb.pPath.begin(), metaDb.pPath.size(), sizeof(PATHID), FileViewMeta_SearhPath);
- psr = std::find_if(metaDb.pPath.begin(), metaDb.pPath.end(),
- [&](PATHID &path) -> bool
- {
- return FileViewMeta_SearhPath(pszPath, &path) == 0;
- }
- );
- }
- //if (!psr)
- if(psr == metaDb.pPath.end())
- {
- PATHID pid;
- pid.id = metaDb.maxPathId+1;
- pid.pszPath = _wcsdup(pszPath);
- metaDb.pPath.push_back(pid);
- metaDb.maxPathId++;
- //psr = &pid;
- psr = metaDb.pPath.end() - 1;
-
- //qsort(metaDb.pPath.begin(), metaDb.pPath.size(), sizeof(PATHID), FileViewMeta_SortPathId);
- std::sort(metaDb.pPath.begin(), metaDb.pPath.end(),
- [&](const PATHID& lhs, const PATHID& rhs) -> bool
- {
- return FileViewMeta_SortPathId(&lhs, &rhs) == CSTR_LESS_THAN;
- }
- );
- }
- metaDb.lastPathIndex = (size_t)(ULONG_PTR)(psr - metaDb.pPath.begin());
- return psr->id;
- }
- static METAINFO *FileViewMeta_GetMeta(LPCWSTR pszPath, LPCWSTR pszFileName, LPCWSTR pszExt, BOOL bCreateIfNotFound)
- {
- WCHAR szBuffer[MAX_PATH] = {0};
- METASEARCHKEY key;
- key.pathId = FileViewMeta_GetPathId(pszPath);
- key.pszFileName = pszFileName;
- if (pszExt == (pszFileName + lstrlenW(pszFileName) + 1))
- {
- StringCchCopyW(szBuffer, sizeof(szBuffer)/sizeof(szBuffer[0]), pszFileName);
- if (pszExt)
- {
- StringCchCatW(szBuffer, sizeof(szBuffer)/sizeof(szBuffer[0]), L".");
- StringCchCatW(szBuffer, sizeof(szBuffer)/sizeof(szBuffer[0]), pszExt);
- }
- key.pszFileName = szBuffer;
- }
- //METAINFO **pr = (METAINFO**)bsearch(&key, metaDb.pRec.at(0), metaDb.pRec.size(), sizeof(METAINFO*), FileViewMeta_SearhMetaInfo);
- auto it = std::find_if(metaDb.pRec.begin(), metaDb.pRec.end(),
- [&](const METAINFO* info) -> bool
- {
- return FileViewMeta_SearhMetaInfo(&key, info) == 0;
- }
- );
- if (it != metaDb.pRec.end())
- {
- return *it;
- }
- //if (pr)
- // return *pr;
- if (!bCreateIfNotFound)
- return NULL;
- METAINFO *pInfo = (METAINFO*)calloc(1, sizeof(METAINFO));
- if (pInfo)
- {
- pInfo->pathId = key.pathId;
- pInfo->pszFileName = _wcsdup(key.pszFileName);
- metaDb.pRec.push_back(pInfo);
- //qsort(metaDb.pRec.first(), metaDb.pRec.size(), sizeof(METAINFO*), FileViewMeta_SortMetaInfo);
- std::sort(metaDb.pRec.begin(), metaDb.pRec.end(), FileViewMeta_SortMetaInfo_V2);
- }
- return pInfo;
- }
- // sets part and parts to -1 or 0 on fail/missing (e.g. parts will be -1 on "1", but 0 on "1/")
- static void ParseIntSlashInt(wchar_t *string, int *part, int *parts)
- {
- *part = -1;
- *parts = -1;
- if (string && string[0])
- {
- *part = _wtoi(string);
- while (*string && *string != '/')
- {
- string++;
- }
- if (*string == '/')
- {
- string++;
- *parts = _wtoi(string);
- }
- }
- }
- #define READFILEINFO(__fileName, __tag, __result, __pszBuffer, __cchBuffer)\
- (apiMetaData->GetExtendedFileInfo((__fileName), (__tag), (__pszBuffer), (__cchBuffer)) && L'\0' != *(__pszBuffer))
- static void FileViewMeta_ReadAudioMeta(LPCWSTR pszFullPath, AUDIOMETA *pa)
- {
- #define GETFILEINFO_STR(__tag, __result) { szBuffer[0] = L'\0';\
- if (READFILEINFO(pszFullPath, __tag, __result, szBuffer, sizeof(szBuffer)/sizeof(szBuffer[0])))\
- {(__result) = _wcsdup(szBuffer); }}
- #define GETFILEINFO_INT(__tag, __result) { szBuffer[0] = L'\0';\
- if (READFILEINFO(pszFullPath, __tag, __result, szBuffer, sizeof(szBuffer)/sizeof(szBuffer[0])))\
- {(__result) = _wtoi(szBuffer); }}
- #define GETFILEINFO_INTINT(__tag, __result1, __result2) { szBuffer[0] = L'\0';\
- if (READFILEINFO(pszFullPath, __tag, __result, szBuffer, sizeof(szBuffer)/sizeof(szBuffer[0])))\
- {ParseIntSlashInt(szBuffer, (__result1), (__result2)); }}
- if (AGAVE_API_MLDB)
- {
- itemRecordW *record = AGAVE_API_MLDB->GetFile(pszFullPath);
- if (record)
- {
- if (record->artist) pa->pszArtist = _wcsdup(record->artist);
- if (record->album) pa->pszAlbum = _wcsdup(record->album);
- if (record->title) pa->pszTitle = _wcsdup(record->title);
- if (record->albumartist) pa->pszAlbumArtist = _wcsdup(record->albumartist);
- if (record->comment) pa->pszComment = _wcsdup(record->comment);
- if (record->composer) pa->pszComposer = _wcsdup(record->composer);
- if (record->genre) pa->pszGenre = _wcsdup(record->genre);
- if (record->publisher) pa->pszPublisher = _wcsdup(record->publisher);
- pa->nLength = record->length;
- pa->nBitrate = record->bitrate;
- pa->nYear = record->year;
- pa->nDiscNum = record->disc;
- pa->nDiscCount = record->discs;
- pa->nTrackNum = record->track;
- pa->nTrackCount = record->tracks;
- pa->nSource = METADATA_SOURCE_MLDB;
- AGAVE_API_MLDB->FreeRecord(record);
- return;
- }
- }
- WCHAR szBuffer[2048] = {0};
- GETFILEINFO_STR(L"artist", pa->pszArtist);
- GETFILEINFO_STR(L"album", pa->pszAlbum);
- GETFILEINFO_STR(L"title", pa->pszTitle);
- GETFILEINFO_STR(L"albumartist", pa->pszAlbumArtist);
- GETFILEINFO_STR(L"comment", pa->pszComment);
- GETFILEINFO_STR(L"composer", pa->pszComposer);
- GETFILEINFO_STR(L"genre", pa->pszGenre);
- GETFILEINFO_STR(L"publisher", pa->pszPublisher);
- GETFILEINFO_INT(L"bitrate", pa->nBitrate);
- GETFILEINFO_INT(L"year", pa->nYear);
- GETFILEINFO_INT(L"length", pa->nLength);
- pa->nLength = pa->nLength/1000;
- GETFILEINFO_INTINT(L"disc", &pa->nDiscNum, &pa->nDiscCount);
- GETFILEINFO_INTINT(L"track",&pa->nTrackNum, &pa->nTrackCount);
- pa->nSource = METADATA_SOURCE_FILEINFO;
- }
- static void FileViewMeta_ReadPlaylistMeta(LPCWSTR pszFullPath, PLAYLISTMETA *plm)
- {
- if (!apiPlaylistManager) return;
- PlMetaLoader plLoaderCb(plm);
- apiPlaylistManager->Load(pszFullPath, &plLoaderCb);
- plm->nLength = plm->nLength/1000;
- }
- static FILEMETARECORD* FileViewMeta_ReadFileMeta(LPCWSTR pszFullPath, UINT uType)
- {
- FILEMETARECORD *pmr = (FILEMETARECORD*)calloc(1, sizeof(FILEMETARECORD));
- if (!pmr) return NULL;
- switch(uType)
- {
- case FVFT_AUDIO:
- pmr->type = METATYPE_AUDIO;
- FileViewMeta_ReadAudioMeta(pszFullPath, &pmr->audio);
- break;
- case FVFT_PLAYLIST:
- pmr->type = METATYPE_PLAYLIST;
- FileViewMeta_ReadPlaylistMeta(pszFullPath, &pmr->playlist);
- break;
- }
- return pmr;
- }
- FILEMETARECORD *FileViewMeta_GetFromCache(LPCWSTR pszPath, FILERECORD *pfr)
- {
- if ((FVFT_AUDIO != pfr->fileType && FVFT_VIDEO != pfr->fileType) || !pszPath) return NULL;
- METAINFO *pMeta = FileViewMeta_GetMeta(pszPath, pfr->Info.cFileName, &pfr->Info.cFileName[pfr->extOffset], FALSE);
- if (pMeta && !pMeta->bBusy && pMeta->fileSizeLow == pfr->Info.nFileSizeLow &&
- pMeta->fileSizeHigh == pfr->Info.nFileSizeHigh && 0 == CompareFileTime(&pMeta->lastWriteTime, &pfr->Info.ftLastWriteTime))
- {
- return pMeta->pFileMeta;
- }
- return NULL;
- }
- BOOL FileViewMeta_Discover(LPCWSTR pszPath, FILERECORD *pfr, DISCOVERCALLBACK fnCallback, ULONG_PTR param, INT queueMax)
- {
- if (!apiMetaData) return FALSE;
- if ((FVFT_AUDIO != pfr->fileType &&
- FVFT_VIDEO != pfr->fileType &&
- FVFT_PLAYLIST != pfr->fileType) || !pszPath) return FALSE;
- METAINFO *pMeta = FileViewMeta_GetMeta(pszPath, pfr->Info.cFileName, &pfr->Info.cFileName[pfr->extOffset], TRUE);
- if (!pMeta || pMeta->bBusy) return FALSE;
- if (0 == CompareFileTime(&pMeta->lastWriteTime, &pfr->Info.ftLastWriteTime) &&
- pMeta->fileSizeLow == pfr->Info.nFileSizeLow && pMeta->fileSizeHigh == pfr->Info.nFileSizeHigh)
- {
- pfr->pMeta = pMeta->pFileMeta;
- return TRUE;
- }
- FileViewMeta_FreeFileMeta(pMeta->pFileMeta);
- pMeta->lastWriteTime = pfr->Info.ftLastWriteTime;
- pMeta->fileSizeLow = pfr->Info.nFileSizeLow;
- pMeta->fileSizeHigh = pfr->Info.nFileSizeHigh;
- pMeta->pFileMeta = NULL;
- pMeta->bBusy = TRUE;
- if (!fnCallback && !param)
- {
- WCHAR szFullPath[MAX_PATH] = {0};
- FileViewMeta_TruncateQueue(0);
- PathCombineW(szFullPath, pszPath, pMeta->pszFileName);
- pMeta->pFileMeta = FileViewMeta_ReadFileMeta(szFullPath, pfr->fileType);
- pMeta->bBusy = FALSE;
- pfr->pMeta = pMeta->pFileMeta;
- return TRUE;
- }
- if (queueMax > 0)
- {
- FileViewMeta_TruncateQueue(--queueMax);
- }
- if (!MetaDiscovery_InitializeThread(&metaDb) ||
- !MetaDiscovery_ScheduleJob(metaDb.hDiscoverWake, pszPath, pMeta, pfr->fileType, fnCallback, param))
- {
- ZeroMemory(&pMeta->lastWriteTime, sizeof(FILETIME));
- pMeta->fileSizeLow = 0;
- pMeta->bBusy = FALSE;
- return FALSE;
- }
- return FALSE;
- }
- static BOOL MetaDiscovery_ScheduleJob(HANDLE hWakeEvent, LPCWSTR pszPath, METAINFO *pMeta, UINT fileType, DISCOVERCALLBACK fnCallback, ULONG_PTR param)
- {
- if (!pszPath || !pMeta || !pMeta->pszFileName || !fnCallback || !hWakeEvent)
- {
- if (pMeta)
- {
- ZeroMemory(&pMeta->lastWriteTime, sizeof(FILETIME));
- pMeta->fileSizeLow = 0;
- pMeta->bBusy = FALSE;
- }
- return FALSE;
- }
- DISCOVERJOB *pJob = (DISCOVERJOB*)calloc(1, sizeof(DISCOVERJOB));
- if (pJob)
- {
- pJob->pMeta = pMeta;
- HANDLE hp = GetCurrentProcess();
- if (DuplicateHandle(hp, GetCurrentThread(), hp, &pJob->hCaller, 0, FALSE, DUPLICATE_SAME_ACCESS))
- {
- pJob->fnCallback = fnCallback;
- pJob->param = param;
- pJob->fileType = fileType;
- PathCombineW(pJob->szFileName, pszPath, pMeta->pszFileName);
- EnterCriticalSection(&g_cs_discover);
- discoverJobs.push_front(pJob);
- LeaveCriticalSection(&g_cs_discover);
- if (SetEvent(hWakeEvent)) return TRUE;
- }
- }
- if (pJob)
- {
- if (pJob->hCaller) CloseHandle(pJob->hCaller);
- free(pJob);
- }
- if (pMeta)
- {
- ZeroMemory(&pMeta->lastWriteTime, sizeof(FILETIME));
- pMeta->fileSizeLow = 0;
- pMeta->bBusy = FALSE;
- }
- return FALSE;
- }
- static void CALLBACK MetaDiscovery_ApcCallback(ULONG_PTR param)
- {
- DISCOVERJOB *pJob = (DISCOVERJOB*)param;
- if (!pJob) return;
- if (pJob->pMeta) pJob->pMeta->bBusy = FALSE;
- if (pJob->fnCallback) pJob->fnCallback(pJob->szFileName, pJob->param);
- if (pJob->hCaller) CloseHandle(pJob->hCaller);
- free(pJob);
- }
- static void MetaDiscovery_ExecuteJob(DISCOVERJOB *pJob)
- {
- pJob->pMeta->pFileMeta = FileViewMeta_ReadFileMeta(pJob->szFileName, pJob->fileType);
- if (pJob->hCaller)
- {
- QueueUserAPC(MetaDiscovery_ApcCallback, pJob->hCaller, (ULONG_PTR)pJob);
- SleepEx(1, TRUE);
- }
- else MetaDiscovery_ApcCallback((ULONG_PTR)pJob);
- }
- static DWORD CALLBACK MetaDiscovery_ThreadProc(LPVOID param)
- {
- METADB *pMetaDb = (METADB*)param;
- HANDLE hEvents[] = { pMetaDb->hDiscoverKill, pMetaDb->hDiscoverWake };
- SetThreadName(-1, "FileView meta discovery");
- SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_IDLE);
- SetEvent(hEvents[METATHREAD_WAKE]);
- for(;;)
- {
- switch (WaitForMultipleObjectsEx(2, hEvents, FALSE, INFINITE, TRUE))
- {
- case WAIT_OBJECT_0: // kill switch
- TRACE_FMT(TEXT("Kill Meta Discovery"));
- return 0;
- case WAIT_OBJECT_0+1: // job
- EnterCriticalSection(&g_cs_discover);
- if (discoverJobs.empty())
- {
- ResetEvent(hEvents[METATHREAD_WAKE]);
- LeaveCriticalSection(&g_cs_discover);
- }
- else
- {
- DISCOVERJOB *pj;
- pj = discoverJobs.front();
- discoverJobs.pop_front();
- LeaveCriticalSection(&g_cs_discover);
- MetaDiscovery_ExecuteJob(pj);
- }
- break;
- }
- }
- return 0;
- }
- static BOOL MetaDiscovery_InitializeThread(METADB *pMetaDb)
- {
- if (!pMetaDb) return FALSE;
- if (pMetaDb->hDiscoverThread) return TRUE;
- DWORD threadId;
- if (!pMetaDb->hDiscoverWake) pMetaDb->hDiscoverWake = CreateEvent(0, TRUE, FALSE, 0);
- if (!pMetaDb->hDiscoverKill) pMetaDb->hDiscoverKill = CreateEvent(0, TRUE, FALSE, 0);
- if (pMetaDb->hDiscoverKill && pMetaDb->hDiscoverWake)
- {
- pMetaDb->hDiscoverThread = CreateThread(NULL, 0, MetaDiscovery_ThreadProc, (LPVOID)pMetaDb, 0, &threadId);
- if (pMetaDb->hDiscoverThread)
- {
- WaitForSingleObject(pMetaDb->hDiscoverWake, INFINITE);
- ResetEvent(pMetaDb->hDiscoverWake);
- return TRUE;
- }
- }
- MetaDiscovery_KillThread(pMetaDb);
- return FALSE;
- }
- static void MetaDiscovery_KillThread(METADB *pMetaDb)
- {
- if (!pMetaDb) return;
- if (pMetaDb->hDiscoverThread)
- {
- if (pMetaDb->hDiscoverKill)
- {
- SetEvent(metaDb.hDiscoverKill);
- WaitForSingleObject(metaDb.hDiscoverThread, INFINITE);
- }
- CloseHandle(pMetaDb->hDiscoverThread);
- pMetaDb->hDiscoverThread = NULL;
- }
- if (pMetaDb->hDiscoverKill) { CloseHandle(pMetaDb->hDiscoverKill); pMetaDb->hDiscoverKill = NULL; }
- if (pMetaDb->hDiscoverWake) { CloseHandle(pMetaDb->hDiscoverWake); pMetaDb->hDiscoverWake = NULL; }
- }
- static BOOL FileViewMeta_GetAudioString(AUDIOMETA *pam, UINT uMetaField, LPCWSTR *ppszOut)
- {
- switch(uMetaField)
- {
- case MF_ARTIST: *ppszOut = pam->pszArtist; return TRUE;
- case MF_ALBUM: *ppszOut = pam->pszAlbum; return TRUE;
- case MF_TITLE: *ppszOut = pam->pszTitle; return TRUE;
- case MF_GENRE: *ppszOut = pam->pszGenre; return TRUE;
- case MF_COMMENT: *ppszOut = pam->pszComment; return TRUE;
- case MF_PUBLISHER: *ppszOut = pam->pszPublisher; return TRUE;
- case MF_COMPOSER: *ppszOut = pam->pszComposer; return TRUE;
- case MF_ALBUMARTIST: *ppszOut = pam->pszAlbumArtist; return TRUE;
- }
- return FALSE;
- }
- static BOOL FileViewMeta_GetAudioInt(AUDIOMETA *pam, UINT uMetaField, INT *pOut)
- {
- switch(uMetaField)
- {
- case MF_BITRATE: *pOut = pam->nBitrate; return TRUE;
- case MF_DISCCOUNT: *pOut = pam->nDiscCount; return TRUE;
- case MF_DISCNUM: *pOut = pam->nDiscNum; return TRUE;
- case MF_LENGTH: *pOut = pam->nLength; return TRUE;
- case MF_SOURCE: *pOut = pam->nSource; return TRUE;
- case MF_TRACKCOUNT: *pOut = pam->nTrackCount; return TRUE;
- case MF_TRACKNUM: *pOut = pam->nTrackNum; return TRUE;
- case MF_YEAR: *pOut = pam->nYear; return TRUE;
- }
- return FALSE;
- }
- BOOL FileViewMeta_GetString(FILEMETARECORD *pMeta, UINT uMetaField, LPCWSTR *ppszOut)
- {
- if (!pMeta) return FALSE;
- switch(pMeta->type)
- {
- case METATYPE_AUDIO: return FileViewMeta_GetAudioString(&pMeta->audio, uMetaField, ppszOut);
- }
- return FALSE;
- }
- BOOL FileViewMeta_GetInt(FILEMETARECORD *pMeta, UINT uMetaField, INT *pOut)
- {
- if (!pMeta) return FALSE;
- switch(pMeta->type)
- {
- case METATYPE_AUDIO: return FileViewMeta_GetAudioInt(&pMeta->audio, uMetaField, pOut);
- }
- return FALSE;
- }
|