Search By Image

Search By Image | 以图搜图

当前为 2014-07-06 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name Search By Image
  3. // @version 1.4
  4. // @description Search By Image | 以图搜图
  5. // @match <all_urls>
  6. // @include *
  7. // @author 864907600cc
  8. // @icon http://1.gravatar.com/avatar/147834caf9ccb0a66b2505c753747867
  9. // @run-at document-start
  10. // @grant GM_getValue
  11. // @grant GM_setValue
  12. // @grant GM_openInTab
  13. // @grant GM_registerMenuCommand
  14. // @namespace http://ext.ccloli.com
  15. // ==/UserScript==
  16.  
  17. // 本脚本基于 GPLv3 协议开源 http://www.gnu.org/licenses/gpl.html‎
  18. // (c) 86497600cc. Some Rights Reserved.
  19. // Default setting: Press Ctrl and click right key on a image to search.
  20.  
  21. 'use strict';
  22. var default_setting={
  23. "site_list":{
  24. "Google":"https://www.google.com/searchbyimage?image_url={%s}",
  25. "Baidu ShiTu":"http://stu.baidu.com/i?ct=1&tn=baiduimage&objurl={%s}",
  26. "Baidu Image":"http://image.baidu.com/i?rainbow=1&ct=1&tn=shituresultpc&objurl={%s}",
  27. "Bing":"http://cn.bing.com/images/searchbyimage?FORM=IRSBIQ&cbir=sbi&imgurl={%s}",
  28. "TinEye":"http://www.tineye.com/search?url={%s}",
  29. //"Cydral":"http://www.cydral.com/#url={%s}",
  30. "Яндекс (Yandex)":"http://yandex.ru/images/search?rpt=imageview&img_url={%s}",
  31. "Sogou":"http://pic.sogou.com/ris?query={%s}",
  32. "360 ShiTu":"http://st.so.com/stu?imgurl={%s}",
  33. "SauceNAO":"http://saucenao.com/search.php?db=999&url={%s}",
  34. "IQDB":"http://iqdb.org/?url={%s}",
  35. "3D IQDB":"http://3d.iqdb.org/?url={%s}"
  36. },
  37. "site_option":["Google","Baidu ShiTu","Baidu Image","Bing","TinEye","Яндекс (Yandex)","Sogou","360 ShiTu","SauceNAO","IQDB","3D IQDB"],
  38. "hot_key":"ctrlKey" // Can be set as one of these: "ctrlKey", "shiftKey", "altKey". Default setting is "ctrlKey".
  39. }
  40. var search_panel=null;
  41. var setting=GM_getValue('setting')?JSON.parse(GM_getValue('setting')):default_setting;
  42. var disable_contextmenu=false;
  43. var img_src=null;
  44. var data_version=GM_getValue('version',0);
  45. var last_update=GM_getValue('timestamp',0);
  46. var xhr=new XMLHttpRequest();
  47. var reader=new FileReader();
  48. reader.onload=function(file){upload_file(this.result);};
  49.  
  50. function set_setting(data){
  51. GM_setValue('setting',JSON.stringify(data));
  52. GM_setValue('timestamp',new Date().getTime());
  53. }
  54.  
  55. function create_panel(){
  56. search_panel=document.createElement('div');
  57. search_panel.style.cssText='width:198px;font-size:14px;text-align:center;position:absolute;color:#000;z-index:9999999999;box-shadow:2px 2px 3px rgba(0,0,0,0.5);border:1px solid #CCC;background:rgba(255,255,255,0.9);border-top-right-radius:2px;border-bottom-left-radius:2px;font-family:"Arial";-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none';
  58. document.body.appendChild(search_panel);
  59. var search_top=document.createElement('div');
  60. search_top.style.cssText='width:90%;height:24px;line-height:24px;font-size:12px;overflow:hidden;margin:0 auto';
  61. search_top.className='image-search-top';
  62. search_top.innerHTML='<div class="search_top_url" style="overflow:hidden;white-space:nowrap;text-overflow:ellipsis;width:100%;height:24px"></div><div class="search_top_file" style="width:100%;height:24px;line-height:24px" draggable="true"><label for="image-search-file">上传图片并搜索</label><input type="file" id="image-search-file" accept="image/*" style="width:0px;height:0px"></div><div class="search_top_progress"><progress style="width:100%;height:16px;vertical-align:middle;margin:4px 0" max="1"></progerss></div>'
  63. search_panel.appendChild(search_top);
  64. var search_item=document.createElement('div');
  65. search_item.style.cssText='width:100%;height:24px;line-height:24px;cursor:pointer';
  66. search_item.className='image-search-item';
  67. for(var i in setting.site_list){
  68. var search_item_child=search_item.cloneNode(true);
  69. search_item_child.textContent=i;
  70. search_item_child.setAttribute('search-option',i);
  71. search_panel.appendChild(search_item_child);
  72. }
  73. search_item.textContent='All';
  74. search_item.setAttribute('search-option','all');
  75. search_panel.appendChild(search_item);
  76. var search_item_setting=search_item.cloneNode(true);
  77. search_item_setting.textContent='Setting';
  78. search_item_setting.setAttribute('search-option','setting');
  79. search_panel.appendChild(search_item_setting);
  80. search_top.getElementsByTagName('input')[0].onchange=function(){reader.readAsDataURL(this.files[0]);};
  81. search_panel.ondragenter=function(event){
  82. event.preventDefault();
  83. search_top.getElementsByClassName('search_top_file')[0].textContent='拖拽文件至此';
  84. };
  85. search_panel.ondragleave=function(event){
  86. event.preventDefault();
  87. search_top.getElementsByClassName('search_top_file')[0].textContent='上传图片并搜索';
  88. };
  89. search_panel.ondragover=function(event){
  90. search_top.getElementsByClassName('search_top_file')[0].textContent='拖拽文件至此';
  91. event.preventDefault();
  92. };
  93. search_panel.ondrop=function(event){
  94. event.stopPropagation();
  95. event.preventDefault();
  96. var files=event.target.files||event.dataTransfer.files;
  97. if(files[files.length-1].type.indexOf('image')>=0)reader.readAsDataURL(files[files.length-1]);
  98. };
  99. search_top.getElementsByTagName('progress').onclick=function(){
  100. if(xhr.readyState!=0&&confirm('确认终止上传文件吗?')==true){
  101. xhr.abort();
  102. search_panel.getElementsByClassName('search_top_url')[0].style.marginTop='-24px';
  103. }
  104. }
  105. }
  106.  
  107. function call_setting(){
  108. var setting_panel=document.createElement('div');
  109. setting_panel.style.cssText='width:520px;font-size:14px;position:fixed;color:#000;z-index:9999999999;box-shadow:2px 2px 3px rgba(0,0,0,0.5);border:1px solid #CCC;background:rgba(255,255,255,0.9);border-top-right-radius:2px;border-bottom-left-radius:2px;padding:10px;left:0;right:0;top:0;bottom:0;margin:auto;font-family:"Arial";height:400px;max-height:90%;overflow:auto;text-align:center;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none';
  110. document.body.appendChild(setting_panel);
  111. var setting_header=document.createElement('div');
  112. setting_header.style.cssText='width:100%;height:32px;line-height:32px;font-size:18px;line-height:32px';
  113. setting_header.className='image-search-setting-header';
  114. setting_header.textContent='Search By Image Setting';
  115. setting_panel.appendChild(setting_header);
  116. var setting_item=document.createElement('div');
  117. setting_item.style.cssText='width:100%;height:24px;line-height:24px;margin:1px 0';
  118. setting_item.className='image-search-setting-title';
  119. setting_item.innerHTML='<div style="text-align:center;display:inline-block;width:30px">多搜</div><div style="width:100px;text-align:center;display:inline-block">名称</div><div style="width:350px;text-align:center;display:inline-block">地址(图片地址以 {%s} 代替)</div><div style="width:20px;display:inline-block"></div>';
  120. setting_panel.appendChild(setting_item);
  121. for(var i in setting.site_list){
  122. var setting_item_child=setting_item.cloneNode(true);
  123. setting_item_child.className='image-search-setting-item';
  124. setting_item_child.innerHTML='<div style="text-align:center;display:inline-block;width:30px;vertical-align:middle"><input type="checkbox"'+(setting.site_option.join('\n').indexOf(i)>=0?' checked="checked"':'')+'></div><div style="width:100px;text-align:center;display:inline-block"><input style="width:90px" type="text" value="'+i+'"></div><div style="width:350px;text-align:center;display:inline-block"><input style="width:340px" type="text" value="'+setting.site_list[i]+'"></div><div style="text-align:center;display:inline-block;cursor:pointer;width:20px">×</div>';
  125. setting_panel.appendChild(setting_item_child);
  126. setting_item_child.getElementsByTagName('div')[3].onclick=function(){this.parentElement.outerHTML='';};
  127. }
  128. var setting_footer=document.createElement('div');
  129. setting_footer.style.cssText='width:100%;height:32px;line-height:32px;margin-top:5px;text-align:right';
  130. setting_footer.className='image-search-setting-footer';
  131. setting_panel.appendChild(setting_footer);
  132. var setting_hotkey=document.createElement('div');
  133. var setting_add=document.createElement('div');
  134. var setting_reset=document.createElement('div');
  135. var setting_save=document.createElement('div');
  136. var setting_cancel=document.createElement('div');
  137. setting_hotkey.style.cssText='height:32px;display:inline-block;text-align:left;float:left';
  138. setting_add.style.cssText='width:90px;height:32px;margin:0 5px;background:#666;color:#FFF;display:inline-block;text-align:center;cursor:pointer';
  139. setting_reset.style.cssText='width:90px;height:32px;background:#666;color:#FFF;display:inline-block;text-align:center;cursor:pointer';
  140. setting_save.style.cssText='width:90px;height:32px;margin:0 5px;background:#666;color:#FFF;display:inline-block;text-align:center;cursor:pointer';
  141. setting_cancel.style.cssText='width:90px;height:32px;background:#666;color:#FFF;display:inline-block;text-align:center;cursor:pointer';
  142. setting_add.textContent='Add Item';
  143. setting_reset.textContent='Reset';
  144. setting_save.textContent='Save';
  145. setting_cancel.textContent='Cancel';
  146. setting_hotkey.innerHTML='Hot Key <select><option value="ctrlKey"'+(setting.hot_key=='ctrlKey'?' selected':'')+'>Ctrl</option><option value="shiftKey"'+(setting.hot_key=='shiftKey'?' selected':'')+'>Shift</option><option value="altKey"'+(setting.hot_key=='altKey'?' selected':'')+'>Alt</option></select>';
  147. setting_footer.appendChild(setting_hotkey);
  148. setting_footer.appendChild(setting_add);
  149. setting_footer.appendChild(setting_reset);
  150. setting_footer.appendChild(setting_save);
  151. setting_footer.appendChild(setting_cancel);
  152. setting_add.onclick=function(){
  153. var setting_item_child=setting_item.cloneNode(true);
  154. setting_item_child.className='image-search-setting-item';
  155. setting_item_child.innerHTML='<div style="text-align:center;display:inline-block;width:30px;vertical-align:middle"><input type="checkbox"></div><div style="width:100px;text-align:center;display:inline-block"><input style="width:90px" type="text"></div><div style="width:350px;text-align:center;display:inline-block"><input style="width:340px" type="text"></div><div style="text-align:center;display:inline-block;cursor:pointer;width:20px">×</div>';
  156. setting_panel.insertBefore(setting_item_child,setting_footer);
  157. setting_item_child.getElementsByTagName('div')[3].onclick=function(){this.parentElement.outerHTML='';}
  158. setting_panel.scrollTop=setting_panel.scrollHeight;
  159. };
  160. setting_reset.onclick=function(){
  161. if(confirm('确定将所有设置初始化么?\n\n(初始化将清除所有所有设置,且不可逆)')==true){
  162. setting=default_setting;
  163. set_setting(setting);
  164. setting_panel.outerHTML='';
  165. if(search_panel!=null){
  166. search_panel.outerHTML='';
  167. search_panel=null;
  168. }
  169. call_setting();
  170. }
  171. };
  172. setting_save.onclick=function(){
  173. var setting_items=document.getElementsByClassName('image-search-setting-item');
  174. var setting_data={"site_list":{},"site_option":[],"hot_key":null};
  175. for(var i=0;i<setting_items.length;i++){
  176. if(setting_items[i].getElementsByTagName('input')[1].value!=''){
  177. if(setting_items[i].getElementsByTagName('input')[0].checked)setting_data.site_option.push(setting_items[i].getElementsByTagName('input')[1].value);
  178. setting_data.site_list[setting_items[i].getElementsByTagName('input')[1].value]=setting_items[i].getElementsByTagName('input')[2].value;
  179. }
  180. }
  181. setting_data.hot_key=setting_hotkey.getElementsByTagName('select')[0].value;
  182. console.log(setting_data);
  183. setting=setting_data;
  184. set_setting(setting);
  185. setting_panel.outerHTML='';
  186. if(search_panel!=null){
  187. search_panel.outerHTML='';
  188. search_panel=null;
  189. }
  190. };
  191. setting_cancel.onclick=function(){setting_panel.outerHTML='';};
  192. }
  193.  
  194. function upload_file(data){
  195. if(xhr.readyState!=0)xhr.abort();
  196. xhr.onreadystatechange=function(){
  197. if(xhr.readyState==4){
  198. if(xhr.status==200){
  199. img_src=xhr.responseText;
  200. search_panel.getElementsByClassName('search_top_url')[0].style.marginTop='0px';
  201. search_panel.getElementsByClassName('search_top_url')[0].textContent='上传完成!';
  202. }
  203. }
  204. };
  205. xhr.upload.onprogress=function(event){search_panel.getElementsByTagName('progress')[0].value=event.loaded/event.total;};
  206. xhr.onerror=function(){alert('上传失败!');};
  207. var form=new FormData();
  208. xhr.open('POST','http://fh13121a.bget.ru/img/upload.php');
  209. form.append('imgdata',data);
  210. xhr.send(form);
  211. search_panel.getElementsByClassName('search_top_url')[0].style.marginTop='-48px';
  212. }
  213.  
  214. function get_clipboard(event){
  215. var items=event.clipboardData.items;
  216. if(items[items.length-1].type.indexOf('image')>=0)reader.readAsDataURL(items[items.length-1].getAsFile());
  217. }
  218.  
  219. document.addEventListener('mousedown',function(event){ // In order to fix a bug on Chrome Tampermonkey
  220. //document.onmousedown=function(event){
  221. console.log('Search Image >>\nevent.ctrlKey: '+event.ctrlKey+'\nevent.button: '+event.button+'\nevent.target.tagName: '+event.target.tagName+'\nevent.target.src: '+event.target.src+'\nevent.pageX: '+event.pageX+'\nevent.pageY: '+event.pageY+'\ndocument.documentElement.clientWidth: '+document.documentElement.clientWidth+'\ndocument.documentElement.clientHeight: '+document.documentElement.clientHeight+'\ndocument.documentElement.scrollWidth: '+document.documentElement.scrollWidth+'\ndocument.documentElement.scrollHeight: '+document.documentElement.scrollHeight+'\ndocument.documentElement.scrollLeft: '+document.documentElement.scrollLeft+'\ndocument.documentElement.scrollTop: '+document.documentElement.scrollTop);
  222. if(disable_contextmenu==true){
  223. document.oncontextmenu=null;
  224. disable_contextmenu=false;
  225. }
  226. if(event[setting.hot_key]==true&&event.button==2){
  227. if(search_panel==null)create_panel();
  228. else if(last_update!=GM_getValue('timestamp',0)){
  229. last_update=GM_getValue('timestamp',0)
  230. search_panel.outerHTML='';
  231. setting=GM_getValue('setting')?JSON.parse(GM_getValue('setting')):default_setting;
  232. create_panel();
  233. }
  234. else search_panel.style.display='block';
  235. search_panel.style.left=(document.documentElement.clientWidth+document.body.scrollLeft-event.pageX>=200?event.pageX:event.pageX>=200?event.pageX-200:0)+'px';
  236. search_panel.style.top=(document.documentElement.scrollHeight-event.pageY>=search_panel.scrollHeight?event.pageY:event.pageY>=search_panel.scrollHeight?event.pageY-search_panel.scrollHeight:0)+'px';
  237. disable_contextmenu=true;
  238. //for(var i=0;i<setting.site_option.length;i++)GM_openInTab(setting.site_list[setting.site_option[i]].replace(/\{%s\}/,encodeURIComponent(event.target.src)));
  239. document.oncontextmenu=function(){return false;};
  240. if(event.target.tagName.toLowerCase()=='img'&&event.target.src!=null){
  241. search_panel.getElementsByClassName('search_top_url')[0].style.marginTop='0px';
  242. search_panel.getElementsByClassName('search_top_url')[0].textContent=event.target.src;
  243. if(event.target.src.match(/^data:.*?;base64,/)!=null)upload_file(event.target.src);
  244. else img_src=event.target.src;
  245. }
  246. else{
  247. search_panel.getElementsByClassName('search_top_url')[0].style.marginTop='-24px';
  248. document.addEventListener('paste',get_clipboard,false);
  249. }
  250. }
  251. else{
  252. if(search_panel!=null&&(event.target.compareDocumentPosition(search_panel)==10||event.target.compareDocumentPosition(search_panel)==0)){
  253. if(event.target.className=='image-search-item'&&event.button==0&&img_src!=null){
  254. switch(event.target.getAttribute('search-option')){
  255. case 'all':
  256. for(var i=setting.site_option.length-1;i>=0;i--)GM_openInTab(setting.site_list[setting.site_option[i]].replace(/\{%s\}/,encodeURIComponent(img_src)));
  257. break;
  258. case 'setting':
  259. call_setting();
  260. break;
  261. default:
  262. GM_openInTab(setting.site_list[event.target.getAttribute('search-option')].replace(/\{%s\}/,encodeURIComponent(img_src)));
  263. }
  264. img_src=null;
  265. search_panel.style.display='none';
  266. document.removeEventListener('paste',get_clipboard,false);
  267. }
  268. }
  269. else{
  270. img_src=null;
  271. if(search_panel!=null)search_panel.style.display='none';
  272. document.removeEventListener('paste',get_clipboard,false);
  273. }
  274. }
  275. },false);
  276.  
  277. if(data_version!=2){
  278. if(data_version==0){
  279. alert('Notice:\nSearch By Image 已更新。\n由于添加了新的搜索引擎,我们重置了脚本的设置。如果您对脚本的设置进行过修改,请重新进行设置。\n对覆盖设置的行为,我们表示抱歉,同时感谢您的使用。');
  280. setting=default_setting;
  281. set_setting(default_setting);
  282. }
  283. alert('Notice:\n \nSearch By Image 已更新。\n脚本现已支持上传图片搜索和 base64 图片搜索(中转上传)。您可以在非图片区呼出搜索菜单,并通过以下操作搜索:\n > 点击“上传图片并搜索”并选择文件\n > 拖拽文件至菜单内\n > 按下 Ctrl + V 粘贴剪贴板内图片(暂不支持 Firefox,原因不明)');
  284. data_version=2;
  285. GM_setValue('version',2);
  286. }
  287.  
  288. GM_registerMenuCommand('Search By Image Setting',call_setting);