CoverDirectory.cpp 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314
  1. #include "api.h"
  2. #include "CoverDirectory.h"
  3. #include <api/service/svcs/svc_imgload.h>
  4. #include <api/service/waservicefactory.h>
  5. #include <shlwapi.h>
  6. #include <strsafe.h>
  7. static void CleanNameForPath(wchar_t *name)
  8. {
  9. while (name && *name)
  10. {
  11. switch(*name)
  12. {
  13. case L'?':
  14. case L'*':
  15. case L'|':
  16. *name = L'_';
  17. break;
  18. case '/':
  19. case L'\\':
  20. case L':':
  21. *name = L'-';
  22. break;
  23. case L'\"':
  24. *name = L'\'';
  25. break;
  26. case L'<':
  27. *name = L'(';
  28. break;
  29. case L'>': *name = L')';
  30. break;
  31. }
  32. name++;
  33. }
  34. }
  35. /* This is just hardcoded for now - Search the albumart in a cover library dir */
  36. static bool BuildCoverFilename(const wchar_t *filename, const wchar_t *type, wchar_t path[MAX_PATH], wchar_t mask[MAX_PATH])
  37. {
  38. // TODO: use tagz for this.
  39. wchar_t artistname[MAX_PATH]=L"", albumname[MAX_PATH]=L"";
  40. // benski> we're abusing short-circuit evaluation in a big way here :)
  41. if (((AGAVE_API_METADATA->GetExtendedFileInfo(filename, L"albumartist", artistname, MAX_PATH) && artistname[0])
  42. || (AGAVE_API_METADATA->GetExtendedFileInfo(filename, L"artist", artistname, MAX_PATH) && artistname[0]))
  43. && AGAVE_API_METADATA->GetExtendedFileInfo(filename, L"album", albumname, MAX_PATH) && albumname[0])
  44. {
  45. CleanNameForPath(artistname);
  46. CleanNameForPath(albumname);
  47. StringCchPrintf(mask, MAX_PATH, L"%s - %s.*",artistname, albumname);
  48. PathCombine(path, WASABI_API_APP->path_getUserSettingsPath(), L"Cover Library");
  49. return true;
  50. }
  51. return false;
  52. }
  53. static svc_imageLoader *FindImageLoader(const wchar_t *filespec, waServiceFactory **factory)
  54. {
  55. FOURCC imgload = svc_imageLoader::getServiceType();
  56. int n = WASABI_API_SVC->service_getNumServices(imgload);
  57. for (int i=0; i<n; i++)
  58. {
  59. waServiceFactory *sf = WASABI_API_SVC->service_enumService(imgload,i);
  60. if (sf)
  61. {
  62. svc_imageLoader * l = (svc_imageLoader*)sf->getInterface();
  63. if (l)
  64. {
  65. if (l->isMine(filespec))
  66. {
  67. *factory = sf;
  68. return l;
  69. }
  70. sf->releaseInterface(l);
  71. }
  72. }
  73. }
  74. return NULL;
  75. }
  76. static bool ImageExists(const wchar_t *path, const wchar_t *mask)
  77. {
  78. wchar_t dirmask[MAX_PATH];
  79. PathCombineW(dirmask, path, mask);
  80. WIN32_FIND_DATAW find;
  81. HANDLE hFind = FindFirstFileW(dirmask, &find);
  82. if (hFind != INVALID_HANDLE_VALUE)
  83. {
  84. do
  85. {
  86. wchar_t fn[MAX_PATH];
  87. PathCombine(fn, path, mask);
  88. waServiceFactory *factory=0;
  89. svc_imageLoader *loader = FindImageLoader(fn, &factory);
  90. if (loader)
  91. {
  92. factory->releaseInterface(loader);
  93. FindClose(hFind);
  94. return true;
  95. }
  96. }
  97. while (FindNextFileW(hFind, &find));
  98. FindClose(hFind);
  99. }
  100. return false;
  101. }
  102. static bool LoadFile(const wchar_t *filename, void **bits, size_t *len)
  103. {
  104. *len=0;
  105. FILE * f = _wfopen(filename,L"rb");
  106. if (!f)
  107. return false;
  108. fseek(f,0,2);
  109. *len = ftell(f);
  110. if (!*len)
  111. {
  112. fclose(f);
  113. return false;
  114. }
  115. fseek(f,0,0);
  116. void * data = WASABI_API_MEMMGR->sysMalloc(*len);
  117. fread(data,*len,1,f);
  118. fclose(f);
  119. *bits = data;
  120. return true;
  121. }
  122. static bool LoadImageData(const wchar_t *path, const wchar_t *mask, void **bits, size_t *len, wchar_t **mimeType)
  123. {
  124. wchar_t dirmask[MAX_PATH];
  125. PathCombineW(dirmask, path, mask);
  126. WIN32_FIND_DATAW find;
  127. HANDLE hFind = FindFirstFileW(dirmask, &find);
  128. if (hFind != INVALID_HANDLE_VALUE)
  129. {
  130. do
  131. {
  132. wchar_t fn[MAX_PATH];
  133. PathCombine(fn, path, find.cFileName);
  134. waServiceFactory *factory=0;
  135. svc_imageLoader *loader = FindImageLoader(fn, &factory);
  136. if (loader)
  137. {
  138. factory->releaseInterface(loader);
  139. if (LoadFile(fn, bits, len))
  140. {
  141. const wchar_t *ext = PathFindExtension(fn);
  142. if (*ext)
  143. {
  144. ext++;
  145. size_t len = wcslen(ext);
  146. *mimeType = (wchar_t *)WASABI_API_MEMMGR->sysMalloc((len + 1) * sizeof(wchar_t));
  147. StringCchCopy(*mimeType, len+1, ext);
  148. CharLower(*mimeType);
  149. }
  150. else
  151. {
  152. *mimeType=0;
  153. }
  154. FindClose(hFind);
  155. return true;
  156. }
  157. }
  158. }
  159. while (FindNextFileW(hFind, &find));
  160. FindClose(hFind);
  161. }
  162. return false;
  163. }
  164. static bool DeleteImage(const wchar_t *path, const wchar_t *mask)
  165. {
  166. wchar_t dirmask[MAX_PATH];
  167. PathCombineW(dirmask, path, mask);
  168. WIN32_FIND_DATAW find;
  169. HANDLE hFind = FindFirstFileW(dirmask, &find);
  170. if (hFind != INVALID_HANDLE_VALUE)
  171. {
  172. do
  173. {
  174. wchar_t fn[MAX_PATH];
  175. PathCombine(fn, path, mask);
  176. waServiceFactory *factory=0;
  177. svc_imageLoader *loader = FindImageLoader(fn, &factory);
  178. if (loader)
  179. {
  180. DeleteFile(fn);
  181. factory->releaseInterface(loader);
  182. }
  183. }
  184. while (FindNextFileW(hFind, &find));
  185. FindClose(hFind);
  186. }
  187. return false;
  188. }
  189. bool CoverDirectory::IsMine(const wchar_t *filename)
  190. {
  191. //wchar_t path[MAX_PATH], mask[MAX_PATH];
  192. //if (BuildCoverFilename(filename, path, mask) && ImageExists(path, mask))
  193. return true;
  194. //else
  195. // return false;
  196. }
  197. int CoverDirectory::ProviderType()
  198. {
  199. return ALBUMARTPROVIDER_TYPE_DATABASE;
  200. }
  201. // implementation note: use WASABI_API_MEMMGR to alloc bits and mimetype, so that the recipient can free through that
  202. int CoverDirectory::GetAlbumArtData(const wchar_t *filename, const wchar_t *type, void **bits, size_t *len, wchar_t **mimeType)
  203. {
  204. wchar_t path[MAX_PATH], mask[MAX_PATH];
  205. if (BuildCoverFilename(filename, type, path, mask))
  206. {
  207. if (LoadImageData(path, mask, bits, len, mimeType))
  208. {
  209. return ALBUMARTPROVIDER_SUCCESS;
  210. }
  211. }
  212. return ALBUMARTPROVIDER_FAILURE;
  213. }
  214. int CoverDirectory::SetAlbumArtData(const wchar_t *filename, const wchar_t *type, void *bits, size_t len, const wchar_t *mimeType)
  215. {
  216. // TODO:
  217. return ALBUMARTPROVIDER_FAILURE;
  218. }
  219. int CoverDirectory::DeleteAlbumArt(const wchar_t *filename, const wchar_t *type)
  220. {
  221. wchar_t path[MAX_PATH], mask[MAX_PATH];
  222. if (BuildCoverFilename(filename, type, path, mask))
  223. {
  224. DeleteImage(path, mask);
  225. return ALBUMARTPROVIDER_SUCCESS;
  226. }
  227. return ALBUMARTPROVIDER_FAILURE;
  228. }
  229. #define CBCLASS CoverDirectory
  230. START_DISPATCH;
  231. CB(SVC_ALBUMARTPROVIDER_PROVIDERTYPE, ProviderType);
  232. CB(SVC_ALBUMARTPROVIDER_GETALBUMARTDATA, GetAlbumArtData);
  233. CB(SVC_ALBUMARTPROVIDER_ISMINE, IsMine);
  234. CB(SVC_ALBUMARTPROVIDER_SETALBUMARTDATA, SetAlbumArtData);
  235. CB(SVC_ALBUMARTPROVIDER_DELETEALBUMART, DeleteAlbumArt);
  236. END_DISPATCH;
  237. #undef CBCLASS
  238. static CoverDirectory albumArtProvider;
  239. // {725084AC-DBAD-4f7b-98FA-478AE20B9517}
  240. static const GUID coverDirectoryGUID =
  241. { 0x725084ac, 0xdbad, 0x4f7b, { 0x98, 0xfa, 0x47, 0x8a, 0xe2, 0xb, 0x95, 0x17 } };
  242. FOURCC AlbumArtFactory::GetServiceType()
  243. {
  244. return svc_albumArtProvider::SERVICETYPE;
  245. }
  246. const char *AlbumArtFactory::GetServiceName()
  247. {
  248. return "Cover Directory";
  249. }
  250. GUID AlbumArtFactory::GetGUID()
  251. {
  252. return coverDirectoryGUID;
  253. }
  254. void *AlbumArtFactory::GetInterface(int global_lock)
  255. {
  256. return &albumArtProvider;
  257. }
  258. int AlbumArtFactory::SupportNonLockingInterface()
  259. {
  260. return 1;
  261. }
  262. int AlbumArtFactory::ReleaseInterface(void *ifc)
  263. {
  264. //WASABI_API_SVC->service_unlock(ifc);
  265. return 1;
  266. }
  267. const char *AlbumArtFactory::GetTestString()
  268. {
  269. return 0;
  270. }
  271. int AlbumArtFactory::ServiceNotify(int msg, int param1, int param2)
  272. {
  273. return 1;
  274. }
  275. #define CBCLASS AlbumArtFactory
  276. START_DISPATCH;
  277. CB(WASERVICEFACTORY_GETSERVICETYPE, GetServiceType)
  278. CB(WASERVICEFACTORY_GETSERVICENAME, GetServiceName)
  279. CB(WASERVICEFACTORY_GETGUID, GetGUID)
  280. CB(WASERVICEFACTORY_GETINTERFACE, GetInterface)
  281. CB(WASERVICEFACTORY_SUPPORTNONLOCKINGGETINTERFACE, SupportNonLockingInterface)
  282. CB(WASERVICEFACTORY_RELEASEINTERFACE, ReleaseInterface)
  283. CB(WASERVICEFACTORY_GETTESTSTRING, GetTestString)
  284. CB(WASERVICEFACTORY_SERVICENOTIFY, ServiceNotify)
  285. END_DISPATCH;
  286. #undef CBCLASS