您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
赤福Firefox版で自動更新しちゃう(実況モードもあるよ!)
当前为
- // ==UserScript==
- // @name futaba auto reloader
- // @namespace https://github.com/himuro-majika
- // @description 赤福Firefox版で自動更新しちゃう(実況モードもあるよ!)
- // @author himuro_majika
- // @include http://*.2chan.net/*/res/*
- // @include https://*.2chan.net/*/res/*
- // @include http://board.futakuro.com/*/res/*
- // @require http://ajax.googleapis.com/ajax/libs/jquery/2.0.3/jquery.min.js
- // @version 1.8.0
- // @grant GM_addStyle
- // @grant GM_xmlhttpRequest
- // @license MIT
- // @icon data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAAPUExURYv4i2PQYy2aLUe0R////zorx9oAAAAFdFJOU/////8A+7YOUwAAAElJREFUeNqUj1EOwDAIQoHn/c88bX+2fq0kRsAoUXVAfwzCttWsDWzw0kNVWd2tZ5K9gqmMZB8libt4pSg6YlO3RnTzyxePAAMAzqMDgTX8hYYAAAAASUVORK5CYII=
- // ==/UserScript==
- this.$ = this.jQuery = jQuery.noConflict(true);
- (function ($) {
- /*
- * 設定
- */
- var USE_SOUDANE = true; //そうだねをハイライト表示する
- var USE_CLEAR_BUTTON = true; //フォームにクリアボタンを表示する
- var USE_TITLE_NAME = true; //新着レス数・スレ消滅状態をタブに表示する
- var RELOAD_INTERVAL_NORMAL = 60000; //リロード間隔[ミリ秒](通常時)
- var RELOAD_INTERVAL_LIVE = 5000; //リロード間隔[ミリ秒](実況モード時)
- var LIVE_SCROLL_INTERVAL = 12; //実況モードスクロール間隔[ミリ秒]
- var LIVE_SCROLL_SPEED = 2; //実況モードスクロール幅[px]
- var LIVE_TOGGLE_KEY = "76"; //実況モードON・OFF切り替えキーコード(With Alt)
- var SHOW_NORMAL_BUTTON = true; //通常モードボタンを表示する
- var USE_NOTIFICATION_DEFAULT = false; // 新着レスの通知をデフォルトで有効にする
- var USE_SAVE_MHT = false; // スレ消滅時にMHTで保存する
- var res = 0; //新着レス数
- var timerNormal, timerLiveReload, timerLiveScroll, timerSoudane;
- var url = location.href;
- var script_name = "futaba_auto_reloader";
- var isWindowActive = true; // タブのアクティブ状態
- var isNotificationEnable = USE_NOTIFICATION_DEFAULT; // 通知の有効フラグ
- var normal_flag = true; //通常モード有効フラグ
- var live_flag = false; //実況モード有効フラグ
- if(!isFileNotFound()){
- setNormalReload();
- }
- soudane();
- makeFormClearButton();
- reset_title();
- make_live_button();
- addCss();
- setWindowFocusEvent();
- observeInserted();
- showFindNextThread();
- //通常リロード開始
- function setNormalReload() {
- timerNormal = setInterval(rel, RELOAD_INTERVAL_NORMAL);
- console.log(script_name + ": Start auto reloading @" + url);
- }
- //通常リロード停止
- function clearNormalReload() {
- clearInterval(timerNormal);
- console.log(script_name + ": Stop auto reloading @" + url);
- }
- /*
- * 404チェック
- */
- function isFileNotFound() {
- if(document.title == "404 File Not Found") {
- return true;
- }
- else {
- return false;
- }
- }
- /*
- * ボタン作成
- */
- function make_live_button() {
- //通常モードボタン
- var $normalButton = $("<a>", {
- id: "GM_FAR_relButton_normal",
- class: "GM_FAR_relButton",
- text: "[通常]",
- title: (RELOAD_INTERVAL_NORMAL / 1000) + "秒毎のリロード",
- css: {
- cursor: "pointer",
- "background-color": "#ea8",
- },
- click: function() {
- toggleNormalMode();
- }
- });
- //実況モードボタン
- var $liveButton = $("<a>", {
- id: "GM_FAR_relButton_live",
- class: "GM_FAR_relButton",
- text: "[実況(Alt+" + String.fromCharCode(LIVE_TOGGLE_KEY) + ")]",
- title: (RELOAD_INTERVAL_LIVE / 1000) + "秒毎のリロード + スクロール",
- css: {
- cursor: "pointer",
- },
- click: function() {
- liveMode();
- }
- });
- // 通知ボタン
- var $notificationButton = $("<a>", {
- id: "GM_FAR_notificationButton",
- text: "[通知]",
- title: "新着レスのポップアップ通知",
- css: {
- cursor: "pointer",
- },
- click: function() {
- toggleNotification();
- }
- });
- if (isNotificationEnable) {
- $notificationButton.css("background-color", "#a9d8ff");
- }
- var $input = $("input[value$='信する']");
- $input.after($notificationButton);
- $input.after($liveButton);
- if(SHOW_NORMAL_BUTTON){
- $input.after($normalButton);
- }
- //実況モードトグルショートカットキー
- window.addEventListener("keydown",function(e) {
- if ( e.altKey && e.keyCode == LIVE_TOGGLE_KEY ) {
- liveMode();
- }
- }, false);
- /*
- * 通常モード切り替え
- */
- function toggleNormalMode() {
- if(normal_flag) {
- clearNormalReload();
- $normalButton.css("background" , "none");
- normal_flag = false;
- } else {
- setNormalReload();
- $normalButton.css("background-color" , "#ea8");
- normal_flag = true;
- }
- }
- /*
- * 通知切り替え
- */
- function toggleNotification() {
- if(isNotificationEnable) {
- $notificationButton.css("background" , "none");
- isNotificationEnable = false;
- } else {
- Notification.requestPermission(function(result) {
- if (result == "denied") {
- $notificationButton.attr("title",
- "通知はFirefoxの設定でブロックされています\n" +
- "ロケーションバー(URL)の左のアイコンをクリックして\n" +
- "「サイトからの通知の表示」を「許可」に設定してください");
- return;
- } else if (result == "default") {
- console.log("default");
- return;
- }
- $notificationButton.attr("title", "新着レスのポップアップ通知");
- $notificationButton.css("background-color" , "#a9d8ff");
- isNotificationEnable = true;
- });
- }
- }
- }
- /*
- * 実況モード
- * 呼出ごとにON/OFFトグル
- */
- function liveMode() {
- var live_button = $("#GM_FAR_relButton_live");
- if (!live_flag) {
- //実況モード時リロード
- timerLiveReload = setInterval(rel_scroll, RELOAD_INTERVAL_LIVE);
- //自動スクロール
- timerLiveScroll = setInterval(live_scroll, LIVE_SCROLL_INTERVAL);
- live_button.css("backgroundColor", "#ffa5f0");
- startspin();
- console.log(script_name + ": Start live mode @" + url);
- live_flag = true;
- } else {
- clearInterval(timerLiveReload);
- clearInterval(timerLiveScroll);
- live_button.css("background", "none");
- stopspin();
- console.log(script_name + ": Stop live mode @" + url);
- live_flag = false;
- }
- //リロード+新着スクロール
- function rel_scroll() {
- $('html, body').animate(
- {scrollTop:window.scrollMaxY},"fast"
- );
- rel();
- }
- function live_scroll() {
- window.scrollBy( 0, LIVE_SCROLL_SPEED );
- }
- function startspin() {
- $("#akahuku_throp_menu_opener").css(
- "animation", "spin 2s infinite steps(8)"
- );
- }
- function stopspin() {
- $("#akahuku_throp_menu_opener").css(
- "animation", "none"
- );
- }
- }
- /*
- * 新着レスをリセット
- */
- function reset_title() {
- //ページ末尾でホイールダウンした時
- window.addEventListener("DOMMouseScroll",function scroll(event) {
- var window_y = Math.ceil(window.scrollY);
- var window_ymax = window.scrollMaxY;
- if (event.detail > 0 && window_y >= window_ymax) {
- reset_titlename();
- }
- return;
- } ,false);
- //F5キー押された時
- window.addEventListener("keydown",function(e) {
- if ( e.keyCode == "116" ) {
- reset_titlename();
- }
- }, false);
- function reset_titlename() {
- res = 0;
- var title_char = title_name();
- document.title = title_char;
- }
- }
- /**
- * 赤福の続きを読むボタンをクリック
- */
- function rel() {
- if(isAkahukuNotFound()) {
- return;
- }
- var relbutton = $("#akahuku_reload_button").get(0);
- if(relbutton){
- var e = document.createEvent("MouseEvents");
- e.initEvent("click", false, true);
- relbutton.dispatchEvent(e);
- }
- setTimeout(function(){
- soudane();
- if (!isWindowActive && isNotificationEnable) {
- getNewResContent();
- }
- if(isAkahukuNotFound()) {
- //404時
- if (live_flag) {
- liveMode();
- }
- changeTitleWhenExpired();
- clearNormalReload();
- if (USE_SAVE_MHT) {
- saveMHT();
- }
- findNextThread();
- console.log(script_name + ": Page not found, Stop auto reloading @" + url);
- }
- }, 1000);
- }
- /**
- * MHTで保存
- */
- function saveMHT() {
- var saveMHTButton = $("#akahuku_throp_savemht_button").get(0);
- if (saveMHTButton) {
- var e = document.createEvent("MouseEvents");
- e.initEvent("click", false, true);
- saveMHTButton.dispatchEvent(e);
- }
- }
- /*
- * そうだねの数に応じてレスを着色
- */
- function soudane() {
- if ( !USE_SOUDANE ) return;
- clearTimeout(timerSoudane);
- timerSoudane = setTimeout(function() {
- var coloredNode = $(".rtd[style]");
- coloredNode.each(function() {
- $(this).removeAttr("style");
- });
- $("td > .sod").each(function(){
- var sodnum = $(this).text().match(/\d+/);
- if (sodnum){
- var col = "rgb(180, 240," + (Math.round(10 * sodnum + 180)) + ")";
- $(this).parent().css("background-color", col);
- }
- });
- }, 100);
- }
- // 続きを読むで挿入される要素を監視
- function observeInserted() {
- var target = $(".thre").length ?
- $(".thre").get(0) :
- $("html > body > form[action]:not([enctype])").get(0);
- var observer = new MutationObserver(function(mutations) {
- soudane();
- mutations.forEach(function(mutation) {
- var $nodes = $(mutation.addedNodes);
- replaceNodeInserted($nodes);
- });
- });
- observer.observe(target, { childList: true });
- }
- // 挿入されたレス
- function replaceNodeInserted($nodes) {
- var insertedRes = $nodes.find(".rtd");
- if( insertedRes.length ) {
- changetitle();
- }
- }
- /*
- * タブタイトルに新着レス数・スレ消滅状態を表示
- */
- function changetitle() {
- if ( !USE_TITLE_NAME ) return;
- var title_char = title_name();
- if (isAkahukuNotFound()) return;
- res++;
- document.title = "(" + res + ")" + title_char;
- }
- function changeTitleWhenExpired() {
- if (!isAkahukuNotFound()) return;
- if(document.title.substr(0,1) !== "#"){
- document.title = "#" + document.title;
- }
- }
- // 新着レスの内容を取得
- function getNewResContent() {
- var $newrestable = $("#akahuku_new_reply_header ~ table:not([id])");
- if ($newrestable.length) {
- var restexts = [];
- $newrestable.each(function() {
- var texts = [];
- $(this).find("blockquote").contents().each(function() {
- if ($(this).text() !== "") {
- texts.push($(this).text());
- }
- });
- restexts.push(texts.join("\r\n"));
- });
- var popupText = restexts.join("\r\n===============\r\n");
- showNotification(popupText);
- }
- }
- /*
- * 赤福のステータスからスレ消滅状態をチェック
- */
- function isAkahukuNotFound() {
- var statustext = $("#akahuku_reload_status").text();
- if (statustext.match(/(No Future)|((M|N)ot Found)/)) {
- return true;
- }
- else {
- return false;
- }
- }
- function title_name() {
- var title = document.title;
- var title_num = title.match(/^(#|\(\d+\))/);
- var title_num_length;
- if(!title_num){
- title_num_length = 0;
- }
- else {
- title_num_length = title_num[0].length;
- }
- var act_title_name = title.substr(title_num_length);
- return act_title_name;
- }
- function makeFormClearButton() {
- if ( USE_CLEAR_BUTTON ) {
- var $formClearButton = $("<div>", {
- id: "formClearButton",
- text: "[クリア]",
- css: {
- cursor: "pointer",
- margin: "0 5px"
- },
- click: function() {
- clearForm();
- }
- });
- var $comeTd = $(".ftdc b:contains('コメント')");
- $comeTd.after($formClearButton);
- }
- function clearForm() {
- $("#ftxa").val("");
- }
- }
- function addCss() {
- GM_addStyle(
- "@keyframes spin {" +
- " 0% { transform: rotate(0deg); }" +
- " 100% { transform: rotate(359deg); }" +
- "}"
- );
- }
- // タブのアクティブ状態を取得
- function setWindowFocusEvent() {
- $(window).bind("focus", function() {
- // タブアクティブ時
- isWindowActive = true;
- }).bind("blur", function() {
- // タブ非アクティブ時
- isWindowActive = false;
- });
- }
- // 新着レスをポップアップでデスクトップ通知する
- function showNotification(body) {
- Notification.requestPermission();
- var icon = $("#akahuku_thumbnail").attr("src");
- var instance = new Notification(
- document.title, {
- body: body,
- icon: icon,
- }
- );
- }
- /**
- * 次スレ候補検索ボタン表示
- */
- function showFindNextThread() {
- $("body").append(
- $("<div>", {
- id: "GM_FAR_next_thread_area",
- class: "GM_FAR"
- }).append(
- $("<div>").append(
- $("<a>", {
- id: "GM_FAR_find_next_thread",
- class: "GM_FAR_Button",
- text: "[次スレ候補検索]",
- css: {
- cursor: "pointer",
- "font-size": "9pt"
- },
- click: function() {
- findNextThread();
- }
- }),
- $("<span>", {
- id: "GM_FAR_next_thread_search_result",
- css: {
- "display": "none",
- "font-size": "9pt"
- }
- }).append(
- $("<span>", {
- text: "検索結果:",
- }),
- $("<span>", {
- id: "GM_FAR_next_thread_search_result_count",
- text: "0"
- })
- )
- ),
- $("<ul>", {
- "id": "GM_FAR_next_thread_found"
- }).append(
- $("<span>", {
- id: "GM_FAR_next_thread_search_status",
- text: "次スレ候補検索中...",
- css: {
- "display": "none"
- }
- })
- )
- )
- )
- }
- /**
- * 次スレ候補検索
- */
- function findNextThread() {
- var foundList = $("#GM_FAR_next_thread_found");
- foundList.empty()
- var statusMessage = $("#GM_FAR_next_thread_search_status")
- statusMessage.show();
- var dir = location.href.substr(0, location.href.lastIndexOf('/') - 3);
- var threadTitle = $("#akahuku_thread_text").text().substr(0, 4);
- var catalogURL = dir + "futaba.php?mode=cat&sort=1"
- var resultCount = 0;
- GM_xmlhttpRequest({
- method: "GET",
- url: catalogURL,
- onload: function(res) {
- statusMessage.hide();
- var catalog = $($.parseHTML(res.response));
- var cattable = catalog.filter("#cattable");
- var td = cattable.find("td small");
- td.each(function() {
- var tdText = $(this).text()
- if( tdText.substr(0, 4) == threadTitle) {
- resultCount++;
- var foundThread = $(this).parent().find("a");
- var foundThreadResCount = $(this).parent().find("font").text();
- var href = foundThread.attr("href");
- foundThread.attr("href", dir + href);
- foundList.append(
- $("<li>").append(
- $(this),
- $("<span>", {
- text: foundThreadResCount + "レス",
- css: {
- "margin-left": "2em"
- }
- }),
- foundThread
- )
- );
- }
- });
- $("#GM_FAR_next_thread_search_result_count").text(resultCount);
- $("#GM_FAR_next_thread_search_result").show();
- }
- });
- }
- })(jQuery);