From ed3dbfd9880c8c781f3a3080695e55edcc21fc89 Mon Sep 17 00:00:00 2001 From: Nicolas Stepien Date: Sun, 23 Sep 2012 01:06:27 +0200 Subject: [PATCH 01/12] Don't stop auto-posting on connection error. --- 4chan_x.user.js | 2 +- script.coffee | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/4chan_x.user.js b/4chan_x.user.js index 066b51e63..6b4466df2 100644 --- a/4chan_x.user.js +++ b/4chan_x.user.js @@ -2515,7 +2515,7 @@ } if (err) { if (/captcha|verification/i.test(err.textContent) || err === 'Connection error with sys.4chan.org.') { - QR.cooldown.auto = !!$.get('captchas', []).length; + QR.cooldown.auto = QR.captchaIsEnabled ? !!$.get('captchas', []).length : true; QR.cooldown.set(2); } else { QR.cooldown.auto = false; diff --git a/script.coffee b/script.coffee index a08ba0713..8774dde25 100644 --- a/script.coffee +++ b/script.coffee @@ -1958,7 +1958,11 @@ QR = if err if /captcha|verification/i.test(err.textContent) or err is 'Connection error with sys.4chan.org.' # Enable auto-post if we have some cached captchas. - QR.cooldown.auto = !!$.get('captchas', []).length + QR.cooldown.auto = + if QR.captchaIsEnabled + !!$.get('captchas', []).length + else + true # Too many frequent mistyped captchas will auto-ban you! # On connection error, the post most likely didn't go through. QR.cooldown.set 2 From 6ce4c2abbd8d2711c9fd4efc71c1eb0539b5243e Mon Sep 17 00:00:00 2001 From: Nicolas Stepien Date: Wed, 26 Sep 2012 16:27:18 +0200 Subject: [PATCH 02/12] Close #775 --- 4chan_x.user.js | 2 +- changelog | 2 ++ script.coffee | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/4chan_x.user.js b/4chan_x.user.js index 6b4466df2..fd2cf8d17 100644 --- a/4chan_x.user.js +++ b/4chan_x.user.js @@ -3886,7 +3886,7 @@ _ref = post.quotes; for (_i = 0, _len = _ref.length; _i < _len; _i++) { quote = _ref[_i]; - if (quote.parentNode.getAttribute('style') === 'font-size: smaller;') { + if (quote.parentNode.parentNode.className === 'capcodeReplies') { break; } if (qid = quote.hash.slice(2)) { diff --git a/changelog b/changelog index 472e7fb3e..e4441a303 100644 --- a/changelog +++ b/changelog @@ -1,4 +1,6 @@ master +- Mayhem + Fix 'Administrator/Moderator/Developer Replies' creating extra backlinks on /q/, again. 2.35.3 - Mayhem diff --git a/script.coffee b/script.coffee index 8774dde25..aa4dd3070 100644 --- a/script.coffee +++ b/script.coffee @@ -3190,7 +3190,7 @@ QuoteBacklink = quotes = {} for quote in post.quotes # Stop at 'Admin/Mod/Dev Replies:' on /q/ - break if quote.parentNode.getAttribute('style') is 'font-size: smaller;' + break if quote.parentNode.parentNode.className is 'capcodeReplies' # Don't process >>>/b/. if qid = quote.hash[2..] # Duplicate quotes get overwritten. From 6e8d4b02dee67d09b66b0b976fe9e4d31243024b Mon Sep 17 00:00:00 2001 From: Nicolas Stepien Date: Wed, 26 Sep 2012 16:39:53 +0200 Subject: [PATCH 03/12] Remove the 4chan Pass ad in mistyped captcha errors. --- 4chan_x.user.js | 3 +++ changelog | 1 + script.coffee | 3 +++ 3 files changed, 7 insertions(+) diff --git a/4chan_x.user.js b/4chan_x.user.js index fd2cf8d17..d9f1d51f8 100644 --- a/4chan_x.user.js +++ b/4chan_x.user.js @@ -2515,6 +2515,9 @@ } if (err) { if (/captcha|verification/i.test(err.textContent) || err === 'Connection error with sys.4chan.org.') { + if (/mistyped/i.test(err.textContent)) { + err.textContent = 'Error: You seem to have mistyped the CAPTCHA.'; + } QR.cooldown.auto = QR.captchaIsEnabled ? !!$.get('captchas', []).length : true; QR.cooldown.set(2); } else { diff --git a/changelog b/changelog index e4441a303..072d22d24 100644 --- a/changelog +++ b/changelog @@ -1,5 +1,6 @@ master - Mayhem + Removed the obnoxious 4chan Pass ad in captcha errors when posting. Fix 'Administrator/Moderator/Developer Replies' creating extra backlinks on /q/, again. 2.35.3 diff --git a/script.coffee b/script.coffee index aa4dd3070..5e27683ca 100644 --- a/script.coffee +++ b/script.coffee @@ -1957,6 +1957,9 @@ QR = if err if /captcha|verification/i.test(err.textContent) or err is 'Connection error with sys.4chan.org.' + # Remove the obnoxious 4chan Pass ad. + if /mistyped/i.test err.textContent + err.textContent = 'Error: You seem to have mistyped the CAPTCHA.' # Enable auto-post if we have some cached captchas. QR.cooldown.auto = if QR.captchaIsEnabled From 76b06eba9742167338baf47788255da857f7ea9c Mon Sep 17 00:00:00 2001 From: Nicolas Stepien Date: Wed, 26 Sep 2012 16:49:01 +0200 Subject: [PATCH 04/12] Release 2.35.4. --- 4chan_x.user.js | 6 +++--- Cakefile | 2 +- changelog | 2 ++ latest.js | 2 +- script.coffee | 2 +- 5 files changed, 8 insertions(+), 6 deletions(-) diff --git a/4chan_x.user.js b/4chan_x.user.js index d9f1d51f8..91e8e6a24 100644 --- a/4chan_x.user.js +++ b/4chan_x.user.js @@ -1,6 +1,6 @@ // ==UserScript== // @name 4chan x -// @version 2.35.3 +// @version 2.35.4 // @namespace aeosynth // @description Adds various features. // @copyright 2009-2011 James Campos @@ -27,7 +27,7 @@ * Copyright (c) 2009-2011 James Campos * Copyright (c) 2012 Nicolas Stepien * http://mayhemydg.github.com/4chan-x/ - * 4chan X 2.35.3 + * 4chan X 2.35.4 * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation @@ -5365,7 +5365,7 @@ return $.globalEval(("(" + code + ")()").replace('_id_', bq.id)); }, namespace: '4chan_x.', - version: '2.35.3', + version: '2.35.4', callbacks: [], css: '\ /* dialog styling */\ diff --git a/Cakefile b/Cakefile index 41b51d179..fcf97be33 100644 --- a/Cakefile +++ b/Cakefile @@ -2,7 +2,7 @@ {exec} = require 'child_process' fs = require 'fs' -VERSION = '2.35.3' +VERSION = '2.35.4' HEADER = """ // ==UserScript== diff --git a/changelog b/changelog index 072d22d24..3b568d710 100644 --- a/changelog +++ b/changelog @@ -1,4 +1,6 @@ master + +2.35.4 - Mayhem Removed the obnoxious 4chan Pass ad in captcha errors when posting. Fix 'Administrator/Moderator/Developer Replies' creating extra backlinks on /q/, again. diff --git a/latest.js b/latest.js index 72c0783fb..003400334 100644 --- a/latest.js +++ b/latest.js @@ -1 +1 @@ -postMessage({version:'2.35.3'},'*') \ No newline at end of file +postMessage({version:'2.35.4'},'*') \ No newline at end of file diff --git a/script.coffee b/script.coffee index 5e27683ca..9dbea41dd 100644 --- a/script.coffee +++ b/script.coffee @@ -4294,7 +4294,7 @@ Main = $.globalEval "(#{code})()".replace '_id_', bq.id namespace: '4chan_x.' - version: '2.35.3' + version: '2.35.4' callbacks: [] css: ' /* dialog styling */ From 3ef78f846138ab16ee225b7809341feef867a858 Mon Sep 17 00:00:00 2001 From: Nicolas Stepien Date: Thu, 27 Sep 2012 01:26:57 +0200 Subject: [PATCH 05/12] Fix QR cooldown on /q/ according to 4chan-JS. --- 4chan_x.user.js | 6 ++++-- script.coffee | 16 +++++++++++++++- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/4chan_x.user.js b/4chan_x.user.js index 91e8e6a24..25c91a019 100644 --- a/4chan_x.user.js +++ b/4chan_x.user.js @@ -2498,7 +2498,7 @@ return QR.ajax = $.ajax($.id('postForm').parentNode.action, callbacks, opts); }, response: function(html) { - var bs, doc, err, msg, persona, postID, reply, threadID, _, _ref, _ref1; + var bs, doc, err, msg, persona, postID, reply, sage, seconds, threadID, _, _ref, _ref1; doc = d.implementation.createHTMLDocument(''); doc.documentElement.innerHTML = html; if (doc.title === '4chan - Banned') { @@ -2547,7 +2547,9 @@ location.pathname = "/" + g.BOARD + "/res/" + postID; } else { QR.cooldown.auto = QR.replies.length > 1; - QR.cooldown.set(g.BOARD === 'q' || /sage/i.test(reply.email) ? 60 : 30); + sage = /sage/i.test(reply.email); + seconds = g.BOARD === 'q' ? reply.file ? 300 : sage ? 600 : 60 : sage ? 60 : 30; + QR.cooldown.set(seconds); if (Conf['Open Reply in New Tab'] && !g.REPLY && !QR.cooldown.auto) { $.open("//boards.4chan.org/" + g.BOARD + "/res/" + threadID + "#p" + postID); } diff --git a/script.coffee b/script.coffee index 9dbea41dd..16542976c 100644 --- a/script.coffee +++ b/script.coffee @@ -1999,7 +1999,21 @@ QR = else # Enable auto-posting if we have stuff to post, disable it otherwise. QR.cooldown.auto = QR.replies.length > 1 - QR.cooldown.set if g.BOARD is 'q' or /sage/i.test reply.email then 60 else 30 + sage = /sage/i.test reply.email + seconds = + if g.BOARD is 'q' + # that makes no sense.png + if reply.file + 300 + else if sage + 600 + else + 60 + else if sage + 60 + else + 30 + QR.cooldown.set seconds if Conf['Open Reply in New Tab'] and !g.REPLY and !QR.cooldown.auto $.open "//boards.4chan.org/#{g.BOARD}/res/#{threadID}#p#{postID}" From c64bb3c361b9dd273c123422ab7daa3fb2b2c601 Mon Sep 17 00:00:00 2001 From: Nicolas Stepien Date: Fri, 28 Sep 2012 00:47:39 +0200 Subject: [PATCH 06/12] More accurate QR/post deletion cooldown. Close #774. --- 4chan_x.user.js | 35 ++++++++++++++++++++++------------- script.coffee | 42 ++++++++++++++++++++++++++---------------- 2 files changed, 48 insertions(+), 29 deletions(-) diff --git a/4chan_x.user.js b/4chan_x.user.js index 25c91a019..0c43e8735 100644 --- a/4chan_x.user.js +++ b/4chan_x.user.js @@ -1836,29 +1836,36 @@ }, cooldown: { init: function() { + var length, timeout, _ref; if (!Conf['Cooldown']) { return; } - QR.cooldown.start($.get("/" + g.BOARD + "/cooldown", 0)); + _ref = $.get("/" + g.BOARD + "/cooldown", {}), timeout = _ref.timeout, length = _ref.length; + if (timeout) { + QR.cooldown.start(timeout, length); + } return $.sync("/" + g.BOARD + "/cooldown", QR.cooldown.start); }, - start: function(timeout) { + start: function(timeout, length) { var seconds; seconds = Math.floor((timeout - Date.now()) / 1000); - return QR.cooldown.count(seconds); + return QR.cooldown.count(seconds, length); }, set: function(seconds) { if (!Conf['Cooldown']) { return; } - QR.cooldown.count(seconds); - return $.set("/" + g.BOARD + "/cooldown", Date.now() + seconds * $.SECOND); + QR.cooldown.count(seconds, seconds); + return $.set("/" + g.BOARD + "/cooldown", { + timeout: Date.now() + seconds * $.SECOND, + length: seconds + }); }, - count: function(seconds) { - if (!((0 <= seconds && seconds <= 60))) { + count: function(seconds, length) { + if (!((0 <= seconds && seconds <= length))) { return; } - setTimeout(QR.cooldown.count, 1000, seconds - 1); + setTimeout(QR.cooldown.count, 1000, seconds - 1, length); QR.cooldown.seconds = seconds; if (seconds === 0) { $["delete"]("/" + g.BOARD + "/cooldown"); @@ -2548,7 +2555,7 @@ } else { QR.cooldown.auto = QR.replies.length > 1; sage = /sage/i.test(reply.email); - seconds = g.BOARD === 'q' ? reply.file ? 300 : sage ? 600 : 60 : sage ? 60 : 30; + seconds = g.BOARD === 'q' ? sage ? 600 : reply.file ? 300 : 60 : sage ? 60 : 30; QR.cooldown.set(seconds); if (Conf['Open Reply in New Tab'] && !g.REPLY && !QR.cooldown.auto) { $.open("//boards.4chan.org/" + g.BOARD + "/res/" + threadID + "#p" + postID); @@ -4331,14 +4338,16 @@ }, cooldown: { start: function(e) { - return DeleteLink.cooldown.count(e.detail.postID, 30); + var seconds; + seconds = g.BOARD === 'q' ? 600 : 30; + return DeleteLink.cooldown.count(e.detail.postID, seconds, seconds); }, - count: function(postID, seconds) { + count: function(postID, seconds, length) { var el; - if (!((0 <= seconds && seconds <= 30))) { + if (!((0 <= seconds && seconds <= length))) { return; } - setTimeout(DeleteLink.cooldown.count, 1000, postID, seconds - 1); + setTimeout(DeleteLink.cooldown.count, 1000, postID, seconds - 1, length); el = DeleteLink.cooldown.el; if (seconds === 0) { if (el != null) { diff --git a/script.coffee b/script.coffee index 16542976c..b7c6e8a8e 100644 --- a/script.coffee +++ b/script.coffee @@ -1418,18 +1418,21 @@ QR = cooldown: init: -> return unless Conf['Cooldown'] - QR.cooldown.start $.get "/#{g.BOARD}/cooldown", 0 + {timeout, length} = $.get "/#{g.BOARD}/cooldown", {} + QR.cooldown.start timeout, length if timeout $.sync "/#{g.BOARD}/cooldown", QR.cooldown.start - start: (timeout) -> + start: (timeout, length) -> seconds = Math.floor (timeout - Date.now()) / 1000 - QR.cooldown.count seconds + QR.cooldown.count seconds, length set: (seconds) -> return unless Conf['Cooldown'] - QR.cooldown.count seconds - $.set "/#{g.BOARD}/cooldown", Date.now() + seconds*$.SECOND - count: (seconds) -> - return unless 0 <= seconds <= 60 - setTimeout QR.cooldown.count, 1000, seconds-1 + QR.cooldown.count seconds, seconds + $.set "/#{g.BOARD}/cooldown", + timeout: Date.now() + seconds * $.SECOND + length: seconds + count: (seconds, length) -> + return unless 0 <= seconds <= length + setTimeout QR.cooldown.count, 1000, seconds-1, length QR.cooldown.seconds = seconds if seconds is 0 $.delete "/#{g.BOARD}/cooldown" @@ -2001,12 +2004,14 @@ QR = QR.cooldown.auto = QR.replies.length > 1 sage = /sage/i.test reply.email seconds = + # 300 seconds cooldown for new threads + # q: 86400 seconds + # b soc r9k: 600 seconds if g.BOARD is 'q' - # that makes no sense.png - if reply.file - 300 - else if sage + if sage 600 + else if reply.file + 300 else 60 else if sage @@ -3566,10 +3571,15 @@ DeleteLink = cooldown: start: (e) -> - DeleteLink.cooldown.count e.detail.postID, 30 - count: (postID, seconds) -> - return unless 0 <= seconds <= 30 - setTimeout DeleteLink.cooldown.count, 1000, postID, seconds-1 + seconds = + if g.BOARD is 'q' + 600 + else + 30 + DeleteLink.cooldown.count e.detail.postID, seconds, seconds + count: (postID, seconds, length) -> + return unless 0 <= seconds <= length + setTimeout DeleteLink.cooldown.count, 1000, postID, seconds-1, length {el} = DeleteLink.cooldown if seconds is 0 el?.textContent = 'Delete' From f411eb3e994a036ea1a69b1441542c474fe36950 Mon Sep 17 00:00:00 2001 From: Nicolas Stepien Date: Sat, 29 Sep 2012 01:43:30 +0200 Subject: [PATCH 07/12] Don't display "Auto" after an connection error during auto-posting. --- 4chan_x.user.js | 1 + script.coffee | 1 + 2 files changed, 2 insertions(+) diff --git a/4chan_x.user.js b/4chan_x.user.js index 0c43e8735..966222bde 100644 --- a/4chan_x.user.js +++ b/4chan_x.user.js @@ -2479,6 +2479,7 @@ return QR.response(this.response); }, onerror: function() { + QR.cooldown.auto = false; QR.status(); return QR.error($.el('a', { href: '//www.4chan.org/banned', diff --git a/script.coffee b/script.coffee index b7c6e8a8e..67bc142f0 100644 --- a/script.coffee +++ b/script.coffee @@ -1925,6 +1925,7 @@ QR = onerror: -> # Connection error, or # CORS disabled error on www.4chan.org/banned + QR.cooldown.auto = false QR.status() QR.error $.el 'a', href: '//www.4chan.org/banned', From 027836b78f8647a29ed096097ab8aa4963190cc4 Mon Sep 17 00:00:00 2001 From: Nicolas Stepien Date: Mon, 1 Oct 2012 17:33:05 +0200 Subject: [PATCH 08/12] Thread creation cooldown. Fix cooldown between different post-type. Fix /q/ cooldowns? Ugh. see #774 --- 4chan_x.user.js | 155 +++++++++++++++++++++++++++++++++++------------- changelog | 4 ++ script.coffee | 149 ++++++++++++++++++++++++++++++++-------------- 3 files changed, 225 insertions(+), 83 deletions(-) diff --git a/4chan_x.user.js b/4chan_x.user.js index 966222bde..b9d5e6b9a 100644 --- a/4chan_x.user.js +++ b/4chan_x.user.js @@ -1738,7 +1738,7 @@ $.on(link.firstChild, 'click', function() { QR.open(); if (!g.REPLY) { - $('select', QR.el).value = 'new'; + QR.threadSelector.value = 'new'; } return $('textarea', QR.el).focus(); }); @@ -1836,44 +1836,118 @@ }, cooldown: { init: function() { - var length, timeout, _ref; if (!Conf['Cooldown']) { return; } - _ref = $.get("/" + g.BOARD + "/cooldown", {}), timeout = _ref.timeout, length = _ref.length; - if (timeout) { - QR.cooldown.start(timeout, length); + QR.cooldown.types = { + thread: (function() { + switch (g.BOARD) { + case 'q': + return 86400; + case 'b': + case 'soc': + case 'r9k': + return 600; + default: + return 300; + } + })(), + sage: g.BOARD === 'q' ? 600 : 60, + file: g.BOARD === 'q' ? 300 : 30, + post: g.BOARD === 'q' ? 60 : 30 + }; + QR.cooldown.cooldowns = $.get("" + g.BOARD + ".cooldown", {}); + QR.cooldown.start(); + return $.sync("" + g.BOARD + ".cooldown", QR.cooldown.sync); + }, + start: function() { + if (QR.cooldown.isCounting) { + return; } - return $.sync("/" + g.BOARD + "/cooldown", QR.cooldown.start); + QR.cooldown.isCounting = true; + return QR.cooldown.count(); }, - start: function(timeout, length) { - var seconds; - seconds = Math.floor((timeout - Date.now()) / 1000); - return QR.cooldown.count(seconds, length); + sync: function(cooldowns) { + QR.cooldown.cooldowns = cooldowns; + return QR.cooldown.start(); }, - set: function(seconds) { + set: function(data) { + var cooldown, hasFile, isReply, isSage, start, type; if (!Conf['Cooldown']) { return; } - QR.cooldown.count(seconds, seconds); - return $.set("/" + g.BOARD + "/cooldown", { - timeout: Date.now() + seconds * $.SECOND, - length: seconds - }); + start = Date.now(); + if (data.delay) { + cooldown = { + delay: data.delay + }; + } else { + isSage = /sage/i.test(data.post.email); + hasFile = !!data.post.file; + isReply = data.isReply; + type = !isReply ? 'thread' : isSage ? 'sage' : hasFile ? 'file' : 'post'; + cooldown = { + isReply: isReply, + isSage: isSage, + hasFile: hasFile, + timeout: start + QR.cooldown.types[type] * $.SECOND + }; + } + QR.cooldown.cooldowns[start] = cooldown; + $.set("" + g.BOARD + ".cooldown", QR.cooldown.cooldowns); + return QR.cooldown.start(); }, - count: function(seconds, length) { - if (!((0 <= seconds && seconds <= length))) { + unset: function(id) { + delete QR.cooldown.cooldowns[id]; + return $.set("" + g.BOARD + ".cooldown", QR.cooldown.cooldowns); + }, + count: function() { + var cooldown, cooldowns, elapsed, hasFile, isReply, isSage, now, post, seconds, start, type, types, _ref; + if (Object.keys(QR.cooldown.cooldowns).length) { + setTimeout(QR.cooldown.count, 1000); + } else { + $["delete"]("" + g.BOARD + ".cooldown"); + QR.cooldown.isCounting = false; return; } - setTimeout(QR.cooldown.count, 1000, seconds - 1, length); - QR.cooldown.seconds = seconds; - if (seconds === 0) { - $["delete"]("/" + g.BOARD + "/cooldown"); - if (QR.cooldown.auto) { - QR.submit(); + if ((isReply = g.REPLY ? true : QR.threadSelector.value !== 'new')) { + post = QR.replies[0]; + isSage = /sage/i.test(post.email); + hasFile = !!post.file; + } + now = Date.now(); + seconds = null; + _ref = QR.cooldown, types = _ref.types, cooldowns = _ref.cooldowns; + for (start in cooldowns) { + cooldown = cooldowns[start]; + if ('delay' in cooldown) { + if (cooldown.delay) { + seconds = Math.max(seconds, cooldown.delay--); + } else { + seconds = Math.max(seconds, 0); + QR.cooldown.unset(start); + } + continue; + } + type = isReply && cooldown.isReply ? isSage && cooldown.isSage ? 'sage' : hasFile && cooldown.hasFile ? 'file' : 'post' : !(isReply || cooldown.isReply) ? type = 'thread' : void 0; + if (type) { + elapsed = Math.floor((now - start) / 1000); + if (elapsed >= 0) { + seconds = Math.max(seconds, types[type] - elapsed); + } + type = ''; + } + if (!((start <= now && now <= cooldown.timeout))) { + QR.cooldown.unset(start); } } - return QR.status(); + QR.cooldown.seconds = seconds; + if (seconds !== null) { + QR.status(); + } + if (seconds === 0 && QR.cooldown.auto) { + return QR.submit(); + } } }, quote: function(e) { @@ -1883,7 +1957,7 @@ } QR.open(); if (!g.REPLY) { - $('select', QR.el).value = $.x('ancestor::div[parent::div[@class="board"]]', this).id.slice(1); + QR.threadSelector.value = $.x('ancestor::div[parent::div[@class="board"]]', this).id.slice(1); } id = this.previousSibling.hash.slice(2); text = ">>" + id + "\n"; @@ -2173,10 +2247,7 @@ (QR.replies[index - 1] || QR.replies[index + 1]).select(); } QR.replies.splice(index, 1); - if (typeof (_base1 = window.URL || window.webkitURL).revokeObjectURL === "function") { - _base1.revokeObjectURL(this.url); - } - return delete this; + return typeof (_base1 = window.URL || window.webkitURL).revokeObjectURL === "function" ? _base1.revokeObjectURL(this.url) : void 0; }; return _Class; @@ -2342,11 +2413,12 @@ id = thread.id.slice(1); threads += ""; } - $.prepend($('.move > span', QR.el), $.el('select', { + QR.threadSelector = $.el('select', { innerHTML: threads, title: 'Create a new thread / Reply to a thread' - })); - $.on($('select', QR.el), 'mousedown', function(e) { + }); + $.prepend($('.move > span', QR.el), QR.threadSelector); + $.on(QR.threadSelector, 'mousedown', function(e) { return e.stopPropagation(); }); } @@ -2380,7 +2452,7 @@ $.on($("[name=" + name + "]", QR.el), 'input', function() { var _ref2; QR.selected[this.name] = this.value; - if (QR.cooldown.auto && QR.selected === QR.replies[0] && (0 < (_ref2 = QR.cooldown.seconds) && _ref2 < 6)) { + if (QR.cooldown.auto && QR.selected === QR.replies[0] && (0 < (_ref2 = QR.cooldown.seconds) && _ref2 <= 5)) { return QR.cooldown.auto = false; } }); @@ -2406,7 +2478,7 @@ } QR.abort(); reply = QR.replies[0]; - threadID = g.THREAD_ID || $('select', QR.el).value; + threadID = g.THREAD_ID || QR.threadSelector.value; if (threadID === 'new') { if (((_ref = g.BOARD) === 'vg' || _ref === 'q') && !reply.sub) { err = 'New threads require a subject.'; @@ -2506,7 +2578,7 @@ return QR.ajax = $.ajax($.id('postForm').parentNode.action, callbacks, opts); }, response: function(html) { - var bs, doc, err, msg, persona, postID, reply, sage, seconds, threadID, _, _ref, _ref1; + var bs, doc, err, msg, persona, postID, reply, threadID, _, _ref, _ref1; doc = d.implementation.createHTMLDocument(''); doc.documentElement.innerHTML = html; if (doc.title === '4chan - Banned') { @@ -2527,7 +2599,9 @@ err.textContent = 'Error: You seem to have mistyped the CAPTCHA.'; } QR.cooldown.auto = QR.captchaIsEnabled ? !!$.get('captchas', []).length : true; - QR.cooldown.set(2); + QR.cooldown.set({ + delay: 2 + }); } else { QR.cooldown.auto = false; } @@ -2551,13 +2625,14 @@ postID: postID } })); + QR.cooldown.set({ + post: reply, + isReply: threadID !== '0' + }); if (threadID === '0') { location.pathname = "/" + g.BOARD + "/res/" + postID; } else { QR.cooldown.auto = QR.replies.length > 1; - sage = /sage/i.test(reply.email); - seconds = g.BOARD === 'q' ? sage ? 600 : reply.file ? 300 : 60 : sage ? 60 : 30; - QR.cooldown.set(seconds); if (Conf['Open Reply in New Tab'] && !g.REPLY && !QR.cooldown.auto) { $.open("//boards.4chan.org/" + g.BOARD + "/res/" + threadID + "#p" + postID); } diff --git a/changelog b/changelog index 3b568d710..971bddfa3 100644 --- a/changelog +++ b/changelog @@ -1,4 +1,8 @@ master +- Mayhem + Added thread creation QR cooldown. + Fix QR cooldown timer between non-sage and sage posts. You can submit a non-sage post 30 seconds after a sage one. + Fix /q/ QR cooldowns. 2.35.4 - Mayhem diff --git a/script.coffee b/script.coffee index 67bc142f0..d5c15bc64 100644 --- a/script.coffee +++ b/script.coffee @@ -1342,7 +1342,7 @@ QR = link = $.el 'h1', innerHTML: "#{if g.REPLY then 'Reply to Thread' else 'Start a Thread'}" $.on link.firstChild, 'click', -> QR.open() - $('select', QR.el).value = 'new' unless g.REPLY + QR.threadSelector.value = 'new' unless g.REPLY $('textarea', QR.el).focus() $.before $.id('postForm'), link @@ -1418,32 +1418,108 @@ QR = cooldown: init: -> return unless Conf['Cooldown'] - {timeout, length} = $.get "/#{g.BOARD}/cooldown", {} - QR.cooldown.start timeout, length if timeout - $.sync "/#{g.BOARD}/cooldown", QR.cooldown.start - start: (timeout, length) -> - seconds = Math.floor (timeout - Date.now()) / 1000 - QR.cooldown.count seconds, length - set: (seconds) -> + QR.cooldown.types = + thread: switch g.BOARD + when 'q' then 86400 + when 'b', 'soc', 'r9k' then 600 + else 300 + sage: if g.BOARD is 'q' then 600 else 60 + file: if g.BOARD is 'q' then 300 else 30 + post: if g.BOARD is 'q' then 60 else 30 + QR.cooldown.cooldowns = $.get "#{g.BOARD}.cooldown", {} + QR.cooldown.start() + $.sync "#{g.BOARD}.cooldown", QR.cooldown.sync + start: -> + return if QR.cooldown.isCounting + QR.cooldown.isCounting = true + QR.cooldown.count() + sync: (cooldowns) -> + QR.cooldown.cooldowns = cooldowns + QR.cooldown.start() + set: (data) -> return unless Conf['Cooldown'] - QR.cooldown.count seconds, seconds - $.set "/#{g.BOARD}/cooldown", - timeout: Date.now() + seconds * $.SECOND - length: seconds - count: (seconds, length) -> - return unless 0 <= seconds <= length - setTimeout QR.cooldown.count, 1000, seconds-1, length + start = Date.now() + if data.delay + cooldown = delay: data.delay + else + isSage = /sage/i.test data.post.email + hasFile = !!data.post.file + isReply = data.isReply + type = + unless isReply + 'thread' + else + if isSage + 'sage' + else if hasFile + 'file' + else + 'post' + cooldown = + isReply: isReply + isSage: isSage + hasFile: hasFile + timeout: start + QR.cooldown.types[type] * $.SECOND + QR.cooldown.cooldowns[start] = cooldown + $.set "#{g.BOARD}.cooldown", QR.cooldown.cooldowns + QR.cooldown.start() + unset: (id) -> + delete QR.cooldown.cooldowns[id] + $.set "#{g.BOARD}.cooldown", QR.cooldown.cooldowns + count: -> + if Object.keys(QR.cooldown.cooldowns).length + setTimeout QR.cooldown.count, 1000 + else + $.delete "#{g.BOARD}.cooldown" + QR.cooldown.isCounting = false + return + + if (isReply = if g.REPLY then true else QR.threadSelector.value isnt 'new') + post = QR.replies[0] + isSage = /sage/i.test post.email + hasFile = !!post.file + now = Date.now() + seconds = null + {types, cooldowns} = QR.cooldown + + for start, cooldown of cooldowns + if 'delay' of cooldown + if cooldown.delay + seconds = Math.max seconds, cooldown.delay-- + else + seconds = Math.max seconds, 0 + QR.cooldown.unset start + continue + + # Only cooldowns relevant to this post can set the seconds value. + # Unset outdated cooldowns that can no longer impact us. + type = + if isReply and cooldown.isReply + if isSage and cooldown.isSage + 'sage' + else if hasFile and cooldown.hasFile + 'file' + else + 'post' + else unless isReply or cooldown.isReply + type = 'thread' + if type + elapsed = Math.floor (now - start) / 1000 + if elapsed >= 0 # clock changed since then? + seconds = Math.max seconds, types[type] - elapsed + type = '' + unless start <= now <= cooldown.timeout + QR.cooldown.unset start + QR.cooldown.seconds = seconds - if seconds is 0 - $.delete "/#{g.BOARD}/cooldown" - QR.submit() if QR.cooldown.auto - QR.status() + QR.status() if seconds isnt null + QR.submit() if seconds is 0 and QR.cooldown.auto quote: (e) -> e?.preventDefault() QR.open() unless g.REPLY - $('select', QR.el).value = $.x('ancestor::div[parent::div[@class="board"]]', @).id[1..] + QR.threadSelector.value = $.x('ancestor::div[parent::div[@class="board"]]', @).id[1..] # Make sure we get the correct number, even with XXX censors id = @previousSibling.hash[2..] text = ">>#{id}\n" @@ -1674,7 +1750,6 @@ QR = (QR.replies[index-1] or QR.replies[index+1]).select() QR.replies.splice index, 1 (window.URL or window.webkitURL).revokeObjectURL? @url - delete @ captcha: init: -> @@ -1804,10 +1879,11 @@ QR = for thread in $$ '.thread' id = thread.id[1..] threads += "" - $.prepend $('.move > span', QR.el), $.el 'select' + QR.threadSelector = $.el 'select' innerHTML: threads title: 'Create a new thread / Reply to a thread' - $.on $('select', QR.el), 'mousedown', (e) -> e.stopPropagation() + $.prepend $('.move > span', QR.el), QR.threadSelector + $.on QR.threadSelector, 'mousedown', (e) -> e.stopPropagation() $.on $('#autohide', QR.el), 'change', QR.toggleHide $.on $('.close', QR.el), 'click', QR.close $.on $('#dump', QR.el), 'click', -> QR.el.classList.toggle 'dump' @@ -1828,7 +1904,7 @@ QR = QR.selected[@name] = @value # Disable auto-posting if you're typing in the first reply # during the last 5 seconds of the cooldown. - if QR.cooldown.auto and QR.selected is QR.replies[0] and 0 < QR.cooldown.seconds < 6 + if QR.cooldown.auto and QR.selected is QR.replies[0] and 0 < QR.cooldown.seconds <= 5 QR.cooldown.auto = false QR.status.input = $ 'input[type=submit]', QR.el @@ -1851,7 +1927,7 @@ QR = QR.abort() reply = QR.replies[0] - threadID = g.THREAD_ID or $('select', QR.el).value + threadID = g.THREAD_ID or QR.threadSelector.value # prevent errors if threadID is 'new' @@ -1972,7 +2048,7 @@ QR = true # Too many frequent mistyped captchas will auto-ban you! # On connection error, the post most likely didn't go through. - QR.cooldown.set 2 + QR.cooldown.set delay: 2 else # stop auto-posting QR.cooldown.auto = false QR.status() @@ -1997,29 +2073,16 @@ QR = threadID: threadID postID: postID + QR.cooldown.set + post: reply + isReply: threadID isnt '0' + if threadID is '0' # new thread # auto-noko location.pathname = "/#{g.BOARD}/res/#{postID}" else # Enable auto-posting if we have stuff to post, disable it otherwise. QR.cooldown.auto = QR.replies.length > 1 - sage = /sage/i.test reply.email - seconds = - # 300 seconds cooldown for new threads - # q: 86400 seconds - # b soc r9k: 600 seconds - if g.BOARD is 'q' - if sage - 600 - else if reply.file - 300 - else - 60 - else if sage - 60 - else - 30 - QR.cooldown.set seconds if Conf['Open Reply in New Tab'] and !g.REPLY and !QR.cooldown.auto $.open "//boards.4chan.org/#{g.BOARD}/res/#{threadID}#p#{postID}" From c2491a7f6650bdb0a589d66b686b1398d89f18dc Mon Sep 17 00:00:00 2001 From: Nicolas Stepien Date: Mon, 1 Oct 2012 18:06:33 +0200 Subject: [PATCH 09/12] Add missing class on file deleted gifs. --- 4chan_x.user.js | 2 +- script.coffee | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/4chan_x.user.js b/4chan_x.user.js index b9d5e6b9a..095c51735 100644 --- a/4chan_x.user.js +++ b/4chan_x.user.js @@ -3896,7 +3896,7 @@ } flag = flagCode ? ("  + flagCode + ") : ''; if (file != null ? file.isDeleted : void 0) { - fileHTML = isOP ? ("
") + ("File deleted.") + "
" : ("
") + ("File deleted.") + "
"; + fileHTML = isOP ? ("
") + ("File deleted.") + "
" : ("
") + ("File deleted.") + "
"; } else if (file) { ext = file.name.slice(-3); if (!file.twidth && !file.theight && ext === 'gif') { diff --git a/script.coffee b/script.coffee index d5c15bc64..95b5c35ee 100644 --- a/script.coffee +++ b/script.coffee @@ -3128,11 +3128,11 @@ Build = fileHTML = if isOP "
" + - "File deleted." + + "File deleted." + "
" else "
" + - "File deleted." + + "File deleted." + "
" else if file ext = file.name[-3..] From 6bafe5189c1764f5e767fb3b799ee58e29f86607 Mon Sep 17 00:00:00 2001 From: Nicolas Stepien Date: Wed, 3 Oct 2012 01:01:28 +0200 Subject: [PATCH 10/12] Some cooldown concurrency fixes. It still needs some more testing. --- 4chan_x.user.js | 18 ++++++++++++------ script.coffee | 19 ++++++++++++++----- 2 files changed, 26 insertions(+), 11 deletions(-) diff --git a/4chan_x.user.js b/4chan_x.user.js index 095c51735..ba34020e3 100644 --- a/4chan_x.user.js +++ b/4chan_x.user.js @@ -1829,7 +1829,7 @@ disabled = true; QR.cooldown.auto = false; } - value = QR.cooldown.seconds || data.progress || value; + value = data.progress || QR.cooldown.seconds || value; input = QR.status.input; input.value = QR.cooldown.auto && Conf['Cooldown'] ? value ? "Auto " + value : 'Auto' : value || 'Submit'; return input.disabled = disabled || false; @@ -1868,7 +1868,10 @@ return QR.cooldown.count(); }, sync: function(cooldowns) { - QR.cooldown.cooldowns = cooldowns; + var id; + for (id in cooldowns) { + QR.cooldown.cooldowns[id] = cooldowns[id]; + } return QR.cooldown.start(); }, set: function(data) { @@ -1902,12 +1905,14 @@ return $.set("" + g.BOARD + ".cooldown", QR.cooldown.cooldowns); }, count: function() { - var cooldown, cooldowns, elapsed, hasFile, isReply, isSage, now, post, seconds, start, type, types, _ref; + var cooldown, cooldowns, elapsed, hasFile, isReply, isSage, now, post, seconds, start, type, types, update, _ref; if (Object.keys(QR.cooldown.cooldowns).length) { setTimeout(QR.cooldown.count, 1000); } else { $["delete"]("" + g.BOARD + ".cooldown"); - QR.cooldown.isCounting = false; + delete QR.cooldown.isCounting; + delete QR.cooldown.seconds; + QR.status(); return; } if ((isReply = g.REPLY ? true : QR.threadSelector.value !== 'new')) { @@ -1929,7 +1934,7 @@ } continue; } - type = isReply && cooldown.isReply ? isSage && cooldown.isSage ? 'sage' : hasFile && cooldown.hasFile ? 'file' : 'post' : !(isReply || cooldown.isReply) ? type = 'thread' : void 0; + type = isReply && cooldown.isReply ? isSage && cooldown.isSage ? 'sage' : hasFile && cooldown.hasFile ? 'file' : 'post' : !(isReply || cooldown.isReply) ? 'thread' : void 0; if (type) { elapsed = Math.floor((now - start) / 1000); if (elapsed >= 0) { @@ -1941,8 +1946,9 @@ QR.cooldown.unset(start); } } + update = seconds !== null || !!QR.cooldown.seconds; QR.cooldown.seconds = seconds; - if (seconds !== null) { + if (update) { QR.status(); } if (seconds === 0 && QR.cooldown.auto) { diff --git a/script.coffee b/script.coffee index 95b5c35ee..636195764 100644 --- a/script.coffee +++ b/script.coffee @@ -1406,7 +1406,7 @@ QR = value = 404 disabled = true QR.cooldown.auto = false - value = QR.cooldown.seconds or data.progress or value + value = data.progress or QR.cooldown.seconds or value {input} = QR.status input.value = if QR.cooldown.auto and Conf['Cooldown'] @@ -1434,7 +1434,10 @@ QR = QR.cooldown.isCounting = true QR.cooldown.count() sync: (cooldowns) -> - QR.cooldown.cooldowns = cooldowns + # Add each cooldowns, don't overwrite everything in case we + # still need to purge one in the current tab to auto-post. + for id of cooldowns + QR.cooldown.cooldowns[id] = cooldowns[id] QR.cooldown.start() set: (data) -> return unless Conf['Cooldown'] @@ -1471,7 +1474,9 @@ QR = setTimeout QR.cooldown.count, 1000 else $.delete "#{g.BOARD}.cooldown" - QR.cooldown.isCounting = false + delete QR.cooldown.isCounting + delete QR.cooldown.seconds + QR.status() return if (isReply = if g.REPLY then true else QR.threadSelector.value isnt 'new') @@ -1502,7 +1507,7 @@ QR = else 'post' else unless isReply or cooldown.isReply - type = 'thread' + 'thread' if type elapsed = Math.floor (now - start) / 1000 if elapsed >= 0 # clock changed since then? @@ -1511,8 +1516,12 @@ QR = unless start <= now <= cooldown.timeout QR.cooldown.unset start + # Update the status when we change posting type. + # Don't get stuck at some random number. + # Don't interfere with progress status updates. + update = seconds isnt null or !!QR.cooldown.seconds QR.cooldown.seconds = seconds - QR.status() if seconds isnt null + QR.status() if update QR.submit() if seconds is 0 and QR.cooldown.auto quote: (e) -> From 3c677174718719d838b372bc5f2d6050195ef0dd Mon Sep 17 00:00:00 2001 From: Nicolas Stepien Date: Wed, 3 Oct 2012 23:28:39 +0200 Subject: [PATCH 11/12] Release 2.36.0. --- 4chan_x.user.js | 6 +++--- Cakefile | 2 +- changelog | 4 +++- latest.js | 2 +- script.coffee | 2 +- 5 files changed, 9 insertions(+), 7 deletions(-) diff --git a/4chan_x.user.js b/4chan_x.user.js index ba34020e3..11ce157d6 100644 --- a/4chan_x.user.js +++ b/4chan_x.user.js @@ -1,6 +1,6 @@ // ==UserScript== // @name 4chan x -// @version 2.35.4 +// @version 2.36.0 // @namespace aeosynth // @description Adds various features. // @copyright 2009-2011 James Campos @@ -27,7 +27,7 @@ * Copyright (c) 2009-2011 James Campos * Copyright (c) 2012 Nicolas Stepien * http://mayhemydg.github.com/4chan-x/ - * 4chan X 2.35.4 + * 4chan X 2.36.0 * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation @@ -5458,7 +5458,7 @@ return $.globalEval(("(" + code + ")()").replace('_id_', bq.id)); }, namespace: '4chan_x.', - version: '2.35.4', + version: '2.36.0', callbacks: [], css: '\ /* dialog styling */\ diff --git a/Cakefile b/Cakefile index fcf97be33..ca2d70d97 100644 --- a/Cakefile +++ b/Cakefile @@ -2,7 +2,7 @@ {exec} = require 'child_process' fs = require 'fs' -VERSION = '2.35.4' +VERSION = '2.36.0' HEADER = """ // ==UserScript== diff --git a/changelog b/changelog index 971bddfa3..161d71413 100644 --- a/changelog +++ b/changelog @@ -1,8 +1,10 @@ master + +2.36.0 - Mayhem Added thread creation QR cooldown. Fix QR cooldown timer between non-sage and sage posts. You can submit a non-sage post 30 seconds after a sage one. - Fix /q/ QR cooldowns. + Fix /q/ QR cooldowns for image and sage posts. 2.35.4 - Mayhem diff --git a/latest.js b/latest.js index 003400334..be75ff81d 100644 --- a/latest.js +++ b/latest.js @@ -1 +1 @@ -postMessage({version:'2.35.4'},'*') \ No newline at end of file +postMessage({version:'2.36.0'},'*') \ No newline at end of file diff --git a/script.coffee b/script.coffee index 636195764..335a7890e 100644 --- a/script.coffee +++ b/script.coffee @@ -4391,7 +4391,7 @@ Main = $.globalEval "(#{code})()".replace '_id_', bq.id namespace: '4chan_x.' - version: '2.35.4' + version: '2.36.0' callbacks: [] css: ' /* dialog styling */ From 4b1391a81b5c1743248e71071aa06e7f13cb3b85 Mon Sep 17 00:00:00 2001 From: Nicolas Stepien Date: Fri, 5 Oct 2012 16:20:37 +0200 Subject: [PATCH 12/12] Tiny refactor. --- 4chan_x.user.js | 5 ++--- script.coffee | 27 ++++++++++++--------------- 2 files changed, 14 insertions(+), 18 deletions(-) diff --git a/4chan_x.user.js b/4chan_x.user.js index 11ce157d6..c34abfb08 100644 --- a/4chan_x.user.js +++ b/4chan_x.user.js @@ -1934,13 +1934,12 @@ } continue; } - type = isReply && cooldown.isReply ? isSage && cooldown.isSage ? 'sage' : hasFile && cooldown.hasFile ? 'file' : 'post' : !(isReply || cooldown.isReply) ? 'thread' : void 0; - if (type) { + if (isReply === cooldown.isReply) { + type = !isReply ? 'thread' : isSage && cooldown.isSage ? 'sage' : hasFile && cooldown.hasFile ? 'file' : 'post'; elapsed = Math.floor((now - start) / 1000); if (elapsed >= 0) { seconds = Math.max(seconds, types[type] - elapsed); } - type = ''; } if (!((start <= now && now <= cooldown.timeout))) { QR.cooldown.unset(start); diff --git a/script.coffee b/script.coffee index 335a7890e..988d3e58b 100644 --- a/script.coffee +++ b/script.coffee @@ -1451,13 +1451,12 @@ QR = type = unless isReply 'thread' + else if isSage + 'sage' + else if hasFile + 'file' else - if isSage - 'sage' - else if hasFile - 'file' - else - 'post' + 'post' cooldown = isReply: isReply isSage: isSage @@ -1496,23 +1495,21 @@ QR = QR.cooldown.unset start continue - # Only cooldowns relevant to this post can set the seconds value. - # Unset outdated cooldowns that can no longer impact us. - type = - if isReply and cooldown.isReply - if isSage and cooldown.isSage + if isReply is cooldown.isReply + # Only cooldowns relevant to this post can set the seconds value. + # Unset outdated cooldowns that can no longer impact us. + type = + unless isReply + 'thread' + else if isSage and cooldown.isSage 'sage' else if hasFile and cooldown.hasFile 'file' else 'post' - else unless isReply or cooldown.isReply - 'thread' - if type elapsed = Math.floor (now - start) / 1000 if elapsed >= 0 # clock changed since then? seconds = Math.max seconds, types[type] - elapsed - type = '' unless start <= now <= cooldown.timeout QR.cooldown.unset start