LEFT | RIGHT |
(no file at all) | |
1 #include "PluginStdAfx.h" | |
2 | |
3 #include "PluginConfig.h" | |
4 #include "PluginClient.h" | |
5 #include "PluginSettings.h" | |
6 #include "PluginMutex.h" | |
7 | |
8 | |
9 class CPluginConfigLock : public CPluginMutex | |
10 { | |
11 public: | |
12 CPluginConfigLock() : CPluginMutex("ConfigFile", PLUGIN_ERROR_MUTEX_CONFIG_F
ILE) {} | |
13 ~CPluginConfigLock() {} | |
14 }; | |
15 | |
16 | |
17 CPluginConfig* CPluginConfig::s_instance = NULL; | |
18 | |
19 CComAutoCriticalSection CPluginConfig::s_criticalSection; | |
20 | |
21 | |
22 CPluginConfig::CPluginConfig(bool forceCreate) | |
23 { | |
24 DEBUG_GENERAL("*** Initializing config") | |
25 | |
26 bool isExisting = true; | |
27 { | |
28 CPluginConfigLock lock; | |
29 if (lock.IsLocked()) | |
30 { | |
31 std::ifstream is; | |
32 is.open(CPluginSettings::GetDataPath(CONFIG_INI_FILE), std::ios_
base::in); | |
33 if (!is.is_open()) | |
34 { | |
35 isExisting = false; | |
36 } | |
37 else | |
38 { | |
39 is.close(); | |
40 } | |
41 } | |
42 } | |
43 | |
44 if (!isExisting) | |
45 { | |
46 Create(forceCreate); | |
47 } | |
48 Read(); | |
49 } | |
50 | |
51 | |
52 CPluginConfig::~CPluginConfig() | |
53 { | |
54 s_criticalSection.Lock(); | |
55 { | |
56 s_instance = NULL; | |
57 } | |
58 s_criticalSection.Unlock(); | |
59 } | |
60 | |
61 | |
62 CPluginConfig* CPluginConfig::GetInstance(bool forceCreate) | |
63 { | |
64 CPluginConfig* instance = NULL; | |
65 | |
66 s_criticalSection.Lock(); | |
67 { | |
68 if (!s_instance) | |
69 { | |
70 s_instance = new CPluginConfig(forceCreate); | |
71 } | |
72 | |
73 instance = s_instance; | |
74 } | |
75 s_criticalSection.Unlock(); | |
76 | |
77 return instance; | |
78 } | |
79 | |
80 | |
81 void CPluginConfig::Read() | |
82 { | |
83 DEBUG_GENERAL("*** Loading config:" + CPluginSettings::GetDataPath(CONFI
G_INI_FILE)) | |
84 | |
85 CPluginConfigLock lock; | |
86 if (lock.IsLocked()) | |
87 { | |
88 CPluginIniFileW iniFile(CPluginSettings::GetDataPath(CONFIG_INI_FILE), f
alse); | |
89 | |
90 if (!iniFile.Read()) | |
91 { | |
92 DEBUG_ERROR_LOG(iniFile.GetLastError(), PLUGIN_ERROR_CONFIG, PLUGIN_
ERROR_CONFIG_READ_FILE, "Dictionary::SetLanguage - Read") | |
93 return; | |
94 } | |
95 | |
96 s_criticalSection.Lock(); | |
97 { | |
98 m_downloadFileProperties.clear(); | |
99 m_downloadFileCategories.clear(); | |
100 m_downloadDomainTitles.clear(); | |
101 | |
102 const CPluginIniFileW::TSectionNames& names = iniFile.Ge
tSectionNames(); | |
103 | |
104 for (CPluginIniFileW::TSectionNames::const_iterator it =
names.begin(); it != names.end(); ++it) | |
105 { | |
106 if (it->Left(8) == L"category") | |
107 { | |
108 CPluginIniFileW::TSectionData data = ini
File.GetSectionData(*it); | |
109 | |
110 SDownloadFileCategory category; | |
111 | |
112 category.description = data["description
"]; | |
113 category.extension = data["extension"]; | |
114 category.ffmpegArgs = data["ffmpeg"]; | |
115 category.type = data["type"]; | |
116 category.category = *it; | |
117 | |
118 m_downloadFileCategories[category.catego
ry] = category; | |
119 } | |
120 else if (it->Left(6) == L"format") | |
121 { | |
122 CPluginIniFileW::TSectionData data = ini
File.GetSectionData(*it); | |
123 | |
124 CString contents = data["type"]; | |
125 | |
126 int pos = 0; | |
127 | |
128 CString content = contents.Tokenize(L";"
, pos); | |
129 while (pos >= 0) | |
130 { | |
131 SDownloadFileProperties properti
es; | |
132 | |
133 properties.category = data["cate
gory"]; | |
134 properties.conversions = data["c
onversions"]; | |
135 properties.content = content; | |
136 | |
137 TDownloadFileCategories::const_i
terator it = m_downloadFileCategories.find(properties.category); | |
138 if (it != m_downloadFileCategori
es.end()) | |
139 { | |
140 properties.properties =
it->second; | |
141 } | |
142 | |
143 m_downloadFileProperties[content
] = properties; | |
144 | |
145 content = contents.Tokenize(L";"
, pos); | |
146 } | |
147 } | |
148 else if (*it == L"titles") | |
149 { | |
150 CPluginIniFileW::TSectionData data = ini
File.GetSectionData(*it); | |
151 | |
152 for (CPluginIniFileW::TSectionData::iter
ator it = data.begin(); it != data.end(); ++it) | |
153 { | |
154 SDownloadDomainTitle title; | |
155 | |
156 int iPos = 0; | |
157 CString token = it->second.Token
ize(L";", iPos); | |
158 while (iPos >= 0) | |
159 { | |
160 int iTagPos = 0; | |
161 CString tag = token.Toke
nize(L"=", iTagPos); | |
162 if (iTagPos >= 0) | |
163 { | |
164 CString value =
token.Mid(iTagPos); | |
165 | |
166 if (tag == "tag"
) | |
167 { | |
168 title.ta
g = value; | |
169 } | |
170 else if (tag ==
"attr") | |
171 { | |
172 title.bs
trAttr = value; | |
173 } | |
174 else if (tag ==
"search") | |
175 { | |
176 title.se
arch = value; | |
177 } | |
178 else if (tag ==
"format") | |
179 { | |
180 int iTit
lePos = value.Find(L"[TITLE]"); | |
181 if (iTit
lePos > 0) | |
182 { | |
183
title.formatPre = value.Left(iTitlePos); | |
184 } | |
185 if (iTit
lePos >= 0) | |
186 { | |
187
title.formatPost = value.Mid(iTitlePos + 7); | |
188 } | |
189 } | |
190 else if (tag ==
"token") | |
191 { | |
192 title.to
ken = value; | |
193 title.to
ken.Replace(L"\\t", L"\t"); | |
194 title.to
ken.Replace(L"\\n", L"\n"); | |
195 title.to
ken.Replace(L"\\r", L"\r"); | |
196 } | |
197 else if (tag.Lef
t(5) == "attr.") | |
198 { | |
199 SDownloa
dDomainTitleAttribute titleAttr; | |
200 | |
201 titleAtt
r.attribute = tag.Mid(5); | |
202 titleAtt
r.bstrAttribute = tag.Mid(5); | |
203 titleAtt
r.value = value; | |
204 | |
205 title.at
tributes.push_back(titleAttr); | |
206 } | |
207 } | |
208 | |
209 token = it->second.Token
ize(L";", iPos); | |
210 } | |
211 | |
212 m_downloadDomainTitles[it->first
] = title; | |
213 } | |
214 } | |
215 } | |
216 } | |
217 s_criticalSection.Unlock(); | |
218 } | |
219 } | |
220 | |
221 | |
222 void CPluginConfig::Create(bool forceCreate) | |
223 { | |
224 DEBUG_GENERAL("*** Creating config:" + CPluginSettings::GetDataPath(CONF
IG_INI_FILE)); | |
225 | |
226 CPluginConfigLock lock; | |
227 if (lock.IsLocked()) | |
228 { | |
229 CPluginIniFileW iniFile(CPluginSettings::GetDataPath(CONFIG_INI_FILE), f
alse); | |
230 | |
231 CPluginSettings* settings = CPluginSettings::GetInstance(); | |
232 | |
233 if (forceCreate) | |
234 { | |
235 } | |
236 else if (iniFile.Exists() || !settings->IsMainProcess()) | |
237 { | |
238 return; | |
239 } | |
240 | |
241 s_criticalSection.Lock(); | |
242 { | |
243 // Formats | |
244 // -----------------------------------------------------
----------- | |
245 // .asf | |
246 { | |
247 CPluginIniFileW::TSectionData format; | |
248 | |
249 format["type"] = "video/x-ms-asf"; | |
250 format["category"] = "categoryAsf"; | |
251 format["conversions"] = "Video;Audio"; | |
252 | |
253 iniFile.UpdateSection("formatAsf", format); | |
254 } | |
255 // .avi | |
256 { | |
257 CPluginIniFileW::TSectionData format; | |
258 | |
259 format["type"] = "video/avi;video/msvideo;video/
x-msvideo"; | |
260 format["category"] = "categoryAvi"; | |
261 format["conversions"] = "Video;Audio"; | |
262 | |
263 iniFile.UpdateSection("formatAvi", format); | |
264 } | |
265 // .flv | |
266 { | |
267 CPluginIniFileW::TSectionData format; | |
268 | |
269 format["type"] = "video/flv;flv-application/octe
t-stream;video/x-flv"; | |
270 format["category"] = "categoryFlv"; | |
271 format["conversions"] = "Video;Audio"; | |
272 | |
273 iniFile.UpdateSection("formatFlv", format); | |
274 } | |
275 // .mov | |
276 { | |
277 CPluginIniFileW::TSectionData format; | |
278 | |
279 format["type"] = "video/quicktime"; | |
280 format["category"] = "categoryMov"; | |
281 format["conversions"] = "Video;Audio"; | |
282 | |
283 iniFile.UpdateSection("formatMov", format); | |
284 } | |
285 // .mp3 | |
286 { | |
287 CPluginIniFileW::TSectionData format; | |
288 | |
289 format["type"] = "audio/mpeg"; | |
290 format["category"] = "categoryMp3"; | |
291 format["conversions"] = "Audio"; | |
292 | |
293 iniFile.UpdateSection("formatMp3", format); | |
294 } | |
295 // .mp4 audio | |
296 { | |
297 CPluginIniFileW::TSectionData format; | |
298 | |
299 format["type"] = "audio/mp4"; | |
300 format["category"] = "categoryMp4Audio"; | |
301 format["conversions"] = "Audio"; | |
302 | |
303 iniFile.UpdateSection("formatMp4Audio", format); | |
304 } | |
305 // .mp4 video | |
306 { | |
307 CPluginIniFileW::TSectionData format; | |
308 | |
309 format["type"] = "video/mp4"; | |
310 format["category"] = "categoryMp4Video"; | |
311 format["conversions"] = "Video;Audio"; | |
312 | |
313 iniFile.UpdateSection("formatMp4Video", format); | |
314 } | |
315 // .wav | |
316 { | |
317 CPluginIniFileW::TSectionData format; | |
318 | |
319 format["type"] = "audio/x-wav;audio/wav;audio/wa
ve"; | |
320 format["category"] = "categoryWav"; | |
321 format["conversions"] = "Audio"; | |
322 | |
323 iniFile.UpdateSection("formatWav", format); | |
324 } | |
325 // .wmv | |
326 { | |
327 CPluginIniFileW::TSectionData format; | |
328 | |
329 format["type"] = "video/x-ms-wmv"; | |
330 format["category"] = "categoryWmv"; | |
331 format["conversions"] = ""; | |
332 | |
333 iniFile.UpdateSection("formatWmv", format); | |
334 } | |
335 | |
336 // Categories | |
337 // -----------------------------------------------------
----------- | |
338 // asf | |
339 { | |
340 CPluginIniFileW::TSectionData category; | |
341 | |
342 category["type"] = "Video"; | |
343 category["extension"] = "asf"; | |
344 category["description"] = "Advanced Systems Form
at"; | |
345 category["ffmpeg"] = ""; | |
346 | |
347 iniFile.UpdateSection("categoryAsf", category); | |
348 } | |
349 // avi | |
350 { | |
351 CPluginIniFileW::TSectionData category; | |
352 | |
353 category["type"] = "Video"; | |
354 category["extension"] = "avi"; | |
355 category["description"] = "Audio Video Interleav
e"; | |
356 category["ffmpeg"] = ""; | |
357 | |
358 iniFile.UpdateSection("categoryAvi", category); | |
359 } | |
360 // flv | |
361 { | |
362 CPluginIniFileW::TSectionData category; | |
363 | |
364 category["type"] = "Video"; | |
365 category["extension"] = "flv"; | |
366 category["description"] = "Flash Video"; | |
367 category["ffmpeg"] = ""; | |
368 | |
369 iniFile.UpdateSection("categoryFlv", category); | |
370 } | |
371 // mp3 | |
372 { | |
373 CPluginIniFileW::TSectionData category; | |
374 | |
375 category["type"] = "Audio"; | |
376 category["extension"] = "mp3"; | |
377 category["description"] = "MP3"; | |
378 category["ffmpeg"] = "-acodec libmp3lame -ab 160
kb -ac 2 -ar 44100"; | |
379 | |
380 iniFile.UpdateSection("categoryMp3", category); | |
381 } | |
382 // mov | |
383 { | |
384 CPluginIniFileW::TSectionData category; | |
385 | |
386 category["type"] = "Video"; | |
387 category["extension"] = "mov"; | |
388 category["description"] = "QuickTime"; | |
389 category["ffmpeg"] = ""; | |
390 | |
391 iniFile.UpdateSection("categoryMov", category); | |
392 } | |
393 // mp4 Audio | |
394 { | |
395 CPluginIniFileW::TSectionData category; | |
396 | |
397 category["type"] = "Audio"; | |
398 category["extension"] = "mp4"; | |
399 category["description"] = "MPEG-4 Audio"; | |
400 category["ffmpeg"] = "exclude"; | |
401 | |
402 iniFile.UpdateSection("categoryMp4Audio", catego
ry); | |
403 } | |
404 // mp4 Video | |
405 { | |
406 CPluginIniFileW::TSectionData category; | |
407 | |
408 category["type"] = "Video"; | |
409 category["extension"] = "mp4"; | |
410 category["description"] = "MPEG-4 Video"; | |
411 category["ffmpeg"] = ""; | |
412 | |
413 iniFile.UpdateSection("categoryMp4Video", catego
ry); | |
414 } | |
415 // wav | |
416 { | |
417 CPluginIniFileW::TSectionData category; | |
418 | |
419 category["type"] = "Audio"; | |
420 category["extension"] = "wav"; | |
421 category["description"] = "Waveform Audio"; | |
422 category["ffmpeg"] = ""; | |
423 | |
424 iniFile.UpdateSection("categoryWav", category); | |
425 } | |
426 // wmv | |
427 { | |
428 CPluginIniFileW::TSectionData category; | |
429 | |
430 category["type"] = "Video"; | |
431 category["extension"] = "wmv"; | |
432 category["description"] = "Windows Media Video"; | |
433 category["ffmpeg"] = "exclude"; | |
434 | |
435 iniFile.UpdateSection("categoryWmv", category); | |
436 } | |
437 | |
438 // Titles | |
439 // -----------------------------------------------------
----------- | |
440 { | |
441 CPluginIniFileW::TSectionData titles; | |
442 | |
443 titles["break.com"] = "tag=title;format=[TITLE]V
ideo"; | |
444 titles["dailymotion.com"] = "tag=h1"; | |
445 titles["guitarworld.com"] = "tag=h1"; | |
446 titles["metacafe.com"] = "tag=h1"; | |
447 titles["mtv.com"] = "tag=title;format=[TITLE]MTV
"; | |
448 titles["pp2g.tv"] = "tag=title;format=PP2G.TV[TI
TLE]"; | |
449 titles["top-channel.tv"] = "tag=span;attr.class=
titullmadh"; | |
450 titles["youporn.com"] = "tag=h1;attr.id="; | |
451 titles["youtube.com"] = "tag=title;format=YouTub
e[TITLE]"; | |
452 titles["video.google.com"] = "tag=title"; | |
453 titles["video.nationalgeographic.com"] = "tag=ti
tle;format=[TITLE]National Geographic"; | |
454 titles["vids.myspace.com"] = "tag=title"; | |
455 titles["wimp.com"] = "tag=title"; | |
456 | |
457 iniFile.UpdateSection("titles", titles); | |
458 } | |
459 } | |
460 s_criticalSection.Unlock(); | |
461 | |
462 if (iniFile.Write()) | |
463 { | |
464 CPluginSettings* settings = CPluginSettings::GetInstance(); | |
465 | |
466 settings->SetValue(SETTING_CONFIG_VERSION, 5); | |
467 settings->Write(); | |
468 } | |
469 else | |
470 { | |
471 DEBUG_ERROR_LOG(iniFile.GetLastError(), PLUGIN_ERROR_CONFIG, PLUGIN_
ERROR_CONFIG_CREATE_FILE, "Config::Create - Write") | |
472 } | |
473 } | |
474 } | |
475 | |
476 bool CPluginConfig::Download(const CString& url, const CString& filename) | |
477 { | |
478 CString tempFile = CPluginSettings::GetTempFile(TEMP_FILE_PREFIX); | |
479 | |
480 DEBUG_GENERAL("*** Downloading config:" + filename + " (to " + tempFile + "
)"); | |
481 | |
482 bool bResult = !tempFile.IsEmpty(); | |
483 if (bResult) | |
484 { | |
485 // if new filter urls are found download them and update the persist
ent data | |
486 HRESULT hr = ::URLDownloadToFile(NULL, url, tempFile, 0, NULL); | |
487 if (SUCCEEDED(hr)) | |
488 { | |
489 CPluginConfigLock lock; | |
490 if (lock.IsLocked()) | |
491 { | |
492 // Move the temporary file to the new text file. | |
493 if (!::MoveFileEx(tempFile, CPluginSettings::GetDataPath(CONFIG_
INI_FILE), MOVEFILE_REPLACE_EXISTING)) | |
494 { | |
495 DWORD dwError = ::GetLastError(); | |
496 | |
497 // Not same device? copy/delete instead | |
498 if (dwError == ERROR_NOT_SAME_DEVICE) | |
499 { | |
500 if (!::CopyFile(tempFile, CPluginSettings::GetDataPath(C
ONFIG_INI_FILE), FALSE)) | |
501 { | |
502 DEBUG_ERROR_LOG(::GetLastError(), PLUGIN_ERROR_CONFI
G, PLUGIN_ERROR_CONFIG_COPY_FILE, "Config::Download - CopyFile(" + filename + ")
") | |
503 | |
504 bResult = false; | |
505 } | |
506 | |
507 ::DeleteFile(tempFile); | |
508 } | |
509 else | |
510 { | |
511 DEBUG_ERROR_LOG(dwError, PLUGIN_ERROR_CONFIG, PLUGIN_ERR
OR_CONFIG_MOVE_FILE, "Config::Download - MoveFileEx(" + filename + ")") | |
512 | |
513 bResult = false; | |
514 } | |
515 } | |
516 } | |
517 else | |
518 { | |
519 bResult = false; | |
520 } | |
521 } | |
522 else | |
523 { | |
524 DEBUG_ERROR_LOG(hr, PLUGIN_ERROR_CONFIG, PLUGIN_ERROR_CONFIG_DOWNLOA
D_FILE, "Config::Download - URLDownloadToFile(" + CString(CONFIG_INI_FILE) + ")"
); | |
525 | |
526 bResult = false; | |
527 } | |
528 } | |
529 | |
530 return bResult; | |
531 } | |
532 | |
533 | |
534 bool CPluginConfig::GetDownloadProperties(const CString& contentType, SDownloadF
ileProperties& properties) const | |
535 { | |
536 bool isValid = false; | |
537 | |
538 s_criticalSection.Lock(); | |
539 { | |
540 TDownloadFileProperties::const_iterator it = m_downloadFileProperties.fi
nd(contentType); | |
541 if (it != m_downloadFileProperties.end()) | |
542 { | |
543 properties = it->second; | |
544 isValid = true; | |
545 } | |
546 } | |
547 s_criticalSection.Unlock(); | |
548 | |
549 return isValid; | |
550 } | |
551 | |
552 | |
553 int CPluginConfig::GenerateFilterString(TCHAR* pBuffer, SDownloadFileProperties&
properties, std::vector<std::pair<CString,CString>>& filterData, bool allowConv
ersion) const | |
554 { | |
555 int filterIndex = 1; | |
556 int bufferIndex = 0; | |
557 | |
558 std::map<CString,SDownloadFileCategory> filters; | |
559 | |
560 s_criticalSection.Lock(); | |
561 { | |
562 int pos = 0; | |
563 CString categories = properties.conversions + ";" + properties.p
roperties.extension; | |
564 CString category = categories.Tokenize(_T(";"), pos); | |
565 while (pos >= 0) | |
566 { | |
567 for (TDownloadFileCategories::const_iterator it = m_down
loadFileCategories.begin(); it != m_downloadFileCategories.end(); ++it) | |
568 { | |
569 if (it->second.type == category) | |
570 { | |
571 filters[category + " - " + it->second.de
scription] = it->second; | |
572 } | |
573 } | |
574 | |
575 category = categories.Tokenize(_T(";"), pos); | |
576 } | |
577 | |
578 int index = 1; | |
579 | |
580 for (std::map<CString,SDownloadFileCategory>::iterator it = filt
ers.begin(); it != filters.end(); ++it) | |
581 { | |
582 if (allowConversion && it->second.ffmpegArgs != "exclude
" || it->second.category == properties.category) | |
583 { | |
584 CString extension = it->second.extension; | |
585 CString description = it->first; | |
586 | |
587 wsprintf(pBuffer + bufferIndex, L"%s (*.%s)\0",
description.GetBuffer(), extension.GetBuffer()); | |
588 bufferIndex += description.GetLength() + extensi
on.GetLength() + 6; | |
589 wsprintf(pBuffer + bufferIndex, L".%s\0", extens
ion.GetBuffer()); | |
590 bufferIndex += extension.GetLength() + 2; | |
591 | |
592 if (it->second.category == properties.category) | |
593 { | |
594 filterIndex = index; | |
595 filterData.push_back(std::make_pair(exte
nsion, "")); | |
596 } | |
597 else | |
598 { | |
599 filterData.push_back(std::make_pair(exte
nsion, it->second.ffmpegArgs)); | |
600 } | |
601 | |
602 index++; | |
603 } | |
604 } | |
605 } | |
606 s_criticalSection.Unlock(); | |
607 | |
608 pBuffer[bufferIndex] = _T('\0'); | |
609 | |
610 return filterIndex; | |
611 } | |
612 | |
613 void CPluginConfig::GetDownloadDomainTitles(TDownloadDomainTitles& domainTitles)
const | |
614 { | |
615 domainTitles.clear(); | |
616 | |
617 s_criticalSection.Lock(); | |
618 { | |
619 domainTitles = m_downloadDomainTitles; | |
620 } | |
621 s_criticalSection.Unlock(); | |
622 } | |
623 | |
624 std::vector<CString> CPluginConfig::GetConversionExtenssions() | |
625 { | |
626 std::vector<CString> returnVector; | |
627 for (TDownloadFileCategories::const_iterator it = m_downloadFileCategori
es.begin(); it != m_downloadFileCategories.end(); ++it) | |
628 { | |
629 bool isUnique = true; | |
630 for (std::vector<CString>::const_iterator ext = returnVector.beg
in(); ext != returnVector.end(); ++ext) | |
631 { | |
632 CString extenssion(ext->GetString()); | |
633 if (extenssion == it->second.extension) | |
634 { | |
635 isUnique = false; | |
636 } | |
637 } | |
638 if (isUnique) | |
639 { | |
640 returnVector.push_back(it->second.extension); | |
641 } | |
642 } | |
643 return returnVector; | |
644 } | |
LEFT | RIGHT |