1
0

FileInfo.cpp 86 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534
  1. // the modern file info box
  2. #include "Main.h"
  3. #include "resource.h"
  4. #include "api.h"
  5. #include "../nu/AutoWide.h"
  6. #include <tataki/export.h>
  7. #include <tataki/bitmap/bitmap.h>
  8. #include <tataki/canvas/bltcanvas.h>
  9. #include <api/service/waservicefactory.h>
  10. #include <api/service/svcs/svc_imgload.h>
  11. #include "language.h"
  12. #ifndef IGNORE_API_GRACENOTE
  13. #ifndef _WIN64
  14. #include "../gracenote/api_gracenote.h"
  15. #endif
  16. #endif
  17. #include "../Agave/Language/api_language.h"
  18. #include "decodefile.h"
  19. #include "../nu/AutoLock.h"
  20. #include <api/service/svcs/svc_imgwrite.h>
  21. #include "../Plugins/General/gen_ml/ml.h"
  22. #include <vector>
  23. extern Nullsoft::Utility::LockGuard getMetadataGuard;
  24. #define TEXTBUFFER_MAX 65536
  25. enum FileInfoMode {
  26. FILEINFO_MODE_0,
  27. FILEINFO_MODE_1,
  28. };
  29. int ModernInfoBox(In_Module * in, FileInfoMode mode, const wchar_t * filename, HWND parent);
  30. static INT_PTR CALLBACK FileInfo(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
  31. static INT_PTR CALLBACK FileInfo_Metadata(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
  32. static INT_PTR CALLBACK FileInfo_Artwork(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
  33. typedef HWND (__cdecl *AddUnifiedFileInfoPane)(int n, const wchar_t * filename, HWND parent, wchar_t *name, size_t namelen);
  34. class info_params
  35. {
  36. public:
  37. const wchar_t * filename;
  38. In_Module * in;
  39. std::vector<HWND> tabs;
  40. FileInfoMode mode;
  41. size_t initial_position, length;
  42. void (*infoBoxExCallback)(size_t position, wchar_t filepath[FILENAME_SIZE]);
  43. private:
  44. wchar_t *buffer_; // to track allocations made by this object
  45. public:
  46. info_params(FileInfoMode mode, const wchar_t* filename, In_Module * in)
  47. {
  48. if (filename) {
  49. // In order to prevent jtfe 1.33 from crashing winamp, we need to make sure that
  50. // this->filename doesn't point to the begining of the allocated block, to do
  51. // this, buffer_offset set to 2 (4 bytes).
  52. size_t buffer_offset = 2; // "voodoo magic"
  53. size_t filename_length = wcslen(filename);
  54. size_t buffer_size = filename_length + 1;
  55. buffer_ = reinterpret_cast<wchar_t*>(malloc((buffer_size + buffer_offset)*sizeof(wchar_t)));
  56. if (buffer_) {
  57. wchar_t *filename_buffer = buffer_ + buffer_offset;
  58. wcsncpy_s(filename_buffer, buffer_size, filename, filename_length);
  59. filename_buffer[filename_length] = '\0';
  60. this->filename = filename_buffer;
  61. } else {
  62. // oops, looks like we out of memory (extremly rare but possible). Probably best thing,
  63. // every responsible person should do at this point is to crash app asap,
  64. // ...but we also can assign filename pointer directly and let nasty things happen
  65. // somewhere later (as of writing of this comment, info_params constructed right before
  66. // going in to the modal loop, which makes it kind of blocking call).
  67. this->filename = filename;
  68. }
  69. }
  70. else {
  71. buffer_ = NULL;
  72. this->filename = filename;
  73. }
  74. this->mode = mode;
  75. this->in = in;
  76. this->initial_position = 0;
  77. this->length = 0;
  78. }
  79. ~info_params() {
  80. free(buffer_);
  81. }
  82. };
  83. int ModernInfoBox(In_Module * in, FileInfoMode mode, const wchar_t * filename, HWND parent)
  84. {
  85. Tataki::Init(WASABI_API_SVC);
  86. info_params params(mode, filename, in);
  87. int ret = (int)LPDialogBoxParamW(IDD_FILEINFO, parent, FileInfo, (LPARAM)&params);
  88. Tataki::Quit();
  89. return ret;
  90. }
  91. static VOID WINAPI OnSelChanged(HWND hwndDlg, HWND hwndTab, info_params * p)
  92. {
  93. ShowWindow(p->tabs[config_last_fileinfo_page], SW_HIDE);
  94. EnableWindow(p->tabs[config_last_fileinfo_page], 0);
  95. config_last_fileinfo_page=TabCtrl_GetCurSel(hwndTab);
  96. ShowWindow(p->tabs[config_last_fileinfo_page], SW_SHOWNA);
  97. EnableWindow(p->tabs[config_last_fileinfo_page], 1);
  98. if (GetFocus() != hwndTab)
  99. {
  100. SetFocus(p->tabs[config_last_fileinfo_page]);
  101. }
  102. }
  103. static HWND CreateTab(FileInfoMode mode, int n, const wchar_t *file, HWND parent, wchar_t * name, size_t namelen, AddUnifiedFileInfoPane aufip)
  104. {
  105. switch (n)
  106. {
  107. case 0:
  108. if (mode == FILEINFO_MODE_0) {
  109. getStringW(IDS_BASICINFO, name, namelen);
  110. return LPCreateDialogW(IDD_FILEINFO_METADATA , parent, (WNDPROC)FileInfo_Metadata);
  111. } else {
  112. getStringW(IDS_STREAMINFO, name, namelen);
  113. return LPCreateDialogW(IDD_FILEINFO_STREAMDATA, parent, (WNDPROC)FileInfo_Metadata);
  114. }
  115. case 1:
  116. getStringW(IDS_ARTWORK,name,namelen);
  117. return LPCreateDialogW(IDD_FILEINFO_ARTWORK,parent,(WNDPROC)FileInfo_Artwork);
  118. default:
  119. if (mode == FILEINFO_MODE_0) {
  120. getStringW(IDS_ADVANCED,name,namelen);
  121. if (aufip) return aufip(n-2,file,parent,name,namelen);
  122. }
  123. return NULL;
  124. }
  125. }
  126. static INT_PTR CALLBACK FileInfo(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
  127. {
  128. switch (uMsg)
  129. {
  130. case WM_INITDIALOG:
  131. {
  132. SetPropW(hwndDlg,L"INBUILT_NOWRITEINFO", (HANDLE)0);
  133. info_params * p = (info_params *)lParam;
  134. SetWindowLongPtrW(hwndDlg,GWLP_USERDATA,lParam);
  135. HWND ok = GetDlgItem(hwndDlg, IDOK);
  136. if (p->mode == FILEINFO_MODE_0) {
  137. EnableWindow(ok, TRUE);
  138. ShowWindow(ok, SW_SHOW);
  139. } else {
  140. EnableWindow(ok, FALSE);
  141. ShowWindow(ok, SW_HIDE);
  142. }
  143. SetDlgItemTextW(hwndDlg,IDC_FN,p->filename);
  144. // added 5.66 so plug-ins can get a hint that something may change...
  145. SendMessageW(hMainWindow, WM_WA_IPC, (WPARAM)p->filename, IPC_FILE_TAG_MAY_UPDATEW);
  146. AddUnifiedFileInfoPane aufip = (AddUnifiedFileInfoPane)GetProcAddress(p->in->hDllInstance, "winampAddUnifiedFileInfoPane");
  147. HWND hwndTab = GetDlgItem(hwndDlg,IDC_TAB1);
  148. wchar_t name[100] = {0};
  149. TCITEMW tie = {0};
  150. tie.mask = TCIF_TEXT;
  151. tie.pszText = name;
  152. HWND tab=NULL;
  153. int n=0;
  154. while (NULL != (tab = CreateTab(p->mode, n, p->filename, hwndDlg, name, 100, aufip)))
  155. {
  156. p->tabs.push_back(tab);
  157. ShowWindow(tab,SW_HIDE);
  158. if (!SendMessageW(hMainWindow,WM_WA_IPC,IPC_ISWINTHEMEPRESENT,IPC_USE_UXTHEME_FUNC))
  159. SendMessageW(hMainWindow,WM_WA_IPC,(WPARAM)tab,IPC_USE_UXTHEME_FUNC);
  160. SendMessageW(hwndTab, TCM_INSERTITEMW, n, (LPARAM)&tie);
  161. n++;
  162. }
  163. RECT r;
  164. GetWindowRect(hwndTab,&r);
  165. TabCtrl_AdjustRect(hwndTab,FALSE,&r);
  166. MapWindowPoints(NULL,hwndDlg,(LPPOINT)&r,2);
  167. r.left += 3;
  168. r.top += 2;
  169. r.right -= 4;
  170. for (size_t i=0; i < p->tabs.size(); i++)
  171. SetWindowPos(p->tabs[i],HWND_TOP,r.left,r.top,r.right-r.left,r.bottom-r.top,SWP_NOACTIVATE);
  172. if (config_last_fileinfo_page >= (int)p->tabs.size()) config_last_fileinfo_page = 0;
  173. TabCtrl_SetCurSel(hwndTab,config_last_fileinfo_page);
  174. ShowWindow(p->tabs[config_last_fileinfo_page], SW_SHOWNA);
  175. // show alt+3 window and restore last position as applicable
  176. POINT pt = {alt3_rect.left, alt3_rect.top};
  177. if (!windowOffScreen(hwndDlg, pt) && !IsWindowVisible(hwndDlg))
  178. SetWindowPos(hwndDlg, HWND_TOP, alt3_rect.left, alt3_rect.top, 0, 0, SWP_NOSIZE | SWP_NOSENDCHANGING);
  179. return 1;
  180. }
  181. break;
  182. case WM_NOTIFY:
  183. {
  184. LPNMHDR lpn = (LPNMHDR) lParam;
  185. if (lpn && lpn->code==TCN_SELCHANGE)
  186. {
  187. info_params * p = (info_params *)GetWindowLongPtrW(hwndDlg,GWLP_USERDATA);
  188. OnSelChanged(hwndDlg,GetDlgItem(hwndDlg,IDC_TAB1),p);
  189. }
  190. }
  191. break;
  192. case WM_USER:
  193. {
  194. info_params * p = (info_params *)GetWindowLongPtrW(hwndDlg,GWLP_USERDATA);
  195. for (size_t i=0; i < p->tabs.size(); i++)
  196. SendMessageW(p->tabs[i],uMsg,wParam,lParam);
  197. }
  198. break;
  199. case WM_COMMAND:
  200. switch (LOWORD(wParam))
  201. {
  202. case IDOK:
  203. {
  204. Nullsoft::Utility::AutoLock metadata_lock(getMetadataGuard);
  205. info_params * p = (info_params *)GetWindowLongPtrW(hwndDlg,GWLP_USERDATA);
  206. for (size_t i=0; i < p->tabs.size(); i++)
  207. {
  208. SendMessageW(p->tabs[i],uMsg,wParam,lParam);
  209. }
  210. GetWindowRect(hwndDlg, &alt3_rect);
  211. EndDialog(hwndDlg,0);
  212. }
  213. break;
  214. case IDCANCEL:
  215. {
  216. Nullsoft::Utility::AutoLock metadata_lock(getMetadataGuard);
  217. info_params * p = (info_params *)GetWindowLongPtrW(hwndDlg,GWLP_USERDATA);
  218. for (size_t i=0; i < p->tabs.size(); i++)
  219. {
  220. SendMessageW(p->tabs[i],uMsg,wParam,lParam);
  221. }
  222. GetWindowRect(hwndDlg, &alt3_rect);
  223. EndDialog(hwndDlg,1);
  224. }
  225. break;
  226. }
  227. break;
  228. case WM_CLOSE:
  229. return FileInfo(hwndDlg,WM_COMMAND,MAKEWPARAM(IDCANCEL,0),0);
  230. }
  231. return 0;
  232. }
  233. const wchar_t *genres[] =
  234. {
  235. L"Blues", L"Classic Rock", L"Country", L"Dance", L"Disco", L"Funk", L"Grunge", L"Hip-Hop",
  236. L"Jazz", L"Metal", L"New Age", L"Oldies", L"Other", L"Pop", L"R&B", L"Rap", L"Reggae", L"Rock",
  237. L"Techno", L"Industrial", L"Alternative", L"Ska", L"Death Metal", L"Pranks", L"Soundtrack",
  238. L"Euro-Techno", L"Ambient", L"Trip-Hop", L"Vocal", L"Jazz+Funk", L"Fusion", L"Trance",
  239. L"Classical", L"Instrumental", L"Acid", L"House", L"Game", L"Sound Clip", L"Gospel", L"Noise",
  240. L"Alt Rock", L"Bass", L"Soul", L"Punk", L"Space", L"Meditative", L"Instrumental Pop",
  241. L"Instrumental Rock", L"Ethnic", L"Gothic", L"Darkwave", L"Techno-Industrial",
  242. L"Electronic", L"Pop-Folk", L"Eurodance", L"Dream", L"Southern Rock", L"Comedy", L"Cult",
  243. L"Gangsta Rap", L"Top 40", L"Christian Rap", L"Pop/Funk", L"Jungle", L"Native American",
  244. L"Cabaret", L"New Wave", L"Psychedelic", L"Rave", L"Showtunes", L"Trailer", L"Lo-Fi", L"Tribal",
  245. L"Acid Punk", L"Acid Jazz", L"Polka", L"Retro", L"Musical", L"Rock & Roll", L"Hard Rock",
  246. L"Folk", L"Folk-Rock", L"National Folk", L"Swing", L"Fast-Fusion", L"Bebop", L"Latin", L"Revival",
  247. L"Celtic", L"Bluegrass", L"Avantgarde", L"Gothic Rock", L"Progressive Rock", L"Psychedelic Rock",
  248. L"Symphonic Rock", L"Slow Rock", L"Big Band", L"Chorus", L"Easy Listening", L"Acoustic", L"Humour",
  249. L"Speech", L"Chanson", L"Opera", L"Chamber Music", L"Sonata", L"Symphony", L"Booty Bass", L"Primus",
  250. L"Porn Groove", L"Satire", L"Slow Jam", L"Club", L"Tango", L"Samba", L"Folklore",
  251. L"Ballad", L"Power Ballad", L"Rhythmic Soul", L"Freestyle", L"Duet", L"Punk Rock", L"Drum Solo",
  252. L"A Cappella", L"Euro-House", L"Dance Hall", L"Goa", L"Drum & Bass", L"Club-House",
  253. L"Hardcore", L"Terror", L"Indie", L"BritPop", L"Afro-Punk", L"Polsk Punk", L"Beat",
  254. L"Christian Gangsta Rap", L"Heavy Metal", L"Black Metal", L"Crossover", L"Contemporary Christian",
  255. L"Christian Rock", L"Merengue", L"Salsa", L"Thrash Metal", L"Anime", L"JPop", L"Synthpop",
  256. L"Abstract", L"Art Rock", L"Baroque", L"Bhangra", L"Big Beat", L"Breakbeat", L"Chillout", L"Downtempo", L"Dub", L"EBM", L"Eclectic", L"Electro",
  257. L"Electroclash", L"Emo", L"Experimental", L"Garage", L"Global", L"IDM", L"Illbient", L"Industro-Goth", L"Jam Band", L"Krautrock", L"Leftfield", L"Lounge",
  258. L"Math Rock", L"New Romantic", L"Nu-Breakz", L"Post-Punk", L"Post-Rock", L"Psytrance", L"Shoegaze", L"Space Rock", L"Trop Rock", L"World Music", L"Neoclassical",
  259. L"Audiobook", L"Audio Theatre", L"Neue Deutsche Welle", L"Podcast", L"Indie Rock", L"G-Funk", L"Dubstep", L"Garage Rock", L"Psybient",
  260. L"Glam Rock", L"Dream Pop", L"Merseybeat", L"K-Pop", L"Chiptune", L"Grime", L"Grindcore", L"Indietronic", L"Indietronica", L"Jazz Rock", L"Jazz Fusion",
  261. L"Post-Punk Revival", L"Electronica", L"Psychill", L"Ethnotronic", L"Americana", L"Ambient Dub", L"Digital Dub", L"Chillwave", L"Stoner Rock",
  262. L"Slowcore", L"Softcore", L"Flamenco", L"Hi-NRG", L"Ethereal", L"Drone", L"Doom Metal", L"Doom Jazz", L"Mainstream", L"Glitch", L"Balearic",
  263. L"Modern Classical", L"Mod", L"Contemporary Classical", L"Psybreaks", L"Psystep", L"Psydub", L"Chillstep", L"Berlin School",
  264. L"Future Jazz", L"Djent", L"Musique Concrète", L"Electroacoustic", L"Folktronica", L"Texas Country", L"Red Dirt",
  265. L"Arabic", L"Asian", L"Bachata", L"Bollywood", L"Cajun", L"Calypso", L"Creole", L"Darkstep", L"Jewish", L"Reggaeton", L"Smooth Jazz",
  266. L"Soca", L"Spiritual", L"Turntablism", L"Zouk", L"Neofolk", L"Nu Jazz", L"Psychobilly", L"Rockabilly", L"Schlager & Volksmusik",
  267. };
  268. const size_t numberOfGenres = sizeof(genres) / sizeof(genres[0]);
  269. const wchar_t * strfields[] =
  270. {
  271. L"artist",
  272. L"album",
  273. L"albumartist",
  274. L"title",
  275. L"year",
  276. L"genre",
  277. L"comment",
  278. L"composer",
  279. L"publisher",
  280. L"disc",
  281. L"track",
  282. L"bpm",
  283. L"GracenoteFileID",
  284. L"GracenoteExtData"
  285. };
  286. const int strfieldctrls[] =
  287. {
  288. IDC_ARTIST,
  289. IDC_ALBUM,
  290. IDC_ALBUM_ARTIST,
  291. IDC_TITLE,
  292. IDC_YEAR,
  293. IDC_GENRE,
  294. IDC_COMMENT,
  295. IDC_COMPOSER,
  296. IDC_PUBLISHER,
  297. IDC_DISC,
  298. IDC_TRACK,
  299. IDC_BPM,
  300. IDC_GN_FILEID,
  301. IDC_GN_EXTDATA
  302. };
  303. const int staticstrfieldctrls[] =
  304. {
  305. IDC_STATIC_ARTIST,
  306. IDC_STATIC_ALBUM,
  307. IDC_STATIC_ALBUM_ARTIST,
  308. IDC_STATIC_TITLE,
  309. IDC_STATIC_YEAR,
  310. IDC_STATIC_GENRE,
  311. IDC_STATIC_COMMENT,
  312. IDC_STATIC_COMPOSER,
  313. IDC_STATIC_PUBLISHER,
  314. IDC_STATIC_DISC,
  315. IDC_STATIC_TRACK,
  316. IDC_STATIC_BPM,
  317. 0,
  318. 0
  319. };
  320. const wchar_t * streamStrfields[] =
  321. {
  322. L"streamtitle",
  323. L"streamgenre",
  324. L"streamurl",
  325. L"streamname",
  326. L"streamcurrenturl",
  327. L"streammetadata",
  328. };
  329. const int streamStrfieldctrls[] =
  330. {
  331. IDC_TITLE,
  332. IDC_GENRE,
  333. IDC_URL,
  334. IDC_STATION,
  335. IDC_PLAY_URL,
  336. IDC_EXTRA_METADATA,
  337. };
  338. const int staticStreamStrfieldctrls[] =
  339. {
  340. IDC_STATIC_TITLE,
  341. IDC_STATIC_GENRE,
  342. IDC_STATIC_URL,
  343. IDC_STATIC_STATION,
  344. IDC_STATIC_PLAY_URL,
  345. 0,
  346. };
  347. #ifndef IGNORE_API_GRACENOTE
  348. #ifndef _WIN64
  349. static IConnectionPoint *GetConnectionPoint(IUnknown *punk, REFIID riid)
  350. {
  351. if (!punk)
  352. return 0;
  353. IConnectionPointContainer *pcpc;
  354. IConnectionPoint *pcp = 0;
  355. HRESULT hr = punk->QueryInterface(IID_IConnectionPointContainer, (void **) & pcpc);
  356. if (SUCCEEDED(hr))
  357. {
  358. pcpc->FindConnectionPoint(riid, &pcp);
  359. pcpc->Release();
  360. }
  361. punk->Release();
  362. return pcp;
  363. }
  364. class autoTagListen : public _ICDDBMusicIDManagerEvents
  365. {
  366. public:
  367. autoTagListen(api_gracenote* gn, ICDDBMusicIDManager3 *musicid, wchar_t *_gracenoteFileId) : hwndDlg(0), h(0), gn(gn),musicid(musicid), done(0), abort(0), gracenoteFileId(_gracenoteFileId)
  368. {
  369. }
  370. HRESULT OnTrackIDStatusUpdate(CddbMusicIDStatus Status, BSTR filename, long* _Abort)
  371. {
  372. if (abort) *_Abort=1;
  373. /*switch(Status)
  374. {
  375. case STATUS_MUSICID_Error:
  376. case STATUS_MUSICID_ProcessingFile:
  377. case STATUS_MUSICID_LookingUpWaveForm:
  378. case STATUS_MUSICID_LookingUpText:
  379. case STATUS_MUSICID_CheckForAbort:
  380. case STATUS_ALBUMID_Querying:
  381. case STATUS_ALBUMID_Queried:
  382. case STATUS_ALBUMID_Processing:
  383. case STATUS_ALBUMID_Processed:
  384. case STATUS_MUSICID_AnalyzingWaveForm:
  385. case STATUS_ALBUMID_QueryingWF:
  386. }*/
  387. // do shit
  388. return S_OK;
  389. }
  390. HRESULT OnTrackIDComplete(LONG match_code, ICddbFileInfo* pInfoIn, ICddbFileInfoList* pListOut)
  391. {
  392. done = 1;
  393. if (match_code <= 1)
  394. {
  395. if (!abort)
  396. {
  397. wchar_t title[16] = {0};
  398. MessageBoxW(h, getStringW(IDS_NO_MATCH_FOUND, NULL, 0),
  399. getStringW(IDS_FAILED, title, 16), MB_ICONWARNING);
  400. }
  401. EndDialog(hwndDlg,0);
  402. return S_OK;
  403. }
  404. long num = 0;
  405. pListOut->get_Count(&num);
  406. if (!num) return S_OK;
  407. ICddbFileInfoPtr infotag = NULL;
  408. pListOut->GetFileInfo(1,&infotag);
  409. if (infotag)
  410. {
  411. wchar_t buf[2048] = {0};
  412. BSTR bstr = buf;
  413. ICddbFileTagPtr tag = NULL;
  414. ICddbDisc2Ptr disc = NULL;
  415. ICddbDisc2_5Ptr disc2_5 = NULL;
  416. ICddbFileTag2_5Ptr tag2_5 = NULL;
  417. infotag->get_Tag(&tag);
  418. infotag->get_Disc(&disc);
  419. if (tag)
  420. {
  421. tag->QueryInterface(&tag2_5);
  422. disc->QueryInterface(&disc2_5);
  423. #define PUTINFO(id, ctrl) if (tag) { tag->get_ ## id ## (&bstr); SetDlgItemTextW(h, ctrl, bstr); }
  424. #define PUTINFO2(id, ctrl) if (tag2_5) { tag2_5->get_ ## id ## (&bstr); SetDlgItemTextW(h, ctrl, bstr); }
  425. PUTINFO(LeadArtist, IDC_ARTIST);
  426. PUTINFO(Album, IDC_ALBUM);
  427. PUTINFO(Title, IDC_TITLE);
  428. PUTINFO(Album, IDC_ALBUM);
  429. if (disc2_5 == NULL
  430. || (FAILED(disc2_5->get_V2GenreStringPrimaryByLevel(3, &bstr))
  431. && FAILED(disc2_5->get_V2GenreStringPrimaryByLevel(2, &bstr))
  432. && FAILED(disc2_5->get_V2GenreStringPrimaryByLevel(1, &bstr))
  433. && FAILED(disc2_5->get_V2GenreStringPrimary(&bstr)))
  434. )
  435. {
  436. PUTINFO(Genre, IDC_GENRE);
  437. }
  438. else
  439. {
  440. SetDlgItemTextW(h,IDC_GENRE,bstr);
  441. }
  442. }
  443. // sending this will ensure that the genre is applied other than in the metadata page
  444. SendMessageW(GetParent(h),WM_USER,(WPARAM)strfields[5],(LPARAM)bstr);
  445. PUTINFO(Year, IDC_YEAR);
  446. PUTINFO(Label, IDC_PUBLISHER);
  447. PUTINFO(BeatsPerMinute, IDC_BPM);
  448. PUTINFO(TrackPosition, IDC_TRACK);
  449. PUTINFO(PartOfSet, IDC_DISC);
  450. PUTINFO2(Composer, IDC_COMPOSER);
  451. PUTINFO2(DiscArtist, IDC_ALBUM_ARTIST);
  452. PUTINFO(FileId, IDC_GN_FILEID);
  453. PUTINFO2(ExtDataSerialized, IDC_GN_EXTDATA);
  454. #undef PUTINFO
  455. #undef PUTINFO2
  456. // CRASH POINT
  457. // This is the starting cause of crashing in the cddb stuff
  458. // Without this or with a manual AddRef() before and it'll work ok
  459. //infotag->Release();
  460. }
  461. EndDialog(hwndDlg,0);
  462. return S_OK;
  463. }
  464. HRESULT FillTag(ICddbFileInfo *info, BSTR filename)
  465. {
  466. if (info)
  467. {
  468. #define PUTINFO(id, ctrl) GetDlgItemTextW(h, ctrl, buf, 2048); if(buf[0]) if (infotag) { infotag->put_ ## id ## (buf); }
  469. #define PUTINFO2(id, ctrl) GetDlgItemTextW(h, ctrl, buf, 2048); if(buf[0]) if (tag2_5) { tag2_5->put_ ## id ## (buf); }
  470. ICddbID3TagPtr infotag = NULL;
  471. infotag.CreateInstance(CLSID_CddbID3Tag);
  472. ICddbFileTag2_5Ptr tag2_5 = NULL;
  473. infotag->QueryInterface(&tag2_5);
  474. wchar_t buf[2048] = {0};
  475. PUTINFO(LeadArtist, IDC_ARTIST);
  476. PUTINFO(Album, IDC_ALBUM);
  477. PUTINFO(Title, IDC_TITLE);
  478. PUTINFO(Album, IDC_ALBUM);
  479. PUTINFO(Genre, IDC_GENRE);
  480. PUTINFO(Year, IDC_YEAR);
  481. PUTINFO(Label, IDC_PUBLISHER);
  482. PUTINFO(BeatsPerMinute, IDC_BPM);
  483. PUTINFO(TrackPosition, IDC_TRACK);
  484. PUTINFO(PartOfSet, IDC_DISC);
  485. PUTINFO2(Composer, IDC_COMPOSER);
  486. PUTINFO2(DiscArtist, IDC_ALBUM_ARTIST);
  487. in_get_extended_fileinfoW(filename,L"length",buf,2048);
  488. tag2_5->put_LengthMS(buf);
  489. if (gracenoteFileId && *gracenoteFileId)
  490. infotag->put_FileId(gracenoteFileId);
  491. #undef PUTINFO
  492. #undef PUTINFO2
  493. info->put_Tag(infotag);
  494. }
  495. return S_OK;
  496. }
  497. STDMETHODIMP STDMETHODCALLTYPE QueryInterface(REFIID riid, PVOID *ppvObject)
  498. {
  499. if (!ppvObject)
  500. return E_POINTER;
  501. else if (IsEqualIID(riid, __uuidof(_ICDDBMusicIDManagerEvents)))
  502. *ppvObject = (_ICDDBMusicIDManagerEvents *)this;
  503. else if (IsEqualIID(riid, IID_IDispatch))
  504. *ppvObject = (IDispatch *)this;
  505. else if (IsEqualIID(riid, IID_IUnknown))
  506. *ppvObject = this;
  507. else
  508. {
  509. *ppvObject = NULL;
  510. return E_NOINTERFACE;
  511. }
  512. AddRef();
  513. return S_OK;
  514. }
  515. ULONG STDMETHODCALLTYPE AddRef(void)
  516. {
  517. return 1;
  518. }
  519. ULONG STDMETHODCALLTYPE Release(void)
  520. {
  521. return 0;
  522. }
  523. HRESULT STDMETHODCALLTYPE Invoke(DISPID dispid, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS FAR *pdispparams, VARIANT FAR *pvarResult, EXCEPINFO FAR * pexecinfo, unsigned int FAR *puArgErr)
  524. {
  525. switch (dispid)
  526. {
  527. case 1: // OnTrackIDStatusUpdate, params: CddbMusicIDStatus Status, BSTR filename, long* Abort
  528. {
  529. long *abort = pdispparams->rgvarg[0].plVal;
  530. BSTR filename = pdispparams->rgvarg[1].bstrVal;
  531. CddbMusicIDStatus status = (CddbMusicIDStatus)pdispparams->rgvarg[2].lVal;
  532. return OnTrackIDStatusUpdate(status,filename,abort);
  533. }
  534. case 3: // OnTrackIDComplete, params: LONG match_code, ICddbFileInfo* pInfoIn, ICddbFileInfoList* pListOut
  535. {
  536. IDispatch *disp1 =pdispparams->rgvarg[0].pdispVal;
  537. IDispatch *disp2 =pdispparams->rgvarg[1].pdispVal;
  538. long match_code = pdispparams->rgvarg[2].lVal;
  539. ICddbFileInfoPtr pInfoIn;
  540. ICddbFileInfoListPtr matchList;
  541. disp1->QueryInterface(&matchList);
  542. disp2->QueryInterface(&pInfoIn);
  543. return OnTrackIDComplete(match_code,pInfoIn,matchList);
  544. }
  545. case 10: // OnGetFingerprintInfo
  546. {
  547. long *abort = pdispparams->rgvarg[0].plVal;
  548. IDispatch *disp = pdispparams->rgvarg[1].pdispVal;
  549. BSTR filename = pdispparams->rgvarg[2].bstrVal;
  550. ICddbFileInfo *info;
  551. disp->QueryInterface(&info);
  552. extern DecodeFile *decodeFile;
  553. return gn->CreateFingerprint(musicid, decodeFile, info, filename, abort);
  554. }
  555. break;
  556. case 11: // OnGetTagInfo
  557. {
  558. //long *Abort = pdispparams->rgvarg[0].plVal;
  559. IDispatch *disp = pdispparams->rgvarg[1].pdispVal;
  560. BSTR filename = pdispparams->rgvarg[2].bstrVal;
  561. ICddbFileInfo *info;
  562. disp->QueryInterface(&info);
  563. return FillTag(info, filename);
  564. }
  565. break;
  566. }
  567. return DISP_E_MEMBERNOTFOUND;
  568. }
  569. HRESULT STDMETHODCALLTYPE GetIDsOfNames(REFIID riid, OLECHAR FAR* FAR* rgszNames, unsigned int cNames, LCID lcid, DISPID FAR* rgdispid)
  570. {
  571. *rgdispid = DISPID_UNKNOWN; return DISP_E_UNKNOWNNAME;
  572. }
  573. HRESULT STDMETHODCALLTYPE GetTypeInfo(unsigned int itinfo, LCID lcid, ITypeInfo FAR* FAR* pptinfo)
  574. {
  575. return E_NOTIMPL;
  576. }
  577. HRESULT STDMETHODCALLTYPE GetTypeInfoCount(unsigned int FAR * pctinfo)
  578. {
  579. return E_NOTIMPL;
  580. }
  581. HWND hwndDlg,h;
  582. api_gracenote* gn;
  583. ICDDBMusicIDManager3 *musicid;
  584. int done;
  585. long abort;
  586. wchar_t *gracenoteFileId;
  587. };
  588. static INT_PTR CALLBACK FileInfo_Autotagging(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
  589. {
  590. switch (uMsg)
  591. {
  592. case WM_INITDIALOG:
  593. {
  594. // have the close button disabled otherwise it might cause confusion
  595. EnableMenuItem(GetSystemMenu(hwndDlg, 0), SC_CLOSE, MF_BYCOMMAND|MF_GRAYED);
  596. SetWindowLong(hwndDlg,GWLP_USERDATA,lParam);
  597. autoTagListen * p = (autoTagListen *)lParam;
  598. p->hwndDlg = hwndDlg;
  599. if (p->done) EndDialog(hwndDlg,0);
  600. }
  601. break;
  602. }
  603. return 0;
  604. }
  605. #endif
  606. #endif
  607. LPCWSTR RepairMutlilineString(LPWSTR pszBuffer, INT cchBufferMax)
  608. {
  609. if (NULL == pszBuffer || cchBufferMax < 1)
  610. return NULL;
  611. LPWSTR temp = (WCHAR*)calloc(cchBufferMax, sizeof(WCHAR));
  612. if (NULL == temp) return NULL;
  613. LPWSTR p1, p2;
  614. p1 = pszBuffer;
  615. p2 = temp;
  616. INT cchLen;
  617. for (cchLen = 0; L'\0' != *p1 && ((p2 - temp) < cchBufferMax); cchLen++)
  618. {
  619. if(*p1 == L'\n')
  620. {
  621. *p2++ = L'\r';
  622. cchLen++;
  623. }
  624. *p2++ = *p1++;
  625. }
  626. CopyMemory(pszBuffer, temp, sizeof(WCHAR) * cchLen);
  627. pszBuffer[cchLen] = L'\0';
  628. free(temp);
  629. return pszBuffer;
  630. }
  631. static INT_PTR CALLBACK FileInfo_Metadata(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
  632. {
  633. static int my_change=0;
  634. switch (uMsg)
  635. {
  636. case WM_INITDIALOG:
  637. {
  638. my_change=1;
  639. int y;
  640. SendMessageW(GetDlgItem(hwndDlg, IDC_GENRE), CB_RESETCONTENT, (WPARAM)0, 0);
  641. SendMessageW(GetDlgItem(hwndDlg, IDC_GENRE), CB_SETCURSEL, (WPARAM)-1, 0);
  642. for (size_t x = 0; x != numberOfGenres; x ++)
  643. {
  644. y = SendMessageW(GetDlgItem(hwndDlg, IDC_GENRE), CB_ADDSTRING, 0, (LPARAM)genres[x]);
  645. SendMessageW(GetDlgItem(hwndDlg, IDC_GENRE), CB_SETITEMDATA, y, x);
  646. }
  647. y = SendMessageW(GetDlgItem(hwndDlg, IDC_GENRE), CB_ADDSTRING, 0, (LPARAM)L"");
  648. SendMessageW(GetDlgItem(hwndDlg, IDC_GENRE), CB_SETITEMDATA, y, 255);
  649. info_params * p = (info_params *)GetWindowLongPtrW(GetParent(hwndDlg),GWLP_USERDATA);
  650. LPWSTR pszBuffer = (LPWSTR)calloc(TEXTBUFFER_MAX, sizeof(WCHAR));
  651. if (p->mode == FILEINFO_MODE_0) {
  652. for (int i=0; i<sizeof(strfields)/sizeof(wchar_t*); i++)
  653. {
  654. memset(pszBuffer, 0, sizeof(WCHAR) * TEXTBUFFER_MAX);
  655. int result = in_get_extended_fileinfoW(p->filename,strfields[i],pszBuffer,TEXTBUFFER_MAX);
  656. SetDlgItemTextW(hwndDlg, strfieldctrls[i], pszBuffer);
  657. EnableWindow(GetDlgItem(hwndDlg, strfieldctrls[i]), result?TRUE:FALSE);
  658. EnableWindow(GetDlgItem(hwndDlg, staticstrfieldctrls[i]), result?TRUE:FALSE);
  659. }
  660. } else {
  661. for (int i=0; i<sizeof(streamStrfields)/sizeof(wchar_t*); i++)
  662. {
  663. memset(pszBuffer, 0, sizeof(WCHAR) * TEXTBUFFER_MAX);
  664. int result = in_get_extended_fileinfoW(p->filename,streamStrfields[i],pszBuffer,TEXTBUFFER_MAX);
  665. if (streamStrfieldctrls[i] != IDC_EXTRA_METADATA) {
  666. SetDlgItemTextW(hwndDlg, streamStrfieldctrls[i], pszBuffer);
  667. } else {
  668. CheckDlgButton(hwndDlg, streamStrfieldctrls[i], result && pszBuffer[0] == L'1' ? TRUE : FALSE);
  669. }
  670. EnableWindow(GetDlgItem(hwndDlg, streamStrfieldctrls[i]), result ? TRUE : FALSE);
  671. EnableWindow(GetDlgItem(hwndDlg, staticStreamStrfieldctrls[i]), result ? TRUE : FALSE);
  672. }
  673. }
  674. pszBuffer[0]=0;
  675. if (p->mode == FILEINFO_MODE_0) {
  676. in_get_extended_fileinfoW(p->filename,L"formatinformation",pszBuffer, TEXTBUFFER_MAX);
  677. } else {
  678. in_get_extended_fileinfoW(p->filename,L"streaminformation",pszBuffer, TEXTBUFFER_MAX);
  679. }
  680. // due to quirks with the more common resource editors, is easier to just store the string
  681. // internally only with \n and post-process to be \r\n (as here) so it will appear correctly
  682. // on new lines as is wanted (silly multiline edit controls)
  683. SetDlgItemTextW(hwndDlg, IDC_FORMATINFO, RepairMutlilineString(pszBuffer, TEXTBUFFER_MAX));
  684. if (p->mode == FILEINFO_MODE_0) {
  685. wchar_t tg[64]=L"", ag[64]=L"";
  686. in_get_extended_fileinfoW(p->filename,L"replaygain_track_gain",tg,64);
  687. in_get_extended_fileinfoW(p->filename,L"replaygain_album_gain",ag,64);
  688. if (!tg[0]) getStringW(IDS_NOTPRESENT,tg,64);
  689. else
  690. {
  691. // this isn't nice but it localises the RG values
  692. // for display as they're saved in the "C" locale
  693. double value = _wtof_l(tg,langManager->Get_C_NumericLocale());
  694. StringCchPrintfW(tg,64,L"%-+.2f dB", value);
  695. }
  696. if (!ag[0]) getStringW(IDS_NOTPRESENT,ag,64);
  697. else
  698. {
  699. // this isn't nice but it localises the RG values
  700. // for display as they're saved in the "C" locale
  701. double value = _wtof_l(ag,langManager->Get_C_NumericLocale());
  702. StringCchPrintfW(ag,64,L"%-+.2f dB", value);
  703. }
  704. wchar_t tgagstr[128] = {0};
  705. StringCbPrintfW(pszBuffer, TEXTBUFFER_MAX, getStringW(IDS_TRACK_GAIN_AND_ALBUM_GAIN,tgagstr,128),tg,ag);
  706. SetDlgItemTextW(hwndDlg, IDC_REPLAYGAIN, RepairMutlilineString(pszBuffer, TEXTBUFFER_MAX));
  707. my_change=0;
  708. free(pszBuffer);
  709. } else {
  710. SetTimer(hwndDlg, 1, 1000, 0);
  711. }
  712. // test for the musicid feature not being available and remove
  713. // the autotag button as required (useful for lite installs)
  714. #ifndef IGNORE_API_GRACENOTE
  715. waServiceFactory *factory = WASABI_API_SVC?WASABI_API_SVC->service_getServiceByGuid(gracenoteApiGUID):0;
  716. api_gracenote* gn = NULL;
  717. int remove = FALSE;
  718. if(factory){
  719. gn = (api_gracenote *)factory->getInterface();
  720. if(gn){
  721. ICDDBMusicIDManager3 *musicid = gn->GetMusicID();
  722. if(musicid){
  723. musicid->Shutdown();
  724. musicid->Release();
  725. }
  726. else{
  727. remove = TRUE;
  728. }
  729. factory->releaseInterface(gn);
  730. }
  731. else{
  732. remove = TRUE;
  733. }
  734. }
  735. #else
  736. int remove = TRUE;
  737. #endif
  738. // remove or disable the button based on what has been
  739. // installed or the internet access levels configured
  740. if (remove)
  741. {
  742. DestroyWindow(GetDlgItem(hwndDlg,IDC_AUTOTAG));
  743. }
  744. else
  745. {
  746. if (!isInetAvailable())
  747. {
  748. EnableWindow(GetDlgItem(hwndDlg,IDC_AUTOTAG), FALSE);
  749. }
  750. }
  751. }
  752. break;
  753. case WM_TIMER:
  754. if (wParam == 1) {
  755. info_params * p = (info_params *)GetWindowLongPtrW(GetParent(hwndDlg),GWLP_USERDATA);
  756. if (p && p->mode == FILEINFO_MODE_1) {
  757. LPWSTR pszBuffer = (LPWSTR)calloc(TEXTBUFFER_MAX, sizeof(WCHAR));
  758. if (pszBuffer) {
  759. int start = -1, end = 0;
  760. SendDlgItemMessage(hwndDlg, IDC_FORMATINFO, EM_GETSEL, (WPARAM)&start, (LPARAM)&end);
  761. in_get_extended_fileinfoW(p->filename, L"streaminformation", pszBuffer, TEXTBUFFER_MAX);
  762. // due to quirks with the more common resource editors, is easier to just store the string
  763. // internally only with \n and post-process to be \r\n (as here) so it will appear correctly
  764. // on new lines as is wanted (silly multiline edit controls)
  765. SetDlgItemTextW(hwndDlg, IDC_FORMATINFO, RepairMutlilineString(pszBuffer, TEXTBUFFER_MAX));
  766. SendDlgItemMessage(hwndDlg, IDC_FORMATINFO, EM_SETSEL, start, end);
  767. for (int i=0; i<sizeof(streamStrfields)/sizeof(wchar_t*); i++) {
  768. memset(pszBuffer, 0, sizeof(WCHAR) * TEXTBUFFER_MAX);
  769. int result = in_get_extended_fileinfoW(p->filename,streamStrfields[i],pszBuffer,TEXTBUFFER_MAX);
  770. if (streamStrfieldctrls[i] != IDC_EXTRA_METADATA) {
  771. SendDlgItemMessage(hwndDlg, streamStrfieldctrls[i], EM_GETSEL, (WPARAM)&start, (LPARAM)&end);
  772. SetDlgItemTextW(hwndDlg, streamStrfieldctrls[i], pszBuffer);
  773. SendDlgItemMessage(hwndDlg, streamStrfieldctrls[i], EM_SETSEL, start, end);
  774. } else {
  775. CheckDlgButton(hwndDlg, streamStrfieldctrls[i], result && pszBuffer[0] == L'1' ? TRUE : FALSE);
  776. }
  777. EnableWindow(GetDlgItem(hwndDlg, streamStrfieldctrls[i]), result ? TRUE : FALSE);
  778. EnableWindow(GetDlgItem(hwndDlg, staticStreamStrfieldctrls[i]), result ? TRUE : FALSE);
  779. }
  780. }
  781. }
  782. }
  783. break;
  784. case WM_COMMAND:
  785. switch (LOWORD(wParam))
  786. {
  787. #ifndef IGNORE_API_GRACENOTE
  788. #ifndef _WIN64
  789. case IDC_AUTOTAG:
  790. {
  791. ICDDBMusicIDManager3 *musicid = NULL;
  792. waServiceFactory *factory = WASABI_API_SVC?WASABI_API_SVC->service_getServiceByGuid(gracenoteApiGUID):0;
  793. api_gracenote* gn = NULL;
  794. if (factory)
  795. {
  796. gn = (api_gracenote *)factory->getInterface();
  797. if (gn)
  798. {
  799. musicid = gn->GetMusicID();
  800. }
  801. }
  802. if (!musicid)
  803. {
  804. wchar_t title[32] = {0};
  805. if (gn)
  806. {
  807. if (factory)
  808. {
  809. factory->releaseInterface(gn);
  810. }
  811. gn = NULL;
  812. }
  813. MessageBoxW(hwndDlg, getStringW(IDS_GRACENOTE_TOOLS_NOT_INSTALLED, NULL, 0),
  814. getStringW(IDS_ERROR, title, 32),0);
  815. break;
  816. }
  817. // we have the musicid pointer, so lets try and tag this mother.
  818. info_params * p = (info_params *)GetWindowLongPtrW(GetParent(hwndDlg),GWLP_USERDATA);
  819. if (NULL == p || NULL == p->filename || L'\0' == p->filename)
  820. break;
  821. // first, see if there's a pre-existing gracenote file id
  822. wchar_t fileid[1024]=L"";
  823. extendedFileInfoStructW gracenote_info;
  824. gracenote_info.filename = p->filename;
  825. gracenote_info.metadata = L"GracenoteFileID";
  826. gracenote_info.ret = fileid;
  827. gracenote_info.retlen = 1024;
  828. if (0 == SendMessageW(hMainWindow, WM_WA_IPC, (WPARAM)&gracenote_info, IPC_GET_EXTENDED_FILE_INFOW_HOOKABLE))
  829. fileid[0] = L'\0';
  830. ICddbFileInfoPtr info = 0;
  831. info.CreateInstance(CLSID_CddbFileInfo);
  832. info->put_Filename((wchar_t*)p->filename);
  833. ICddbFileInfoList *dummy=0;
  834. long match_code=666;
  835. IConnectionPoint *icp = GetConnectionPoint(musicid, DIID__ICDDBMusicIDManagerEvents);
  836. DWORD m_dwCookie = 0;
  837. autoTagListen listen(gn,musicid, fileid);
  838. listen.h = hwndDlg;
  839. if (icp) icp->Advise(static_cast<IDispatch *>(&listen), &m_dwCookie);
  840. musicid->TrackID(info, MUSICID_LOOKUP_ASYNC|MUSICID_RETURN_SINGLE|MUSICID_GET_TAG_FROM_APP|MUSICID_GET_FP_FROM_APP|MUSICID_PREFER_WF_MATCHES, &match_code, &dummy);
  841. if (dummy)
  842. dummy->Release();
  843. LPDialogBoxParamW(IDD_AUTOTAGGING,hwndDlg,FileInfo_Autotagging,(LPARAM)&listen);
  844. musicid->Shutdown();
  845. musicid->Release();
  846. factory->releaseInterface(gn);
  847. }
  848. break;
  849. #endif
  850. #endif
  851. case IDOK:
  852. if (!GetPropW(GetParent(hwndDlg),L"INBUILT_NOWRITEINFO"))
  853. {
  854. info_params * p = (info_params *)GetWindowLongPtrW(GetParent(hwndDlg),GWLP_USERDATA);
  855. LPWSTR pszBuffer = (LPWSTR)calloc(TEXTBUFFER_MAX, sizeof(WCHAR));
  856. if (pszBuffer)
  857. {
  858. for (int i=0; i<sizeof(strfields)/sizeof(wchar_t*); i++)
  859. {
  860. if (!GetDlgItemTextW(hwndDlg,strfieldctrls[i],pszBuffer, TEXTBUFFER_MAX))
  861. pszBuffer[0] = L'\0';
  862. in_set_extended_fileinfoW(p->filename,strfields[i], pszBuffer);
  863. }
  864. free(pszBuffer);
  865. }
  866. if (in_write_extended_fileinfo() == 0)
  867. {
  868. wchar_t title[256] = {0};
  869. MessageBoxW(hwndDlg,
  870. getStringW(IDS_METADATA_ERROR, NULL, 0),
  871. getStringW(IDS_METADATA_ERROR_TITLE, title, 256),
  872. MB_OK | MB_ICONWARNING);
  873. }
  874. }
  875. break;
  876. default:
  877. if (!my_change && (HIWORD(wParam) == EN_CHANGE || HIWORD(wParam) == CBN_SELCHANGE || HIWORD(wParam) == CBN_EDITCHANGE || HIWORD(wParam) == CBN_EDITUPDATE))
  878. {
  879. my_change=1;
  880. for (int i=0; i<sizeof(strfields)/sizeof(wchar_t*); i++)
  881. {
  882. if (LOWORD(wParam) == strfieldctrls[i])
  883. {
  884. if (HIWORD(wParam) != CBN_SELCHANGE)
  885. {
  886. LPWSTR pszBuffer = (LPWSTR)calloc(TEXTBUFFER_MAX, sizeof(WCHAR));
  887. if (pszBuffer)
  888. {
  889. GetDlgItemTextW(hwndDlg,strfieldctrls[i], pszBuffer, TEXTBUFFER_MAX);
  890. SendMessageW(GetParent(hwndDlg),WM_USER,(WPARAM)strfields[i],(LPARAM)pszBuffer);
  891. free(pszBuffer);
  892. }
  893. }
  894. else
  895. {
  896. int n = SendMessageW(GetDlgItem(hwndDlg, strfieldctrls[i]), CB_GETCURSEL, 0, 0);
  897. int m = SendMessageW(GetDlgItem(hwndDlg, strfieldctrls[i]), CB_GETITEMDATA, n, 0);
  898. if (m>=0 && m<numberOfGenres)
  899. {
  900. SendMessageW(GetParent(hwndDlg),WM_USER,(WPARAM)strfields[i],(LPARAM)genres[m]);
  901. }
  902. // handles case where genre is cleared
  903. else if (!n && m == 255)
  904. {
  905. SendMessageW(GetParent(hwndDlg),WM_USER,(WPARAM)strfields[i],(LPARAM)L"");
  906. }
  907. else if(n == CB_ERR)
  908. {
  909. // if we got here then it is likely to be from a genre not in the built in list
  910. LPWSTR pszBuffer = (LPWSTR)calloc(TEXTBUFFER_MAX, sizeof(WCHAR));
  911. if (pszBuffer)
  912. {
  913. if(GetDlgItemTextW(hwndDlg,strfieldctrls[i], pszBuffer, TEXTBUFFER_MAX)){
  914. SendMessageW(GetParent(hwndDlg),WM_USER,(WPARAM)strfields[i],(LPARAM)pszBuffer);
  915. }
  916. free(pszBuffer);
  917. }
  918. }
  919. }
  920. }
  921. }
  922. my_change=0;
  923. }
  924. }
  925. break;
  926. case WM_USER:
  927. if (wParam && lParam && !my_change)
  928. {
  929. for (int i=0; i<sizeof(strfields)/sizeof(wchar_t*); i++)
  930. if (_wcsicmp((wchar_t*)wParam,strfields[i])==0)
  931. SetDlgItemTextW(hwndDlg,strfieldctrls[i],(wchar_t*)lParam);
  932. }
  933. break;
  934. }
  935. return 0;
  936. }
  937. static void Adjust(int bmpw, int bmph, int &x, int &y, int &w, int &h)
  938. {
  939. // maintain 'square' stretching
  940. double aspX = (double)(w)/(double)bmpw;
  941. double aspY = (double)(h)/(double)bmph;
  942. double asp = min(aspX, aspY);
  943. int newW = (int)(bmpw*asp);
  944. int newH = (int)(bmph*asp);
  945. x = (w - newW)/2;
  946. y = (h - newH)/2;
  947. w = newW;
  948. h = newH;
  949. }
  950. static HBITMAP getBitmap(ARGB32 * data, int w, int h, HWND parent)
  951. {
  952. BITMAPINFO info={0};
  953. info.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
  954. info.bmiHeader.biWidth = w;
  955. info.bmiHeader.biHeight = -h;
  956. info.bmiHeader.biPlanes = 1;
  957. info.bmiHeader.biBitCount = 32;
  958. info.bmiHeader.biCompression = BI_RGB;
  959. HDC dc = GetDC(parent);
  960. HBITMAP bm = CreateCompatibleBitmap(dc,w,h);
  961. SetDIBits(dc,bm,0,h,data,&info,DIB_RGB_COLORS);
  962. ReleaseDC(parent,dc);
  963. return bm;
  964. }
  965. // these two are also used by AlbumArtRetrival.cpp
  966. ARGB32 * decompressImage(const void *data, int datalen, int * dataW, int * dataH)
  967. {
  968. ARGB32* ret=NULL;
  969. FOURCC imgload = svc_imageLoader::getServiceType();
  970. int n = (int) WASABI_API_SVC->service_getNumServices(imgload);
  971. for (int i=0; i<n; i++)
  972. {
  973. waServiceFactory *sf = WASABI_API_SVC->service_enumService(imgload,i);
  974. if (sf)
  975. {
  976. svc_imageLoader * l = (svc_imageLoader*)sf->getInterface();
  977. if (l)
  978. {
  979. if (l->testData(data,datalen))
  980. {
  981. ret = l->loadImage(data,datalen,dataW,dataH);
  982. sf->releaseInterface(l);
  983. break;
  984. }
  985. sf->releaseInterface(l);
  986. }
  987. }
  988. }
  989. return ret;
  990. }
  991. HBITMAP getBitmap(ARGB32 * data, int dw, int dh, int targetW, int targetH, HWND parent)
  992. {
  993. HQSkinBitmap bm(data,dw,dh);
  994. int x=0,y=0,w=targetW,h=targetH;
  995. Adjust(dw,dh,x,y,w,h);
  996. BltCanvas canv(targetW,targetH);
  997. bm.stretch(&canv,x,y,w,h);
  998. return getBitmap((ARGB32*)canv.getBits(),targetW,targetH,parent);
  999. }
  1000. void EnableArtFrame(HWND hwndDlg, BOOL enable)
  1001. {
  1002. const int artFrameElements[] =
  1003. {
  1004. IDC_STATIC_FRAME,
  1005. IDC_ARTHOLDER,
  1006. IDC_BUTTON_CHANGE,
  1007. IDC_BUTTON_SAVEAS,
  1008. IDC_BUTTON_COPY,
  1009. IDC_BUTTON_PASTE,
  1010. IDC_BUTTON_DELETE,
  1011. };
  1012. for (int i=0; i<sizeof(artFrameElements)/sizeof(int); i++)
  1013. EnableWindow(GetDlgItem(hwndDlg,artFrameElements[i]),enable);
  1014. SetDlgItemTextW(hwndDlg,IDC_STATIC_FRAME,getStringW(IDS_NO_IMAGE,0,0));
  1015. }
  1016. class EditArtItem
  1017. {
  1018. public:
  1019. ARGB32 * bits;
  1020. int w;
  1021. int h;
  1022. void *data;
  1023. size_t datalen;
  1024. wchar_t *mimetype;
  1025. bool dirty;
  1026. EditArtItem(ARGB32 *bits, int w, int h, bool dirty=false) : bits(bits), w(w), h(h), data(0), datalen(0), mimetype(0), dirty(dirty) {}
  1027. ~EditArtItem()
  1028. {
  1029. if (bits) WASABI_API_MEMMGR->sysFree(bits);
  1030. if (mimetype) free(mimetype);
  1031. if (data) WASABI_API_MEMMGR->sysFree(data);
  1032. }
  1033. };
  1034. static EditArtItem * getCurrentArtItem(HWND hwndDlg)
  1035. {
  1036. int sel = SendDlgItemMessage(hwndDlg,IDC_ARTLIST,LB_GETCURSEL,0,0);
  1037. if (sel == -1)
  1038. return NULL;
  1039. EditArtItem *e = (EditArtItem *)SendDlgItemMessage(hwndDlg,IDC_ARTLIST,LB_GETITEMDATA,sel,0);
  1040. if (e != (EditArtItem *)-1)
  1041. return e;
  1042. return NULL;
  1043. }
  1044. static void GetSize(HBITMAP bm, int &w, int &h, HWND hwndDlg)
  1045. {
  1046. HDC dc = GetDC(hwndDlg);
  1047. BITMAPINFO info={0};
  1048. info.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
  1049. GetDIBits(dc,bm,0,0,NULL,&info,DIB_RGB_COLORS);
  1050. w = abs(info.bmiHeader.biWidth);
  1051. h = abs(info.bmiHeader.biHeight);
  1052. ReleaseDC(hwndDlg,dc);
  1053. }
  1054. static bool AddNewArtItem(HWND hwndDlg)
  1055. {
  1056. wchar_t buf[100]=L"";
  1057. GetDlgItemTextW(hwndDlg,IDC_COMBO_ARTTYPE,buf,100);
  1058. if (!buf[0]) return false;
  1059. int s=SendDlgItemMessageW(hwndDlg,IDC_ARTLIST,LB_FINDSTRINGEXACT, (WPARAM)-1,(LPARAM)buf);
  1060. if (s != LB_ERR && SendDlgItemMessage(hwndDlg,IDC_ARTLIST,LB_GETCOUNT,0,0))
  1061. {
  1062. // user has selected something already in our list
  1063. SendDlgItemMessage(hwndDlg,IDC_ARTLIST,LB_SETCURSEL,s,0);
  1064. SendMessageW(hwndDlg,WM_COMMAND,MAKEWPARAM(IDC_ARTLIST,LBN_SELCHANGE),0);
  1065. return true;
  1066. }
  1067. // let's add this new item
  1068. s=SendDlgItemMessageW(hwndDlg,IDC_ARTLIST,LB_ADDSTRING,0,(LPARAM)buf);
  1069. if (s == LB_ERR) return false;
  1070. EditArtItem *e = new EditArtItem(0,0,0);
  1071. SendDlgItemMessage(hwndDlg,IDC_ARTLIST,LB_SETITEMDATA,s,(LPARAM)e);
  1072. SendDlgItemMessage(hwndDlg,IDC_ARTLIST,LB_SETCURSEL,s,0);
  1073. EnableArtFrame(hwndDlg,TRUE);
  1074. return true;
  1075. }
  1076. static svc_imageLoader *FindImageLoader(const wchar_t *filespec, waServiceFactory **factory)
  1077. {
  1078. FOURCC imgload = svc_imageLoader::getServiceType();
  1079. int n = (int) WASABI_API_SVC->service_getNumServices(imgload);
  1080. for (int i=0; i<n; i++)
  1081. {
  1082. waServiceFactory *sf = WASABI_API_SVC->service_enumService(imgload,i);
  1083. if (sf)
  1084. {
  1085. svc_imageLoader * l = (svc_imageLoader*)sf->getInterface();
  1086. if (l)
  1087. {
  1088. if (l->isMine(filespec))
  1089. {
  1090. *factory = sf;
  1091. return l;
  1092. }
  1093. sf->releaseInterface(l);
  1094. }
  1095. }
  1096. }
  1097. return NULL;
  1098. }
  1099. static ARGB32 *loadImgFromFile(const wchar_t *file, int *len, int *w, int *h, wchar_t ** mime, ARGB32** imageData)
  1100. {
  1101. waServiceFactory *sf;
  1102. svc_imageLoader *loader = FindImageLoader(file, &sf);
  1103. if (loader)
  1104. {
  1105. HANDLE hf = CreateFileW(file, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
  1106. if (hf != INVALID_HANDLE_VALUE)
  1107. {
  1108. *len = GetFileSize(hf, 0);
  1109. HANDLE hmap = CreateFileMapping(hf, 0, PAGE_READONLY, 0, 0, 0);
  1110. if (hmap)
  1111. {
  1112. void *data = MapViewOfFile(hmap, FILE_MAP_READ, 0, 0, 0);
  1113. if (data)
  1114. {
  1115. if (loader->testData(data,*len))
  1116. {
  1117. ARGB32* im = loader->loadImage(data,*len,w,h);
  1118. if (im && !_wcsicmp(loader->mimeType(), L"image/jpeg"))
  1119. {
  1120. *mime = _wcsdup(L"jpg");
  1121. *imageData = (ARGB32*)WASABI_API_MEMMGR->sysMalloc(*len);
  1122. memcpy(*imageData, data, *len);
  1123. }
  1124. UnmapViewOfFile(data);
  1125. CloseHandle(hmap);
  1126. CloseHandle(hf);
  1127. sf->releaseInterface(loader);
  1128. return im;
  1129. }
  1130. UnmapViewOfFile(data);
  1131. }
  1132. CloseHandle(hmap);
  1133. }
  1134. CloseHandle(hf);
  1135. }
  1136. sf->releaseInterface(loader);
  1137. }
  1138. return 0;
  1139. }
  1140. static void * writeImg(const ARGB32 *data, int w, int h, int *length, const wchar_t *ext)
  1141. {
  1142. if (!ext || (ext && !*ext)) return NULL;
  1143. if (*ext == L'.') ext++;
  1144. FOURCC imgwrite = svc_imageWriter::getServiceType();
  1145. int n = (int) WASABI_API_SVC->service_getNumServices(imgwrite);
  1146. for (int i=0; i<n; i++)
  1147. {
  1148. waServiceFactory *sf = WASABI_API_SVC->service_enumService(imgwrite,i);
  1149. if (sf)
  1150. {
  1151. svc_imageWriter * l = (svc_imageWriter*)sf->getInterface();
  1152. if (l)
  1153. {
  1154. if (wcsstr(l->getExtensions(),ext))
  1155. {
  1156. void* ret = l->convert(data,32,w,h,length);
  1157. sf->releaseInterface(l);
  1158. return ret;
  1159. }
  1160. sf->releaseInterface(l);
  1161. }
  1162. }
  1163. }
  1164. return NULL;
  1165. }
  1166. static int writeFile(const wchar_t *file, const void * data, int length)
  1167. {
  1168. FILE *f=_wfopen(file,L"wb");
  1169. if (!f) return ALBUMART_FAILURE;
  1170. if (fwrite(data,length,1,f) != 1)
  1171. {
  1172. fclose(f);
  1173. return ALBUMART_FAILURE;
  1174. }
  1175. fclose(f);
  1176. return ALBUMART_SUCCESS;
  1177. }
  1178. static void UpdateArtItemFrame(HWND hwndDlg)
  1179. {
  1180. EditArtItem * e = getCurrentArtItem(hwndDlg);
  1181. if (e)
  1182. {
  1183. wchar_t type[100] = {0}, buf[100] = {0}, *uiType = 0;
  1184. int sel = SendDlgItemMessage(hwndDlg,IDC_ARTLIST,LB_GETCURSEL,0,0);
  1185. SendDlgItemMessageW(hwndDlg,IDC_ARTLIST,LB_GETTEXT,sel,(LPARAM)type);
  1186. if (e->mimetype)
  1187. {
  1188. uiType = wcschr(e->mimetype, L'/');
  1189. if (uiType && *uiType)
  1190. {
  1191. uiType++;
  1192. }
  1193. }
  1194. int origin[] = {IDS_ORIGIN_NONE, IDS_ORIGIN_EMBEDDED, IDS_ORIGIN_ALBUM_MATCH, IDS_ORIGIN_NFO,
  1195. IDS_ORIGIN_COVER_MATCH, IDS_ORIGIN_FOLDER_MATCH, IDS_ORIGIN_FRONT_MATCH, IDS_ORIGIN_ARTWORK_MATCH};
  1196. StringCchPrintfW(caption,128,getStringW(IDS_ARTWORK_DETAILS, NULL, 0), type, e->w, e->h,
  1197. // TODO: review what we set as the type for this from pasting...
  1198. getStringW(origin[2/*ret*/], buf, sizeof(buf)), (uiType && *uiType ? uiType : e->mimetype));
  1199. SetDlgItemTextW(hwndDlg,IDC_STATIC_FRAME, caption);
  1200. }
  1201. else
  1202. {
  1203. SetDlgItemTextW(hwndDlg,IDC_STATIC_FRAME,getStringW(IDS_NO_IMAGE,0,0));
  1204. }
  1205. }
  1206. static void writeImageToFile(ARGB32 * img, int w, int h, const wchar_t *file)
  1207. {
  1208. int length=0;
  1209. void * data = writeImg(img,w,h,&length,wcsrchr(file,L'.'));
  1210. if (data)
  1211. {
  1212. writeFile(file,data,length);
  1213. WASABI_API_MEMMGR->sysFree(data);
  1214. }
  1215. }
  1216. static INT_PTR CALLBACK FileInfo_Artwork(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
  1217. {
  1218. switch (uMsg)
  1219. {
  1220. case WM_INITDIALOG:
  1221. {
  1222. EnableArtFrame(hwndDlg,FALSE);
  1223. // added 30 May 2012 as per email from Tejas w.r.t. to Rovi deal ending
  1224. // as doing this means we keep the placeholder incase of a change at a
  1225. // later time and without doing anything to require an translation updates
  1226. HWND wnd = GetDlgItem(hwndDlg, IDC_BUTTON_DOWNLOAD);
  1227. if (IsWindow(wnd)) DestroyWindow(wnd);
  1228. info_params * p = (info_params *)GetWindowLongPtrW(GetParent(hwndDlg),GWLP_USERDATA);
  1229. if (AGAVE_API_ALBUMART)
  1230. {
  1231. int w = 0, h = 0;
  1232. ARGB32 *bits = NULL;
  1233. if (AGAVE_API_ALBUMART->GetAlbumArt(p->filename, L"cover", &w, &h, &bits) == ALBUMART_SUCCESS)
  1234. {
  1235. WASABI_API_MEMMGR->sysFree(bits);
  1236. int i = SendDlgItemMessageW(hwndDlg,IDC_ARTLIST,LB_ADDSTRING,0,(LPARAM)getStringW(IDS_COVER,NULL,0));
  1237. SendDlgItemMessage(hwndDlg,IDC_ARTLIST,LB_SETCURSEL,i,0);
  1238. PostMessageW(hwndDlg,WM_COMMAND,MAKEWPARAM(IDC_ARTLIST,LBN_SELCHANGE),0);
  1239. }
  1240. wchar_t *types = NULL;
  1241. #if 0 // benski> TODO:
  1242. if (AGAVE_API_ALBUMART->GetAlbumArtTypes(p->filename,&types) == ALBUMART_SUCCESS)
  1243. {
  1244. wchar_t *p = types;
  1245. int sel = 0;
  1246. while (p && *p)
  1247. {
  1248. int is_cover = (!_wcsicmp(p,L"cover") || !_wcsicmp(p,getStringW(IDS_COVER,NULL,0)));
  1249. int i = SendDlgItemMessageW(hwndDlg,IDC_ARTLIST,LB_ADDSTRING,0,(LPARAM)(is_cover?getStringW(IDS_COVER,NULL,0):p));
  1250. if (!_wcsicmp(p,L"cover"))
  1251. sel = i;
  1252. p += wcslen(p) + 1;
  1253. }
  1254. WASABI_API_MEMMGR->sysFree(types);
  1255. SendDlgItemMessage(hwndDlg,IDC_ARTLIST,LB_SETCURSEL,sel,0);
  1256. PostMessageW(hwndDlg,WM_COMMAND,MAKEWPARAM(IDC_ARTLIST,LBN_SELCHANGE),0);
  1257. }
  1258. #endif
  1259. if (AGAVE_API_ALBUMART->GetValidAlbumArtTypes(p->filename,&types) == ALBUMART_SUCCESS)
  1260. {
  1261. wchar_t *p = types;
  1262. int sel = 0;
  1263. while (p && *p)
  1264. {
  1265. int is_cover = (!_wcsicmp(p,L"cover") || !_wcsicmp(p,getStringW(IDS_COVER,NULL,0)));
  1266. int i = SendDlgItemMessageW(hwndDlg,IDC_COMBO_ARTTYPE,CB_ADDSTRING,0,(LPARAM)(is_cover?getStringW(IDS_COVER,NULL,0):p));
  1267. if (is_cover || !_wcsicmp(p, config_artwork_filter))
  1268. sel = i;
  1269. p += wcslen(p) + 1;
  1270. }
  1271. WASABI_API_MEMMGR->sysFree(types);
  1272. SendDlgItemMessage(hwndDlg,IDC_COMBO_ARTTYPE,CB_SETCURSEL,sel,0);
  1273. }
  1274. }
  1275. }
  1276. break;
  1277. case WM_COMMAND:
  1278. switch (LOWORD(wParam))
  1279. {
  1280. case IDC_ARTLIST:
  1281. if (HIWORD(wParam) == LBN_SELCHANGE)
  1282. {
  1283. info_params * p = (info_params *)GetWindowLongPtrW(GetParent(hwndDlg),GWLP_USERDATA);
  1284. wchar_t type[100]=L"";
  1285. int sel = SendDlgItemMessage(hwndDlg,IDC_ARTLIST,LB_GETCURSEL,0,0);
  1286. if (sel == -1)
  1287. {
  1288. HBITMAP bmold = (HBITMAP)SendDlgItemMessage(hwndDlg,IDC_ARTHOLDER,STM_SETIMAGE,IMAGE_BITMAP,(LPARAM)0);
  1289. if (bmold) DeleteObject(bmold);
  1290. EnableArtFrame(hwndDlg,FALSE);
  1291. return 0;
  1292. }
  1293. EnableArtFrame(hwndDlg,TRUE);
  1294. SendDlgItemMessageW(hwndDlg,IDC_ARTLIST,LB_GETTEXT,sel,(LPARAM)type);
  1295. int w = 0, h = 0;
  1296. ARGB32 *bits = NULL;
  1297. if (AGAVE_API_ALBUMART && AGAVE_API_ALBUMART->GetAlbumArt(p->filename,(!_wcsicmp(type,getStringW(IDS_COVER,NULL,0))?L"cover":type),&w,&h,&bits) == ALBUMART_SUCCESS)
  1298. {
  1299. HBITMAP bm = getBitmap(bits,w,h,228,228,hwndDlg);
  1300. HBITMAP bmold = (HBITMAP)SendDlgItemMessage(hwndDlg,IDC_ARTHOLDER,STM_SETIMAGE,IMAGE_BITMAP,(LPARAM)bm);
  1301. if (bmold) DeleteObject(bmold);
  1302. wchar_t caption[128], *mimeType = 0, *uiType = 0;
  1303. int origin[] = {IDS_ORIGIN_NONE, IDS_ORIGIN_EMBEDDED, IDS_ORIGIN_ALBUM_MATCH, IDS_ORIGIN_NFO,
  1304. IDS_ORIGIN_COVER_MATCH, IDS_ORIGIN_FOLDER_MATCH, IDS_ORIGIN_FRONT_MATCH, IDS_ORIGIN_ARTWORK_MATCH};
  1305. int ret = AGAVE_API_ALBUMART->GetAlbumArtOrigin(p->filename,(!_wcsicmp(type,getStringW(IDS_COVER,NULL,0))?L"cover":type), &mimeType);
  1306. if (mimeType)
  1307. {
  1308. uiType = wcschr(mimeType, L'/');
  1309. if (uiType && *uiType)
  1310. {
  1311. uiType++;
  1312. }
  1313. }
  1314. EditArtItem *e = new EditArtItem(bits,w,h);
  1315. if (e)
  1316. {
  1317. size_t len = 0;
  1318. ARGB32 *data = NULL;
  1319. if (AGAVE_API_ALBUMART->GetAlbumArtData(p->filename, L"cover", (void**)&data, &len, NULL) == ALBUMART_SUCCESS)
  1320. {
  1321. e->data = data;
  1322. e->datalen = len;
  1323. }
  1324. wchar_t mime[32] = {L"image/jpeg"};
  1325. if (uiType && *uiType)
  1326. {
  1327. StringCchPrintfW(mime, 32, L"image/%s", uiType);
  1328. }
  1329. else if(mimeType && *mimeType && _wcsicmp(mimeType, L"image/jpeg"))
  1330. {
  1331. lstrcpynW(mime, mimeType, 32);
  1332. }
  1333. if (mime && *mime) e->mimetype = _wcsdup(mime);
  1334. EditArtItem *eold = (EditArtItem *)SendDlgItemMessage(hwndDlg,IDC_ARTLIST,LB_GETITEMDATA,sel,0);
  1335. if (eold && eold != (EditArtItem *)-1) delete eold;
  1336. SendDlgItemMessage(hwndDlg,IDC_ARTLIST,LB_SETITEMDATA,sel,(LPARAM)e);
  1337. }
  1338. wchar_t buf[100] = {0}, buf2[32] = {0};
  1339. StringCchPrintfW(caption,128,getStringW(IDS_ARTWORK_DETAILS, NULL, 0), type, w, h,
  1340. getStringW(origin[ret], buf, ARRAYSIZE(buf)),
  1341. (uiType && *uiType ? uiType :
  1342. (mimeType && *mimeType ? mimeType :
  1343. getStringW(IDS_UNKNOWN_MIME, buf2, ARRAYSIZE(buf2)))));
  1344. SetDlgItemTextW(hwndDlg,IDC_STATIC_FRAME, caption);
  1345. WASABI_API_MEMMGR->sysFree(mimeType);
  1346. }
  1347. }
  1348. break;
  1349. // disabled 30 May 2012 as per email from Tejas w.r.t. to Rovi deal ending
  1350. #if 0
  1351. case IDC_BUTTON_DOWNLOAD:
  1352. {
  1353. wchar_t artist[256]=L"";
  1354. wchar_t album[256]=L"";
  1355. info_params * p = (info_params *)GetWindowLongPtrW(GetParent(hwndDlg),GWLP_USERDATA);
  1356. GetDlgItemTextW(p->tabs[0],IDC_ALBUM_ARTIST,artist,256);
  1357. if (!artist[0]) GetDlgItemTextW(p->tabs[0],IDC_ARTIST,artist,256);
  1358. GetDlgItemTextW(p->tabs[0],IDC_ALBUM,album,256);
  1359. artFetchData d = {sizeof(d),hwndDlg,artist,album,0};
  1360. int r = (int)SendMessageW(hMainWindow,WM_WA_IPC,(LPARAM)&d,IPC_FETCH_ALBUMART);
  1361. if (r == -2) break; // cancel all was pressed
  1362. if (r == 0 && d.imgData && d.imgDataLen) // success
  1363. {
  1364. if (AddNewArtItem(hwndDlg))
  1365. {
  1366. bool success=false;
  1367. EditArtItem *e = getCurrentArtItem(hwndDlg);
  1368. if (e)
  1369. {
  1370. int w=0,h=0;
  1371. ARGB32* data = decompressImage(d.imgData,d.imgDataLen,&w,&h);
  1372. if (data)
  1373. {
  1374. if (e->bits)
  1375. {
  1376. WASABI_API_MEMMGR->sysFree(e->bits);
  1377. e->bits = 0;
  1378. }
  1379. if (e->data)
  1380. {
  1381. WASABI_API_MEMMGR->sysFree(e->data);
  1382. e->data = 0;
  1383. e->datalen = 0;
  1384. }
  1385. e->bits = data;
  1386. e->w = w;
  1387. e->h = h;
  1388. if (e->data) WASABI_API_MEMMGR->sysFree(e->data);
  1389. e->data = d.imgData;
  1390. d.imgData = 0;
  1391. e->datalen = d.imgDataLen;
  1392. if (e->mimetype) free(e->mimetype);
  1393. e->mimetype = _wcsdup(L"jpg");
  1394. e->dirty = true;
  1395. HBITMAP dispbm = getBitmap(e->bits,e->w,e->h,228,228,hwndDlg);
  1396. HBITMAP bmold = (HBITMAP)SendDlgItemMessage(hwndDlg,IDC_ARTHOLDER,STM_SETIMAGE,IMAGE_BITMAP,(LPARAM)dispbm);
  1397. if (bmold) DeleteObject(bmold);
  1398. success=true;
  1399. }
  1400. }
  1401. if (!success)
  1402. {
  1403. // fail, remove :(
  1404. int sel = SendDlgItemMessage(hwndDlg,IDC_ARTLIST,LB_GETCURSEL,0,0);
  1405. if (sel == -1)
  1406. return 0;
  1407. if (e) delete e;
  1408. SendDlgItemMessage(hwndDlg,IDC_ARTLIST,LB_DELETESTRING,sel,0);
  1409. EnableArtFrame(hwndDlg,0);
  1410. }
  1411. }
  1412. if (d.imgData)
  1413. WASABI_API_MEMMGR->sysFree(d.imgData);
  1414. }
  1415. }
  1416. break;
  1417. #endif
  1418. case IDC_BUTTON_LOAD:
  1419. if (AddNewArtItem(hwndDlg))
  1420. {
  1421. if (!FileInfo_Artwork(hwndDlg,WM_COMMAND,IDC_BUTTON_CHANGE,0))
  1422. {
  1423. // fail, remove :(
  1424. int sel = SendDlgItemMessage(hwndDlg,IDC_ARTLIST,LB_GETCURSEL,0,0);
  1425. if (sel == -1)
  1426. return 0;
  1427. EditArtItem * e = getCurrentArtItem(hwndDlg);
  1428. if (e) delete e;
  1429. SendDlgItemMessage(hwndDlg,IDC_ARTLIST,LB_DELETESTRING,sel,0);
  1430. EnableArtFrame(hwndDlg,0);
  1431. }
  1432. }
  1433. break;
  1434. case IDC_BUTTON_CHANGE:
  1435. {
  1436. EditArtItem *e = getCurrentArtItem(hwndDlg);
  1437. if (!e) break;
  1438. info_params * p = (info_params *)GetWindowLongPtrW(GetParent(hwndDlg),GWLP_USERDATA);
  1439. wchar_t file[1024]=L"", folder[MAX_PATH]=L"";
  1440. OPENFILENAMEW fn = {sizeof(OPENFILENAMEW),0};
  1441. // set the ofd to the current file's folder
  1442. lstrcpynW(folder,p->filename,MAX_PATH);
  1443. PathRemoveFileSpecW(folder);
  1444. PathAddBackslashW(folder);
  1445. fn.lpstrInitialDir = folder;
  1446. fn.hwndOwner = hwndDlg;
  1447. fn.lpstrFile = file;
  1448. fn.nMaxFile = 1024;
  1449. static wchar_t fileExtensionsString[MAX_PATH] = {0};
  1450. if(!fileExtensionsString[0])
  1451. {
  1452. getStringW(IDS_IMAGE_FILES,fileExtensionsString,MAX_PATH);
  1453. wchar_t *temp=fileExtensionsString+lstrlenW(fileExtensionsString) + 1;
  1454. // query the available image loaders and build it against the supported formats
  1455. FOURCC imgload = svc_imageLoader::getServiceType();
  1456. int n = (int) WASABI_API_SVC->service_getNumServices(imgload);
  1457. for (int i=0; i<n; i++)
  1458. {
  1459. waServiceFactory *sf = WASABI_API_SVC->service_enumService(imgload,i);
  1460. if (sf)
  1461. {
  1462. svc_imageLoader * l = (svc_imageLoader*)sf->getInterface();
  1463. if (l)
  1464. {
  1465. wchar_t *tests[] = {L"*.jpg",L"*.jpeg",L"*.png",L"*.gif",L"*.bmp"};
  1466. for(int i = 0; i < sizeof(tests)/sizeof(tests[0]); i++)
  1467. {
  1468. if (l->isMine(tests[i]))
  1469. {
  1470. StringCchCatW(temp,MAX_PATH,tests[i]);
  1471. StringCchCatW(temp,MAX_PATH,L";");
  1472. }
  1473. }
  1474. sf->releaseInterface(l);
  1475. }
  1476. }
  1477. }
  1478. *(temp = temp + lstrlenW(temp) + 1) = 0;
  1479. }
  1480. fn.lpstrFilter = fileExtensionsString;
  1481. fn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST | OFN_NOVALIDATE;
  1482. if (GetOpenFileNameW(&fn))
  1483. {
  1484. int len = 0, w = 0, h = 0;
  1485. wchar_t * mime = 0;
  1486. // TODO: benski> save original bits and mime type
  1487. // UPDATE: will only grab the raw data for jpeg files at the moment
  1488. ARGB32 * data = 0, * bits = loadImgFromFile(file,&len,&w,&h,&mime,&data);
  1489. if (bits)
  1490. {
  1491. if (e->bits)
  1492. {
  1493. WASABI_API_MEMMGR->sysFree(e->bits);
  1494. e->bits = 0;
  1495. }
  1496. if (e->data)
  1497. {
  1498. WASABI_API_MEMMGR->sysFree(e->data);
  1499. e->data = 0;
  1500. e->datalen = 0;
  1501. }
  1502. e->bits = bits;
  1503. e->w = w;
  1504. e->h = h;
  1505. if (data)
  1506. {
  1507. e->data = data;
  1508. e->datalen = len;
  1509. }
  1510. if (e->mimetype) free(e->mimetype);
  1511. e->mimetype = mime;
  1512. e->dirty = true;
  1513. HBITMAP dispbm = getBitmap(e->bits,e->w,e->h,228,228,hwndDlg);
  1514. HBITMAP bmold = (HBITMAP)SendDlgItemMessage(hwndDlg,IDC_ARTHOLDER,STM_SETIMAGE,IMAGE_BITMAP,(LPARAM)dispbm);
  1515. if (bmold) DeleteObject(bmold);
  1516. return 1;
  1517. }
  1518. }
  1519. break;
  1520. }
  1521. case IDC_BUTTON_SAVEAS:
  1522. {
  1523. EditArtItem *e = getCurrentArtItem(hwndDlg);
  1524. if (!e) break;
  1525. info_params * p = (info_params *)GetWindowLongPtrW(GetParent(hwndDlg),GWLP_USERDATA);
  1526. wchar_t file[1024]=L"", folder[MAX_PATH]=L"";
  1527. OPENFILENAMEW fn = {sizeof(OPENFILENAMEW),0};
  1528. // set the ofd to the current file's folder
  1529. lstrcpynW(folder,p->filename,MAX_PATH);
  1530. PathRemoveFileSpecW(folder);
  1531. PathAddBackslashW(folder);
  1532. fn.lpstrInitialDir = folder;
  1533. fn.hwndOwner = hwndDlg;
  1534. fn.lpstrFile = file;
  1535. fn.nMaxFile = 1020;
  1536. static wchar_t *mimes[4] = {0};
  1537. wchar_t *tests[] = {L"*.jpg",L"*.png",L"*.gif",L"*.bmp"};
  1538. static int tests_idx[4] = {0,1,2,3}, tests_run = 0, last_filter = -1;
  1539. static wchar_t filter[1024] = {0}, *sff = filter;
  1540. if(!tests_run)
  1541. {
  1542. int def_idx = 0;
  1543. tests_run = 1;
  1544. FOURCC imgload = svc_imageLoader::getServiceType();
  1545. int n = (int) WASABI_API_SVC->service_getNumServices(imgload);
  1546. for (int i = 0, j = 0; i < n; i++)
  1547. {
  1548. waServiceFactory *sf = WASABI_API_SVC->service_enumService(imgload,i);
  1549. if (sf)
  1550. {
  1551. svc_imageLoader * l = (svc_imageLoader*)sf->getInterface();
  1552. if (l)
  1553. {
  1554. int tests_str[] = {IDS_JPEG_FILE,IDS_PNG_FILE,IDS_GIF_FILE,IDS_BMP_FILE};
  1555. size_t size = 1024;
  1556. for(int k = 0; k < ARRAYSIZE(tests); k++)
  1557. {
  1558. if (l->isMine(tests[k]))
  1559. {
  1560. if (!k) def_idx = tests_idx[j] + 1;
  1561. tests_idx[j] = k;
  1562. mimes[j] = _wcsdup(l->mimeType());
  1563. j++;
  1564. int len = 0;
  1565. getStringW(tests_str[k],sff,size);
  1566. size-=(len = lstrlenW(sff)+1);
  1567. sff+=len;
  1568. lstrcpynW(sff,tests[k], (int)size);
  1569. if (!k) lstrcatW(sff, L";*.jpeg");
  1570. size-=(len = lstrlenW(sff)+1);
  1571. sff+=len;
  1572. }
  1573. }
  1574. sf->releaseInterface(l);
  1575. }
  1576. }
  1577. }
  1578. last_filter = _r_i("art_flt",last_filter);
  1579. if (last_filter == -1) last_filter = def_idx;
  1580. }
  1581. fn.lpstrFilter = filter;
  1582. fn.nFilterIndex = last_filter; // default to *.jpg / last filter
  1583. fn.Flags = OFN_OVERWRITEPROMPT;
  1584. if (GetSaveFileNameW(&fn))
  1585. {
  1586. int l = (int) wcslen(file);
  1587. if (l>4 && file[l-4]==L'.'); // we have an extention
  1588. else StringCchCatW(file,1024,tests[tests_idx[fn.nFilterIndex-1]]+1); // map to the extension to use
  1589. // where possible see if we can just save the image data without conversion
  1590. if (e->data && e->mimetype && !_wcsicmp(mimes[fn.nFilterIndex-1], e->mimetype))
  1591. {
  1592. writeFile(file, e->data, (int)e->datalen);
  1593. }
  1594. else
  1595. {
  1596. // though if we're not sure or it is a different format from what is stored
  1597. // then we'll need to convert (not nice to do) and hope it doesn't fail...
  1598. writeImageToFile(e->bits,e->w,e->h,file);
  1599. }
  1600. }
  1601. last_filter = fn.nFilterIndex;
  1602. _w_i("art_flt",last_filter);
  1603. break;
  1604. }
  1605. case IDC_BUTTON_COPY:
  1606. {
  1607. EditArtItem *e = getCurrentArtItem(hwndDlg);
  1608. if (!e) break;
  1609. if (!OpenClipboard(hwndDlg)) break;
  1610. EmptyClipboard();
  1611. HBITMAP bm = getBitmap(e->bits,e->w,e->h,hwndDlg);
  1612. SetClipboardData(CF_BITMAP,bm);
  1613. CloseClipboard();
  1614. DeleteObject(bm);
  1615. break;
  1616. }
  1617. case IDC_BUTTON_PASTENEW:
  1618. if (AddNewArtItem(hwndDlg))
  1619. {
  1620. if (!FileInfo_Artwork(hwndDlg,WM_COMMAND,IDC_BUTTON_PASTE,0))
  1621. {
  1622. // fail, remove :(
  1623. int sel = SendDlgItemMessage(hwndDlg,IDC_ARTLIST,LB_GETCURSEL,0,0);
  1624. if (sel == -1)
  1625. return 0;
  1626. EditArtItem * e = getCurrentArtItem(hwndDlg);
  1627. if (e) delete e;
  1628. SendDlgItemMessage(hwndDlg,IDC_ARTLIST,LB_DELETESTRING,sel,0);
  1629. EnableArtFrame(hwndDlg,0);
  1630. }
  1631. }
  1632. UpdateArtItemFrame(hwndDlg);
  1633. break;
  1634. case IDC_BUTTON_PASTE:
  1635. {
  1636. EditArtItem *e = getCurrentArtItem(hwndDlg);
  1637. if (!e) break;
  1638. if (!OpenClipboard(hwndDlg)) break;
  1639. HBITMAP bm = (HBITMAP)GetClipboardData(CF_BITMAP);
  1640. if (bm)
  1641. {
  1642. GetSize(bm,e->w,e->h,hwndDlg);
  1643. BITMAPINFO info={0};
  1644. info.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
  1645. info.bmiHeader.biWidth = e->w;
  1646. info.bmiHeader.biHeight = -e->h;
  1647. info.bmiHeader.biPlanes = 1;
  1648. info.bmiHeader.biBitCount = 32;
  1649. info.bmiHeader.biCompression = BI_RGB;
  1650. HDC dc = GetDC(hwndDlg);
  1651. if (e->bits)
  1652. {
  1653. WASABI_API_MEMMGR->sysFree(e->bits);
  1654. e->bits = 0;
  1655. }
  1656. if (e->data)
  1657. {
  1658. WASABI_API_MEMMGR->sysFree(e->data);
  1659. e->data = 0;
  1660. e->datalen = 0;
  1661. }
  1662. e->bits = (ARGB32*)WASABI_API_MEMMGR->sysMalloc(e->w*e->h*sizeof(ARGB32));
  1663. if (e->mimetype) free(e->mimetype);
  1664. e->mimetype = _wcsdup(L"image/jpeg");
  1665. GetDIBits(dc,bm,0,e->h,e->bits,&info,DIB_RGB_COLORS);
  1666. ReleaseDC(hwndDlg,dc);
  1667. e->dirty=true;
  1668. HBITMAP dispbm = getBitmap(e->bits,e->w,e->h,228,228,hwndDlg);
  1669. HBITMAP bmold = (HBITMAP)SendDlgItemMessage(hwndDlg,IDC_ARTHOLDER,STM_SETIMAGE,IMAGE_BITMAP,(LPARAM)dispbm);
  1670. if (bmold) DeleteObject(bmold);
  1671. CloseClipboard();
  1672. UpdateArtItemFrame(hwndDlg);
  1673. return 1;
  1674. }
  1675. CloseClipboard();
  1676. break;
  1677. }
  1678. case IDC_BUTTON_DELETE:
  1679. {
  1680. wchar_t buf[1024] = {0};
  1681. getStringW(IDS_ARTDELETE,buf,1024);
  1682. if (MessageBoxW(hwndDlg,buf,getStringW(IDS_AREYOUSURE,0,0),MB_YESNO|MB_ICONQUESTION) != IDYES) break;
  1683. info_params * p = (info_params *)GetWindowLongPtrW(GetParent(hwndDlg),GWLP_USERDATA);
  1684. EditArtItem *e = getCurrentArtItem(hwndDlg);
  1685. if (!e) break;
  1686. int sel = SendDlgItemMessage(hwndDlg,IDC_ARTLIST,LB_GETCURSEL,0,0);
  1687. buf[0]=0;
  1688. SendDlgItemMessageW(hwndDlg,IDC_ARTLIST,LB_GETTEXT,sel,(LPARAM)buf);
  1689. AGAVE_API_ALBUMART->DeleteAlbumArt(p->filename,(!_wcsicmp(buf,getStringW(IDS_COVER,NULL,0))?L"cover":buf));
  1690. HBITMAP bmold = (HBITMAP)SendDlgItemMessage(hwndDlg,IDC_ARTHOLDER,STM_SETIMAGE,IMAGE_BITMAP,(LPARAM)0);
  1691. if (bmold) DeleteObject(bmold);
  1692. delete e;
  1693. SendDlgItemMessage(hwndDlg,IDC_ARTLIST,LB_DELETESTRING,sel,0);
  1694. EnableArtFrame(hwndDlg,0);
  1695. break;
  1696. }
  1697. case IDOK:
  1698. {
  1699. info_params * p = (info_params *)GetWindowLongPtrW(GetParent(hwndDlg),GWLP_USERDATA);
  1700. int l = SendDlgItemMessage(hwndDlg,IDC_ARTLIST,LB_GETCOUNT,0,0);
  1701. for (int i=0; i<l; i++)
  1702. {
  1703. EditArtItem *e = (EditArtItem *)SendDlgItemMessage(hwndDlg,IDC_ARTLIST,LB_GETITEMDATA,i,0);
  1704. if (e && e->dirty)
  1705. {
  1706. wchar_t buf[1024] = {0};
  1707. SendDlgItemMessageW(hwndDlg,IDC_ARTLIST,LB_GETTEXT,i,(LPARAM)buf);
  1708. if (e->data)
  1709. {
  1710. AGAVE_API_ALBUMART->SetAlbumArt(p->filename,(!_wcsicmp(buf,getStringW(IDS_COVER,NULL,0))?L"cover":buf),
  1711. 0,0,e->data,e->datalen,e->mimetype);
  1712. }
  1713. else
  1714. {
  1715. AGAVE_API_ALBUMART->SetAlbumArt(p->filename,(!_wcsicmp(buf,getStringW(IDS_COVER,NULL,0))?L"cover":buf),
  1716. e->w,e->h,e->bits,0,0);
  1717. }
  1718. }
  1719. }
  1720. }
  1721. break;
  1722. }
  1723. break;
  1724. case WM_DESTROY:
  1725. {
  1726. HBITMAP bmold = (HBITMAP)SendDlgItemMessage(hwndDlg,IDC_ARTHOLDER,STM_GETIMAGE,IMAGE_BITMAP,0);
  1727. if (bmold) DeleteObject(bmold);
  1728. int l = SendDlgItemMessage(hwndDlg,IDC_ARTLIST,LB_GETCOUNT,0,0);
  1729. for (int i=0; i<l; i++)
  1730. {
  1731. EditArtItem *e = (EditArtItem *)SendDlgItemMessage(hwndDlg,IDC_ARTLIST,LB_GETITEMDATA,i,0);
  1732. if (e && e != (EditArtItem *)-1) delete e;
  1733. }
  1734. GetDlgItemTextW(hwndDlg, IDC_COMBO_ARTTYPE, config_artwork_filter, ARRAYSIZE(config_artwork_filter));
  1735. }
  1736. break;
  1737. }
  1738. return 0;
  1739. }
  1740. static int checkEditInfoClick(HWND hwndDlg, POINT p, int item, int check)
  1741. {
  1742. RECT r = {0};
  1743. GetWindowRect(GetDlgItem(hwndDlg, item), &r);
  1744. ScreenToClient(hwndDlg, (LPPOINT)&r);
  1745. ScreenToClient(hwndDlg, (LPPOINT)&r.right);
  1746. if (PtInRect(&r, p) && !IsDlgButtonChecked(hwndDlg, check))
  1747. {
  1748. CheckDlgButton(hwndDlg, check, TRUE);
  1749. if (item == IDC_COMBO_RATING) SendDlgItemMessage(hwndDlg, IDC_COMBO_RATING, CB_SHOWDROPDOWN, TRUE, 0);
  1750. EnableWindow(GetDlgItem(hwndDlg, item), TRUE);
  1751. EnableWindow(GetDlgItem(hwndDlg, IDOK), TRUE);
  1752. PostMessageW(hwndDlg, WM_NEXTDLGCTL, (WPARAM)GetDlgItem(hwndDlg, item), (LPARAM)TRUE);
  1753. return 1;
  1754. }
  1755. return 0;
  1756. }
  1757. // sets part and parts to -1 or 0 on fail/missing (e.g. parts will be -1 on "1", but 0 on "1/")
  1758. void ParseIntSlashInt(wchar_t *string, int *part, int *parts)
  1759. {
  1760. *part = -1;
  1761. *parts = -1;
  1762. if (string && string[0])
  1763. {
  1764. *part = _wtoi(string);
  1765. while (string && *string && *string != '/')
  1766. {
  1767. string++;
  1768. }
  1769. if (string && *string == '/')
  1770. {
  1771. string++;
  1772. *parts = _wtoi(string);
  1773. }
  1774. }
  1775. }
  1776. typedef struct
  1777. {
  1778. mlQueryStructW item;
  1779. int idx;
  1780. int ml;
  1781. } queryStructW;
  1782. std::vector<queryStructW*> queryList;
  1783. static int got_local_ml = -1;
  1784. static size_t m_upd_nb, m_stopped, m_upd_nb_all, m_upd_nb_cur;
  1785. #define MAKESAFE(x) ((x)?(x):L"")
  1786. static void FreeQueryList()
  1787. {
  1788. for ( queryStructW *query : queryList )
  1789. {
  1790. free( query->item.query );
  1791. if ( query->ml )
  1792. sendMlIpc( ML_IPC_DB_FREEQUERYRESULTSW, (WPARAM)query );
  1793. else
  1794. freeRecordList( &query->item.results );
  1795. free( query );
  1796. }
  1797. queryList.clear();
  1798. }
  1799. void CHECK_AND_COPY(itemRecordW *song, HWND hwndParent, int IDCHECK, int ID, wchar_t *&item)
  1800. {
  1801. if (IsDlgButtonChecked(hwndParent, IDCHECK)) {
  1802. wchar_t blah[2048];
  1803. GetDlgItemTextW(hwndParent, ID, blah, 2048);
  1804. if (wcscmp(MAKESAFE(item), blah))
  1805. {
  1806. free(item);
  1807. item = _wcsdup(blah);
  1808. }
  1809. }
  1810. }
  1811. static void CHECK_AND_COPY_EXTENDED(itemRecordW *song, HWND hwndParent, int IDCHECK, int ID, const wchar_t *name)
  1812. {
  1813. if (IsDlgButtonChecked(hwndParent, IDCHECK)) {
  1814. wchar_t blah[2048];
  1815. GetDlgItemTextW(hwndParent, ID, blah, 2048);
  1816. wchar_t *oldData = getRecordExtendedItem(song, name);
  1817. if (wcscmp(MAKESAFE(oldData), blah)) {
  1818. setRecordExtendedItem(song, name, blah);
  1819. }
  1820. }
  1821. }
  1822. static INT_PTR CALLBACK updateFiles_dialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
  1823. {
  1824. switch (uMsg)
  1825. {
  1826. case WM_INITDIALOG:
  1827. {
  1828. SetWindowTextW(hwndDlg, getStringW(IDS_UPDATING_FILES, NULL, 0));
  1829. SetWindowLong(GetDlgItem(hwndDlg, 1008), GWL_STYLE, (GetWindowLongW(GetDlgItem(hwndDlg, 1008), GWL_STYLE)&~SS_CENTER) | SS_LEFTNOWORDWRAP);
  1830. SetTimer(hwndDlg, 0x123, 30, NULL);
  1831. m_upd_nb = 0;
  1832. m_stopped = 0;
  1833. SendDlgItemMessage(hwndDlg, 1007, PBM_SETRANGE, 0, MAKELPARAM(0, m_upd_nb_all));
  1834. m_upd_nb_cur = 0;
  1835. break;
  1836. }
  1837. case WM_TIMER:
  1838. if (wParam == 0x123 && !m_stopped)
  1839. {
  1840. unsigned int start_t = GetTickCount();
  1841. again:
  1842. {
  1843. if (m_upd_nb >= queryList.size())
  1844. {
  1845. //done
  1846. if (got_local_ml == 1) sendMlIpc(ML_IPC_DB_SYNCDB, 0);
  1847. EndDialog(hwndDlg, 1);
  1848. break;
  1849. }
  1850. int i = (int) m_upd_nb++;
  1851. itemRecordW *mlsong = &queryList[i]->item.results.Items[0];
  1852. itemRecordW copy;
  1853. itemRecordW *song = &copy;
  1854. copyRecord(&copy, mlsong);
  1855. HWND hwndParent = GetParent(hwndDlg);
  1856. wchar_t stattmp[512] = {0};
  1857. wchar_t *p = scanstr_backW(song->filename, L"\\", song->filename - 1) + 1;
  1858. wsprintfW(stattmp, getStringW(IDS_UPDATING_X, NULL, 0), p);
  1859. SetDlgItemTextW(hwndDlg, 1008, stattmp);
  1860. SendDlgItemMessage(hwndDlg, 1007, PBM_SETPOS, m_upd_nb_cur, 0);
  1861. m_upd_nb_cur++;
  1862. int updtagz = !!IsDlgButtonChecked(hwndParent, 1052);
  1863. CHECK_AND_COPY(song, hwndParent, IDC_CHECK_ARTIST, IDC_EDIT_ARTIST, song->artist);
  1864. CHECK_AND_COPY(song, hwndParent, IDC_CHECK_TITLE, IDC_EDIT_TITLE, song->title);
  1865. CHECK_AND_COPY(song, hwndParent, IDC_CHECK_ALBUM, IDC_EDIT_ALBUM, song->album);
  1866. CHECK_AND_COPY(song, hwndParent, IDC_CHECK_COMMENT, IDC_EDIT_COMMENT, song->comment);
  1867. CHECK_AND_COPY(song, hwndParent, IDC_CHECK_GENRE, IDC_EDIT_GENRE, song->genre);
  1868. CHECK_AND_COPY(song, hwndParent, IDC_CHECK_ALBUMARTIST, IDC_EDIT_ALBUMARTIST, song->albumartist);
  1869. CHECK_AND_COPY(song, hwndParent, IDC_CHECK_PUBLISHER, IDC_EDIT_PUBLISHER, song->publisher);
  1870. CHECK_AND_COPY(song, hwndParent, IDC_CHECK_COMPOSER, IDC_EDIT_COMPOSER, song->composer);
  1871. CHECK_AND_COPY(song, hwndParent, IDC_CHECK_CATEGORY, IDC_EDIT_CATEGORY, song->category);
  1872. CHECK_AND_COPY_EXTENDED(song, hwndParent, IDC_CHECK_DIRECTOR, IDC_EDIT_DIRECTOR, L"director");
  1873. CHECK_AND_COPY_EXTENDED(song, hwndParent, IDC_CHECK_PRODUCER, IDC_EDIT_PRODUCER, L"producer");
  1874. CHECK_AND_COPY_EXTENDED(song, hwndParent, IDC_CHECK_PODCAST_CHANNEL, IDC_EDIT_PODCAST_CHANNEL, L"podcastchannel");
  1875. #define CHECK_AND_COPY_EXTENDED_PC(IDCHECK, field, name) \
  1876. wchar_t blah[2048] = {0}; StringCchPrintfW(blah, 2048, L"%d", (IsDlgButtonChecked(hwndParent, IDCHECK) == BST_CHECKED));\
  1877. wchar_t *oldData = getRecordExtendedItem(song, name);\
  1878. if (wcscmp(MAKESAFE(oldData), blah)) { setRecordExtendedItem(song, name, blah); }
  1879. CHECK_AND_COPY_EXTENDED_PC(IDC_CHECK_PODCAST, MAINTABLE_ID_ISPODCAST, L"ispodcast");
  1880. if (IsDlgButtonChecked(hwndParent, IDC_CHECK_TRACK))
  1881. {
  1882. wchar_t blah[64] = {0};
  1883. GetDlgItemTextW(hwndParent, IDC_EDIT_TRACK, blah, 64);
  1884. int track, tracks;
  1885. ParseIntSlashInt(blah, &track, &tracks);
  1886. if (tracks <= 0) tracks = -1;
  1887. if (track <= 0) track = -1;
  1888. if (song->track != track || song->tracks != tracks)
  1889. {
  1890. song->track = track;
  1891. song->tracks = tracks;
  1892. }
  1893. }
  1894. if (IsDlgButtonChecked(hwndParent, IDC_CHECK_DISC))
  1895. {
  1896. wchar_t blah[64] = {0};
  1897. GetDlgItemTextW(hwndParent, IDC_EDIT_DISC, blah, 64);
  1898. int disc, discs;
  1899. ParseIntSlashInt(blah, &disc, &discs);
  1900. if (discs <= 0) discs = -1;
  1901. if (disc <= 0) disc = -1;
  1902. if (song->disc != disc || song->discs != discs)
  1903. {
  1904. song->disc = disc;
  1905. song->discs = discs;
  1906. }
  1907. }
  1908. if (IsDlgButtonChecked(hwndParent, IDC_CHECK_YEAR))
  1909. {
  1910. char blah[64] = {0};
  1911. GetDlgItemTextA(hwndParent, IDC_EDIT_YEAR, blah, 64);
  1912. int n = atoi(blah);
  1913. if (n <= 0) n = -1;
  1914. if (song->year != n) song->year = n;
  1915. }
  1916. if (IsDlgButtonChecked(hwndParent, IDC_CHECK_BPM))
  1917. {
  1918. char blah[64] = {0};
  1919. GetDlgItemTextA(hwndParent, IDC_EDIT_BPM, blah, 64);
  1920. int n = atoi(blah);
  1921. if (n <= 0) n = -1;
  1922. if (song->bpm != n) song->bpm = n;
  1923. }
  1924. if (IsDlgButtonChecked(hwndParent, IDC_CHECK_RATING))
  1925. {
  1926. int n = SendDlgItemMessage(hwndParent, IDC_COMBO_RATING, CB_GETCURSEL, 0, 0), rating = -1;
  1927. if (n != CB_ERR && (n >= 0 && n < 5)) rating = 5 - n;
  1928. if (song->rating != rating) song->rating = rating;
  1929. }
  1930. // no need to send this if there's no ml present
  1931. if (got_local_ml == 1) sendMlIpc((!config_upd_mode ? ML_IPC_DB_ADDORUPDATEITEMW : ML_IPC_DB_UPDATEITEMW), (WPARAM)song);
  1932. if (updtagz || !got_local_ml)
  1933. {
  1934. m_stopped = 1;
  1935. retry:
  1936. if (in_set_extended_fileinfoW(song->filename, L"title", song->title)) // if this returns 0, then this format doesnt even support extended
  1937. {
  1938. in_set_extended_fileinfoW(song->filename, L"artist", song->artist);
  1939. in_set_extended_fileinfoW(song->filename, L"album", song->album);
  1940. in_set_extended_fileinfoW(song->filename, L"comment", song->comment);
  1941. in_set_extended_fileinfoW(song->filename, L"genre", song->genre);
  1942. wchar_t buf[32] = {0};
  1943. if (song->track > 0)
  1944. {
  1945. if (song->tracks > 0)
  1946. wsprintfW(buf, L"%d/%d", song->track, song->tracks);
  1947. else
  1948. wsprintfW(buf, L"%d", song->track);
  1949. }
  1950. else buf[0] = 0;
  1951. in_set_extended_fileinfoW(song->filename, L"track", buf);
  1952. if (song->year > 0) wsprintfW(buf, L"%d", song->year);
  1953. else buf[0] = 0;
  1954. in_set_extended_fileinfoW(song->filename, L"year", buf);
  1955. if (song->disc > 0)
  1956. {
  1957. if (song->discs > 0)
  1958. wsprintfW(buf, L"%d/%d", song->disc, song->discs);
  1959. else
  1960. wsprintfW(buf, L"%d", song->disc);
  1961. }
  1962. else buf[0] = 0;
  1963. in_set_extended_fileinfoW(song->filename, L"disc", buf);
  1964. if (song->rating > 0) wsprintfW(buf, L"%d", song->rating);
  1965. else buf[0] = 0;
  1966. if (!in_set_extended_fileinfoW(song->filename, L"rating", buf))
  1967. {
  1968. // for ratings, try using the library just to cover all bases for format types
  1969. file_set_ratingW rate = {0};
  1970. rate.fileName = song->filename;
  1971. rate.newRating = song->rating;
  1972. sendMlIpc(ML_IPC_SET_FILE_RATINGW, (WPARAM)&rate);
  1973. }
  1974. if (song->bpm > 0) wsprintfW(buf, L"%d", song->bpm);
  1975. else buf[0] = 0;
  1976. in_set_extended_fileinfoW(song->filename, L"bpm", buf);
  1977. in_set_extended_fileinfoW(song->filename, L"albumartist", song->albumartist);
  1978. in_set_extended_fileinfoW(song->filename, L"publisher", song->publisher);
  1979. in_set_extended_fileinfoW(song->filename, L"composer", song->composer);
  1980. in_set_extended_fileinfoW(song->filename, L"category", song->category);
  1981. in_set_extended_fileinfoW(song->filename, L"director", getRecordExtendedItem(song, L"director"));
  1982. in_set_extended_fileinfoW(song->filename, L"producer", getRecordExtendedItem(song, L"producer"));
  1983. if (in_write_extended_fileinfo() == 0)
  1984. {
  1985. wchar_t tmp[1024] = {0};
  1986. wsprintfW(tmp, getStringW(IDS_ERROR_UPDATING_FILE, NULL, 0), song->filename);
  1987. int ret = MessageBoxW(hwndDlg, tmp, getStringW(IDS_INFO_UPDATING_ERROR, NULL, 0), MB_RETRYCANCEL);
  1988. if (ret == IDRETRY) goto retry;
  1989. if (ret == IDCANCEL)
  1990. {
  1991. EndDialog(hwndDlg, 0);
  1992. freeRecord(&copy);
  1993. break;
  1994. }
  1995. }
  1996. }
  1997. int x = queryList[i]->idx;
  1998. SendMessageW(hMainWindow, WM_WA_IPC, (WPARAM)song->filename, IPC_FILE_TAG_MAY_HAVE_UPDATEDW);
  1999. PlayList_setitem(x, song->filename, PlayList_gettitle(song->filename, 1));
  2000. PlayList_setlastlen(x);
  2001. m_stopped = 0;
  2002. }
  2003. freeRecord(&copy);
  2004. }
  2005. if (GetTickCount() - start_t < 30) goto again;
  2006. }
  2007. break;
  2008. case WM_COMMAND:
  2009. if (LOWORD(wParam) == IDCANCEL)
  2010. {
  2011. EndDialog(hwndDlg, 0);
  2012. }
  2013. break;
  2014. }
  2015. return FALSE;
  2016. }
  2017. INT_PTR CALLBACK EditInfo(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
  2018. {
  2019. switch (uMsg)
  2020. {
  2021. case WM_INITDIALOG:
  2022. {
  2023. wchar_t *last_artist = NULL, *last_title = NULL, *last_album = NULL, *last_genre = NULL,
  2024. *last_comment = NULL, *last_albumartist = NULL, *last_composer = NULL,
  2025. *last_publisher = NULL, *last_ispodcast = NULL, *last_podcastchannel = NULL;
  2026. const wchar_t *last_category = NULL, *last_director = NULL, *last_producer = NULL;
  2027. int last_year = -1, last_track = -1, last_disc = -1, last_discs = -1, last_tracks = -1,
  2028. last_bpm = -1, last_rating = -1, disable_artist = 0, disable_title = 0,
  2029. disable_album = 0, disable_genre = 0, disable_year = 0, disable_track = 0,
  2030. disable_comment = 0, disable_disc = 0, disable_albumartist = 0, disable_composer = 0,
  2031. disable_publisher = 0, disable_discs = 0, disable_tracks = 0, disable_category = 0,
  2032. disable_director = 0, disable_producer = 0, disable_bpm = 0, disable_rating = 0,
  2033. disable_ispodcast = 0, disable_podcastchannel = 0, nb = 0;
  2034. if (got_local_ml == -1)
  2035. {
  2036. got_local_ml = (got_ml ? !!GetModuleHandleW(L"ml_local.dll") : 0);
  2037. }
  2038. if (got_local_ml == 1)
  2039. {
  2040. if (GetPrivateProfileIntW(L"gen_ml_config", L"upd_tagz", 1, ML_INI_FILE))
  2041. CheckDlgButton(hwndDlg, 1052, BST_CHECKED);
  2042. }
  2043. else
  2044. ShowWindow(GetDlgItem(hwndDlg, 1052), SW_HIDE);
  2045. EnableWindow(GetDlgItem(hwndDlg, IDOK), FALSE);
  2046. SendDlgItemMessageW(hwndDlg, IDC_COMBO_RATING, CB_ADDSTRING, 0, (LPARAM)L"\u2605\u2605\u2605\u2605\u2605");
  2047. SendDlgItemMessageW(hwndDlg, IDC_COMBO_RATING, CB_ADDSTRING, 0, (LPARAM)L"\u2605\u2605\u2605\u2605");
  2048. SendDlgItemMessageW(hwndDlg, IDC_COMBO_RATING, CB_ADDSTRING, 0, (LPARAM)L"\u2605\u2605\u2605");
  2049. SendDlgItemMessageW(hwndDlg, IDC_COMBO_RATING, CB_ADDSTRING, 0, (LPARAM)L"\u2605\u2605");
  2050. SendDlgItemMessageW(hwndDlg, IDC_COMBO_RATING, CB_ADDSTRING, 0, (LPARAM)L"\u2605");
  2051. SendDlgItemMessageW(hwndDlg, IDC_COMBO_RATING, CB_ADDSTRING, 0, (LPARAM)getStringW(IDS_NO_RATING, NULL, 0));
  2052. FreeQueryList();
  2053. LPWSTR pszBuffer = (LPWSTR)calloc(TEXTBUFFER_MAX, sizeof(WCHAR));
  2054. if (pszBuffer)
  2055. {
  2056. for (int i = 0; i < PlayList_getlength(); i++)
  2057. {
  2058. wchar_t fn[FILENAME_SIZE] = {0};
  2059. if (PlayList_getselect2(i, fn))
  2060. {
  2061. if (!PathIsURLW(fn) || !_wcsnicmp(fn, L"cda://", 6))
  2062. {
  2063. queryStructW *query = (queryStructW *)calloc(1, sizeof(queryStructW));
  2064. if (query)
  2065. {
  2066. queryList.push_back(query);
  2067. query->item.query = _wcsdup(fn);
  2068. // hit the library where possible as it'll be faster (and more integrated)
  2069. if (got_local_ml == 1)
  2070. {
  2071. if (sendMlIpc(ML_IPC_DB_RUNQUERY_FILENAMEW, (WPARAM)query) == 1)
  2072. {
  2073. #define SAVE_LAST_STR(last, check, disable) if (!disable && check && check[0]) { if (!last) last = check; else if (wcscmp(check, last)) disable = 1; }
  2074. #define SAVE_LAST_INT(last, check, disable) if (!disable && check > 0) { if (last == -1) last = check; else if (last != check) disable = 1; }
  2075. SAVE_LAST_STR(last_artist, query->item.results.Items[0].artist, disable_artist);
  2076. SAVE_LAST_STR(last_title, query->item.results.Items[0].title, disable_title);
  2077. SAVE_LAST_STR(last_album, query->item.results.Items[0].album, disable_album);
  2078. SAVE_LAST_STR(last_comment, query->item.results.Items[0].comment, disable_comment);
  2079. SAVE_LAST_STR(last_genre, query->item.results.Items[0].genre, disable_genre);
  2080. SAVE_LAST_INT(last_year, query->item.results.Items[0].year, disable_year);
  2081. SAVE_LAST_INT(last_track, query->item.results.Items[0].track, disable_track);
  2082. SAVE_LAST_INT(last_tracks, query->item.results.Items[0].tracks, disable_tracks);
  2083. SAVE_LAST_INT(last_disc, query->item.results.Items[0].disc, disable_disc);
  2084. SAVE_LAST_INT(last_discs, query->item.results.Items[0].discs, disable_discs);
  2085. SAVE_LAST_INT(last_rating, query->item.results.Items[0].rating, disable_rating);
  2086. SAVE_LAST_INT(last_bpm, query->item.results.Items[0].bpm, disable_bpm);
  2087. SAVE_LAST_STR(last_albumartist, query->item.results.Items[0].albumartist, disable_albumartist);
  2088. SAVE_LAST_STR(last_composer, query->item.results.Items[0].composer, disable_composer);
  2089. SAVE_LAST_STR(last_publisher, query->item.results.Items[0].publisher, disable_publisher);
  2090. SAVE_LAST_STR(last_category, query->item.results.Items[0].category, disable_category);
  2091. #define SAVE_LAST_STR_EXTENDED(last, name, disable) if (!disable) { wchar_t *check = getRecordExtendedItem(&query->item.results.Items[0], name); if (check && check[0]) { if (!last) last = check; else if (wcscmp(check, last)) disable = 1; }};
  2092. SAVE_LAST_STR_EXTENDED(last_director, L"director", disable_director);
  2093. SAVE_LAST_STR_EXTENDED(last_producer, L"producer", disable_producer);
  2094. SAVE_LAST_STR_EXTENDED(last_podcastchannel, L"podcastchannel", disable_podcastchannel);
  2095. SAVE_LAST_STR_EXTENDED(last_ispodcast, L"ispodcast", disable_ispodcast);
  2096. nb++;
  2097. query->ml = 1;
  2098. query->idx = i;
  2099. }
  2100. else
  2101. {
  2102. goto non_ml;
  2103. }
  2104. }
  2105. else
  2106. {
  2107. non_ml:
  2108. allocRecordList(&query->item.results, 1, 0);
  2109. query->item.results.Items[0].filename = _wcsdup(fn);
  2110. #define SAVE_LAST_STR(last, check, disable) if (!disable && check && check[0]) { if (!last) last = check; else if (wcscmp(check, last)) disable = 1; }
  2111. #define SAVE_LAST_INT(last, check, disable) if (!disable && check > 0) { if (last == -1) last = check; else if (last != check) disable = 1; }
  2112. if (in_get_extended_fileinfoW(fn, L"artist", pszBuffer, TEXTBUFFER_MAX))
  2113. query->item.results.Items[0].artist = _wcsdup(pszBuffer);
  2114. SAVE_LAST_STR(last_artist, query->item.results.Items[0].artist, disable_artist);
  2115. if (in_get_extended_fileinfoW(fn, L"title", pszBuffer, TEXTBUFFER_MAX))
  2116. query->item.results.Items[0].title = _wcsdup(pszBuffer);
  2117. SAVE_LAST_STR(last_title, query->item.results.Items[0].title, disable_title);
  2118. if (in_get_extended_fileinfoW(fn, L"album", pszBuffer, TEXTBUFFER_MAX))
  2119. query->item.results.Items[0].album = _wcsdup(pszBuffer);
  2120. SAVE_LAST_STR(last_album, query->item.results.Items[0].album, disable_album);
  2121. if (in_get_extended_fileinfoW(fn, L"comment", pszBuffer, TEXTBUFFER_MAX))
  2122. query->item.results.Items[0].comment = _wcsdup(pszBuffer);
  2123. SAVE_LAST_STR(last_comment, query->item.results.Items[0].comment, disable_comment);
  2124. if (in_get_extended_fileinfoW(fn, L"genre", pszBuffer, TEXTBUFFER_MAX))
  2125. query->item.results.Items[0].genre = _wcsdup(pszBuffer);
  2126. SAVE_LAST_STR(last_genre, query->item.results.Items[0].genre, disable_genre);
  2127. if (in_get_extended_fileinfoW(fn, L"year", pszBuffer, TEXTBUFFER_MAX))
  2128. query->item.results.Items[0].year = _wtoi(pszBuffer);
  2129. SAVE_LAST_INT(last_year, query->item.results.Items[0].year, disable_year);
  2130. if (in_get_extended_fileinfoW(fn, L"track", pszBuffer, TEXTBUFFER_MAX))
  2131. query->item.results.Items[0].track = _wtoi(pszBuffer);
  2132. SAVE_LAST_INT(last_track, query->item.results.Items[0].track, disable_track);
  2133. if (in_get_extended_fileinfoW(fn, L"tracks", pszBuffer, TEXTBUFFER_MAX))
  2134. query->item.results.Items[0].tracks = _wtoi(pszBuffer);
  2135. SAVE_LAST_INT(last_tracks, query->item.results.Items[0].tracks, disable_tracks);
  2136. if (in_get_extended_fileinfoW(fn, L"disc", pszBuffer, TEXTBUFFER_MAX))
  2137. query->item.results.Items[0].disc = _wtoi(pszBuffer);
  2138. SAVE_LAST_INT(last_disc, query->item.results.Items[0].disc, disable_disc);
  2139. if (in_get_extended_fileinfoW(fn, L"discs", pszBuffer, TEXTBUFFER_MAX))
  2140. query->item.results.Items[0].discs = _wtoi(pszBuffer);
  2141. SAVE_LAST_INT(last_discs, query->item.results.Items[0].discs, disable_discs);
  2142. // for ratings, try using the library just to cover all bases for format types
  2143. if (in_get_extended_fileinfoW(fn, L"rating", pszBuffer, TEXTBUFFER_MAX))
  2144. query->item.results.Items[0].rating = _wtoi(pszBuffer);
  2145. else
  2146. query->item.results.Items[0].rating = sendMlIpc(ML_IPC_GET_FILE_RATINGW, (WPARAM)fn);
  2147. SAVE_LAST_INT(last_rating, query->item.results.Items[0].rating, disable_rating);
  2148. if (in_get_extended_fileinfoW(fn, L"bpm", pszBuffer, TEXTBUFFER_MAX))
  2149. query->item.results.Items[0].bpm = _wtoi(pszBuffer);
  2150. SAVE_LAST_INT(last_bpm, query->item.results.Items[0].bpm, disable_bpm);
  2151. if (in_get_extended_fileinfoW(fn, L"albumartist", pszBuffer, TEXTBUFFER_MAX))
  2152. query->item.results.Items[0].albumartist = _wcsdup(pszBuffer);
  2153. SAVE_LAST_STR(last_albumartist, query->item.results.Items[0].albumartist, disable_albumartist);
  2154. if (in_get_extended_fileinfoW(fn, L"composer", pszBuffer, TEXTBUFFER_MAX))
  2155. query->item.results.Items[0].composer = _wcsdup(pszBuffer);
  2156. SAVE_LAST_STR(last_composer, query->item.results.Items[0].composer, disable_composer);
  2157. if (in_get_extended_fileinfoW(fn, L"publisher", pszBuffer, TEXTBUFFER_MAX))
  2158. query->item.results.Items[0].publisher = _wcsdup(pszBuffer);
  2159. SAVE_LAST_STR(last_publisher, query->item.results.Items[0].publisher, disable_publisher);
  2160. if (in_get_extended_fileinfoW(fn, L"category", pszBuffer, TEXTBUFFER_MAX))
  2161. query->item.results.Items[0].category = _wcsdup(pszBuffer);
  2162. SAVE_LAST_STR(last_category, query->item.results.Items[0].category, disable_category);
  2163. #define SAVE_LAST_STR_EXTENDED(last, name, disable) if (!disable) { wchar_t *check = getRecordExtendedItem(&query->item.results.Items[0], name); if (check && check[0]) { if (!last) last = check; else if (wcscmp(check, last)) disable = 1; }};
  2164. if (in_get_extended_fileinfoW(fn, L"director", pszBuffer, TEXTBUFFER_MAX))
  2165. {
  2166. setRecordExtendedItem(&query->item.results.Items[0], L"director", pszBuffer);
  2167. SAVE_LAST_STR_EXTENDED(last_director, L"director", disable_director);
  2168. }
  2169. if (in_get_extended_fileinfoW(fn, L"producer", pszBuffer, TEXTBUFFER_MAX))
  2170. {
  2171. setRecordExtendedItem(&query->item.results.Items[0], L"producer", pszBuffer);
  2172. SAVE_LAST_STR_EXTENDED(last_producer, L"producer", disable_producer);
  2173. }
  2174. // not available in non-ml setups
  2175. /*SAVE_LAST_STR_EXTENDED(last_podcastchannel, L"podcastchannel", disable_podcastchannel);
  2176. SAVE_LAST_STR_EXTENDED(last_ispodcast, L"ispodcast", disable_ispodcast);*/
  2177. nb++;
  2178. query->ml = 0;
  2179. query->idx = i;
  2180. }
  2181. }
  2182. }
  2183. }
  2184. }
  2185. free(pszBuffer);
  2186. }
  2187. if (!disable_artist && last_artist) SetDlgItemTextW(hwndDlg, IDC_EDIT_ARTIST, last_artist);
  2188. if (!disable_title && last_title) SetDlgItemTextW(hwndDlg, IDC_EDIT_TITLE, last_title);
  2189. if (!disable_album && last_album) SetDlgItemTextW(hwndDlg, IDC_EDIT_ALBUM, last_album);
  2190. if (!disable_comment && last_comment) SetDlgItemTextW(hwndDlg, IDC_EDIT_COMMENT, last_comment);
  2191. if (!disable_albumartist && last_albumartist) SetDlgItemTextW(hwndDlg, IDC_EDIT_ALBUMARTIST, last_albumartist);
  2192. if (!disable_composer && last_composer) SetDlgItemTextW(hwndDlg, IDC_EDIT_COMPOSER, last_composer);
  2193. if (!disable_publisher && last_publisher) SetDlgItemTextW(hwndDlg, IDC_EDIT_PUBLISHER, last_publisher);
  2194. if (!disable_genre && last_genre) SetDlgItemTextW(hwndDlg, IDC_EDIT_GENRE, last_genre);
  2195. if (!disable_category && last_category) SetDlgItemTextW(hwndDlg, IDC_EDIT_CATEGORY, last_category);
  2196. if (!disable_director && last_director) SetDlgItemTextW(hwndDlg, IDC_EDIT_DIRECTOR, last_director);
  2197. if (!disable_producer && last_producer) SetDlgItemTextW(hwndDlg, IDC_EDIT_PRODUCER, last_producer);
  2198. if (!disable_podcastchannel && last_podcastchannel) SetDlgItemTextW(hwndDlg, IDC_EDIT_PODCAST_CHANNEL, last_podcastchannel);
  2199. if (!disable_ispodcast && last_ispodcast)
  2200. {
  2201. CheckDlgButton(hwndDlg, IDC_CHECK_PODCAST, (_wtoi(last_ispodcast) == 1 ? BST_CHECKED : BST_UNCHECKED));
  2202. }
  2203. if (!disable_year && last_year > 0)
  2204. {
  2205. wchar_t tmp[64] = {0};
  2206. wsprintfW(tmp, L"%d", last_year);
  2207. SetDlgItemTextW(hwndDlg, IDC_EDIT_YEAR, tmp);
  2208. }
  2209. if (!disable_bpm && last_bpm > 0)
  2210. {
  2211. wchar_t tmp[64] = {0};
  2212. wsprintfW(tmp, L"%d", last_bpm);
  2213. SetDlgItemTextW(hwndDlg, IDC_EDIT_BPM, tmp);
  2214. }
  2215. if (!disable_rating)
  2216. {
  2217. if (last_rating > 0 && last_rating <= 5)
  2218. {
  2219. SendDlgItemMessage(hwndDlg, IDC_COMBO_RATING, CB_SETCURSEL, 5 - last_rating, 0);
  2220. }
  2221. else SendDlgItemMessage(hwndDlg, IDC_COMBO_RATING, CB_SETCURSEL, 5, 0);
  2222. }
  2223. if (!disable_track && last_track > 0 && !disable_tracks)
  2224. {
  2225. wchar_t tmp[64] = {0};
  2226. if (!disable_tracks && last_tracks > 0)
  2227. wsprintfW(tmp, L"%d/%d", last_track, last_tracks);
  2228. else
  2229. wsprintfW(tmp, L"%d", last_track);
  2230. SetDlgItemTextW(hwndDlg, IDC_EDIT_TRACK, tmp);
  2231. }
  2232. if (!disable_disc && last_disc > 0
  2233. && !disable_discs)
  2234. {
  2235. wchar_t tmp[64] = {0};
  2236. if (!disable_discs && last_discs > 0)
  2237. wsprintfW(tmp, L"%d/%d", last_disc, last_discs);
  2238. else
  2239. wsprintfW(tmp, L"%d", last_disc);
  2240. SetDlgItemTextW(hwndDlg, IDC_EDIT_DISC, tmp);
  2241. }
  2242. wchar_t tmp[512] = {0};
  2243. wsprintfW(tmp, getStringW((nb==1?IDS_X_ITEM_SELECTED:IDS_X_ITEMS_SELECTED), NULL, 0), nb);
  2244. SetDlgItemTextW(hwndDlg, 1051, tmp);
  2245. if (!nb)
  2246. {
  2247. EnableWindow(GetDlgItem(hwndDlg, IDOK), FALSE);
  2248. ShowWindow(GetDlgItem(hwndDlg, 1052), SW_HIDE);
  2249. }
  2250. // show edit info window and restore last position as applicable
  2251. POINT pt = {editinfo_rect.left, editinfo_rect.top};
  2252. if (!windowOffScreen(hwndDlg, pt) && !IsWindowVisible(hwndDlg))
  2253. SetWindowPos(hwndDlg, HWND_TOP, editinfo_rect.left, editinfo_rect.top, 0, 0, SWP_NOSIZE | SWP_NOSENDCHANGING);
  2254. }
  2255. return 1;
  2256. case WM_COMMAND:
  2257. #define HANDLE_CONTROL(item, check) { int enabled = IsDlgButtonChecked(hwndDlg, check); EnableWindow(GetDlgItem(hwndDlg, item), enabled); EnableWindow(GetDlgItem(hwndDlg, IDOK), enabled); }
  2258. switch (LOWORD(wParam))
  2259. {
  2260. case IDC_CHECK_ARTIST: HANDLE_CONTROL(IDC_EDIT_ARTIST, IDC_CHECK_ARTIST); break;
  2261. case IDC_CHECK_TITLE: HANDLE_CONTROL(IDC_EDIT_TITLE, IDC_CHECK_TITLE); break;
  2262. case IDC_CHECK_ALBUM: HANDLE_CONTROL(IDC_EDIT_ALBUM, IDC_CHECK_ALBUM); break;
  2263. case IDC_CHECK_COMMENT: HANDLE_CONTROL(IDC_EDIT_COMMENT, IDC_CHECK_COMMENT); break;
  2264. case IDC_CHECK_ALBUMARTIST: HANDLE_CONTROL(IDC_EDIT_ALBUMARTIST, IDC_CHECK_ALBUMARTIST); break;
  2265. case IDC_CHECK_COMPOSER: HANDLE_CONTROL(IDC_EDIT_COMPOSER, IDC_CHECK_COMPOSER); break;
  2266. case IDC_CHECK_PUBLISHER: HANDLE_CONTROL(IDC_EDIT_PUBLISHER, IDC_CHECK_PUBLISHER); break;
  2267. case IDC_CHECK_TRACK: HANDLE_CONTROL(IDC_EDIT_TRACK, IDC_CHECK_TRACK); break;
  2268. case IDC_CHECK_DISC: HANDLE_CONTROL(IDC_EDIT_DISC, IDC_CHECK_DISC); break;
  2269. case IDC_CHECK_GENRE: HANDLE_CONTROL(IDC_EDIT_GENRE, IDC_CHECK_GENRE); break;
  2270. case IDC_CHECK_YEAR: HANDLE_CONTROL(IDC_EDIT_YEAR, IDC_CHECK_YEAR); break;
  2271. case IDC_CHECK_CATEGORY: HANDLE_CONTROL(IDC_EDIT_CATEGORY, IDC_CHECK_CATEGORY); break;
  2272. case IDC_CHECK_DIRECTOR: HANDLE_CONTROL(IDC_EDIT_DIRECTOR, IDC_CHECK_DIRECTOR); break;
  2273. case IDC_CHECK_PRODUCER: HANDLE_CONTROL(IDC_EDIT_PRODUCER, IDC_CHECK_PRODUCER); break;
  2274. case IDC_CHECK_PODCAST_CHANNEL: HANDLE_CONTROL(IDC_EDIT_PODCAST_CHANNEL, IDC_CHECK_PODCAST_CHANNEL); break;
  2275. case IDC_CHECK_BPM: HANDLE_CONTROL(IDC_EDIT_BPM, IDC_CHECK_BPM); break;
  2276. case IDC_CHECK_RATING: HANDLE_CONTROL(IDC_COMBO_RATING, IDC_CHECK_RATING); break;
  2277. case IDOK:
  2278. {
  2279. if (got_local_ml == 1)
  2280. {
  2281. wchar_t str[4] = {0};
  2282. StringCchPrintfW(str, 4, L"%d", !!IsDlgButtonChecked(hwndDlg, 1052));
  2283. WritePrivateProfileStringW(L"gen_ml_config", L"upd_tagz", str, ML_INI_FILE);
  2284. }
  2285. int ret = LPDialogBoxW(IDD_ADDSTUFF, hwndDlg, updateFiles_dialogProc);
  2286. if (!ret) break;
  2287. }
  2288. case IDCANCEL:
  2289. {
  2290. FreeQueryList();
  2291. GetWindowRect(hwndDlg, &editinfo_rect);
  2292. EndDialog(hwndDlg, 0);
  2293. break;
  2294. }
  2295. }
  2296. break;
  2297. case WM_LBUTTONDOWN:
  2298. {
  2299. POINTS p = MAKEPOINTS(lParam);
  2300. POINT p2 = {p.x, p.y};
  2301. if (checkEditInfoClick(hwndDlg, p2, IDC_EDIT_ARTIST, IDC_CHECK_ARTIST)) break;
  2302. if (checkEditInfoClick(hwndDlg, p2, IDC_EDIT_TITLE, IDC_CHECK_TITLE)) break;
  2303. if (checkEditInfoClick(hwndDlg, p2, IDC_EDIT_ALBUM, IDC_CHECK_ALBUM)) break;
  2304. if (checkEditInfoClick(hwndDlg, p2, IDC_EDIT_COMMENT, IDC_CHECK_COMMENT)) break;
  2305. if (checkEditInfoClick(hwndDlg, p2, IDC_EDIT_ALBUMARTIST, IDC_CHECK_ALBUMARTIST)) break;
  2306. if (checkEditInfoClick(hwndDlg, p2, IDC_EDIT_COMPOSER, IDC_CHECK_COMPOSER)) break;
  2307. if (checkEditInfoClick(hwndDlg, p2, IDC_EDIT_PUBLISHER, IDC_CHECK_PUBLISHER)) break;
  2308. if (checkEditInfoClick(hwndDlg, p2, IDC_EDIT_TRACK, IDC_CHECK_TRACK)) break;
  2309. if (checkEditInfoClick(hwndDlg, p2, IDC_EDIT_GENRE, IDC_CHECK_GENRE)) break;
  2310. if (checkEditInfoClick(hwndDlg, p2, IDC_EDIT_YEAR, IDC_CHECK_YEAR)) break;
  2311. if (checkEditInfoClick(hwndDlg, p2, IDC_EDIT_DISC, IDC_CHECK_DISC)) break;
  2312. if (checkEditInfoClick(hwndDlg, p2, IDC_EDIT_CATEGORY, IDC_CHECK_CATEGORY)) break;
  2313. if (checkEditInfoClick(hwndDlg, p2, IDC_EDIT_DIRECTOR, IDC_CHECK_DIRECTOR)) break;
  2314. if (checkEditInfoClick(hwndDlg, p2, IDC_EDIT_PRODUCER, IDC_CHECK_PRODUCER)) break;
  2315. if (checkEditInfoClick(hwndDlg, p2, IDC_EDIT_PODCAST_CHANNEL, IDC_CHECK_PODCAST_CHANNEL)) break;
  2316. if (checkEditInfoClick(hwndDlg, p2, IDC_EDIT_BPM, IDC_CHECK_BPM)) break;
  2317. if (checkEditInfoClick(hwndDlg, p2, IDC_COMBO_RATING, IDC_CHECK_RATING)) break;
  2318. }
  2319. break;
  2320. }
  2321. return FALSE;
  2322. }