tagDuplicator

Duplicate tags for translated galleries from original galleries

  1. // ==UserScript==
  2. // @name tagDuplicator
  3. // @namespace tagDuplicator
  4. // @description Duplicate tags for translated galleries from original galleries
  5. // @include https://exhentai.org/g/*
  6. // @include https://e-hentai.org/g/*
  7. // @version alpha
  8. // @grant none
  9. // @run-at document-end
  10. // ==/UserScript==
  11. /**
  12. * Created by atashiyuki on 2017/2/27.
  13. */
  14.  
  15. var exclude_namespaces=[
  16. "language",
  17. "reclass",
  18. ];
  19.  
  20. var prompt_map={
  21. "zh-CN":"请输入要导入tag的画廊地址",
  22. "en-US":"please input the link of the gallery you want to import tags from",
  23. "default":"please input the link of the gallery you want to import tags from",
  24. };
  25.  
  26. var confirm_map={
  27. "zh-CN":"两个画廊看起来并不像同一个作品的说...即使如此仍然想要导入tag吗?",
  28. "en-US":"the two galleries are not likely to be the same piece, still want to import tags?",
  29. "default":"the two galleries are not likely to be the same piece, still want to import tags?",
  30. }
  31.  
  32. var wrong_url_map={
  33. "zh-CN":"请输入从\"https\"开始的完整的画廊链接",
  34. "en-US":"please input the complete gallery link, from \"https\"",
  35. "default":"please input the complete gallery link, from \"https\"",
  36. }
  37.  
  38. function get_text_in_local_language(map){
  39. var user_language = navigator.language || navigator.userLanguage;
  40. var text=map[user_language];
  41. if(text==undefined)
  42. text=map.default;
  43. return text;
  44. }
  45.  
  46. function get_source_sync(url){
  47. var req=new XMLHttpRequest();
  48. req.open('GET',url,false);
  49. req.send();
  50. return req.response;
  51. }
  52.  
  53. function get_source_async(url,call_back){
  54. var req=new XMLHttpRequest();
  55. req.open('GET',url,true);
  56. req.onreadystatechange=function(){
  57. if(req.readyState === XMLHttpRequest.DONE && req.status === 200)
  58. call_back(req.response);
  59. };
  60. req.send();
  61. }
  62.  
  63. function check_gallery(current_source, target_source) {
  64. var regexp="<h1 id=\"gj\">(.+?)\\[(.+?)\\](.+?)\\[.+?</h1>";
  65. var result_current=current_source.match(regexp);
  66. var result_target=target_source.match(regexp);
  67. var diff=0;
  68.  
  69. if(result_current==result_target)
  70. return false;
  71. for(let i=1;i<4;++i){
  72. if((""+result_current[i]).trim()!=(""+result_target[i]).trim())
  73. diff+=1;
  74. }
  75.  
  76. return diff<=1;
  77. }
  78.  
  79. function parse_tags(source_text) {
  80. var ret={};
  81. var regexp=/return toggle_tagmenu\('(.+?)',/g;
  82. var result;
  83. while(result=regexp.exec(source_text)){
  84. var namespace_tag=result[1].split(':');
  85. if(namespace_tag.length==1){
  86. namespace_tag=["misc",namespace_tag[0]];
  87. }
  88. // do not add excluded namespaces
  89. if(exclude_namespaces.includes(namespace_tag[0]))
  90. continue;
  91.  
  92. if(ret[namespace_tag[0]]==undefined)
  93. ret[namespace_tag[0]]=[];
  94. ret[namespace_tag[0]].push(namespace_tag[1]);
  95. }
  96. return ret;
  97. }
  98.  
  99. function fill_tag_field(tags){
  100. var field=document.getElementById('newtagfield');
  101. var text="";
  102. for(let namespace in tags){
  103. for(let tag of tags[namespace]){
  104. text+=namespace+':'+tag+',';
  105. }
  106. }
  107. field.value=text;
  108.  
  109. if(text.length==0)
  110. field.placeholder="no tags to add...";
  111. }
  112.  
  113. // this tool is to add tag to a translated gallery, not to farm tagging MP
  114. // please do not abuse this
  115. function subtract_tags(current_tags, tags_to_add){
  116. var ret={};
  117. for(let namespace in tags_to_add){
  118. if(current_tags[namespace]==undefined){
  119. ret[namespace]=tags_to_add[namespace];
  120. continue;
  121. }
  122. for(let tag of tags_to_add[namespace]){
  123. if(current_tags[namespace].includes(tag))
  124. continue;
  125. if(ret[namespace]==undefined)
  126. ret[namespace]=[];
  127. ret[namespace].push(tag);
  128. }
  129. }
  130. return ret;
  131. }
  132.  
  133. function make_callbacks(parse,subtract,fill) {
  134. var current_finished_getting=false;
  135. var current_source="";
  136. var target_finished_getting=false;
  137. var target_source="";
  138.  
  139. var action=function() {
  140. if(current_finished_getting&&target_finished_getting){
  141. if(!check_gallery(current_source,target_source)){
  142. var confirm_text=get_text_in_local_language(confirm_map);
  143. var keep=confirm(confirm_text);
  144. if(!keep)
  145. return;
  146. }
  147. var tags_current=parse(current_source);
  148. var tags_target=parse(target_source);
  149. var tags_to_add=subtract(tags_current,tags_target);
  150. fill(tags_to_add);
  151. }
  152. }
  153.  
  154. return {
  155. current_callback:function(text) {
  156. current_finished_getting=true;
  157. current_source=text;
  158. action();
  159. },
  160. target_callback:function(text) {
  161. target_finished_getting=true;
  162. target_source=text;
  163. action();
  164. }
  165. }
  166. }
  167.  
  168. function start() {
  169. var prompt_text=get_text_in_local_language(prompt_map);
  170.  
  171. var url=prompt(prompt_text);
  172. if(url.substr(0,23)!=location.href.substr(0,23))
  173. alert(get_text_in_local_language(wrong_url_map));
  174.  
  175. var callbacks=make_callbacks(parse_tags,subtract_tags,fill_tag_field);
  176. get_source_async(window.location.href,callbacks.current_callback);
  177. get_source_async(url,callbacks.target_callback);
  178. }
  179.  
  180. function init() {
  181. var div=document.getElementById("tagmenu_new");
  182. var btn=document.createElement('input'); // use input rather than button to inherit some style
  183. btn.type="submit";
  184. btn.name="submit";
  185. btn.value="duplicate tags from another gallery";
  186. btn.style.position="relative";
  187. btn.style.bottom="55px";
  188. btn.style.margin="0px";
  189. btn.style.cursor="pointer";
  190. btn.onclick=start;
  191. div.appendChild(btn);
  192. }
  193.  
  194.  
  195. init();