· 8 years ago · Jul 05, 2018, 02:04 AM
1function DanbooruDownloaderTab(TabDocument)
2{
3 this.tabDocument = TabDocument;
4 this.picSaved = false;
5 this.tabDocument.picSaved = false;
6 this.logData = DanbooruDownloaderPreferences.getBoolPref("useLog");
7}
8DanbooruDownloaderTab.prototype =
9{
10 log:function(text)
11 { if(this.logData) this.getLogger().log(text); }
12
13 ,getLogger:function()
14 {
15 if(typeof this.logger == "undefined")
16 { this.logger = new Logger(DanbooruDownloaderPreferences.getCharPref("targetFolder")+DanbooruDownloaderPreferences.getCharPref("logfile")); }
17 return this.logger;
18 }
19
20 ,getHashcode:function()
21 {
22 if(typeof this.hashcode == "undefined")
23 {
24 var content = this.getPicContent();
25 var converter = Components.classes["@mozilla.org/intl/scriptableunicodeconverter"].createInstance(Components.interfaces.nsIScriptableUnicodeConverter);
26 converter.charset = "UTF-8";
27 var result = {};
28 var data = converter.convertToByteArray(content, result);
29 var ch = Components.classes["@mozilla.org/security/hash;1"].createInstance(Components.interfaces.nsICryptoHash);
30 ch.init(ch.MD5);
31 ch.update(data, data.length);
32 var hash = ch.finish(false);
33 var hashcode = [this.toHexString(hash.charCodeAt(i)) for (i in hash)].join("");
34 this.hashcode = hashcode.substr(0,32); //Por algun motivo saca 64 caracteres, los ultimos 32 siendo los primeros 2 repetidos 16 veces
35 }
36 return this.hashcode;
37 }
38
39 ,toHexString:function(charCode)
40 {
41 return ("0" + charCode.toString(16)).slice(-2);
42 }
43
44 ,getPicFilename:function()
45 {
46 if(typeof this.picFilename == "undefined")
47 {
48 var last_slash_index = this.getPicUrl().lastIndexOf("/");
49 var last_dot_index = this.getPicUrl().lastIndexOf(".");
50 var filename = this.getPicUrl().substring(last_slash_index+1,last_dot_index);
51 this.picFilename = filename;
52 }
53 return this.picFilename;
54 }
55
56 ,getPicExtension:function()
57 {
58 if(typeof this.picExtension == "undefined")
59 {
60 var last_dot_index = this.getPicUrl().lastIndexOf(".");
61 var fileExt = this.getPicUrl().substring(last_dot_index+1).replace(/[^a-zA-Z]/gi,""); //Quitando numeros y espacios para arreglar gelbooru
62 this.picExtension = fileExt;
63 }
64 return this.picExtension;
65 }
66
67 ,parseToken:function(token)
68 {
69 var tokenValue="";
70 switch(token)
71 {
72 case '%md5%':
73 tokenValue = this.getHashcode();
74 break;
75
76 case '%website%':
77 tokenValue = this.tabDocument.location.hostname;
78 break;
79
80 case '%artist%': //Artist tags
81 var artistTags = this.getSpecificTags('artist');
82 if(artistTags.length == 0)
83 tokenValue = DanbooruDownloaderPreferences.getCharPref("noArtist");
84 else if(artistTags.length == 1)
85 tokenValue = artistTags[0];
86 else if(!DanbooruDownloaderPreferences.getBoolPref("multipleArtistsAll"))
87 tokenValue = DanbooruDownloaderPreferences.getCharPref("multipleArtistsDefault");
88 else
89 {
90 for(y=0;y<artistTags.length;y++)
91 {
92 if(y>0) tokenValue += DanbooruDownloaderPreferences.getCharPref("multipleArtistsSeparator");
93 tokenValue += artistTags[y];
94 }
95 }
96 break;
97
98 case '%all%': //All the tags
99 var generalTags = this.getAllTags();
100 for(y=0;y<generalTags.length;y++)
101 {
102 if(y>0) tokenValue += DanbooruDownloaderPreferences.getCharPref("generalTagsSeparator");
103 tokenValue += generalTags[y];
104 }
105 break;
106
107 case '%general%': //General tags, all of them
108 var generalTags = this.getSpecificTags('general');
109 for(y=0;y<generalTags.length;y++)
110 {
111 if(y>0) tokenValue += DanbooruDownloaderPreferences.getCharPref("generalTagsSeparator");
112 tokenValue += generalTags[y];
113 }
114 break;
115
116 case '%copyright%': //Copyright tags
117 var copyrightTags = this.getSpecificTags('copyright');
118 if(copyrightTags.length == 0)
119 tokenValue = DanbooruDownloaderPreferences.getCharPref("noCopyright");
120 else if(copyrightTags.length == 1)
121 tokenValue = copyrightTags[0];
122 else if(DanbooruDownloaderPreferences.getBoolPref("multipleCopyrightsFindShorter"))
123 {
124 var shorter_series = this.getSmaller(copyrightTags);
125 var subseries = true;
126 for(y=0;y<copyrightTags.length;y++)
127 if(copyrightTags[y].indexOf(shorter_series) == -1)
128 subseries = false;
129 if(subseries)
130 tokenValue = shorter_series;
131 else
132 tokenValue = DanbooruDownloaderPreferences.getCharPref("multipleCopyrightsDefault");
133 }
134 else if(!DanbooruDownloaderPreferences.getBoolPref("multipleCopyrightsAll"))
135 tokenValue = DanbooruDownloaderPreferences.getCharPref("multipleCopyrightsDefault");
136 else
137 {
138 for(y=0;y<copyrightTags.length;y++)
139 {
140 if(y>0) tokenValue += DanbooruDownloaderPreferences.getCharPref("multipleCopyrightsSeparator");
141 tokenValue += copyrightTags[y];
142 }
143 }
144 break;
145
146 case '%character%': //Character tags
147 var characterTags = this.getSpecificTags('character');
148 if(characterTags.length == 0)
149 tokenValue = DanbooruDownloaderPreferences.getCharPref("noCharacter");
150 else if(characterTags.length == 1)
151 tokenValue = characterTags[0];
152 else if(!DanbooruDownloaderPreferences.getBoolPref("multipleCharactersAll"))
153 tokenValue = DanbooruDownloaderPreferences.getCharPref("multipleCharactersDefault");
154 else
155 {
156 for(y=0;y<characterTags.length;y++)
157 {
158 if(y>0) tokenValue += DanbooruDownloaderPreferences.getCharPref("multipleCharactersSeparator");
159 tokenValue += characterTags[y];
160 }
161 }
162 break;
163
164 case '%filename%':
165 tokenValue = this.getPicFilename();
166 break;
167
168 case '%ext%':
169 tokenValue = this.getPicExtension();
170 break;
171
172 case '%rating%':
173 tokenValue = this.getRating();
174 break;
175 }
176 return tokenValue;
177 }
178
179 ,getTargetPath:function()
180 {
181 if(typeof this.tagetDir == "undefined")
182 {
183 if(!DanbooruDownloaderPreferences.getBoolPref("customCubePath"))
184 {
185 var basePath = DanbooruDownloaderPreferences.getCharPref("targetFolder");
186
187 //Nos pasamos por todas las whitelist tags, y en la que corresponda, agarramos el nombre
188 var whitelistedTags = this.getWhitelist();
189 var picTags = this.getAllTags();
190 for(var x=0; x<whitelistedTags.length; x++)
191 {
192 if(picTags.indexOf(whitelistedTags[x]) >= 0)
193 {
194 var tentativeFilename = DanbooruDownloaderPreferences.getCharPref("whitelistFilename"+x);
195 if(tentativeFilename != "")
196 {
197 var fileName = tentativeFilename;
198 break;
199 }
200 }
201 }
202 if(typeof fileName == "undefined") //Si no estuvo whitelisteado, o si no tiene filename especifico su whitelist tag
203 { var fileName = DanbooruDownloaderPreferences.getCharPref("targetName"); }
204
205 var re = /%[^%]+%/g;
206
207 var path = fileName;
208 var strTokens = fileName.match(re);
209 if(strTokens != null)
210 {
211 var tokenValues = new Object();
212 for(var t=0;t<strTokens.length;t++)
213 {
214 var token = strTokens[t];
215 if(typeof tokenValues[token] == "undefined")
216 {
217 tokenValue = this.parseToken(token);
218 tokenValues[token] = tokenValue;
219 path = path.replace(token,tokenValue,"g");
220 tokenValues[token] = tokenValue;
221 }
222 }
223 }
224 //Quitando caracteres invalidos
225 if(DanbooruDownloaderPreferences.getBoolPref("underscoreTags"))
226 path = path.replace(/[\/:*?"<>|]/g,"_");
227 else
228 path = path.replace(/[\/:*?"<>|]/g," ");
229
230 this.targetDir = basePath+"\\"+path;
231 }
232 else //Solo para mi! MWAHAHAHAHA!
233 {
234 var path = DanbooruDownloaderPreferences.getCharPref("targetFolder"); //<- to be replaced by the base dir selected by the user
235
236 //Si son sub-series una de las otras
237 //(i.e. "mahou_shoujo_lyrical_nanoha" y "mahou_shoujo_lyrical_nanoha_strikers")
238 //lo guardamos en la 'raÃz'
239 //Si no, en la carpeta cross-overs
240 //Y si no tiene ninguna, dependiendo de tags en particular ('loli' por ejemplo, si es explicit se va a 'ecchi')
241 var target_folder = null;
242 if(this.getRating()=="Explicit")
243 { target_folder = "ecchi"; }
244 else
245 { target_folder = DanbooruDownloaderPreferences.getCharPref("noCopyright"); }
246
247 //Quitando caracteres inválidos
248 if(DanbooruDownloaderPreferences.getBoolPref("underscoreTags"))
249 target_folder = target_folder.replace(/[\/:*?"<>|]/g,"_");
250 else
251 target_folder = target_folder.replace(/[\/:*?"<>|]/g," ");
252
253 path += target_folder;
254 path += "\\" + this.getPicFilename() + "." + this.getPicExtension();
255 this.targetDir = path;
256 }
257 }
258
259 this.targetDir = this.targetDir.replace("\\\\","\\","g"); //Quitando dobles barras
260 //Trimming to 256 chars or less, keeping extension, trimming everything else
261 if(this.targetDir.length > DanbooruDownloaderPreferences.getIntPref("maxPathLength"))
262 {
263 //Buscamos la extension para mantenerla, lo demas lo cortamos
264 if(this.targetDir.lastIndexOf(".") >= 0)
265 {
266 var ext = this.targetDir.substr(this.targetDir.lastIndexOf("."));
267 var path= this.targetDir.substr(0,DanbooruDownloaderPreferences.getIntPref("maxPathLength")-ext.length)
268 this.targetDir = path + ext;
269 }
270 else
271 {
272 this.targetDir = this.targetDir.substr(0,DanbooruDownloaderPreferences.getIntPref("maxPathLength"));
273 }
274 }
275 return this.targetDir;
276 }
277
278 ,getIsLoli:function()
279 {
280 if(typeof this.isLoli == "undefined")
281 {
282 var general_tags = this.getSpecificTags('general');
283 this.isLoli = false;
284 for(x=0; x<general_tags.length; x++)
285 if(general_tags[x] == "loli")
286 this.isLoli = true;
287 }
288 return this.isLoli;
289 }
290
291 ,getRating:function()
292 {
293 if(typeof this.rating == "undefined")
294 {
295 var details = this.tabDocument.getElementById('stats').childNodes[3].childNodes;
296 var options = ['Safe','Questionable','Explicit'];
297 for(var x=0; x<details.length; x++)
298 {
299 if(details[x].tagName == "LI")
300 {
301 for(var y=0; y<options.length; y++)
302 {
303 //if(details[x].innerHTML.indexOf(options[y])>= 0 && details[x].innerHTML.indexOf(options[y]) == details[x].innerHTML.length - options[y].length) //Si Safe/Quest/etc. son exactamente la última parte del html. EXPLOTA en moe imouto, xq tiene un span escondido al final
304 if(details[x].innerHTML.indexOf(": "+options[y])>= 0) //Si tiene ': Safe/Quest/etc.'
305 { this.rating = options[y]; }
306 }
307 }
308 }
309 }
310 // DocumentStats| element |List of stats| Rating row |Rating text|Only rating
311 return this.rating;
312 }
313
314 ,getBlacklist:function()
315 {
316 return DanbooruDownloaderPreferences.getCharPref("blacklist").split(/[\r\n]|$/); //Splitting by endlines
317 }
318
319 ,isBlacklisted:function()
320 {
321 if(DanbooruDownloaderPreferences.getBoolPref("useBlacklist"))
322 {
323 var blacklistedTags = this.getBlacklist();
324 var picTags = this.getAllTags();
325 for(var x=0; x<blacklistedTags.length; x++)
326 {
327 if(picTags.indexOf(blacklistedTags[x]) >= 0)
328 { return true; }
329 }
330 }
331 return false;
332 }
333
334 ,getWhitelist:function()
335 {
336 var totalTags = DanbooruDownloaderPreferences.getIntPref("whitelistTagsCount");
337 var whitelistedTags = new Array(totalTags);
338 for(var x=0; x<totalTags; x++)
339 { whitelistedTags[x] = DanbooruDownloaderPreferences.getCharPref("whitelistTag"+x); }
340 return whitelistedTags;
341 }
342
343 ,isWhitelisted:function()
344 {
345 var whitelistedTags = this.getWhitelist();
346 var picTags = this.getAllTags();
347 for(var x=0; x<whitelistedTags.length; x++)
348 {
349 if(picTags.indexOf(whitelistedTags[x]) >= 0)
350 { return true; }
351 }
352 return false;
353 }
354
355 /*
356 Si la blacklist esta activada
357 Revisar que no este blacklisted
358 Si la whitelist exclusiva esta activada
359 Revisar que esta whitelisted
360 Revisar si tiene una direccion para guardar en la whitelist <- Mejor en el metodo que obtiene la URL?
361 */
362 ,autoSavePic:function()
363 {
364 //Checando la blacklist
365 if(!this.isBlacklisted() && ( !DanbooruDownloaderPreferences.getBoolPref("useWhitelist") || this.isWhitelisted() ) )
366 { this.savePic(); }
367 }
368
369 ,savePic:function()
370 {
371 if(!this.picSaved)
372 {
373 var dict = document.getElementById("DS_dict");
374 try
375 {
376 DanbooruDownloader.setStatus(this.tabDocument,dict.getString("danbooruStatus.savingPic"));
377 var destiny = this.getTargetPath();
378 DanbooruDownloader.setStatus(this.tabDocument,dict.getString("danbooruStatus.fetchingPicUrl"));
379 var pic_url = this.getPicUrl();
380 DanbooruDownloader.setStatus(this.tabDocument,dict.getString("danbooruStatus.fetchingPicContent"));
381 var content = this.getPicContent();
382 var hashcode = this.getHashcode();
383
384 if(content != "")
385 {
386 DanbooruDownloader.setStatus(this.tabDocument,dict.getString("danbooruStatus.savingPic"));
387
388 /*****
389
390 Pasos a realizar:
391 1- Ver si ya tenemos el hashcode en la BBDD
392 2- Si lo tenemos, mover la imágen al directorio correcto
393 3- Insertar o actualizar los datos de la BBDD con los nuevos
394 Para optimizar, ejecutaremos ambos comandos de golpe (select path where hashcode = @@@ e insert or replace @@@), y luego hacemos el guardado/movido
395
396 ******/
397
398 //Creating SQLite file
399 var originalPath;
400 var file = Components.classes["@mozilla.org/file/directory_service;1"].getService(Components.interfaces.nsIProperties).get("ProfD", Components.interfaces.nsIFile);
401 file.append("danboorudownloader.sqlite");
402 var storageService = Components.classes["@mozilla.org/storage/service;1"].getService(Components.interfaces.mozIStorageService);
403 var dbConn = storageService.openDatabase(file); // Will also create the file if it does not exist
404 //Creating table
405 dbConn.executeSimpleSQL("CREATE TABLE IF NOT EXISTS downloads (md5 VARCHAR(32) PRIMARY KEY, url TEXT, src TEXT, path TEXT, tags TEXT)");
406 //Preparing statements
407 var allTags = this.getAllTags();
408 var selectPath = dbConn.createStatement("SELECT path FROM downloads WHERE md5 = :md5");
409 selectPath.params.md5 = hashcode;
410 var updateData = dbConn.createStatement("INSERT OR REPLACE INTO downloads (md5,url,src,path,tags) VALUES (:md5,:url,:src,:path,:tags)");
411 updateData.params.md5 = hashcode;
412 updateData.params.src = pic_url;
413 updateData.params.path = destiny;
414 updateData.params.tags = allTags.join();
415 updateData.params.url = this.tabDocument.location.href;
416 //Starting transaction
417 dbConn.beginTransaction();
418 //Checking if pic already exists, getting saved path if it does
419 if(selectPath.executeStep())
420 originalPath = selectPath.row.path;
421 else
422 originalPath = "";
423 selectPath.reset();
424 //Update DB with new pic data
425 updateData.execute();
426 //End transaction and close connection
427 dbConn.commitTransaction();
428 selectPath.finalize();
429 updateData.finalize();
430 dbConn.close();
431
432 if(originalPath != "" && originalPath != destiny)
433 {
434 this.log("Deleting"+'\t'+originalPath);
435 var original = FileIO.open(originalPath);
436 FileIO.unlink(original);
437 }
438
439 var picFile = FileIO.open(destiny);
440 //Podriamos validar que originalPath == destiny para ver si es duplicado,
441 //pero el usuario puede haber borrado la imágen,
442 //y de todos modos ya creamos el archivo
443 if(!picFile.exists())
444 {
445 FileIO.create(picFile);
446 var rv = FileIO.write(picFile,content);
447 //this.log("Guardando "+pic_url+" en "+destiny);
448 this.log("Saved"+'\t'+pic_url+'\t'+destiny+'\t'+this.tabDocument.location.hostname+'\t'+allTags);
449 DanbooruDownloader.setStatus(this.tabDocument,dict.getString("danbooruStatus.picSaved"));
450 }
451 else
452 {
453 this.log("Dup"+'\t'+pic_url+'\t'+destiny+'\t'+this.tabDocument.location.hostname+'\t'+allTags);
454 //this.log("Ya existe "+pic_url+" en "+destiny);
455 DanbooruDownloader.setStatus(this.tabDocument,dict.getString("danbooruStatus.picExists"));
456 }
457 }
458 else
459 {
460 //this.log(pic_url+" no tiene contenido.");
461 this.log("Empty"+'\t'+pic_url+'\t'+destiny+'\t'+this.tabDocument.location.hostname+'\t'+this.getAllTags());
462 DanbooruDownloader.setStatus(this.tabDocument,dict.getString("danbooruStatus.noContent"));
463 }
464 this.picSaved = true;
465 this.tabDocument.picSaved = true;
466 }
467 catch(Ex)
468 {
469 this.log("Error|"+Ex.fileName+":"+Ex.lineNumber+"|"+Ex.message+"|"+this.tabDocument.location+"|"+this.picUrl);
470 DanbooruDownloader.setStatus(this.tabDocument,dict.getString("danbooruStatus.savingError"));
471 }
472 }
473 else
474 {
475 DanbooruDownloader.setStatus(this.tabDocument,dict.getString("danbooruStatus.picAlreadySaved"));
476 }
477 }
478
479 ,getSmaller:function(words)
480 {
481 var min = words[0];
482 for(x=1;x<words.length;x++)
483 if(min.length > words[x].length)
484 min = words[x];
485 return min;
486 }
487
488 ,getLarger:function(words)
489 {
490 var max = words[0];
491 for(x=1;x<words.length;x++)
492 if(max.length < words[x].length)
493 max = words[x];
494 return max;
495 }
496
497 ,getPicUrl:function()
498 {
499 if(typeof this.picUrl == "undefined")
500 {
501 //No todos tienen HQ link, algunos se muestran ya en la resolución grande y otros si estan resized
502 //Por eso, vemos si tiene link a version HQ, y si no, agarramos el SRC de la imagen
503 var pic_url;
504 var hq_link = this.tabDocument.getElementById('highres');
505 if(hq_link != null && DanbooruDownloaderPreferences.getBoolPref("downloadHQpic"))
506 { pic_url = hq_link.href; }
507 else
508 { pic_url = this.tabDocument.getElementById('image').src; }
509 this.picUrl = pic_url;
510 }
511 return this.picUrl;
512 }
513
514 ,getPicContent:function()
515 {
516 if(typeof this.picContent == "undefined")
517 {
518 this.picContent = GetImageFromURL(this.getPicUrl());
519 }
520 return this.picContent;
521 }
522
523 ,getTagsSidebar:function()
524 {
525 if(typeof this.tagsSidebar == "undefined")
526 { this.tagsSidebar = this.tabDocument.getElementById('tag-sidebar'); }
527 return this.tagsSidebar;
528 }
529
530 ,getAllTags:function()
531 {
532 var tags_sidebar = this.getTagsSidebar().childNodes;
533 var tags = new Array();
534 var replace = DanbooruDownloaderPreferences.getBoolPref("underscoreTags");
535
536 for(var x=0; x<tags_sidebar.length; x++)
537 {
538 if(tags_sidebar[x].tagName == "LI")
539 {
540 //var tag = tags_sidebar[x].childNodes[2].text;
541 //Llendo de atras hacia adelante, el primer link q encontremos es el de la tag (usualmente es <wiki> <tag> <count>)
542 for(var y=tags_sidebar[x].childNodes.length-1; y>=0; y--)
543 {
544 if(tags_sidebar[x].childNodes[y].tagName == "A")
545 {
546 var tag = tags_sidebar[x].childNodes[y].text;
547 break;
548 }
549 }
550
551 if(replace)
552 { tag = tag.replace(/ /g,"_"); }
553 //Removing / to avoid creating extra directories
554 tag = tag.replace(/\\/g,"");
555 tags[tags.length] = tag;
556 }
557 }
558 return tags;
559 }
560
561 //Type: 'character','general','copyright','artist'
562 ,getSpecificTags:function(tagType)
563 {
564 var tags_sidebar = this.getTagsSidebar().childNodes;
565 var tags = new Array();
566 var replace = DanbooruDownloaderPreferences.getBoolPref("underscoreTags");
567
568 for(var x=1; x<tags_sidebar.length-1; x++)
569 {
570 if(tags_sidebar[x].className == "tag-type-"+tagType)
571 {
572 //var tag = tags_sidebar[x].childNodes[2].text;
573 //Llendo de atras hacia adelante, el primer link q encontremos es el de la tag (usualmente es <wiki> <tag> <count>)
574 for(var y=tags_sidebar[x].childNodes.length-1; y>=0; y--)
575 {
576 if(tags_sidebar[x].childNodes[y].tagName == "A")
577 {
578 var tag = tags_sidebar[x].childNodes[y].text;
579 break;
580 }
581 }
582 if(replace)
583 { tag = tag.replace(/ /g,"_"); }
584 //Removing / to avoid creating extra directories
585 tag = tag.replace(/\\/g,"");
586 tags[tags.length] = tag;
587 }
588 }
589 return tags;
590 }
591}