Merge branch 'master' into v3
I really need to get back to this.
This commit is contained in:
commit
cf55f670c0
@ -3,7 +3,7 @@
|
||||
// @version 3.0.0
|
||||
// @description Cross-browser userscript for maximum lurking on 4chan.
|
||||
// @copyright 2009-2011 James Campos <james.r.campos@gmail.com>
|
||||
// @copyright 2012 Nicolas Stepien <stepien.nicolas@gmail.com>
|
||||
// @copyright 2012-2013 Nicolas Stepien <stepien.nicolas@gmail.com>
|
||||
// @license MIT; http://en.wikipedia.org/wiki/Mit_license
|
||||
// @match *://boards.4chan.org/*
|
||||
// @match *://images.4chan.org/*
|
||||
|
||||
192
4chan_x.user.js
192
4chan_x.user.js
@ -3,7 +3,7 @@
|
||||
// @version 3.0.0
|
||||
// @description Cross-browser userscript for maximum lurking on 4chan.
|
||||
// @copyright 2009-2011 James Campos <james.r.campos@gmail.com>
|
||||
// @copyright 2012 Nicolas Stepien <stepien.nicolas@gmail.com>
|
||||
// @copyright 2012-2013 Nicolas Stepien <stepien.nicolas@gmail.com>
|
||||
// @license MIT; http://en.wikipedia.org/wiki/Mit_license
|
||||
// @match *://boards.4chan.org/*
|
||||
// @match *://images.4chan.org/*
|
||||
@ -20,11 +20,11 @@
|
||||
// @icon https://github.com/MayhemYDG/4chan-x/raw/stable/img/icon.gif
|
||||
// ==/UserScript==
|
||||
|
||||
/* 4chan X Alpha - Version 3.0.0 - 2012-10-25
|
||||
/* 4chan X Alpha - Version 3.0.0 - 2013-01-13
|
||||
* http://mayhemydg.github.com/4chan-x/
|
||||
*
|
||||
* Copyright (c) 2009-2011 James Campos <james.r.campos@gmail.com>
|
||||
* Copyright (c) 2012 Nicolas Stepien <stepien.nicolas@gmail.com>
|
||||
* Copyright (c) 2012-2013 Nicolas Stepien <stepien.nicolas@gmail.com>
|
||||
* Licensed under the MIT license.
|
||||
* https://github.com/MayhemYDG/4chan-x/blob/master/LICENSE
|
||||
*
|
||||
@ -161,6 +161,7 @@
|
||||
},
|
||||
updater: {
|
||||
checkbox: {
|
||||
'Beep': [false, 'Beep on new post to completely read thread.'],
|
||||
'Auto Scroll': [false, 'Scroll updated posts into view. Only enabled at bottom of page.'],
|
||||
'Scroll BG': [false, 'Auto-scroll background tabs.'],
|
||||
'Auto Update': [true, 'Automatically fetch new posts.']
|
||||
@ -571,6 +572,9 @@
|
||||
open: function(url) {
|
||||
return (GM_openInTab || window.open)(url, '_blank');
|
||||
},
|
||||
hidden: function() {
|
||||
return d.hidden || d.oHidden || d.mozHidden || d.webkitHidden;
|
||||
},
|
||||
queueTask: (function() {
|
||||
var execTask, taskChannel, taskQueue;
|
||||
taskQueue = [];
|
||||
@ -691,6 +695,8 @@
|
||||
return "//archive.foolz.us/" + board + "/full_image/" + filename;
|
||||
case 'u':
|
||||
return "//nsfw.foolz.us/" + board + "/full_image/" + filename;
|
||||
case 'po':
|
||||
return "http://archive.thedarkcave.org/" + board + "/full_image/" + filename;
|
||||
case 'ck':
|
||||
case 'lit':
|
||||
return "//fuuka.warosu.org/" + board + "/full_image/" + filename;
|
||||
@ -700,7 +706,6 @@
|
||||
case 'cgl':
|
||||
case 'g':
|
||||
case 'mu':
|
||||
case 'soc':
|
||||
case 'w':
|
||||
return "//rbt.asia/" + board + "/full_image/" + filename;
|
||||
case 'an':
|
||||
@ -711,6 +716,8 @@
|
||||
case 'toy':
|
||||
case 'x':
|
||||
return "http://archive.heinessen.com/" + board + "/full_image/" + filename;
|
||||
case 'c':
|
||||
return "//archive.nyafuu.org/" + board + "/full_image/" + filename;
|
||||
}
|
||||
},
|
||||
post: function(board, postID) {
|
||||
@ -732,6 +739,8 @@
|
||||
case 'u':
|
||||
case 'kuku':
|
||||
return "//nsfw.foolz.us/_/api/chan/post/?board=" + board + "&num=" + postID;
|
||||
case 'po':
|
||||
return "http://archive.thedarkcave.org/_/api/chan/post/?board=" + board + "&num=" + postID;
|
||||
}
|
||||
},
|
||||
to: function(data) {
|
||||
@ -757,6 +766,9 @@
|
||||
case 'kuku':
|
||||
url = Redirect.path('//nsfw.foolz.us', 'foolfuuka', data);
|
||||
break;
|
||||
case 'po':
|
||||
url = Redirect.path('http://archive.thedarkcave.org', 'foolfuuka', data);
|
||||
break;
|
||||
case 'ck':
|
||||
case 'lit':
|
||||
url = Redirect.path('//fuuka.warosu.org', 'fuuka', data);
|
||||
@ -768,7 +780,6 @@
|
||||
case 'cgl':
|
||||
case 'g':
|
||||
case 'mu':
|
||||
case 'soc':
|
||||
case 'w':
|
||||
url = Redirect.path('//rbt.asia', 'fuuka', data);
|
||||
break;
|
||||
@ -781,6 +792,9 @@
|
||||
case 'x':
|
||||
url = Redirect.path('http://archive.heinessen.com', 'fuuka', data);
|
||||
break;
|
||||
case 'c':
|
||||
url = Redirect.path('//archive.nyafuu.org', 'fuuka', data);
|
||||
break;
|
||||
default:
|
||||
if (data.threadID) {
|
||||
url = "//boards.4chan.org/" + board + "/";
|
||||
@ -807,6 +821,9 @@
|
||||
postID = postID.match(/\d+/)[0];
|
||||
}
|
||||
path = threadID ? "" + board + "/thread/" + threadID : "" + board + "/post/" + postID;
|
||||
if (archiver === 'foolfuuka') {
|
||||
path += '/';
|
||||
}
|
||||
if (threadID && postID) {
|
||||
path += archiver === 'foolfuuka' ? "#" + postID : "#p" + postID;
|
||||
}
|
||||
@ -835,7 +852,7 @@
|
||||
capcode: data.capcode,
|
||||
tripcode: data.trip,
|
||||
uniqueID: data.id,
|
||||
email: data.email ? encodeURIComponent(data.email.replace(/"/g, '"')) : '',
|
||||
email: data.email ? encodeURI(data.email.replace(/"/g, '"')) : '',
|
||||
subject: data.sub,
|
||||
flagCode: data.country,
|
||||
flagName: data.country_name,
|
||||
@ -1111,7 +1128,7 @@
|
||||
return '</b>';
|
||||
}
|
||||
});
|
||||
comment = bq.innerHTML.replace(/(^|>)(>[^<$]+)(<|$)/g, '$1<span class=quote>$2</span>$3');
|
||||
comment = bq.innerHTML.replace(/(^|>)(>[^<$]*)(<|$)/g, '$1<span class=quote>$2</span>$3').replace(/((>){2}(>\/[a-z\d]+\/)?\d+)/g, '<span class=deadlink>$1</span>');
|
||||
threadID = data.thread_num;
|
||||
o = {
|
||||
postID: "" + postID,
|
||||
@ -1130,7 +1147,7 @@
|
||||
})(),
|
||||
tripcode: data.trip,
|
||||
uniqueID: data.poster_hash,
|
||||
email: data.email ? encodeURIComponent(data.email) : '',
|
||||
email: data.email ? encodeURI(data.email) : '',
|
||||
subject: data.title_processed,
|
||||
flagCode: data.poster_country,
|
||||
flagName: data.poster_country_name_processed,
|
||||
@ -1171,79 +1188,73 @@
|
||||
});
|
||||
},
|
||||
node: function() {
|
||||
var ID, a, board, data, i, index, m, node, nodes, post, quote, quoteID, quotes, snapshot, text, _i, _j, _len, _ref;
|
||||
var ID, a, board, deadlink, m, post, quote, quoteID, redirect, _i, _len, _ref, _ref1;
|
||||
if (this.isClone) {
|
||||
return;
|
||||
}
|
||||
snapshot = d.evaluate('.//text()[not(parent::a)]', this.nodes.comment, null, 6, null);
|
||||
for (i = _i = 0, _ref = snapshot.snapshotLength; 0 <= _ref ? _i < _ref : _i > _ref; i = 0 <= _ref ? ++_i : --_i) {
|
||||
node = snapshot.snapshotItem(i);
|
||||
data = node.data;
|
||||
if (!(quotes = data.match(/>>(>\/[a-z\d]+\/)?\d+/g))) {
|
||||
_ref = $$('.deadlink', post.blockquote);
|
||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||
deadlink = _ref[_i];
|
||||
if (deadlink.parentNode.className === 'prettyprint') {
|
||||
$.replace(deadlink, Array.prototype.slice.call(deadlink.childNodes));
|
||||
continue;
|
||||
}
|
||||
nodes = [];
|
||||
for (_j = 0, _len = quotes.length; _j < _len; _j++) {
|
||||
quote = quotes[_j];
|
||||
index = data.indexOf(quote);
|
||||
if (text = data.slice(0, index)) {
|
||||
nodes.push($.tn(text));
|
||||
}
|
||||
ID = quote.match(/\d+$/)[0];
|
||||
board = (m = quote.match(/^>>>\/([a-z\d]+)/)) ? m[1] : this.board.ID;
|
||||
quoteID = "" + board + "." + ID;
|
||||
if (post = g.posts[quoteID]) {
|
||||
if (post.isDead) {
|
||||
a = $.el('a', {
|
||||
href: Redirect.to({
|
||||
board: board,
|
||||
threadID: 0,
|
||||
postID: ID
|
||||
}),
|
||||
className: 'quotelink deadlink',
|
||||
textContent: "" + quote + "\u00A0(Dead)",
|
||||
target: '_blank'
|
||||
});
|
||||
a.setAttribute('data-board', board);
|
||||
a.setAttribute('data-threadid', post.thread.ID);
|
||||
a.setAttribute('data-postid', ID);
|
||||
} else {
|
||||
a = $.el('a', {
|
||||
href: "/" + board + "/" + post.thread + "/res/#p" + ID,
|
||||
className: 'quotelink',
|
||||
textContent: quote
|
||||
});
|
||||
}
|
||||
} else {
|
||||
quote = deadlink.textContent;
|
||||
if (!(ID = (_ref1 = quote.match(/\d+$/)) != null ? _ref1[0] : void 0)) {
|
||||
continue;
|
||||
}
|
||||
board = (m = quote.match(/^>>>\/([a-z\d]+)/)) ? m[1] : this.board.ID;
|
||||
quoteID = "" + board + "." + ID;
|
||||
if (post = g.posts[quoteID]) {
|
||||
if (!post.isDead) {
|
||||
a = $.el('a', {
|
||||
href: Redirect.to({
|
||||
board: board,
|
||||
threadID: 0,
|
||||
postID: ID
|
||||
}),
|
||||
className: 'deadlink',
|
||||
href: "/" + board + "/" + post.thread + "/res/#p" + ID,
|
||||
className: 'quotelink',
|
||||
textContent: quote
|
||||
});
|
||||
} else if (redirect = Redirect.to({
|
||||
board: board,
|
||||
threadID: post.thread.ID,
|
||||
postID: ID
|
||||
})) {
|
||||
a = $.el('a', {
|
||||
href: redirect,
|
||||
className: 'quotelink deadlink',
|
||||
target: '_blank',
|
||||
textContent: "" + quote + "\u00A0(Dead)"
|
||||
});
|
||||
if (Redirect.post(board, ID)) {
|
||||
$.addClass(a, 'quotelink');
|
||||
a.setAttribute('data-board', board);
|
||||
a.setAttribute('data-postid', ID);
|
||||
}
|
||||
a.setAttribute('data-board', board);
|
||||
a.setAttribute('data-threadid', post.thread.ID);
|
||||
a.setAttribute('data-postid', ID);
|
||||
}
|
||||
if (this.quotes.indexOf(quoteID) === -1) {
|
||||
this.quotes.push(quoteID);
|
||||
} else if (redirect = Redirect.to({
|
||||
board: board,
|
||||
threadID: 0,
|
||||
postID: ID
|
||||
})) {
|
||||
a = $.el('a', {
|
||||
href: redirect,
|
||||
className: 'deadlink',
|
||||
target: '_blank',
|
||||
textContent: "" + quote + "\u00A0(Dead)"
|
||||
});
|
||||
if (Redirect.post(board, ID)) {
|
||||
$.addClass(a, 'quotelink');
|
||||
a.setAttribute('data-board', board);
|
||||
a.setAttribute('data-postid', ID);
|
||||
}
|
||||
if ($.hasClass(a, 'quotelink')) {
|
||||
this.nodes.quotelinks.push(a);
|
||||
}
|
||||
nodes.push(a);
|
||||
data = data.slice(index + quote.length);
|
||||
}
|
||||
if (data) {
|
||||
nodes.push($.tn(data));
|
||||
if (a) {
|
||||
$.replace(deadlink, a);
|
||||
} else {
|
||||
deadlink.textContent += "\u00A0(Dead)";
|
||||
}
|
||||
if (this.quotes.indexOf(quoteID) === -1) {
|
||||
this.quotes.push(quoteID);
|
||||
}
|
||||
if ($.hasClass(a, 'quotelink')) {
|
||||
this.nodes.quotelinks.push(a);
|
||||
}
|
||||
$.replace(node, nodes);
|
||||
}
|
||||
}
|
||||
};
|
||||
@ -1988,6 +1999,12 @@
|
||||
node: function() {
|
||||
return new ThreadUpdater.Updater(this);
|
||||
},
|
||||
/*
|
||||
http://freesound.org/people/pierrecartoons1979/sounds/90112/
|
||||
cc-by-nc-3.0
|
||||
*/
|
||||
|
||||
beep: 'data:audio/wav;base64,UklGRjQDAABXQVZFZm10IBAAAAABAAEAgD4AAIA+AAABAAgAc21wbDwAAABBAAADAAAAAAAAAAA8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABkYXRhzAIAAGMms8em0tleMV4zIpLVo8nhfSlcPR102Ki+5JspVEkdVtKzs+K1NEhUIT7DwKrcy0g6WygsrM2k1NpiLl0zIY/WpMrjgCdbPhxw2Kq+5Z4qUkkdU9K1s+K5NkVTITzBwqnczko3WikrqM+l1NxlLF0zIIvXpsnjgydZPhxs2ay95aIrUEkdUdC3suK8N0NUIjq+xKrcz002WioppdGm091pK1w0IIjYp8jkhydXPxxq2K295aUrTkoeTs65suK+OUFUIzi7xqrb0VA0WSoootKm0t5tKlo1H4TYqMfkiydWQBxm16+85actTEseS8y7seHAPD9TIza5yKra01QyWSson9On0d5wKVk2H4DYqcfkjidUQB1j1rG75KsvSkseScu8seDCPz1TJDW2yara1FYxWSwnm9Sn0N9zKVg2H33ZqsXkkihSQR1g1bK65K0wSEsfR8i+seDEQTxUJTOzy6rY1VowWC0mmNWoz993KVc3H3rYq8TklSlRQh1d1LS647AyR0wgRMbAsN/GRDpTJTKwzKrX1l4vVy4lldWpzt97KVY4IXbUr8LZljVPRCxhw7W3z6ZISkw1VK+4sMWvXEhSPk6buay9sm5JVkZNiLWqtrJ+TldNTnquqbCwilZXU1BwpKirrpNgWFhTaZmnpquZbFlbVmWOpaOonHZcXlljhaGhpZ1+YWBdYn2cn6GdhmdhYGN3lp2enIttY2Jjco+bnJuOdGZlZXCImJqakHpoZ2Zug5WYmZJ/bGlobX6RlpeSg3BqaW16jZSVkoZ0bGtteImSk5KIeG5tbnaFkJKRinxxbm91gY2QkIt/c3BwdH6Kj4+LgnZxcXR8iI2OjIR5c3J0e4WLjYuFe3VzdHmCioyLhn52dHR5gIiKioeAeHV1eH+GiYqHgXp2dnh9hIiJh4J8eHd4fIKHiIeDfXl4eHyBhoeHhH96eHmA',
|
||||
Updater: (function() {
|
||||
|
||||
function _Class(thread) {
|
||||
@ -2064,9 +2081,7 @@
|
||||
}
|
||||
},
|
||||
visibility: function() {
|
||||
var state;
|
||||
state = d.visibilityState || d.oVisibilityState || d.mozVisibilityState || d.webkitVisibilityState;
|
||||
if (state !== 'visible') {
|
||||
if ($.hidden()) {
|
||||
return;
|
||||
}
|
||||
this.unsuccessfulFetchCount = 0;
|
||||
@ -2085,7 +2100,7 @@
|
||||
return this.scrollBG = this['Scroll BG'] ? function() {
|
||||
return true;
|
||||
} : function() {
|
||||
return !(d.hidden || d.oHidden || d.mozHidden || d.webkitHidden);
|
||||
return !$.hidden();
|
||||
};
|
||||
},
|
||||
autoUpdate: function() {
|
||||
@ -2143,7 +2158,7 @@
|
||||
var i, j;
|
||||
i = this.interval;
|
||||
j = Math.min(this.unsuccessfulFetchCount, 10);
|
||||
if (!(d.hidden || d.oHidden || d.mozHidden || d.webkitHidden)) {
|
||||
if (!$.hidden()) {
|
||||
j = Math.min(j, 7);
|
||||
}
|
||||
return this.seconds = Math.max(i, [0, 5, 10, 15, 20, 30, 60, 90, 120, 240, 300][j]);
|
||||
@ -2231,6 +2246,14 @@
|
||||
}
|
||||
}
|
||||
if (count) {
|
||||
if (Conf['Beep'] && $.hidden() && (Unread.replies.length === 0)) {
|
||||
if (!this.audio) {
|
||||
this.audio = $.el('audio', {
|
||||
src: ThreadUpdater.beep
|
||||
});
|
||||
}
|
||||
audio.play();
|
||||
}
|
||||
this.set('status', "+" + count);
|
||||
this.status.className = 'new';
|
||||
this.unsuccessfulFetchCount = 0;
|
||||
@ -2299,7 +2322,7 @@
|
||||
};
|
||||
|
||||
function Post(root, thread, board, that) {
|
||||
var alt, anchor, bq, capcode, data, date, email, file, fileInfo, flag, i, info, name, node, nodes, post, quotelink, quotes, size, subject, text, thumb, tripcode, uniqueID, unit, _i, _j, _k, _len, _len1, _ref, _ref1, _ref2;
|
||||
var alt, anchor, bq, capcode, data, date, email, file, fileInfo, flag, hash, i, info, name, node, nodes, pathname, post, quotelink, quotes, size, subject, text, thumb, tripcode, uniqueID, unit, _i, _j, _k, _len, _len1, _ref, _ref1, _ref2;
|
||||
this.thread = thread;
|
||||
this.board = board;
|
||||
if (that == null) {
|
||||
@ -2365,13 +2388,22 @@
|
||||
_ref2 = $$('.quotelink', this.nodes.comment);
|
||||
for (_k = 0, _len1 = _ref2.length; _k < _len1; _k++) {
|
||||
quotelink = _ref2[_k];
|
||||
if (quotelink.hash) {
|
||||
this.nodes.quotelinks.push(quotelink);
|
||||
if (quotelink.parentNode.parentNode.className === 'capcodeReplies') {
|
||||
continue;
|
||||
}
|
||||
quotes["" + (quotelink.pathname.split('/')[1]) + "." + quotelink.hash.slice(2)] = true;
|
||||
hash = quotelink.hash;
|
||||
if (!hash) {
|
||||
continue;
|
||||
}
|
||||
pathname = quotelink.pathname;
|
||||
if (/catalog$/.test(pathname)) {
|
||||
continue;
|
||||
}
|
||||
if (quotelink.hostname !== 'boards.4chan.org') {
|
||||
continue;
|
||||
}
|
||||
this.nodes.quotelinks.push(quotelink);
|
||||
if (quotelink.parentNode.parentNode.className === 'capcodeReplies') {
|
||||
continue;
|
||||
}
|
||||
quotes["" + (pathname.split('/')[1]) + "." + hash.slice(2)] = true;
|
||||
}
|
||||
this.quotes = Object.keys(quotes);
|
||||
if ((file = $('.file', post)) && (thumb = $('img[data-md5]', file))) {
|
||||
|
||||
2
LICENSE
2
LICENSE
@ -1,5 +1,5 @@
|
||||
Copyright (c) 2009-2011 James Campos <james.r.campos@gmail.com>
|
||||
Copyright (c) 2012 Nicolas Stepien <stepien.nicolas@gmail.com>
|
||||
Copyright (c) 2012-2013 Nicolas Stepien <stepien.nicolas@gmail.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
|
||||
41
changelog
41
changelog
@ -7,6 +7,47 @@ alpha
|
||||
Fix Quote Highlighting not affecting inlined quotes.
|
||||
|
||||
master
|
||||
- Mayhem
|
||||
Add /po/ archive redirection for threads, images and post resurrection.
|
||||
|
||||
2.37.3
|
||||
- Mayhem
|
||||
Fix successful posting causing errors.
|
||||
Fix 4chan X trying to interact with >>>/board/rules links.
|
||||
|
||||
2.37.2
|
||||
- aeosynth
|
||||
Beep on new post to completely read thread
|
||||
- Mayhem
|
||||
Fix dead quotes.
|
||||
|
||||
2.37.1
|
||||
- noface
|
||||
Fix Anonymize not working on stubs.
|
||||
- Mayhem
|
||||
Fix selection quoting on Opera.
|
||||
Fix history bug with Persistent QR enabled on Chrome.
|
||||
Fix posting warning not displaying the reason.
|
||||
Fix deadquotes showing up in code-tags.
|
||||
|
||||
2.37.0
|
||||
- noface
|
||||
Add Catalog Links toggle.
|
||||
Fix Anonymize not working on hovered posts.
|
||||
- Mayhem
|
||||
Added catalog support.
|
||||
Sync thread hiding between index and catalog.
|
||||
Add /c/ archived thread and image redirection.
|
||||
|
||||
2.36.3
|
||||
- Mayhem
|
||||
Fix next/previous page keybinds.
|
||||
|
||||
2.36.2
|
||||
- noface
|
||||
Add tags support on /f/.
|
||||
- Mayhem
|
||||
Add /mu/ archived image redirection.
|
||||
|
||||
2.36.1
|
||||
- noface
|
||||
|
||||
@ -1 +1 @@
|
||||
postMessage({version:'2.36.1'},'*')
|
||||
postMessage({version:'2.37.3'},'*')
|
||||
@ -138,6 +138,8 @@ $.extend $,
|
||||
return
|
||||
open: (url) ->
|
||||
(GM_openInTab or window.open) url, '_blank'
|
||||
hidden: ->
|
||||
d.hidden or d.oHidden or d.mozHidden or d.webkitHidden
|
||||
queueTask: (->
|
||||
# inspired by https://www.w3.org/Bugs/Public/show_bug.cgi?id=15007
|
||||
taskQueue = []
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
* http://mayhemydg.github.com/4chan-x/
|
||||
*
|
||||
* Copyright (c) 2009-2011 James Campos <james.r.campos@gmail.com>
|
||||
* Copyright (c) <%= grunt.template.today('yyyy') %> Nicolas Stepien <stepien.nicolas@gmail.com>
|
||||
* Copyright (c) 2012-<%= grunt.template.today('yyyy') %> Nicolas Stepien <stepien.nicolas@gmail.com>
|
||||
* Licensed under the MIT license.
|
||||
* <%= meta.repo %>blob/master/LICENSE
|
||||
*
|
||||
|
||||
@ -156,6 +156,7 @@ Config =
|
||||
'hide': ['x', 'Hide thread.']
|
||||
updater:
|
||||
checkbox:
|
||||
'Beep': [false, 'Beep on new post to completely read thread.']
|
||||
'Auto Scroll': [false, 'Scroll updated posts into view. Only enabled at bottom of page.']
|
||||
'Scroll BG': [false, 'Auto-scroll background tabs.']
|
||||
'Auto Update': [true, 'Automatically fetch new posts.']
|
||||
|
||||
@ -7,20 +7,26 @@ Redirect =
|
||||
"//archive.foolz.us/#{board}/full_image/#{filename}"
|
||||
when 'u'
|
||||
"//nsfw.foolz.us/#{board}/full_image/#{filename}"
|
||||
when 'po'
|
||||
"http://archive.thedarkcave.org/#{board}/full_image/#{filename}"
|
||||
when 'ck', 'lit'
|
||||
"//fuuka.warosu.org/#{board}/full_image/#{filename}"
|
||||
when 'diy', 'sci'
|
||||
"//archive.installgentoo.net/#{board}/full_image/#{filename}"
|
||||
when 'cgl', 'g', 'mu', 'soc', 'w'
|
||||
when 'cgl', 'g', 'mu', 'w'
|
||||
"//rbt.asia/#{board}/full_image/#{filename}"
|
||||
when 'an', 'fit', 'k', 'mlp', 'r9k', 'toy', 'x'
|
||||
"http://archive.heinessen.com/#{board}/full_image/#{filename}"
|
||||
when 'c'
|
||||
"//archive.nyafuu.org/#{board}/full_image/#{filename}"
|
||||
post: (board, postID) ->
|
||||
switch board
|
||||
when 'a', 'co', 'jp', 'm', 'q', 'sp', 'tg', 'tv', 'v', 'vg', 'wsg', 'dev', 'foolz'
|
||||
"//archive.foolz.us/_/api/chan/post/?board=#{board}&num=#{postID}"
|
||||
when 'u', 'kuku'
|
||||
"//nsfw.foolz.us/_/api/chan/post/?board=#{board}&num=#{postID}"
|
||||
when 'po'
|
||||
"http://archive.thedarkcave.org/_/api/chan/post/?board=#{board}&num=#{postID}"
|
||||
# for fuuka-based archives:
|
||||
# https://github.com/eksopl/fuuka/issues/27
|
||||
to: (data) ->
|
||||
@ -30,14 +36,18 @@ Redirect =
|
||||
url = Redirect.path '//archive.foolz.us', 'foolfuuka', data
|
||||
when 'u', 'kuku'
|
||||
url = Redirect.path '//nsfw.foolz.us', 'foolfuuka', data
|
||||
when 'po'
|
||||
url = Redirect.path 'http://archive.thedarkcave.org', 'foolfuuka', data
|
||||
when 'ck', 'lit'
|
||||
url = Redirect.path '//fuuka.warosu.org', 'fuuka', data
|
||||
when 'diy', 'sci'
|
||||
url = Redirect.path '//archive.installgentoo.net', 'fuuka', data
|
||||
when 'cgl', 'g', 'mu', 'soc', 'w'
|
||||
when 'cgl', 'g', 'mu', 'w'
|
||||
url = Redirect.path '//rbt.asia', 'fuuka', data
|
||||
when 'an', 'fit', 'k', 'mlp', 'r9k', 'toy', 'x'
|
||||
url = Redirect.path 'http://archive.heinessen.com', 'fuuka', data
|
||||
when 'c'
|
||||
url = Redirect.path '//archive.nyafuu.org', 'fuuka', data
|
||||
else
|
||||
if data.threadID
|
||||
url = "//boards.4chan.org/#{board}/"
|
||||
@ -68,6 +78,8 @@ Redirect =
|
||||
"#{board}/thread/#{threadID}"
|
||||
else
|
||||
"#{board}/post/#{postID}"
|
||||
if archiver is 'foolfuuka'
|
||||
path += '/'
|
||||
if threadID and postID
|
||||
path +=
|
||||
if archiver is 'foolfuuka'
|
||||
@ -98,7 +110,7 @@ Build =
|
||||
capcode: data.capcode
|
||||
tripcode: data.trip
|
||||
uniqueID: data.id
|
||||
email: if data.email then encodeURIComponent data.email.replace /"/g, '"' else ''
|
||||
email: if data.email then encodeURI data.email.replace /"/g, '"' else ''
|
||||
subject: data.sub
|
||||
flagCode: data.country
|
||||
flagName: data.country_name
|
||||
@ -474,8 +486,12 @@ Get =
|
||||
'<b style="color: red;">'
|
||||
when '[/banned]'
|
||||
'</b>'
|
||||
# greentext
|
||||
comment = bq.innerHTML.replace /(^|>)(>[^<$]+)(<|$)/g, '$1<span class=quote>$2</span>$3'
|
||||
|
||||
comment = bq.innerHTML
|
||||
# greentext
|
||||
.replace(/(^|>)(>[^<$]*)(<|$)/g, '$1<span class=quote>$2</span>$3')
|
||||
# quotes
|
||||
.replace /((>){2}(>\/[a-z\d]+\/)?\d+)/g, '<span class=deadlink>$1</span>'
|
||||
|
||||
threadID = data.thread_num
|
||||
o =
|
||||
@ -491,7 +507,7 @@ Get =
|
||||
when 'D' then 'developer'
|
||||
tripcode: data.trip
|
||||
uniqueID: data.poster_hash
|
||||
email: if data.email then encodeURIComponent data.email else ''
|
||||
email: if data.email then encodeURI data.email else ''
|
||||
subject: data.title_processed
|
||||
flagCode: data.poster_country
|
||||
flagName: data.poster_country_name_processed
|
||||
@ -529,82 +545,63 @@ Quotify =
|
||||
cb: @node
|
||||
node: ->
|
||||
return if @isClone
|
||||
for deadlink in $$ '.deadlink', post.blockquote
|
||||
if deadlink.parentNode.className is 'prettyprint'
|
||||
# Don't quotify deadlinks inside code tags,
|
||||
# un-`span` them.
|
||||
$.replace deadlink, Array::slice.call deadlink.childNodes
|
||||
continue
|
||||
|
||||
# XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE === 6
|
||||
# Get all the text nodes that are not inside an anchor.
|
||||
snapshot = d.evaluate './/text()[not(parent::a)]', @nodes.comment, null, 6, null
|
||||
|
||||
for i in [0...snapshot.snapshotLength]
|
||||
node = snapshot.snapshotItem i
|
||||
data = node.data
|
||||
|
||||
# Only accept nodes with potentially valid links
|
||||
continue unless quotes = data.match />>(>\/[a-z\d]+\/)?\d+/g
|
||||
|
||||
nodes = []
|
||||
|
||||
for quote in quotes
|
||||
index = data.indexOf quote
|
||||
if text = data[...index]
|
||||
# Potential text before this valid quote.
|
||||
nodes.push $.tn text
|
||||
|
||||
ID = quote.match(/\d+$/)[0]
|
||||
board =
|
||||
if m = quote.match /^>>>\/([a-z\d]+)/
|
||||
m[1]
|
||||
else
|
||||
@board.ID
|
||||
|
||||
quoteID = "#{board}.#{ID}"
|
||||
|
||||
# \u00A0 is nbsp
|
||||
if post = g.posts[quoteID]
|
||||
if post.isDead
|
||||
a = $.el 'a',
|
||||
href: Redirect.to
|
||||
board: board
|
||||
threadID: 0
|
||||
postID: ID
|
||||
className: 'quotelink deadlink'
|
||||
textContent: "#{quote}\u00A0(Dead)"
|
||||
target: '_blank'
|
||||
a.setAttribute 'data-board', board
|
||||
a.setAttribute 'data-threadid', post.thread.ID
|
||||
a.setAttribute 'data-postid', ID
|
||||
else
|
||||
# Don't (Dead) when quotifying in an archived post,
|
||||
# and we know the post still exists.
|
||||
a = $.el 'a',
|
||||
href: "/#{board}/#{post.thread}/res/#p#{ID}"
|
||||
className: 'quotelink'
|
||||
textContent: quote
|
||||
quote = deadlink.textContent
|
||||
continue unless ID = quote.match(/\d+$/)?[0]
|
||||
board =
|
||||
if m = quote.match /^>>>\/([a-z\d]+)/
|
||||
m[1]
|
||||
else
|
||||
@board.ID
|
||||
quoteID = "#{board}.#{ID}"
|
||||
|
||||
# \u00A0 is nbsp
|
||||
if post = g.posts[quoteID]
|
||||
unless post.isDead
|
||||
# Don't (Dead) when quotifying in an archived post,
|
||||
# and we know the post still exists.
|
||||
a = $.el 'a',
|
||||
href: Redirect.to
|
||||
board: board
|
||||
threadID: 0
|
||||
postID: ID
|
||||
className: 'deadlink'
|
||||
href: "/#{board}/#{post.thread}/res/#p#{ID}"
|
||||
className: 'quotelink'
|
||||
textContent: quote
|
||||
else if redirect = Redirect.to {board: board, threadID: post.thread.ID, postID: ID}
|
||||
# Replace the .deadlink span if we can redirect.
|
||||
a = $.el 'a',
|
||||
href: redirect
|
||||
className: 'quotelink deadlink'
|
||||
target: '_blank'
|
||||
textContent: "#{quote}\u00A0(Dead)"
|
||||
if Redirect.post board, ID
|
||||
$.addClass a, 'quotelink'
|
||||
a.setAttribute 'data-board', board
|
||||
a.setAttribute 'data-postid', ID
|
||||
a.setAttribute 'data-board', board
|
||||
a.setAttribute 'data-threadid', post.thread.ID
|
||||
a.setAttribute 'data-postid', ID
|
||||
else if redirect = Redirect.to {board: board, threadID: 0, postID: ID}
|
||||
# Replace the .deadlink span if we can redirect.
|
||||
a = $.el 'a',
|
||||
href: redirect
|
||||
className: 'deadlink'
|
||||
target: '_blank'
|
||||
textContent: "#{quote}\u00A0(Dead)"
|
||||
if Redirect.post board, ID
|
||||
# Make it function as a normal quote if we can fetch the post.
|
||||
$.addClass a, 'quotelink'
|
||||
a.setAttribute 'data-board', board
|
||||
a.setAttribute 'data-postid', ID
|
||||
|
||||
if @quotes.indexOf(quoteID) is -1
|
||||
@quotes.push quoteID
|
||||
if $.hasClass a, 'quotelink'
|
||||
@nodes.quotelinks.push a
|
||||
nodes.push a
|
||||
data = data[index + quote.length..]
|
||||
if a
|
||||
$.replace deadlink, a
|
||||
else
|
||||
deadlink.textContent += "\u00A0(Dead)"
|
||||
|
||||
if data
|
||||
# Potential text after the last valid quote.
|
||||
nodes.push $.tn data
|
||||
|
||||
$.replace node, nodes
|
||||
if @quotes.indexOf(quoteID) is -1
|
||||
@quotes.push quoteID
|
||||
if $.hasClass a, 'quotelink'
|
||||
@nodes.quotelinks.push a
|
||||
return
|
||||
|
||||
QuoteInline =
|
||||
@ -1109,6 +1106,12 @@ ThreadUpdater =
|
||||
cb: @node
|
||||
node: ->
|
||||
new ThreadUpdater.Updater @
|
||||
###
|
||||
http://freesound.org/people/pierrecartoons1979/sounds/90112/
|
||||
cc-by-nc-3.0
|
||||
###
|
||||
beep: 'data:audio/wav;base64,UklGRjQDAABXQVZFZm10IBAAAAABAAEAgD4AAIA+AAABAAgAc21wbDwAAABBAAADAAAAAAAAAAA8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABkYXRhzAIAAGMms8em0tleMV4zIpLVo8nhfSlcPR102Ki+5JspVEkdVtKzs+K1NEhUIT7DwKrcy0g6WygsrM2k1NpiLl0zIY/WpMrjgCdbPhxw2Kq+5Z4qUkkdU9K1s+K5NkVTITzBwqnczko3WikrqM+l1NxlLF0zIIvXpsnjgydZPhxs2ay95aIrUEkdUdC3suK8N0NUIjq+xKrcz002WioppdGm091pK1w0IIjYp8jkhydXPxxq2K295aUrTkoeTs65suK+OUFUIzi7xqrb0VA0WSoootKm0t5tKlo1H4TYqMfkiydWQBxm16+85actTEseS8y7seHAPD9TIza5yKra01QyWSson9On0d5wKVk2H4DYqcfkjidUQB1j1rG75KsvSkseScu8seDCPz1TJDW2yara1FYxWSwnm9Sn0N9zKVg2H33ZqsXkkihSQR1g1bK65K0wSEsfR8i+seDEQTxUJTOzy6rY1VowWC0mmNWoz993KVc3H3rYq8TklSlRQh1d1LS647AyR0wgRMbAsN/GRDpTJTKwzKrX1l4vVy4lldWpzt97KVY4IXbUr8LZljVPRCxhw7W3z6ZISkw1VK+4sMWvXEhSPk6buay9sm5JVkZNiLWqtrJ+TldNTnquqbCwilZXU1BwpKirrpNgWFhTaZmnpquZbFlbVmWOpaOonHZcXlljhaGhpZ1+YWBdYn2cn6GdhmdhYGN3lp2enIttY2Jjco+bnJuOdGZlZXCImJqakHpoZ2Zug5WYmZJ/bGlobX6RlpeSg3BqaW16jZSVkoZ0bGtteImSk5KIeG5tbnaFkJKRinxxbm91gY2QkIt/c3BwdH6Kj4+LgnZxcXR8iI2OjIR5c3J0e4WLjYuFe3VzdHmCioyLhn52dHR5gIiKioeAeHV1eH+GiYqHgXp2dnh9hIiJh4J8eHd4fIKHiIeDfXl4eHyBhoeHhH96eHmA'
|
||||
|
||||
|
||||
Updater: class
|
||||
constructor: (@thread) ->
|
||||
@ -1175,8 +1178,7 @@ ThreadUpdater =
|
||||
@unsuccessfulFetchCount = 0
|
||||
setTimeout @update.bind(@), 1000 if @seconds > 2
|
||||
visibility: ->
|
||||
state = d.visibilityState or d.oVisibilityState or d.mozVisibilityState or d.webkitVisibilityState
|
||||
return if state isnt 'visible'
|
||||
return if $.hidden()
|
||||
# Reset the counter when we focus this tab.
|
||||
@unsuccessfulFetchCount = 0
|
||||
if @seconds > @interval
|
||||
@ -1191,7 +1193,7 @@ ThreadUpdater =
|
||||
if @['Scroll BG']
|
||||
-> true
|
||||
else
|
||||
-> !(d.hidden or d.oHidden or d.mozHidden or d.webkitHidden)
|
||||
-> not $.hidden()
|
||||
autoUpdate: ->
|
||||
if @['Auto Update This'] and @online
|
||||
@timeoutID = setTimeout @timeout.bind(@), 1000
|
||||
@ -1241,7 +1243,7 @@ ThreadUpdater =
|
||||
getInterval: ->
|
||||
i = @interval
|
||||
j = Math.min @unsuccessfulFetchCount, 10
|
||||
unless d.hidden or d.oHidden or d.mozHidden or d.webkitHidden
|
||||
unless $.hidden()
|
||||
# Lower the max refresh rate limit on visible tabs.
|
||||
j = Math.min j, 7
|
||||
@seconds = Math.max i, [0, 5, 10, 15, 20, 30, 60, 90, 120, 240, 300][j]
|
||||
@ -1308,6 +1310,10 @@ ThreadUpdater =
|
||||
post.kill true
|
||||
|
||||
if count
|
||||
if Conf['Beep'] and $.hidden() and (Unread.replies.length is 0)
|
||||
unless @audio
|
||||
@audio = $.el 'audio', src: ThreadUpdater.beep
|
||||
audio.play()
|
||||
@set 'status', "+#{count}"
|
||||
@status.className = 'new'
|
||||
@unsuccessfulFetchCount = 0
|
||||
|
||||
@ -88,13 +88,24 @@ class Post
|
||||
quotes = {}
|
||||
for quotelink in $$ '.quotelink', @nodes.comment
|
||||
# Don't add board links. (>>>/b/)
|
||||
hash = quotelink.hash
|
||||
continue unless hash
|
||||
|
||||
# Don't add catalog links. (>>>/b/catalog or >>>/b/search)
|
||||
pathname = quotelink.pathname
|
||||
continue if /catalog$/.test pathname
|
||||
|
||||
# Don't add rules links. (>>>/a/rules)
|
||||
# Don't add text-board quotelinks. (>>>/img/1234)
|
||||
continue if quotelink.hostname isnt 'boards.4chan.org'
|
||||
|
||||
@nodes.quotelinks.push quotelink
|
||||
|
||||
# Don't count capcode replies as quotes. (Admin/Mod/Dev Replies: ...)
|
||||
# Only add quotes that link to posts on an imageboard.
|
||||
if quotelink.hash
|
||||
@nodes.quotelinks.push quotelink
|
||||
continue if quotelink.parentNode.parentNode.className is 'capcodeReplies'
|
||||
quotes["#{quotelink.pathname.split('/')[1]}.#{quotelink.hash[2..]}"] = true
|
||||
continue if quotelink.parentNode.parentNode.className is 'capcodeReplies'
|
||||
|
||||
# Basically, only add quotes that link to posts on an imageboard.
|
||||
quotes["#{pathname.split('/')[1]}.#{hash[2..]}"] = true
|
||||
@quotes = Object.keys quotes
|
||||
|
||||
if (file = $ '.file', post) and thumb = $ 'img[data-md5]', file
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
// @version <%= pkg.version %>
|
||||
// @description Cross-browser userscript for maximum lurking on 4chan.
|
||||
// @copyright 2009-2011 James Campos <james.r.campos@gmail.com>
|
||||
// @copyright <%= grunt.template.today('yyyy') %> Nicolas Stepien <stepien.nicolas@gmail.com>
|
||||
// @copyright 2012-<%= grunt.template.today('yyyy') %> Nicolas Stepien <stepien.nicolas@gmail.com>
|
||||
// @license MIT; http://en.wikipedia.org/wiki/Mit_license
|
||||
// @match *://boards.4chan.org/*
|
||||
// @match *://images.4chan.org/*
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user