KKRdQFBU

Imgur Stamp Menu

Jan 13th, 2016
1,064
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. // ==UserScript==
  2. // @name        Imgur Stamp Menu
  3. // @author      https://www.reddit.com/u/KKRdQFBU/
  4. // @copyright   Copyright (c) 2016 KKRdQFBU
  5. // @license     MIT License - https://osdn.jp/projects/opensource/wiki/licenses%2FMIT_license
  6. // @include     https://www.reddit.com/r/lowlevelaware/comments/*
  7. // @version     16.01.13
  8. // @grant       GM_setValue
  9. // @grant       GM_getValue
  10. // @grant       GM_listValues
  11. // @grant       GM_deleteValue
  12. // ==/UserScript==
  13.  
  14. //スタンプを読み込む最大個数, スペックに応じて増減してね
  15. var max_stamp = 1000;
  16. //サムネをキャッシュする場合はtrue, しない場合はfalse
  17. var cache_thumbnail = false;
  18.  
  19. var req_list = [];
  20. var def_img = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAAAAAA6fptVAAAACklEQVQIHWP4DwABAQEANl9ngAAAAABJRU5ErkJggg==";
  21. var utb = document.querySelectorAll(".usertext-buttons");
  22. if(utb[0]){ ISM_init(); }
  23.  
  24. //現在のサブレ名をURLから取得(LLLならlowlevelaware, ばかにゅ~ならBakaNewsJP
  25. function SubRedditName(){
  26.     return window.location.href.match(/.*reddit\.com\/r\/(.*?)\/.*/)[1];
  27. }
  28. //https://www.reddit.com/r/<現在のサブレ名>/wiki/imgurstamp.jsonを返す
  29. function StamplistURL(){
  30.     return "https://www.reddit.com/r/"+SubRedditName()+"/wiki/imgurstamp.json";
  31. }
  32.  
  33. //キャッシュを全部削除
  34. function deleteValueAll(){
  35.     ret = confirm("キャッシュをすべて削除しますか?");
  36.     if(ret != true){ return; }
  37.     var list = GM_listValues();
  38.     for(var i = 0;i < list.length;i++){
  39. //      console.log("delete: "+list[i]);
  40.         GM_deleteValue(list[i]);
  41.     }
  42. }
  43.  
  44. //urlを分解して画像IDを抽出, キャッシュに有ればbase64で返す
  45. //無い場合は非同期で取得を開始してurlをそのまま返す
  46. function GetThumbnail(url){
  47.     if(!cache_thumbnail){return url;}
  48.     var thum = GM_getValue(URL2ID(url));
  49.     if(typeof(thum) == "undefined"){
  50. //      console.log("no cached: "+URL2ID(url));
  51.         var idx = CreateXHR();
  52.         var req = req_list[idx][0];
  53.         req.overrideMimeType("text/plain; charset=x-user-defined");
  54.         req.open("GET",url,true);
  55.         req.onreadystatechange = function(){ var arg0 = arguments[0]; var arg1 = arguments[1]; return function() { ReceiveThumbnail(arg0,arg1); }; }(idx,URL2ID(url));
  56.         req.send(null);
  57.         return url;
  58.     }
  59. //  else{
  60. //      console.log("chached: "+URL2ID(url));
  61. //  }
  62.     return thum;
  63. }
  64. //受信したサムネをbase64に変換
  65. function ThumnailToBase64(raw){
  66. //  console.log(raw.length);
  67.     var bytes = [];
  68.     for(var i = 0;i < raw.length;i++){
  69.         bytes[i] = raw.charCodeAt(i) & 0xFF;
  70.     }
  71.     var bin_data = String.fromCharCode.apply(String,bytes);
  72.     var base64 = btoa(bin_data);
  73.     var header = bin_data.substring(0,9);
  74.     var ext;
  75.     var img;
  76.     if(header.match(/^\x89PNG/)){ ext = "png";}
  77.     else if(header.match(/^BM/)){ ext = "bmp"; }
  78.     else if(header.match(/^GIF87a/) || header.match(/^GIF89a/)){ ext = "gif"}
  79.     else if(header.match(/^\xFF\xD8/)){ ext = "jpeg"; }
  80.     else{ ext = false; }
  81.  
  82.     if(ext != false){ img = "data:image/"+ ext +";base64,"+ base64; }
  83.     else{ img = def_img }
  84.  
  85.     return img;
  86. }
  87. //サムネデータ受信callback, base64エンコードしてキャッシュし、<img>のsrcを差し替える
  88. function ReceiveThumbnail(idx,id){
  89.     var req = req_list[idx][0];
  90.     if(req.readyState == 4){
  91.         var img;
  92.         if(req.status == 200){
  93.             var raw = req.responseText;
  94.             req_list[idx][1] = false;
  95.             img = ThumnailToBase64(raw);
  96.             GM_setValue(id,img);
  97.         }else{
  98.             img = def_img;
  99.         }
  100.         document.getElementById("ISM_"+id).src = img;
  101.     }
  102. }
  103.  
  104. //[0]にurl、[1]にurlをサムネURLにした物を追加して配列で返す
  105. function GetThumbnailURLs(url){
  106.     return [url,"https://i.imgur.com/"+ URL2ID(url) +"s."+url.match(/.*\.(.*)/)[1]];
  107. }
  108.  
  109. //imgurURLのID部を返す, http://i.imgur.com/VfsdF9Ls.jpg なら"VfsdF9L"
  110. function URL2ID(url){
  111.     return url.match(/.*imgur\.com\/([A-Za-z0-9]{7,8})\..*/)[1].substring(0,7);
  112. }
  113.  
  114. //空いているreq_listのインデックスを返す, [i][1]がfalseなら使用可能
  115. function GetNewRequestIndex(){
  116.     for (var i = 0; i < req_list.length; i++) {
  117.         if(req_list[i][1] == false){return i;}
  118.     };
  119.     return req_list.length;
  120. }
  121.  
  122. //空いているreq_listにXHRを生成してそのインデックスを返す
  123. function CreateXHR(){
  124.     var idx = GetNewRequestIndex();
  125. //  console.log("CreateXHR: "+idx);
  126.     req_list[idx] = [];
  127.     req_list[idx][0] = new XMLHttpRequest();
  128.     req_list[idx][1] = true;
  129.     return idx;
  130. }
  131.  
  132. //wikiのスタンプリストを持ってくる
  133. function UpdateMenu(){
  134.     var idx = CreateXHR();
  135.     var req = req_list[idx][0];
  136.     req.open("GET",StamplistURL(),true);
  137.     req.onreadystatechange = function(){ var idx = arguments[0]; return function() { ReceiveStampList(idx); }; }(idx);
  138.     req.send(null);
  139. }
  140.  
  141. //スタンプリスト受信callback, 取得したjsonをキャッシュしてからGenerateMenuへ渡す
  142. function ReceiveStampList(idx){
  143.     var req = req_list[idx][0];
  144.     if(req.readyState == 4 && req.status == 200){
  145.         var json_text = req.responseText;
  146.         GM_setValue(SubRedditName()+"@imgurstamp.json",json_text);
  147.         req_list[idx][1] = false;
  148.         GenerateMenu(json_text);
  149.     }
  150. }
  151.  
  152. //.ISM_listの中身を全部削除
  153. function removeListAll(){
  154.     var list = document.querySelector(".ISM_list");
  155.     for(var i = list.childNodes.length-1;i >= 0;i--){
  156.         list.removeChild(list.childNodes[i]);
  157.     }
  158. }
  159. //stringのjson_textを元にメニュー化する
  160. //とりあえずすべての"i.imgur.com"のURLを抽出
  161. function GenerateMenu(json_text){
  162.     var raw = JSON.parse(json_text)["data"]["content_md"];
  163.     var m = raw.match(/(http.*i\.imgur\.com\/.*\.[A-Za-z0-9]*)/g);
  164.     var imgur_list = [];
  165.     var stamp = [];
  166.     removeListAll();
  167.     var list = document.querySelector(".ISM_list");
  168. //  console.log(m.length);
  169.     for (var i = 0; i < m.length && i < max_stamp; i++) {
  170.         var img = GetThumbnailURLs(m[i]);
  171.         stamp[i] = document.createElement("img");
  172.         stamp[i].id     = "ISM_"+URL2ID(img[0]);
  173.         stamp[i].width  = 90;
  174.         stamp[i].height = 90;
  175.         stamp[i].title  = img[0];
  176.         stamp[i].href   = stamp[i].title;
  177.         stamp[i].src    = GetThumbnail(img[1]);
  178.         stamp[i].style  = "display: inline;margin: 2px;";
  179.         stamp[i].setAttribute("onclick","ISM_func(this,3);return false;");
  180.         list.appendChild(stamp[i]);
  181.     };
  182. }
  183.  
  184. //初期化
  185. function ISM_init(){
  186.     var btn = [];
  187.     btn[0] = document.createElement("button");
  188.     btn[0].className = "ISM_stmp";
  189.     btn[0].textContent = "istmp";
  190.     btn[0].setAttribute("onclick","ISM_func(this,1);return false;");
  191.     utb[0].appendChild(btn[0]);
  192.     for(var i = 1;i < utb.length;i++){
  193.         btn[i] = btn[0].cloneNode(1);
  194.         btn[i].setAttribute("onclick","ISM_func(this,1);return false;");
  195.         utb[i].appendChild(btn[i]);
  196.     }
  197.  
  198.     var menu = document.createElement("div");
  199.     menu.className = "ISM_menu ISM_hide";
  200.     menu.title = "ISM "+ GM_info.script.version;
  201.     menu.setAttribute("onclick","ISM_func(this,2);return false;");
  202.  
  203.     var style = document.createElement("style");
  204.     style.textContent =  ".ISM_menu{zoom:.8;z-index:99;overflow-y:scroll;position:fixed;top:0;right:0;bottom:0;left:0;background:#888;opacity:.8;padding:40px;}";
  205.     style.textContent += ".ISM_hide{display:none;}.ISM_target{opacity:0.5;}";
  206.     style.className = "ISM_style";
  207.     menu.appendChild(style);
  208.  
  209.     btn_ud = document.createElement("button");
  210.     btn_ud.className = "ISM_";
  211.     btn_ud.textContent = "更新";
  212.     btn_ud.title = "スタンプリストを更新";
  213.     btn_ud.addEventListener("click",function(){UpdateMenu();return false;});
  214.     menu.appendChild(btn_ud);
  215.  
  216.     var script = document.createElement("script");
  217.     script.type = "text/javascript";
  218.     script.textContent = function ISM_func(_this_,_type_){
  219.         if(1 == _type_){
  220.             document.querySelector(".ISM_menu").classList.remove("ISM_hide");
  221.             _this_.parentNode.parentNode.parentNode.querySelector("textarea").classList.add("ISM_target");
  222.         }else if(2 == _type_){
  223.             document.querySelector(".ISM_menu").classList.add("ISM_hide");
  224.             document.querySelector(".ISM_target").classList.remove("ISM_target");
  225.         }else if(3 == _type_){
  226.             document.querySelector(".ISM_target").value += _this_.title;
  227.         }
  228.     }.toString();
  229.     menu.appendChild(script);
  230.  
  231.     var list = document.createElement("div");
  232.     list.className = "ISM_list";
  233.     menu.appendChild(list);
  234.  
  235.     btn_del = document.createElement("button");
  236.     btn_del.className = "ISM_delcache";
  237.     btn_del.textContent = "キャッシュを削除";
  238.     btn_del.title = "基本的に使わなくていいと思う";
  239.     btn_del.addEventListener("click",function(){deleteValueAll();return false;});
  240.     menu.appendChild(btn_del);
  241.  
  242.     document.body.appendChild(menu);
  243.  
  244.     //前回取得したjsonデータを読み込む
  245.     json_text = GM_getValue(SubRedditName()+"@imgurstamp.json");
  246.     if(typeof(json_text) == "undefined"){//ない場合は取得
  247.         UpdateMenu();
  248.     }else{
  249.         GenerateMenu(json_text);
  250.     }
  251. }
  252.  
  253. //// script-end ////
Add Comment
Please, Sign In to add comment