您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
redditに既読つけます。http://redd.it/2yrx0l
// ==UserScript== // @name Kidoku for Reddit // @namespace kidoku-for-reddit // @include http://www.reddit.com* // @include https://www.reddit.com* // @description redditに既読つけます。http://redd.it/2yrx0l // @version 0.505.5 // @grant none // ==/UserScript== var url = location.href; if( url.indexOf("http://www.reddit.com/tb/") != -1)return; if( url.indexOf("http://www.reddit.com/toolbar/") != -1)return; if( url.indexOf("https://www.reddit.com/live/") != -1)return; //プロトコルが別だとストレージも別になってしまうので移動 if( url.indexOf("http://") === 0){ location.href = "https://" + url.substring(7); return; } // 携帯版なら「読んだ」ボタンを埋め込んで終了 var timeForMobile = 0; if( url.indexOf(".compact") != -1 ){ if( document.body.getAttribute("class").indexOf("comments-page") == -1 )return; // コメントページ以外でも終了 timeForMobile = Math.floor(Date.now()/1000); var button = document.createElement("button"); button.innerHTML = "読んだ"; button.style.float = "right"; button.addEventListener("click", function(){ var sComment, c, count = 0; var temp = document.querySelectorAll(".title-button"); var temp2 = document.querySelectorAll("span.title"); if( temp[0] ){ sComment = temp[0].innerHTML; count = sComment.match(/\d+/); // コメントがすべて表示されていない場合 } else if( temp2[0] ){ sComment = temp2[0].innerHTML; count = sComment.match(/\d+/); // コメントがすべて表示されている場合 if(!count)count = 0; } else count = 0; count = parseInt(count); var json = { "count": count, "time": timeForMobile, }; var key = "kidoku_" + document.querySelectorAll("link[rel=shorturl]")[0].getAttribute("href").split("/")[3]; localStorage.setItem(key, JSON.stringify(json)); // 保存 button.style.display = "none"; }); document.querySelectorAll(".tabmenu")[0].appendChild( button ); return; } // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // URLからIDを取り出す var getKey = function(arglink){ var list = arglink.split("/"); var key = "kidoku_" + list[6]; // サブミID if(!list[6])return false; return key; }; // NEW!をクリックすると次へジャンプ var jumpNextNew = function(){ var targ, i; var list = document.querySelectorAll(".kidoku_new"); for(i = 0; i< list.length; i++){ if(list[i] == this)break; } targ = list[i+1] || list[0]; $('html, body').animate({ scrollTop: $( targ ).offset().top - 200 }, 200); }; // コメント数を開くときlimitを指定して開くボタン var popupLimit = { element: null, nowElement: null, setup:function(){ var div = document.createElement("DIV"); var button0 = document.createElement("BUTTON"); div.setAttribute("style", "display:block;position:absolute;width:60px;"); button0.setAttribute("style", "width:30px;height:15px;font-size:10px;padding:0px;"); button1 = button0.cloneNode(); button0.innerHTML = "50"; button1.innerHTML = "500"; div.appendChild( button0 ); div.appendChild( button1 ); this.element = div; // クリックで表示を消す document.body.addEventListener("click", function(){ if( !popupLimit.nowElement )return; popupLimit.nowElement.style.display = "none"; }); }, append: function( targetEl ){ var url = targetEl.getAttribute("href"); var bounds = targetEl.getBoundingClientRect(); var l = Math.max( document.body.scrollLeft, document.documentElement.scrollLeft); var t = Math.max( document.body.scrollTop, document.documentElement.scrollTop); var x = bounds.left + l; var y = bounds.bottom + t; if(this.nowElement)document.body.removeChild( this.nowElement ); var div = this.element.cloneNode(true); div.addEventListener("click", function(){ targetEl.parentNode.style.textDecoration = "line-through"; }); document.body.appendChild( div ); var buttons = div.querySelectorAll("button"); if(url.indexOf("?") == -1)url += "?"; buttons[0].addEventListener("click", function(){ window.open( url + "&limit=50"); }); buttons[1].addEventListener("click", function(){ window.open( url + "&limit=500"); }); div.style.left = x + "px"; div.style.top = y + "px"; this.nowElement = div; }, }; // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ソート // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ リストページの既読sort var submiList = []; // num, bKidoku, bSintyaku, node 既読スレのみ var sortKidoku = { sorted: false, sort : function (){ if(document.querySelectorAll(".thing.link, .thing.comment").length > submiList.length)listPageFunc(); // 全部取得できていなければ取得 sortedListSintyaku = []; sortedList = []; sortedListMidoku = []; var container = submiList[submiList.length-1].node.parentNode; var navi = document.querySelectorAll(".nav-buttons")[0]; if(this.sorted){ submiList.sort(function(a,b){ return(a.num>b.num)? 1 : -1; });// 元の順に戻す } else{ // 既読を上にソート for(var i = 0; i< submiList.length; i++){ if(submiList[i].bKidoku){ if(submiList[i].bSintyaku) sortedListSintyaku.push(submiList[i]); else sortedList.push(submiList[i]); } else sortedListMidoku.push(submiList[i]); } submiList = sortedListSintyaku.concat(sortedList, sortedListMidoku); } for(var i = 0; i< submiList.length; i++){ container.appendChild(submiList[i].node); } if(navi)container.appendChild(navi); this.sorted = !this.sorted; var sepalist = document.querySelectorAll(".NERPageMarker"); if(sepalist){ for(var i = 0; i < sepalist.length; i++){ sepalist[i].style.display = "none"; } } } }; // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ コメントページの新着2ソート var commentPage = { "commentArea":null, "pjson":null, "comments":[], // obj, time, num, nest, nestTime "sorted":false, "sorter":function(){ var box = this.commentArea.querySelectorAll(".sitetable")[0]; if(box.lastChild.getAttribute("class") == "clearleft")box.removeChild(box.lastChild); var last = box.lastChild; if(!this.sorted){ //新着2 this.comments.sort(function(a,b){ var x = a.nestTime || a.time; var y = b.nestTime || b.time; if( x > y ) return -1; else return 1 ; }); } else{ this.comments.sort(function(a,b){return(a.num>b.num)?1:-1;}); } for(var i = 0; i < this.comments.length; i++){ if(this.comments[i].nest)continue; box.appendChild(this.comments[i].obj); } if(last.getAttribute("class").indexOf("morechildren") != -1)box.appendChild(last); this.sorted = !this.sorted; } }; // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 長さが変わるかチェック。never ending reddit用。 var neverEnding = { pSubmiListLength: 0, waiting: false, checkTime: Date.now(), check: function(){ // マウスが動くと一秒に一回チェック if(!this.waiting){ this.checkTime = Date.now() + 1000; this.waiting = true; } else if(Date.now() > this.checkTime){ if(!commentPage.commentArea){ if(document.querySelectorAll(".thing.link, .thing.comment").length > submiList.length)listPageFunc(); } else if(document.querySelectorAll(".thing.comment").length > commentPage.comments.length){ commentFunc(); } this.waiting = false; } }, }; // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 読み込み時、エンドレスRESで表示数が伸びる度に使う関数 // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ コメントページにいろいろ追加してソート用に保存 var commentFunc = function(){ // 新着コメントを確認するため時間を確認 var commentElList = document.querySelectorAll(".thing.comment"); var newMark = function(){ if(timeEl.parentNode.lastChild.getAttribute("class") == "kidoku_new")return; var newEl = document.createElement("span"); newEl.innerHTML = "NEW!"; newEl.setAttribute("class", "kidoku_new"); newEl.setAttribute("style", "color:red; text-decoration:underline; cursor:pointer"); newEl.addEventListener("click",jumpNextNew ); timeEl.parentNode.appendChild(newEl); }; commentPage.comments = []; for(var i = commentPage.comments.length; i < commentElList.length; i++){ var timeEl = commentElList[i].querySelectorAll("time")[0]; var time = Date.parse(timeEl.getAttribute("datetime"))/1000; //入れ子の中ならtrue var nest = false; if(commentElList[i].parentNode.getAttribute("class") == "sitetable listing")nest = true; //一番外なら一番早い時間を取得 var nestTime = false; if(!nest){ var nestTimeElList = commentElList[i].querySelectorAll("time"); if(nestTimeElList.length != 1){ var array = []; for(var j = 0; j< nestTimeElList.length; j++){ array.push( Date.parse(nestTimeElList[j].getAttribute("datetime")) ); } nestTime = array.sort().reverse()[0]/1000; } } commentPage.comments.push({"obj":commentElList[i], "time":time, "num": i, "nest":nest, "nestTime":nestTime }); if(commentPage.pjson){ var jsonobj = JSON.parse(commentPage.pjson); if(jsonobj.time < time)newMark();// 印をつける } else newMark(); } }; // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ リストページにいろいろ追加してソート用に保存 var listPageFunc = function(){ popupLimit.setup(); var temp = document.querySelectorAll(".first"); var linklist = []; for(var i = 0; i< temp.length; i++){ var el = temp[i].querySelectorAll(".may-blank")[0]; if(el)linklist.push( el ); } var submiNodeList = document.querySelectorAll(".thing.link, .thing.comment");//既読ソート用 for(var i = neverEnding.pSubmiListLength; i< linklist.length ; i++ ){ //既読コメント数をストレージから取得 var value = null; var key = getKey(linklist[i].getAttribute("href")); var json = localStorage.getItem(key); if(json){ var obj = JSON.parse(json); value =obj.count; } //ソート用 var subm ={ num:i, node:submiNodeList[i], bKidoku:false, bSintyaku:false }; submiList.push(subm); // 現在のコメント数と比べて増えていれば赤線を引く if(value !== null){ subm.bKidoku = true; var element = document.createElement('span'); element.innerHTML = "既読" + value + "/" ; linklist[i].parentNode.insertBefore(element, linklist[i]); linklist[i].parentNode.style.borderBottom = "1px solid gray"; var nowValue = linklist[i].innerHTML.match(/\d+/); value = parseInt(value); nowValue = parseInt(nowValue); if( !nowValue ); else if(nowValue <= value); else{ subm.bSintyaku = true; linklist[i].parentNode.style.borderBottom = "1px solid red"; } } linklist[i].setAttribute("target", "_blank"); // key にすればターゲット固定 // ベストで開いたりnewで開いたり var addLink = function( txt, type ){ var link = linklist[i].cloneNode(); link.innerHTML = txt; link.setAttribute("href", link.getAttribute("href") + type ); linklist[i].parentNode.appendChild( link ); link.addEventListener( "mouseover", function( event ){ popupLimit.append( event.target ); }); }; addLink(" best", "?sort=confidence" ); addLink(" new", "?sort=new" ); addLink(" 小", ".compact?sort=new" ); // 削除したり if( subm.bKidoku ){ var delf = (function() { var key2 = key; return function(){ localStorage.removeItem(key2); }; })(); var delkey = document.createElement("button"); delkey.innerHTML = "del"; delkey.setAttribute("style", "margin:0px 0px 0px 10px; padding:0px;max-height:15px; vertical-align:bottom; font-size:12px; line-height:100%;"); delkey.addEventListener("click", delf); linklist[i].parentNode.appendChild(delkey); } // クリックイベントで雑に打ち消し線をつける var f = (function() { var ii = i; return function(){ linklist[ii].parentNode.style.textDecoration = "line-through"; }; })(); linklist[i].parentNode.addEventListener("click",f); } neverEnding.pSubmiListLength = submiList.length; }; // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 以下読み込み時に一度 // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ var bSearchPage = false, bCommentsPage = false; var pageTypeCss = document.body.getAttribute("class"); if( pageTypeCss ){ if( pageTypeCss.indexOf("search-page") != -1 )bSearchPage = true; if( pageTypeCss.indexOf("comments-page") != -1 )bCommentsPage = true; //if(document.body.getAttribute("class").indexOf("related-page") != -1)return; } if( bCommentsPage ){ // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ コメントページの場合 commentPage.commentArea = document.querySelectorAll(".commentarea")[0]; var key = getKey(url); commentPage.pjson = localStorage.getItem(key); document.body.addEventListener("mousemove", neverEnding.check); commentFunc(); // 既読コメント数と時間をストレージに保存 var setStorage = function (postComment){ if(key){ var sComment = document.querySelectorAll(".comments.may-blank")[0].innerHTML; var count = sComment.match(/\d+/); if(count === null)count = 0; count = parseInt( count ); var json = { "count": count, "time": Math.floor(Date.now()/1000), }; localStorage.setItem(key, JSON.stringify(json)); } }; setStorage(false); // 新着ソートボタン var newElem = document.createElement("button"); newElem.setAttribute("style", "margin:10px 5px 0px 0px; padding:0px; width: 60px;vertical-align:bottom; font-size:11px; line-height:100%;"); newElem.innerHTML = "新着2"; newElem.addEventListener("click", function(){ commentPage.sorter(); if(this.innerHTML == "新着2")this.innerHTML = "戻す"; else this.innerHTML = "新着2"; }); var drop = document.querySelectorAll(".dropdown-title.lightdrop")[0]; drop.parentNode.appendChild(newElem); // ニューにジャンプ if(document.querySelectorAll(".kidoku_new")[0]){ var newEl = document.createElement("span"); newEl.innerHTML = "NEW!へジャンプ"; newEl.setAttribute("style", "color:red; text-decoration:underline; cursor:pointer; font-size:11px"); newEl.addEventListener("click",jumpNextNew ); drop.parentNode.appendChild(newEl); } } else if( document.querySelectorAll(".first")[1] ){ // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ リストページの場合 listPageFunc(); document.body.addEventListener("mousemove", neverEnding.check); function setTabButton( button ){ if( !bSearchPage ){ var tab1 = document.querySelectorAll(".tabmenu > li")[0]; tab1.parentNode.insertBefore( button , tab1); } else document.querySelectorAll(".menuarea")[0].appendChild(button); } // 既読ソートボタン var newElem = document.createElement("button"); newElem.setAttribute("style", "font-size:11px;line-height:100%;padding:0px;max-height:15px;min-width:65px; vertical-align:bottom;"); newElem.innerHTML = "既読sort"; newElem.addEventListener("click",function(){ sortKidoku.sort(); if(this.innerHTML == "既読sort")this.innerHTML = "戻す"; else this.innerHTML = "既読sort"; }); setTabButton( newElem ); } // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 全ページ // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 右上 既読 最近開いたスレをリストで開く var getRecentButton = document.createElement("span"); getRecentButton.innerHTML = " 既読"; getRecentButton.style.cursor = "pointer"; getRecentButton.addEventListener("mouseup", function(event){ var array =[], idnames = ""; for(var i = localStorage.length-1 ; i > 0; i--){ var k = localStorage.key(i); if(k.indexOf("kidoku_") === 0){ array.push( { time:JSON.parse(localStorage[k]).time, key:k.split("kidoku_")[1] } ); } } array.sort(function(a,b){return (a.time < b.time)? 1: -1;}); for(var i = 0; i < array.length; i++){ idnames += "t3_" + array[i].key + ","; if (idnames.length > 5000)break; // 多すぎると拒否される?ので500スレ分くらいだけにする } if( event.button === 0 )location.href = "https://www.reddit.com/by_id/" + idnames; else if( event.button == 2 )setTimeout(function(){alert( array.length + "記憶中" );},1); else if( event.button == 1 || true )window.open( "https://www.reddit.com/by_id/" + idnames ); event.preventDefault(); }); var topbar = document.querySelector("#header-bottom-right"); //if( !topbar )topbar = document.body; if( topbar )topbar.appendChild( getRecentButton ); // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 下部 削除ボタン var s = document.querySelectorAll(".bottommenu")[0]; if(s){ var newElem = document.createElement("button"); newElem.innerHTML = "削除"; newElem.style.margin = "10px 0px"; var inputEl = document.createElement("input"); inputEl.setAttribute("type", "number"); inputEl.setAttribute("id", "kidoku_delete_day"); inputEl.setAttribute("style", "text-align:right;width:40px;"); inputEl.setAttribute("value", "0"); s.parentNode.appendChild(inputEl); s.parentNode.appendChild(document.createTextNode("日以上前の既読履歴を")); s.parentNode.appendChild(newElem); newElem.addEventListener("click", function(){ var day = document.querySelector("#kidoku_delete_day").value; var pDay = Math.floor( ( Date.now() - (day * 24 * 60 * 60 * 1000) ) / 1000); var delCount = 0; var count = 0; if(window.confirm( "既読データを消します" )){ for(var i = localStorage.length-1 ; i > 0; i--){ var k = localStorage.key(i); if(k.indexOf("kidoku_") === 0){ count++; if(JSON.parse(localStorage[k]).time < pDay){ delCount++; localStorage.removeItem(k); } } } alert(delCount + "/" + count + "削除しました"); } }); }