diff --git a/builds/4chan-X.js b/builds/4chan-X.js
index 2817d9d1b..83959c986 100644
--- a/builds/4chan-X.js
+++ b/builds/4chan-X.js
@@ -2048,7 +2048,10 @@
return $.cache("//api.4chan.org/" + boardID + "/res/" + threadID + ".json", function() {
return Get.fetchedPost(this, boardID, threadID, postID, root, context);
});
- } else if (url = Redirect.post(boardID, postID)) {
+ } else if (url = Redirect.to('post', {
+ boardID: boardID,
+ postID: postID
+ })) {
return $.cache(url, function() {
return Get.archivedPost(this, boardID, postID, root, context);
});
@@ -2077,7 +2080,10 @@
}
status = req.status;
if (![200, 304].contains(status)) {
- if (url = Redirect.post(boardID, postID)) {
+ if (url = Redirect.to('post', {
+ boardID: boardID,
+ postID: postID
+ })) {
$.cache(url, function() {
return Get.archivedPost(this, boardID, postID, root, context);
});
@@ -2095,7 +2101,10 @@
break;
}
if (post.no > postID) {
- if (url = Redirect.post(boardID, postID)) {
+ if (url = Redirect.to('post', {
+ boardID: boardID,
+ postID: postID
+ })) {
$.cache(url, function() {
return Get.archivedPost(this, boardID, postID, root, context);
});
@@ -4223,7 +4232,7 @@
a.setAttribute('data-threadid', post.thread.ID);
a.setAttribute('data-postid', postID);
}
- } else if (redirect = Redirect.to({
+ } else if (redirect = Redirect.to('thread', {
boardID: boardID,
threadID: 0,
postID: postID
@@ -4234,7 +4243,10 @@
target: '_blank',
textContent: "" + quote + "\u00A0(Dead)"
});
- if (Redirect.post(boardID, postID)) {
+ if (Redirect.to('post', {
+ boardID: boardID,
+ postID: postID
+ })) {
$.addClass(a, 'quotelink');
a.setAttribute('data-boardid', boardID);
a.setAttribute('data-postid', postID);
@@ -6233,7 +6245,11 @@
ImageExpand.contract(post);
src = this.src.split('/');
if (src[2] === 'images.4chan.org') {
- if (URL = Redirect.image(src[3], src[5])) {
+ URL = Redirect.to('file', {
+ boardID: src[3],
+ filename: src[5]
+ });
+ if (URL) {
setTimeout(ImageExpand.expand, 10000, post, URL);
return;
}
@@ -6369,7 +6385,11 @@
post = g.posts[this.dataset.fullid];
src = this.src.split('/');
if (src[2] === 'images.4chan.org') {
- if (URL = Redirect.image(src[3], src[5].replace(/\?.+$/, ''))) {
+ URL = Redirect.to('file', {
+ boardID: src[3],
+ filename: src[5].replace(/\?.+$/, '')
+ });
+ if (URL) {
this.src = URL;
return;
}
@@ -6475,15 +6495,14 @@
el: div,
order: 90,
open: function(_arg) {
- var ID, board, redirect, thread;
+ var ID, board, thread;
ID = _arg.ID, thread = _arg.thread, board = _arg.board;
- redirect = Redirect.to({
+ return !!Redirect.to('thread', {
postID: ID,
threadID: thread.ID,
boardID: board.ID
});
- return redirect !== ("//boards.4chan.org/" + board + "/");
},
subEntries: []
};
@@ -6505,7 +6524,7 @@
var ID, board, thread;
ID = _arg.ID, thread = _arg.thread, board = _arg.board;
- el.href = Redirect.to({
+ el.href = Redirect.to('thread', {
postID: ID,
threadID: thread.ID,
boardID: board.ID
@@ -6518,7 +6537,7 @@
if (!value) {
return false;
}
- el.href = Redirect.to({
+ el.href = Redirect.to('search', {
boardID: post.board.ID,
type: type,
value: value,
@@ -7731,185 +7750,197 @@
};
Redirect = {
+ thread: {},
+ post: {},
+ file: {},
init: function() {
- return $.sync('archivers', this.updateArchives);
- },
- updateArchives: function() {
- return $.get('archivers', {}, function(_arg) {
- var archivers;
+ var archive, arr, boardID, data, id, name, type, _i, _len, _ref, _ref1, _ref2, _ref3;
- archivers = _arg.archivers;
- return Conf['archivers'] = archivers;
- });
- },
- imageArchives: (function() {
- var o;
-
- o = {
- a: "//archive.foolz.us/",
- ck: "//fuuka.warosu.org/",
- an: "http://archive.heinessen.com/",
- cgl: "//rbt.asia/",
- c: "//archive.nyafuu.org/",
- d: "//loveisover.me/",
- e: "http://archive.foolzashit.com",
- hr: "http://archive.4plebs.org/",
- u: "//nsfw.foolz.us/",
- po: "//archive.thedarkcave.org/",
- vg: "http://nth.pensivenonsen.se/",
- c: "//archive.nyafuu.org/"
- };
- o.adv = o.asp = o.cm = o.i = o.n = o.o = o.p = o.s = o.t = o.trv = o.y = o.lgbt = o.s4s = o.e;
- o.gd = o.jp = o.m = o.q = o.tg = o.vp = o.vr = o.wsg = o.a;
- o.fa = o.lit = o.ck;
- o.k = o.toy = o.x = o.an;
- o.g = o.mu = o.cgl;
- o.w = o.wg = o.c;
- o.h = o.v = o.d;
- o.tv = o.hr;
- return o;
- })(),
- image: function(boardID, filename) {
- return "" + Redirect.imageArchives[boardID] + boardID + "/full_image/" + filename;
- },
- post: function(boardID, postID) {
- var archive, name, _base, _ref;
-
- if (Redirect.post[boardID] == null) {
- _ref = this.archiver;
- for (name in _ref) {
- archive = _ref[name];
- if (archive.type === 'foolfuuka' && archive.boards.contains(boardID)) {
- Redirect.post[boardID] = archive.base;
- break;
+ _ref = Conf['selectedArchives'];
+ for (boardID in _ref) {
+ data = _ref[boardID];
+ for (type in data) {
+ id = data[type];
+ _ref1 = Redirect.archives;
+ for (name in _ref1) {
+ archive = _ref1[name];
+ if (name !== id || type === 'post' && archive.software !== 'foolfuuka') {
+ continue;
+ }
+ arr = type === 'file' ? archive.files : archive.boards;
+ if (arr.contains(boardID)) {
+ Redirect[type][boardID] = archive;
+ }
}
}
- (_base = Redirect.post)[boardID] || (_base[boardID] = false);
}
- if (Redirect.post[boardID]) {
- return "" + Redirect.post[boardID] + "/_/api/chan/post/?board=" + boardID + "&num=" + postID;
- } else {
- return null;
- }
- },
- select: function(board) {
- var archive, name, _ref, _results;
-
- _ref = this.archiver;
- _results = [];
- for (name in _ref) {
- archive = _ref[name];
- if (!archive.boards.contains(board)) {
- continue;
+ _ref2 = Redirect.archives;
+ for (name in _ref2) {
+ archive = _ref2[name];
+ _ref3 = archive.boards;
+ for (_i = 0, _len = _ref3.length; _i < _len; _i++) {
+ boardID = _ref3[_i];
+ if (!(boardID in Redirect.thread)) {
+ Redirect.thread[boardID] = archive;
+ }
+ if (!(boardID in Redirect.post || archive.software !== 'foolfuuka')) {
+ Redirect.post[boardID] = archive;
+ }
+ if (!(boardID in Redirect.file || !archive.files.contains(boardID))) {
+ Redirect.file[boardID] = archive;
+ }
}
- _results.push(name);
- }
- return _results;
- },
- to: function(data) {
- var arch, archive, boardID;
-
- boardID = data.boardID;
- if ((arch = Conf.archivers[boardID]) == null) {
- Conf.archivers[boardID] = arch = this.select(boardID)[0];
- $.set('archivers', Conf.archivers);
- }
- return (arch && (archive = this.archiver[arch]) ? Redirect.path(archive.base, archive.type, data) : data.threadID ? "//boards.4chan.org/" + boardID + "/" : null);
- if (!archive.boards.contains(g.BOARD.ID)) {
- return Conf['archivers'] = archive;
}
},
- archiver: {
+ archives: {
'Foolz': {
- base: 'https://archive.foolz.us',
- boards: ['a', 'co', 'gd', 'jp', 'm', 'q', 'sp', 'tg', 'tv', 'vp', 'vr', 'wsg'],
- type: 'foolfuuka'
+ 'domain': 'archive.foolz.us',
+ 'http': true,
+ 'https': true,
+ 'software': 'foolfuuka',
+ 'boards': ['a', 'co', 'gd', 'jp', 'm', 'q', 'sp', 'tg', 'tv', 'vp', 'vr', 'wsg'],
+ 'files': ['a', 'gd', 'jp', 'm', 'q', 'tg', 'vp', 'vr', 'wsg']
},
- 'NSFWFoolz': {
- base: 'https://nsfw.foolz.us',
- boards: ['u'],
- type: 'foolfuuka'
+ 'NSFW Foolz': {
+ 'domain': 'nsfw.foolz.us',
+ 'http': true,
+ 'https': true,
+ 'software': 'foolfuuka',
+ 'boards': ['u'],
+ 'files': ['u']
},
- 'TheDarkCave': {
- base: 'http://archive.thedarkcave.org',
- boards: ['c', 'int', 'out', 'po'],
- type: 'foolfuuka'
+ 'The Dark Cave': {
+ 'domain': 'archive.thedarkcave.org',
+ 'http': true,
+ 'https': true,
+ 'software': 'foolfuuka',
+ 'boards': ['c', 'int', 'out', 'po'],
+ 'files': ['c', 'po']
},
'4plebs': {
- base: 'http://archive.4plebs.org',
- boards: ['hr', 'tg', 'tv', 'x'],
- base: 'foolfuuka'
+ 'domain': 'archive.4plebs.org',
+ 'http': true,
+ 'software': 'foolfuuka',
+ 'boards': ['hr', 'tg', 'tv', 'x'],
+ 'files': ['hr', 'tg', 'tv', 'x']
},
- 'NyaFuu': {
- base: '//archive.nyafuu.org',
- boards: ['c', 'w', 'wg'],
- type: 'foolfuuka'
+ 'Nyafuu': {
+ 'http': true,
+ 'https': true,
+ 'software': 'foolfuuka',
+ 'boards': ['c', 'w', 'wg'],
+ 'files': ['c', 'w', 'wg']
},
- 'LoveIsOver': {
- base: '//loveisover.me',
- boards: ['d', 'h', 'v'],
- type: 'foolfuuka'
+ 'Love is Over': {
+ 'domain': 'loveisover.me',
+ 'http': true,
+ 'https': true,
+ 'software': 'foolfuuka',
+ 'boards': ['d', 'h', 'v'],
+ 'files': ['d', 'h', 'v']
},
- 'PensiveNonsen': {
- base: 'http://nth.pensivenonsen.se',
- boards: ['vg'],
- type: 'foolfuuka'
+ 'nth-chan': {
+ 'domain': 'nth.pensivenonsen.se',
+ 'http': true,
+ 'software': 'foolfuuka',
+ 'boards': ['vg'],
+ 'files': ['vg']
},
- 'FoolzaShit': {
- base: 'http://archive.foolzashit.com',
- boards: ["adv", "asp", "cm", "e", "i", "lgbt", "n", "o", "p", "s", "s4s", "t", "trv", "y"],
- type: 'foolfuuka'
+ 'Foolz a Shit': {
+ 'domain': 'archive.foolzashit.com',
+ 'http': true,
+ 'https': true,
+ 'software': 'foolfuuka',
+ 'boards': ['adv', 'asp', 'cm', 'e', 'i', 'lgbt', 'n', 'o', 'p', 's', 's4s', 't', 'trv', 'y'],
+ 'files': ['adv', 'asp', 'cm', 'e', 'i', 'lgbt', 'n', 'o', 'p', 's', 's4s', 't', 'trv', 'y']
},
- 'Warosu': {
- base: '//fuuka.warosu.org',
- boards: ['cgl', 'ck', 'fa', 'jp', 'lit', 's4s', 'q', 'tg', 'vr'],
- type: 'fuuka'
+ 'Install Gentoo': {
+ 'domain': 'archive.installgentoo.net',
+ 'http': true,
+ 'https': true,
+ 'software': 'fuuka',
+ 'boards': ['diy', 'g', 'sci'],
+ 'files': []
},
- 'InstallGentoo': {
- base: '//archive.installgentoo.net',
- boards: ['diy', 'g', 'sci'],
- type: 'fuuka'
- },
- 'RebeccaBlackTech': {
- base: '//rbt.asia',
- boards: ['cgl', 'g', 'mu', 'w'],
- type: 'fuuka_mail'
+ 'Rebecca Black Tech': {
+ 'domain': 'rbt.asia',
+ 'http': true,
+ 'https': true,
+ 'software': 'fuuka',
+ 'boards': ['cgl', 'g', 'mu', 'w'],
+ 'files': ['cgl', 'g', 'mu', 'w']
},
'Heinessen': {
- base: 'http://archive.heinessen.com',
- boards: ['an', 'fit', 'k', 'mlp', 'r9k', 'toy', 'x'],
- type: 'fuuka'
+ 'domain': 'archive.heinessen.com',
+ 'http': true,
+ 'software': 'fuuka',
+ 'boards': ['an', 'fit', 'k', 'mlp', 'r9k', 'toy', 'x'],
+ 'files': ['an', 'k', 'toy', 'x']
},
- 'Cliche': {
- base: '//www.cliché.net/4chan/cgi-board.pl',
- boards: ['e'],
- type: 'fuuka'
+ 'warosu': {
+ 'domain': 'fuuka.warosu.org',
+ 'http': true,
+ 'https': true,
+ 'software': 'fuuka',
+ 'boards': ['3', 'cgl', 'ck', 'fa', 'ic', 'jp', 'lit', 'q', 's4s', 'tg', 'vr'],
+ 'files': ['3', 'cgl', 'ck', 'fa', 'ic', 'jp', 'lit', 'q', 's4s', 'vr']
}
},
- path: function(base, archiver, data) {
- var boardID, path, postID, threadID, type, value;
+ to: function(dest, data) {
+ var archive;
- if (data.isSearch) {
- boardID = data.boardID, type = data.type, value = data.value;
- type = type === 'name' ? 'username' : type === 'MD5' ? 'image' : type;
- value = encodeURIComponent(value);
- if (archiver === 'foolfuuka') {
- return "" + base + "/" + boardID + "/search/" + type + "/" + value;
- } else if (type === 'image') {
- return "" + base + "/" + boardID + "/?task=search2&search_media_hash=" + value;
- } else {
- return "" + base + "/" + boardID + "/?task=search2&search_" + type + "=" + value;
- }
+ archive = (dest === 'search' ? Redirect.thread : Redirect[dest])[data.boardID];
+ if (!archive) {
+ return '';
}
- boardID = data.boardID, threadID = data.threadID, postID = data.postID;
+ return Redirect[dest](archive, data);
+ },
+ protocol: function(archive) {
+ var protocol;
+
+ protocol = location.protocol;
+ if (!archive[protocol.slice(0, -1)]) {
+ protocol = protocol === 'https:' ? 'http:' : 'https:';
+ }
+ return "" + protocol + "//";
+ },
+ thread: function(archive, _arg) {
+ var boardID, path, postID, threadID;
+
+ boardID = _arg.boardID, threadID = _arg.threadID, postID = _arg.postID;
path = threadID ? "" + boardID + "/thread/" + threadID : "" + boardID + "/post/" + postID;
- if (archiver === 'foolfuuka') {
+ if (archive.software === 'foolfuuka') {
path += '/';
}
if (threadID && postID) {
- path += archiver === 'foolfuuka' ? "#" + postID : "#p" + postID;
+ path += archive.software === 'foolfuuka' ? "#" + postID : "#p" + postID;
}
- return "" + base + "/" + path;
+ return "" + (Redirect.protocol(archive)) + archive.domain + "/" + path;
+ },
+ post: function(archive, _arg) {
+ var boardID, postID, protocol;
+
+ boardID = _arg.boardID, postID = _arg.postID;
+ protocol = Redirect.protocol(archive);
+ if (['Foolz', 'NSFW Foolz'].contains(archive.name)) {
+ protocol = 'https://';
+ }
+ return "" + protocol + archive.domain + "/_/api/chan/post/?board=" + boardID + "&num=" + postID;
+ },
+ file: function(archive, _arg) {
+ var boardID, filename;
+
+ boardID = _arg.boardID, filename = _arg.filename;
+ return "" + (Redirect.protocol(archive)) + archive.domain + "/" + boardID + "/full_image/" + filename;
+ },
+ search: function(archive, _arg) {
+ var boardID, path, type, value;
+
+ boardID = _arg.boardID, type = _arg.type, value = _arg.value;
+ type = type === 'name' ? 'username' : type === 'MD5' ? 'image' : type;
+ value = encodeURIComponent(value);
+ path = archive.software === 'foolfuuka' ? "" + boardID + "/search/" + type + "/" + value : "" + boardID + "/?task=search2&search_" + (type === 'image' ? 'media_hash' : type) + "=" + value;
+ return "" + (Redirect.protocol(archive)) + archive.domain + "/" + path;
}
};
@@ -9345,6 +9376,7 @@
Settings.addSection('Filter', Settings.filter);
Settings.addSection('Sauce', Settings.sauce);
Settings.addSection('Advanced', Settings.advanced);
+ Settings.addSection('Archives', Settings.archives);
Settings.addSection('Keybinds', Settings.keybinds);
$.on(d, 'AddSettingsSection', Settings.addSection);
$.on(d, 'OpenSettings', function(e) {
@@ -9725,9 +9757,9 @@
return $.on(ta, 'change', $.cb.value);
},
advanced: function(section) {
- var archiver, event, input, inputs, items, name, ta, toSelect, _i, _j, _len, _len1, _ref;
+ var event, input, inputs, items, name, ta, _i, _len, _ref;
- section.innerHTML = "
";
+ section.innerHTML = " ";
items = {};
inputs = {};
_ref = ['boardnav', 'time', 'backlink', 'fileInfo', 'favicon', 'sageEmoji', 'emojiPos', 'usercss'];
@@ -9744,31 +9776,12 @@
return ta.value = item['QR.personas'];
});
$.on(ta, 'change', $.cb.value);
- archiver = $('select[name=archiver]', section);
- toSelect = Redirect.select(g.BOARD.ID);
- if (!toSelect[0]) {
- toSelect = ['No Archive Available'];
- }
- for (_j = 0, _len1 = toSelect.length; _j < _len1; _j++) {
- name = toSelect[_j];
- $.add(archiver, $.el('option', {
- textContent: name
- }));
- }
- if (toSelect[1]) {
- Conf['archivers'][g.BOARD];
- archiver.value = Conf['archivers'][g.BOARD] || toSelect[0];
- $.on(archiver, 'change', function() {
- Conf['archivers'][g.BOARD] = this.value;
- return $.set('archivers', Conf.archivers);
- });
- }
$.get(items, function(items) {
var key, val;
for (key in items) {
val = items[key];
- if (['emojiPos', 'archiver'].contains(key)) {
+ if (['emojiPos'].contains(key)) {
continue;
}
input = inputs[key];
@@ -9835,6 +9848,101 @@
usercss: function() {
return CustomCSS.update();
},
+ archives: function(section) {
+ var archive, boardID, boards, data, name, row, rows, _i, _j, _len, _len1, _ref, _ref1, _ref2;
+
+ section.innerHTML = "404 Redirect is disabled.
Disabled selections indicate that only one archive is available for that board and redirection type.
Archived boards| Board | Thread redirection | Post fetching | File redirection |
";
+ boards = {};
+ _ref = Redirect.archives;
+ for (name in _ref) {
+ archive = _ref[name];
+ _ref1 = archive.boards;
+ for (_i = 0, _len = _ref1.length; _i < _len; _i++) {
+ boardID = _ref1[_i];
+ data = boards[boardID] || (boards[boardID] = {
+ thread: [],
+ post: [],
+ file: []
+ });
+ data.thread.push(name);
+ if (archive.software === 'foolfuuka') {
+ data.post.push(name);
+ }
+ if (archive.files.contains(boardID)) {
+ data.file.push(name);
+ }
+ }
+ }
+ rows = [];
+ _ref2 = Object.keys(boards).sort();
+ for (_j = 0, _len1 = _ref2.length; _j < _len1; _j++) {
+ boardID = _ref2[_j];
+ row = $.el('tr');
+ rows.push(row);
+ $.add(row, $.el('th', {
+ textContent: "/" + boardID + "/",
+ className: boardID === g.BOARD.ID ? 'warning' : ''
+ }));
+ data = boards[boardID];
+ Settings.addArchiveCell(row, boardID, data, 'thread');
+ Settings.addArchiveCell(row, boardID, data, 'post');
+ Settings.addArchiveCell(row, boardID, data, 'file');
+ }
+ $.add($('tbody', section), rows);
+ return $.get('selectedArchives', Conf['selectedArchives'], function(_arg) {
+ var option, selectedArchives, type;
+
+ selectedArchives = _arg.selectedArchives;
+ for (boardID in selectedArchives) {
+ data = selectedArchives[boardID];
+ for (type in data) {
+ name = data[type];
+ if (option = $("select[data-boardid='" + boardID + "'][data-type='" + type + "'] > option[value='" + name + "']", section)) {
+ option.selected = true;
+ }
+ }
+ }
+ });
+ },
+ addArchiveCell: function(row, boardID, data, type) {
+ var archive, length, options, select, td, _i, _len, _ref;
+
+ options = [];
+ _ref = data[type];
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+ archive = _ref[_i];
+ options.push($.el('option', {
+ textContent: archive,
+ value: archive
+ }));
+ }
+ td = $.el('td');
+ length = options.length;
+ if (length) {
+ td.innerHTML = '';
+ select = td.firstElementChild;
+ if (!(select.disabled = length === 1)) {
+ select.setAttribute('data-boardid', boardID);
+ select.setAttribute('data-type', type);
+ $.on(select, 'change', Settings.saveSelectedArchive);
+ }
+ $.add(select, options);
+ } else {
+ td.textContent = 'N/A';
+ }
+ return $.add(row, td);
+ },
+ saveSelectedArchive: function() {
+ var _this = this;
+
+ return $.get('selectedArchives', Conf['selectedArchives'], function(_arg) {
+ var selectedArchives, _name;
+
+ selectedArchives = _arg.selectedArchives;
+ (selectedArchives[_name = _this.dataset.boardid] || (selectedArchives[_name] = {}))[_this.dataset.type] = _this.value;
+ return $.set('selectedArchives', selectedArchives);
+ });
+ },
keybinds: function(section) {
var arr, input, inputs, items, key, tbody, tr, _ref;
@@ -9906,7 +10014,7 @@
boards: {}
};
}
- Conf['archivers'] = {};
+ Conf['selectedArchives'] = {};
$.get(Conf, Main.initFeatures);
return $.asap((function() {
var _ref;
@@ -9944,7 +10052,11 @@
var url;
if (Conf['404 Redirect'] && d.title === '4chan - 404 Not Found') {
- url = Redirect.image(pathname[1], pathname[3]);
+ Redirect.init();
+ url = Redirect.to('file', {
+ boardID: pathname[1],
+ filename: pathname[3]
+ });
if (url) {
return location.href = url;
}
@@ -10080,7 +10192,7 @@
if (d.title === '4chan - 404 Not Found') {
if (Conf['404 Redirect'] && g.VIEW === 'thread') {
- href = Redirect.to({
+ href = Redirect.to('thread', {
boardID: g.BOARD.ID,
threadID: g.THREADID,
postID: +location.hash.match(/\d+/)
diff --git a/builds/4chan-X.user.js b/builds/4chan-X.user.js
index 78e629115..457d39388 100644
--- a/builds/4chan-X.user.js
+++ b/builds/4chan-X.user.js
@@ -2044,7 +2044,10 @@
return $.cache("//api.4chan.org/" + boardID + "/res/" + threadID + ".json", function() {
return Get.fetchedPost(this, boardID, threadID, postID, root, context);
});
- } else if (url = Redirect.post(boardID, postID)) {
+ } else if (url = Redirect.to('post', {
+ boardID: boardID,
+ postID: postID
+ })) {
return $.cache(url, function() {
return Get.archivedPost(this, boardID, postID, root, context);
});
@@ -2073,7 +2076,10 @@
}
status = req.status;
if (![200, 304].contains(status)) {
- if (url = Redirect.post(boardID, postID)) {
+ if (url = Redirect.to('post', {
+ boardID: boardID,
+ postID: postID
+ })) {
$.cache(url, function() {
return Get.archivedPost(this, boardID, postID, root, context);
});
@@ -2091,7 +2097,10 @@
break;
}
if (post.no > postID) {
- if (url = Redirect.post(boardID, postID)) {
+ if (url = Redirect.to('post', {
+ boardID: boardID,
+ postID: postID
+ })) {
$.cache(url, function() {
return Get.archivedPost(this, boardID, postID, root, context);
});
@@ -4207,7 +4216,7 @@
a.setAttribute('data-threadid', post.thread.ID);
a.setAttribute('data-postid', postID);
}
- } else if (redirect = Redirect.to({
+ } else if (redirect = Redirect.to('thread', {
boardID: boardID,
threadID: 0,
postID: postID
@@ -4218,7 +4227,10 @@
target: '_blank',
textContent: "" + quote + "\u00A0(Dead)"
});
- if (Redirect.post(boardID, postID)) {
+ if (Redirect.to('post', {
+ boardID: boardID,
+ postID: postID
+ })) {
$.addClass(a, 'quotelink');
a.setAttribute('data-boardid', boardID);
a.setAttribute('data-postid', postID);
@@ -6242,7 +6254,11 @@
ImageExpand.contract(post);
src = this.src.split('/');
if (src[2] === 'images.4chan.org') {
- if (URL = Redirect.image(src[3], src[5])) {
+ URL = Redirect.to('file', {
+ boardID: src[3],
+ filename: src[5]
+ });
+ if (URL) {
setTimeout(ImageExpand.expand, 10000, post, URL);
return;
}
@@ -6378,7 +6394,11 @@
post = g.posts[this.dataset.fullid];
src = this.src.split('/');
if (src[2] === 'images.4chan.org') {
- if (URL = Redirect.image(src[3], src[5].replace(/\?.+$/, ''))) {
+ URL = Redirect.to('file', {
+ boardID: src[3],
+ filename: src[5].replace(/\?.+$/, '')
+ });
+ if (URL) {
this.src = URL;
return;
}
@@ -6484,15 +6504,14 @@
el: div,
order: 90,
open: function(_arg) {
- var ID, board, redirect, thread;
+ var ID, board, thread;
ID = _arg.ID, thread = _arg.thread, board = _arg.board;
- redirect = Redirect.to({
+ return !!Redirect.to('thread', {
postID: ID,
threadID: thread.ID,
boardID: board.ID
});
- return redirect !== ("//boards.4chan.org/" + board + "/");
},
subEntries: []
};
@@ -6514,7 +6533,7 @@
var ID, board, thread;
ID = _arg.ID, thread = _arg.thread, board = _arg.board;
- el.href = Redirect.to({
+ el.href = Redirect.to('thread', {
postID: ID,
threadID: thread.ID,
boardID: board.ID
@@ -6527,7 +6546,7 @@
if (!value) {
return false;
}
- el.href = Redirect.to({
+ el.href = Redirect.to('search', {
boardID: post.board.ID,
type: type,
value: value,
@@ -7740,185 +7759,197 @@
};
Redirect = {
+ thread: {},
+ post: {},
+ file: {},
init: function() {
- return $.sync('archivers', this.updateArchives);
- },
- updateArchives: function() {
- return $.get('archivers', {}, function(_arg) {
- var archivers;
+ var archive, arr, boardID, data, id, name, type, _i, _len, _ref, _ref1, _ref2, _ref3;
- archivers = _arg.archivers;
- return Conf['archivers'] = archivers;
- });
- },
- imageArchives: (function() {
- var o;
-
- o = {
- a: "//archive.foolz.us/",
- ck: "//fuuka.warosu.org/",
- an: "http://archive.heinessen.com/",
- cgl: "//rbt.asia/",
- c: "//archive.nyafuu.org/",
- d: "//loveisover.me/",
- e: "http://archive.foolzashit.com",
- hr: "http://archive.4plebs.org/",
- u: "//nsfw.foolz.us/",
- po: "//archive.thedarkcave.org/",
- vg: "http://nth.pensivenonsen.se/",
- c: "//archive.nyafuu.org/"
- };
- o.adv = o.asp = o.cm = o.i = o.n = o.o = o.p = o.s = o.t = o.trv = o.y = o.lgbt = o.s4s = o.e;
- o.gd = o.jp = o.m = o.q = o.tg = o.vp = o.vr = o.wsg = o.a;
- o.fa = o.lit = o.ck;
- o.k = o.toy = o.x = o.an;
- o.g = o.mu = o.cgl;
- o.w = o.wg = o.c;
- o.h = o.v = o.d;
- o.tv = o.hr;
- return o;
- })(),
- image: function(boardID, filename) {
- return "" + Redirect.imageArchives[boardID] + boardID + "/full_image/" + filename;
- },
- post: function(boardID, postID) {
- var archive, name, _base, _ref;
-
- if (Redirect.post[boardID] == null) {
- _ref = this.archiver;
- for (name in _ref) {
- archive = _ref[name];
- if (archive.type === 'foolfuuka' && archive.boards.contains(boardID)) {
- Redirect.post[boardID] = archive.base;
- break;
+ _ref = Conf['selectedArchives'];
+ for (boardID in _ref) {
+ data = _ref[boardID];
+ for (type in data) {
+ id = data[type];
+ _ref1 = Redirect.archives;
+ for (name in _ref1) {
+ archive = _ref1[name];
+ if (name !== id || type === 'post' && archive.software !== 'foolfuuka') {
+ continue;
+ }
+ arr = type === 'file' ? archive.files : archive.boards;
+ if (arr.contains(boardID)) {
+ Redirect[type][boardID] = archive;
+ }
}
}
- (_base = Redirect.post)[boardID] || (_base[boardID] = false);
}
- if (Redirect.post[boardID]) {
- return "" + Redirect.post[boardID] + "/_/api/chan/post/?board=" + boardID + "&num=" + postID;
- } else {
- return null;
- }
- },
- select: function(board) {
- var archive, name, _ref, _results;
-
- _ref = this.archiver;
- _results = [];
- for (name in _ref) {
- archive = _ref[name];
- if (!archive.boards.contains(board)) {
- continue;
+ _ref2 = Redirect.archives;
+ for (name in _ref2) {
+ archive = _ref2[name];
+ _ref3 = archive.boards;
+ for (_i = 0, _len = _ref3.length; _i < _len; _i++) {
+ boardID = _ref3[_i];
+ if (!(boardID in Redirect.thread)) {
+ Redirect.thread[boardID] = archive;
+ }
+ if (!(boardID in Redirect.post || archive.software !== 'foolfuuka')) {
+ Redirect.post[boardID] = archive;
+ }
+ if (!(boardID in Redirect.file || !archive.files.contains(boardID))) {
+ Redirect.file[boardID] = archive;
+ }
}
- _results.push(name);
- }
- return _results;
- },
- to: function(data) {
- var arch, archive, boardID;
-
- boardID = data.boardID;
- if ((arch = Conf.archivers[boardID]) == null) {
- Conf.archivers[boardID] = arch = this.select(boardID)[0];
- $.set('archivers', Conf.archivers);
- }
- return (arch && (archive = this.archiver[arch]) ? Redirect.path(archive.base, archive.type, data) : data.threadID ? "//boards.4chan.org/" + boardID + "/" : null);
- if (!archive.boards.contains(g.BOARD.ID)) {
- return Conf['archivers'] = archive;
}
},
- archiver: {
+ archives: {
'Foolz': {
- base: 'https://archive.foolz.us',
- boards: ['a', 'co', 'gd', 'jp', 'm', 'q', 'sp', 'tg', 'tv', 'vp', 'vr', 'wsg'],
- type: 'foolfuuka'
+ 'domain': 'archive.foolz.us',
+ 'http': true,
+ 'https': true,
+ 'software': 'foolfuuka',
+ 'boards': ['a', 'co', 'gd', 'jp', 'm', 'q', 'sp', 'tg', 'tv', 'vp', 'vr', 'wsg'],
+ 'files': ['a', 'gd', 'jp', 'm', 'q', 'tg', 'vp', 'vr', 'wsg']
},
- 'NSFWFoolz': {
- base: 'https://nsfw.foolz.us',
- boards: ['u'],
- type: 'foolfuuka'
+ 'NSFW Foolz': {
+ 'domain': 'nsfw.foolz.us',
+ 'http': true,
+ 'https': true,
+ 'software': 'foolfuuka',
+ 'boards': ['u'],
+ 'files': ['u']
},
- 'TheDarkCave': {
- base: 'http://archive.thedarkcave.org',
- boards: ['c', 'int', 'out', 'po'],
- type: 'foolfuuka'
+ 'The Dark Cave': {
+ 'domain': 'archive.thedarkcave.org',
+ 'http': true,
+ 'https': true,
+ 'software': 'foolfuuka',
+ 'boards': ['c', 'int', 'out', 'po'],
+ 'files': ['c', 'po']
},
'4plebs': {
- base: 'http://archive.4plebs.org',
- boards: ['hr', 'tg', 'tv', 'x'],
- base: 'foolfuuka'
+ 'domain': 'archive.4plebs.org',
+ 'http': true,
+ 'software': 'foolfuuka',
+ 'boards': ['hr', 'tg', 'tv', 'x'],
+ 'files': ['hr', 'tg', 'tv', 'x']
},
- 'NyaFuu': {
- base: '//archive.nyafuu.org',
- boards: ['c', 'w', 'wg'],
- type: 'foolfuuka'
+ 'Nyafuu': {
+ 'http': true,
+ 'https': true,
+ 'software': 'foolfuuka',
+ 'boards': ['c', 'w', 'wg'],
+ 'files': ['c', 'w', 'wg']
},
- 'LoveIsOver': {
- base: '//loveisover.me',
- boards: ['d', 'h', 'v'],
- type: 'foolfuuka'
+ 'Love is Over': {
+ 'domain': 'loveisover.me',
+ 'http': true,
+ 'https': true,
+ 'software': 'foolfuuka',
+ 'boards': ['d', 'h', 'v'],
+ 'files': ['d', 'h', 'v']
},
- 'PensiveNonsen': {
- base: 'http://nth.pensivenonsen.se',
- boards: ['vg'],
- type: 'foolfuuka'
+ 'nth-chan': {
+ 'domain': 'nth.pensivenonsen.se',
+ 'http': true,
+ 'software': 'foolfuuka',
+ 'boards': ['vg'],
+ 'files': ['vg']
},
- 'FoolzaShit': {
- base: 'http://archive.foolzashit.com',
- boards: ["adv", "asp", "cm", "e", "i", "lgbt", "n", "o", "p", "s", "s4s", "t", "trv", "y"],
- type: 'foolfuuka'
+ 'Foolz a Shit': {
+ 'domain': 'archive.foolzashit.com',
+ 'http': true,
+ 'https': true,
+ 'software': 'foolfuuka',
+ 'boards': ['adv', 'asp', 'cm', 'e', 'i', 'lgbt', 'n', 'o', 'p', 's', 's4s', 't', 'trv', 'y'],
+ 'files': ['adv', 'asp', 'cm', 'e', 'i', 'lgbt', 'n', 'o', 'p', 's', 's4s', 't', 'trv', 'y']
},
- 'Warosu': {
- base: '//fuuka.warosu.org',
- boards: ['cgl', 'ck', 'fa', 'jp', 'lit', 's4s', 'q', 'tg', 'vr'],
- type: 'fuuka'
+ 'Install Gentoo': {
+ 'domain': 'archive.installgentoo.net',
+ 'http': true,
+ 'https': true,
+ 'software': 'fuuka',
+ 'boards': ['diy', 'g', 'sci'],
+ 'files': []
},
- 'InstallGentoo': {
- base: '//archive.installgentoo.net',
- boards: ['diy', 'g', 'sci'],
- type: 'fuuka'
- },
- 'RebeccaBlackTech': {
- base: '//rbt.asia',
- boards: ['cgl', 'g', 'mu', 'w'],
- type: 'fuuka_mail'
+ 'Rebecca Black Tech': {
+ 'domain': 'rbt.asia',
+ 'http': true,
+ 'https': true,
+ 'software': 'fuuka',
+ 'boards': ['cgl', 'g', 'mu', 'w'],
+ 'files': ['cgl', 'g', 'mu', 'w']
},
'Heinessen': {
- base: 'http://archive.heinessen.com',
- boards: ['an', 'fit', 'k', 'mlp', 'r9k', 'toy', 'x'],
- type: 'fuuka'
+ 'domain': 'archive.heinessen.com',
+ 'http': true,
+ 'software': 'fuuka',
+ 'boards': ['an', 'fit', 'k', 'mlp', 'r9k', 'toy', 'x'],
+ 'files': ['an', 'k', 'toy', 'x']
},
- 'Cliche': {
- base: '//www.cliché.net/4chan/cgi-board.pl',
- boards: ['e'],
- type: 'fuuka'
+ 'warosu': {
+ 'domain': 'fuuka.warosu.org',
+ 'http': true,
+ 'https': true,
+ 'software': 'fuuka',
+ 'boards': ['3', 'cgl', 'ck', 'fa', 'ic', 'jp', 'lit', 'q', 's4s', 'tg', 'vr'],
+ 'files': ['3', 'cgl', 'ck', 'fa', 'ic', 'jp', 'lit', 'q', 's4s', 'vr']
}
},
- path: function(base, archiver, data) {
- var boardID, path, postID, threadID, type, value;
+ to: function(dest, data) {
+ var archive;
- if (data.isSearch) {
- boardID = data.boardID, type = data.type, value = data.value;
- type = type === 'name' ? 'username' : type === 'MD5' ? 'image' : type;
- value = encodeURIComponent(value);
- if (archiver === 'foolfuuka') {
- return "" + base + "/" + boardID + "/search/" + type + "/" + value;
- } else if (type === 'image') {
- return "" + base + "/" + boardID + "/?task=search2&search_media_hash=" + value;
- } else {
- return "" + base + "/" + boardID + "/?task=search2&search_" + type + "=" + value;
- }
+ archive = (dest === 'search' ? Redirect.thread : Redirect[dest])[data.boardID];
+ if (!archive) {
+ return '';
}
- boardID = data.boardID, threadID = data.threadID, postID = data.postID;
+ return Redirect[dest](archive, data);
+ },
+ protocol: function(archive) {
+ var protocol;
+
+ protocol = location.protocol;
+ if (!archive[protocol.slice(0, -1)]) {
+ protocol = protocol === 'https:' ? 'http:' : 'https:';
+ }
+ return "" + protocol + "//";
+ },
+ thread: function(archive, _arg) {
+ var boardID, path, postID, threadID;
+
+ boardID = _arg.boardID, threadID = _arg.threadID, postID = _arg.postID;
path = threadID ? "" + boardID + "/thread/" + threadID : "" + boardID + "/post/" + postID;
- if (archiver === 'foolfuuka') {
+ if (archive.software === 'foolfuuka') {
path += '/';
}
if (threadID && postID) {
- path += archiver === 'foolfuuka' ? "#" + postID : "#p" + postID;
+ path += archive.software === 'foolfuuka' ? "#" + postID : "#p" + postID;
}
- return "" + base + "/" + path;
+ return "" + (Redirect.protocol(archive)) + archive.domain + "/" + path;
+ },
+ post: function(archive, _arg) {
+ var boardID, postID, protocol;
+
+ boardID = _arg.boardID, postID = _arg.postID;
+ protocol = Redirect.protocol(archive);
+ if (['Foolz', 'NSFW Foolz'].contains(archive.name)) {
+ protocol = 'https://';
+ }
+ return "" + protocol + archive.domain + "/_/api/chan/post/?board=" + boardID + "&num=" + postID;
+ },
+ file: function(archive, _arg) {
+ var boardID, filename;
+
+ boardID = _arg.boardID, filename = _arg.filename;
+ return "" + (Redirect.protocol(archive)) + archive.domain + "/" + boardID + "/full_image/" + filename;
+ },
+ search: function(archive, _arg) {
+ var boardID, path, type, value;
+
+ boardID = _arg.boardID, type = _arg.type, value = _arg.value;
+ type = type === 'name' ? 'username' : type === 'MD5' ? 'image' : type;
+ value = encodeURIComponent(value);
+ path = archive.software === 'foolfuuka' ? "" + boardID + "/search/" + type + "/" + value : "" + boardID + "/?task=search2&search_" + (type === 'image' ? 'media_hash' : type) + "=" + value;
+ return "" + (Redirect.protocol(archive)) + archive.domain + "/" + path;
}
};
@@ -9354,6 +9385,7 @@
Settings.addSection('Filter', Settings.filter);
Settings.addSection('Sauce', Settings.sauce);
Settings.addSection('Advanced', Settings.advanced);
+ Settings.addSection('Archives', Settings.archives);
Settings.addSection('Keybinds', Settings.keybinds);
$.on(d, 'AddSettingsSection', Settings.addSection);
$.on(d, 'OpenSettings', function(e) {
@@ -9736,9 +9768,9 @@
return $.on(ta, 'change', $.cb.value);
},
advanced: function(section) {
- var archiver, event, input, inputs, items, name, ta, toSelect, _i, _j, _len, _len1, _ref;
+ var event, input, inputs, items, name, ta, _i, _len, _ref;
- section.innerHTML = " ";
+ section.innerHTML = " ";
items = {};
inputs = {};
_ref = ['boardnav', 'time', 'backlink', 'fileInfo', 'favicon', 'sageEmoji', 'emojiPos', 'usercss'];
@@ -9755,31 +9787,12 @@
return ta.value = item['QR.personas'];
});
$.on(ta, 'change', $.cb.value);
- archiver = $('select[name=archiver]', section);
- toSelect = Redirect.select(g.BOARD.ID);
- if (!toSelect[0]) {
- toSelect = ['No Archive Available'];
- }
- for (_j = 0, _len1 = toSelect.length; _j < _len1; _j++) {
- name = toSelect[_j];
- $.add(archiver, $.el('option', {
- textContent: name
- }));
- }
- if (toSelect[1]) {
- Conf['archivers'][g.BOARD];
- archiver.value = Conf['archivers'][g.BOARD] || toSelect[0];
- $.on(archiver, 'change', function() {
- Conf['archivers'][g.BOARD] = this.value;
- return $.set('archivers', Conf.archivers);
- });
- }
$.get(items, function(items) {
var key, val;
for (key in items) {
val = items[key];
- if (['emojiPos', 'archiver'].contains(key)) {
+ if (['emojiPos'].contains(key)) {
continue;
}
input = inputs[key];
@@ -9846,6 +9859,101 @@
usercss: function() {
return CustomCSS.update();
},
+ archives: function(section) {
+ var archive, boardID, boards, data, name, row, rows, _i, _j, _len, _len1, _ref, _ref1, _ref2;
+
+ section.innerHTML = "404 Redirect is disabled.
Disabled selections indicate that only one archive is available for that board and redirection type.
Archived boards| Board | Thread redirection | Post fetching | File redirection |
";
+ boards = {};
+ _ref = Redirect.archives;
+ for (name in _ref) {
+ archive = _ref[name];
+ _ref1 = archive.boards;
+ for (_i = 0, _len = _ref1.length; _i < _len; _i++) {
+ boardID = _ref1[_i];
+ data = boards[boardID] || (boards[boardID] = {
+ thread: [],
+ post: [],
+ file: []
+ });
+ data.thread.push(name);
+ if (archive.software === 'foolfuuka') {
+ data.post.push(name);
+ }
+ if (archive.files.contains(boardID)) {
+ data.file.push(name);
+ }
+ }
+ }
+ rows = [];
+ _ref2 = Object.keys(boards).sort();
+ for (_j = 0, _len1 = _ref2.length; _j < _len1; _j++) {
+ boardID = _ref2[_j];
+ row = $.el('tr');
+ rows.push(row);
+ $.add(row, $.el('th', {
+ textContent: "/" + boardID + "/",
+ className: boardID === g.BOARD.ID ? 'warning' : ''
+ }));
+ data = boards[boardID];
+ Settings.addArchiveCell(row, boardID, data, 'thread');
+ Settings.addArchiveCell(row, boardID, data, 'post');
+ Settings.addArchiveCell(row, boardID, data, 'file');
+ }
+ $.add($('tbody', section), rows);
+ return $.get('selectedArchives', Conf['selectedArchives'], function(_arg) {
+ var option, selectedArchives, type;
+
+ selectedArchives = _arg.selectedArchives;
+ for (boardID in selectedArchives) {
+ data = selectedArchives[boardID];
+ for (type in data) {
+ name = data[type];
+ if (option = $("select[data-boardid='" + boardID + "'][data-type='" + type + "'] > option[value='" + name + "']", section)) {
+ option.selected = true;
+ }
+ }
+ }
+ });
+ },
+ addArchiveCell: function(row, boardID, data, type) {
+ var archive, length, options, select, td, _i, _len, _ref;
+
+ options = [];
+ _ref = data[type];
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+ archive = _ref[_i];
+ options.push($.el('option', {
+ textContent: archive,
+ value: archive
+ }));
+ }
+ td = $.el('td');
+ length = options.length;
+ if (length) {
+ td.innerHTML = '';
+ select = td.firstElementChild;
+ if (!(select.disabled = length === 1)) {
+ select.setAttribute('data-boardid', boardID);
+ select.setAttribute('data-type', type);
+ $.on(select, 'change', Settings.saveSelectedArchive);
+ }
+ $.add(select, options);
+ } else {
+ td.textContent = 'N/A';
+ }
+ return $.add(row, td);
+ },
+ saveSelectedArchive: function() {
+ var _this = this;
+
+ return $.get('selectedArchives', Conf['selectedArchives'], function(_arg) {
+ var selectedArchives, _name;
+
+ selectedArchives = _arg.selectedArchives;
+ (selectedArchives[_name = _this.dataset.boardid] || (selectedArchives[_name] = {}))[_this.dataset.type] = _this.value;
+ return $.set('selectedArchives', selectedArchives);
+ });
+ },
keybinds: function(section) {
var arr, input, inputs, items, key, tbody, tr, _ref;
@@ -9917,7 +10025,7 @@
boards: {}
};
}
- Conf['archivers'] = {};
+ Conf['selectedArchives'] = {};
$.get(Conf, Main.initFeatures);
return $.asap((function() {
var _ref;
@@ -9955,7 +10063,11 @@
var url;
if (Conf['404 Redirect'] && d.title === '4chan - 404 Not Found') {
- url = Redirect.image(pathname[1], pathname[3]);
+ Redirect.init();
+ url = Redirect.to('file', {
+ boardID: pathname[1],
+ filename: pathname[3]
+ });
if (url) {
return location.href = url;
}
@@ -10091,7 +10203,7 @@
if (d.title === '4chan - 404 Not Found') {
if (Conf['404 Redirect'] && g.VIEW === 'thread') {
- href = Redirect.to({
+ href = Redirect.to('thread', {
boardID: g.BOARD.ID,
threadID: g.THREADID,
postID: +location.hash.match(/\d+/)
diff --git a/builds/crx/script.js b/builds/crx/script.js
index 892bb4eef..490c0e920 100644
--- a/builds/crx/script.js
+++ b/builds/crx/script.js
@@ -2046,7 +2046,10 @@
return $.cache("//api.4chan.org/" + boardID + "/res/" + threadID + ".json", function() {
return Get.fetchedPost(this, boardID, threadID, postID, root, context);
});
- } else if (url = Redirect.post(boardID, postID)) {
+ } else if (url = Redirect.to('post', {
+ boardID: boardID,
+ postID: postID
+ })) {
return $.cache(url, function() {
return Get.archivedPost(this, boardID, postID, root, context);
});
@@ -2075,7 +2078,10 @@
}
status = req.status;
if (![200, 304].contains(status)) {
- if (url = Redirect.post(boardID, postID)) {
+ if (url = Redirect.to('post', {
+ boardID: boardID,
+ postID: postID
+ })) {
$.cache(url, function() {
return Get.archivedPost(this, boardID, postID, root, context);
});
@@ -2093,7 +2099,10 @@
break;
}
if (post.no > postID) {
- if (url = Redirect.post(boardID, postID)) {
+ if (url = Redirect.to('post', {
+ boardID: boardID,
+ postID: postID
+ })) {
$.cache(url, function() {
return Get.archivedPost(this, boardID, postID, root, context);
});
@@ -4209,7 +4218,7 @@
a.setAttribute('data-threadid', post.thread.ID);
a.setAttribute('data-postid', postID);
}
- } else if (redirect = Redirect.to({
+ } else if (redirect = Redirect.to('thread', {
boardID: boardID,
threadID: 0,
postID: postID
@@ -4220,7 +4229,10 @@
target: '_blank',
textContent: "" + quote + "\u00A0(Dead)"
});
- if (Redirect.post(boardID, postID)) {
+ if (Redirect.to('post', {
+ boardID: boardID,
+ postID: postID
+ })) {
$.addClass(a, 'quotelink');
a.setAttribute('data-boardid', boardID);
a.setAttribute('data-postid', postID);
@@ -6220,7 +6232,11 @@
ImageExpand.contract(post);
src = this.src.split('/');
if (src[2] === 'images.4chan.org') {
- if (URL = Redirect.image(src[3], src[5])) {
+ URL = Redirect.to('file', {
+ boardID: src[3],
+ filename: src[5]
+ });
+ if (URL) {
setTimeout(ImageExpand.expand, 10000, post, URL);
return;
}
@@ -6356,7 +6372,11 @@
post = g.posts[this.dataset.fullid];
src = this.src.split('/');
if (src[2] === 'images.4chan.org') {
- if (URL = Redirect.image(src[3], src[5].replace(/\?.+$/, ''))) {
+ URL = Redirect.to('file', {
+ boardID: src[3],
+ filename: src[5].replace(/\?.+$/, '')
+ });
+ if (URL) {
this.src = URL;
return;
}
@@ -6462,15 +6482,14 @@
el: div,
order: 90,
open: function(_arg) {
- var ID, board, redirect, thread;
+ var ID, board, thread;
ID = _arg.ID, thread = _arg.thread, board = _arg.board;
- redirect = Redirect.to({
+ return !!Redirect.to('thread', {
postID: ID,
threadID: thread.ID,
boardID: board.ID
});
- return redirect !== ("//boards.4chan.org/" + board + "/");
},
subEntries: []
};
@@ -6492,7 +6511,7 @@
var ID, board, thread;
ID = _arg.ID, thread = _arg.thread, board = _arg.board;
- el.href = Redirect.to({
+ el.href = Redirect.to('thread', {
postID: ID,
threadID: thread.ID,
boardID: board.ID
@@ -6505,7 +6524,7 @@
if (!value) {
return false;
}
- el.href = Redirect.to({
+ el.href = Redirect.to('search', {
boardID: post.board.ID,
type: type,
value: value,
@@ -7723,185 +7742,197 @@
};
Redirect = {
+ thread: {},
+ post: {},
+ file: {},
init: function() {
- return $.sync('archivers', this.updateArchives);
- },
- updateArchives: function() {
- return $.get('archivers', {}, function(_arg) {
- var archivers;
+ var archive, arr, boardID, data, id, name, type, _i, _len, _ref, _ref1, _ref2, _ref3;
- archivers = _arg.archivers;
- return Conf['archivers'] = archivers;
- });
- },
- imageArchives: (function() {
- var o;
-
- o = {
- a: "//archive.foolz.us/",
- ck: "//fuuka.warosu.org/",
- an: "http://archive.heinessen.com/",
- cgl: "//rbt.asia/",
- c: "//archive.nyafuu.org/",
- d: "//loveisover.me/",
- e: "http://archive.foolzashit.com",
- hr: "http://archive.4plebs.org/",
- u: "//nsfw.foolz.us/",
- po: "//archive.thedarkcave.org/",
- vg: "http://nth.pensivenonsen.se/",
- c: "//archive.nyafuu.org/"
- };
- o.adv = o.asp = o.cm = o.i = o.n = o.o = o.p = o.s = o.t = o.trv = o.y = o.lgbt = o.s4s = o.e;
- o.gd = o.jp = o.m = o.q = o.tg = o.vp = o.vr = o.wsg = o.a;
- o.fa = o.lit = o.ck;
- o.k = o.toy = o.x = o.an;
- o.g = o.mu = o.cgl;
- o.w = o.wg = o.c;
- o.h = o.v = o.d;
- o.tv = o.hr;
- return o;
- })(),
- image: function(boardID, filename) {
- return "" + Redirect.imageArchives[boardID] + boardID + "/full_image/" + filename;
- },
- post: function(boardID, postID) {
- var archive, name, _base, _ref;
-
- if (Redirect.post[boardID] == null) {
- _ref = this.archiver;
- for (name in _ref) {
- archive = _ref[name];
- if (archive.type === 'foolfuuka' && archive.boards.contains(boardID)) {
- Redirect.post[boardID] = archive.base;
- break;
+ _ref = Conf['selectedArchives'];
+ for (boardID in _ref) {
+ data = _ref[boardID];
+ for (type in data) {
+ id = data[type];
+ _ref1 = Redirect.archives;
+ for (name in _ref1) {
+ archive = _ref1[name];
+ if (name !== id || type === 'post' && archive.software !== 'foolfuuka') {
+ continue;
+ }
+ arr = type === 'file' ? archive.files : archive.boards;
+ if (arr.contains(boardID)) {
+ Redirect[type][boardID] = archive;
+ }
}
}
- (_base = Redirect.post)[boardID] || (_base[boardID] = false);
}
- if (Redirect.post[boardID]) {
- return "" + Redirect.post[boardID] + "/_/api/chan/post/?board=" + boardID + "&num=" + postID;
- } else {
- return null;
- }
- },
- select: function(board) {
- var archive, name, _ref, _results;
-
- _ref = this.archiver;
- _results = [];
- for (name in _ref) {
- archive = _ref[name];
- if (!archive.boards.contains(board)) {
- continue;
+ _ref2 = Redirect.archives;
+ for (name in _ref2) {
+ archive = _ref2[name];
+ _ref3 = archive.boards;
+ for (_i = 0, _len = _ref3.length; _i < _len; _i++) {
+ boardID = _ref3[_i];
+ if (!(boardID in Redirect.thread)) {
+ Redirect.thread[boardID] = archive;
+ }
+ if (!(boardID in Redirect.post || archive.software !== 'foolfuuka')) {
+ Redirect.post[boardID] = archive;
+ }
+ if (!(boardID in Redirect.file || !archive.files.contains(boardID))) {
+ Redirect.file[boardID] = archive;
+ }
}
- _results.push(name);
- }
- return _results;
- },
- to: function(data) {
- var arch, archive, boardID;
-
- boardID = data.boardID;
- if ((arch = Conf.archivers[boardID]) == null) {
- Conf.archivers[boardID] = arch = this.select(boardID)[0];
- $.set('archivers', Conf.archivers);
- }
- return (arch && (archive = this.archiver[arch]) ? Redirect.path(archive.base, archive.type, data) : data.threadID ? "//boards.4chan.org/" + boardID + "/" : null);
- if (!archive.boards.contains(g.BOARD.ID)) {
- return Conf['archivers'] = archive;
}
},
- archiver: {
+ archives: {
'Foolz': {
- base: 'https://archive.foolz.us',
- boards: ['a', 'co', 'gd', 'jp', 'm', 'q', 'sp', 'tg', 'tv', 'vp', 'vr', 'wsg'],
- type: 'foolfuuka'
+ 'domain': 'archive.foolz.us',
+ 'http': true,
+ 'https': true,
+ 'software': 'foolfuuka',
+ 'boards': ['a', 'co', 'gd', 'jp', 'm', 'q', 'sp', 'tg', 'tv', 'vp', 'vr', 'wsg'],
+ 'files': ['a', 'gd', 'jp', 'm', 'q', 'tg', 'vp', 'vr', 'wsg']
},
- 'NSFWFoolz': {
- base: 'https://nsfw.foolz.us',
- boards: ['u'],
- type: 'foolfuuka'
+ 'NSFW Foolz': {
+ 'domain': 'nsfw.foolz.us',
+ 'http': true,
+ 'https': true,
+ 'software': 'foolfuuka',
+ 'boards': ['u'],
+ 'files': ['u']
},
- 'TheDarkCave': {
- base: 'http://archive.thedarkcave.org',
- boards: ['c', 'int', 'out', 'po'],
- type: 'foolfuuka'
+ 'The Dark Cave': {
+ 'domain': 'archive.thedarkcave.org',
+ 'http': true,
+ 'https': true,
+ 'software': 'foolfuuka',
+ 'boards': ['c', 'int', 'out', 'po'],
+ 'files': ['c', 'po']
},
'4plebs': {
- base: 'http://archive.4plebs.org',
- boards: ['hr', 'tg', 'tv', 'x'],
- base: 'foolfuuka'
+ 'domain': 'archive.4plebs.org',
+ 'http': true,
+ 'software': 'foolfuuka',
+ 'boards': ['hr', 'tg', 'tv', 'x'],
+ 'files': ['hr', 'tg', 'tv', 'x']
},
- 'NyaFuu': {
- base: '//archive.nyafuu.org',
- boards: ['c', 'w', 'wg'],
- type: 'foolfuuka'
+ 'Nyafuu': {
+ 'http': true,
+ 'https': true,
+ 'software': 'foolfuuka',
+ 'boards': ['c', 'w', 'wg'],
+ 'files': ['c', 'w', 'wg']
},
- 'LoveIsOver': {
- base: '//loveisover.me',
- boards: ['d', 'h', 'v'],
- type: 'foolfuuka'
+ 'Love is Over': {
+ 'domain': 'loveisover.me',
+ 'http': true,
+ 'https': true,
+ 'software': 'foolfuuka',
+ 'boards': ['d', 'h', 'v'],
+ 'files': ['d', 'h', 'v']
},
- 'PensiveNonsen': {
- base: 'http://nth.pensivenonsen.se',
- boards: ['vg'],
- type: 'foolfuuka'
+ 'nth-chan': {
+ 'domain': 'nth.pensivenonsen.se',
+ 'http': true,
+ 'software': 'foolfuuka',
+ 'boards': ['vg'],
+ 'files': ['vg']
},
- 'FoolzaShit': {
- base: 'http://archive.foolzashit.com',
- boards: ["adv", "asp", "cm", "e", "i", "lgbt", "n", "o", "p", "s", "s4s", "t", "trv", "y"],
- type: 'foolfuuka'
+ 'Foolz a Shit': {
+ 'domain': 'archive.foolzashit.com',
+ 'http': true,
+ 'https': true,
+ 'software': 'foolfuuka',
+ 'boards': ['adv', 'asp', 'cm', 'e', 'i', 'lgbt', 'n', 'o', 'p', 's', 's4s', 't', 'trv', 'y'],
+ 'files': ['adv', 'asp', 'cm', 'e', 'i', 'lgbt', 'n', 'o', 'p', 's', 's4s', 't', 'trv', 'y']
},
- 'Warosu': {
- base: '//fuuka.warosu.org',
- boards: ['cgl', 'ck', 'fa', 'jp', 'lit', 's4s', 'q', 'tg', 'vr'],
- type: 'fuuka'
+ 'Install Gentoo': {
+ 'domain': 'archive.installgentoo.net',
+ 'http': true,
+ 'https': true,
+ 'software': 'fuuka',
+ 'boards': ['diy', 'g', 'sci'],
+ 'files': []
},
- 'InstallGentoo': {
- base: '//archive.installgentoo.net',
- boards: ['diy', 'g', 'sci'],
- type: 'fuuka'
- },
- 'RebeccaBlackTech': {
- base: '//rbt.asia',
- boards: ['cgl', 'g', 'mu', 'w'],
- type: 'fuuka_mail'
+ 'Rebecca Black Tech': {
+ 'domain': 'rbt.asia',
+ 'http': true,
+ 'https': true,
+ 'software': 'fuuka',
+ 'boards': ['cgl', 'g', 'mu', 'w'],
+ 'files': ['cgl', 'g', 'mu', 'w']
},
'Heinessen': {
- base: 'http://archive.heinessen.com',
- boards: ['an', 'fit', 'k', 'mlp', 'r9k', 'toy', 'x'],
- type: 'fuuka'
+ 'domain': 'archive.heinessen.com',
+ 'http': true,
+ 'software': 'fuuka',
+ 'boards': ['an', 'fit', 'k', 'mlp', 'r9k', 'toy', 'x'],
+ 'files': ['an', 'k', 'toy', 'x']
},
- 'Cliche': {
- base: '//www.cliché.net/4chan/cgi-board.pl',
- boards: ['e'],
- type: 'fuuka'
+ 'warosu': {
+ 'domain': 'fuuka.warosu.org',
+ 'http': true,
+ 'https': true,
+ 'software': 'fuuka',
+ 'boards': ['3', 'cgl', 'ck', 'fa', 'ic', 'jp', 'lit', 'q', 's4s', 'tg', 'vr'],
+ 'files': ['3', 'cgl', 'ck', 'fa', 'ic', 'jp', 'lit', 'q', 's4s', 'vr']
}
},
- path: function(base, archiver, data) {
- var boardID, path, postID, threadID, type, value;
+ to: function(dest, data) {
+ var archive;
- if (data.isSearch) {
- boardID = data.boardID, type = data.type, value = data.value;
- type = type === 'name' ? 'username' : type === 'MD5' ? 'image' : type;
- value = encodeURIComponent(value);
- if (archiver === 'foolfuuka') {
- return "" + base + "/" + boardID + "/search/" + type + "/" + value;
- } else if (type === 'image') {
- return "" + base + "/" + boardID + "/?task=search2&search_media_hash=" + value;
- } else {
- return "" + base + "/" + boardID + "/?task=search2&search_" + type + "=" + value;
- }
+ archive = (dest === 'search' ? Redirect.thread : Redirect[dest])[data.boardID];
+ if (!archive) {
+ return '';
}
- boardID = data.boardID, threadID = data.threadID, postID = data.postID;
+ return Redirect[dest](archive, data);
+ },
+ protocol: function(archive) {
+ var protocol;
+
+ protocol = location.protocol;
+ if (!archive[protocol.slice(0, -1)]) {
+ protocol = protocol === 'https:' ? 'http:' : 'https:';
+ }
+ return "" + protocol + "//";
+ },
+ thread: function(archive, _arg) {
+ var boardID, path, postID, threadID;
+
+ boardID = _arg.boardID, threadID = _arg.threadID, postID = _arg.postID;
path = threadID ? "" + boardID + "/thread/" + threadID : "" + boardID + "/post/" + postID;
- if (archiver === 'foolfuuka') {
+ if (archive.software === 'foolfuuka') {
path += '/';
}
if (threadID && postID) {
- path += archiver === 'foolfuuka' ? "#" + postID : "#p" + postID;
+ path += archive.software === 'foolfuuka' ? "#" + postID : "#p" + postID;
}
- return "" + base + "/" + path;
+ return "" + (Redirect.protocol(archive)) + archive.domain + "/" + path;
+ },
+ post: function(archive, _arg) {
+ var boardID, postID, protocol;
+
+ boardID = _arg.boardID, postID = _arg.postID;
+ protocol = Redirect.protocol(archive);
+ if (['Foolz', 'NSFW Foolz'].contains(archive.name)) {
+ protocol = 'https://';
+ }
+ return "" + protocol + archive.domain + "/_/api/chan/post/?board=" + boardID + "&num=" + postID;
+ },
+ file: function(archive, _arg) {
+ var boardID, filename;
+
+ boardID = _arg.boardID, filename = _arg.filename;
+ return "" + (Redirect.protocol(archive)) + archive.domain + "/" + boardID + "/full_image/" + filename;
+ },
+ search: function(archive, _arg) {
+ var boardID, path, type, value;
+
+ boardID = _arg.boardID, type = _arg.type, value = _arg.value;
+ type = type === 'name' ? 'username' : type === 'MD5' ? 'image' : type;
+ value = encodeURIComponent(value);
+ path = archive.software === 'foolfuuka' ? "" + boardID + "/search/" + type + "/" + value : "" + boardID + "/?task=search2&search_" + (type === 'image' ? 'media_hash' : type) + "=" + value;
+ return "" + (Redirect.protocol(archive)) + archive.domain + "/" + path;
}
};
@@ -9337,6 +9368,7 @@
Settings.addSection('Filter', Settings.filter);
Settings.addSection('Sauce', Settings.sauce);
Settings.addSection('Advanced', Settings.advanced);
+ Settings.addSection('Archives', Settings.archives);
Settings.addSection('Keybinds', Settings.keybinds);
$.on(d, 'AddSettingsSection', Settings.addSection);
$.on(d, 'OpenSettings', function(e) {
@@ -9717,9 +9749,9 @@
return $.on(ta, 'change', $.cb.value);
},
advanced: function(section) {
- var archiver, event, input, inputs, items, name, ta, toSelect, _i, _j, _len, _len1, _ref;
+ var event, input, inputs, items, name, ta, _i, _len, _ref;
- section.innerHTML = " ";
+ section.innerHTML = " ";
items = {};
inputs = {};
_ref = ['boardnav', 'time', 'backlink', 'fileInfo', 'favicon', 'sageEmoji', 'emojiPos', 'usercss'];
@@ -9736,31 +9768,12 @@
return ta.value = item['QR.personas'];
});
$.on(ta, 'change', $.cb.value);
- archiver = $('select[name=archiver]', section);
- toSelect = Redirect.select(g.BOARD.ID);
- if (!toSelect[0]) {
- toSelect = ['No Archive Available'];
- }
- for (_j = 0, _len1 = toSelect.length; _j < _len1; _j++) {
- name = toSelect[_j];
- $.add(archiver, $.el('option', {
- textContent: name
- }));
- }
- if (toSelect[1]) {
- Conf['archivers'][g.BOARD];
- archiver.value = Conf['archivers'][g.BOARD] || toSelect[0];
- $.on(archiver, 'change', function() {
- Conf['archivers'][g.BOARD] = this.value;
- return $.set('archivers', Conf.archivers);
- });
- }
$.get(items, function(items) {
var key, val;
for (key in items) {
val = items[key];
- if (['emojiPos', 'archiver'].contains(key)) {
+ if (['emojiPos'].contains(key)) {
continue;
}
input = inputs[key];
@@ -9827,6 +9840,101 @@
usercss: function() {
return CustomCSS.update();
},
+ archives: function(section) {
+ var archive, boardID, boards, data, name, row, rows, _i, _j, _len, _len1, _ref, _ref1, _ref2;
+
+ section.innerHTML = "404 Redirect is disabled.
Disabled selections indicate that only one archive is available for that board and redirection type.
Archived boards| Board | Thread redirection | Post fetching | File redirection |
";
+ boards = {};
+ _ref = Redirect.archives;
+ for (name in _ref) {
+ archive = _ref[name];
+ _ref1 = archive.boards;
+ for (_i = 0, _len = _ref1.length; _i < _len; _i++) {
+ boardID = _ref1[_i];
+ data = boards[boardID] || (boards[boardID] = {
+ thread: [],
+ post: [],
+ file: []
+ });
+ data.thread.push(name);
+ if (archive.software === 'foolfuuka') {
+ data.post.push(name);
+ }
+ if (archive.files.contains(boardID)) {
+ data.file.push(name);
+ }
+ }
+ }
+ rows = [];
+ _ref2 = Object.keys(boards).sort();
+ for (_j = 0, _len1 = _ref2.length; _j < _len1; _j++) {
+ boardID = _ref2[_j];
+ row = $.el('tr');
+ rows.push(row);
+ $.add(row, $.el('th', {
+ textContent: "/" + boardID + "/",
+ className: boardID === g.BOARD.ID ? 'warning' : ''
+ }));
+ data = boards[boardID];
+ Settings.addArchiveCell(row, boardID, data, 'thread');
+ Settings.addArchiveCell(row, boardID, data, 'post');
+ Settings.addArchiveCell(row, boardID, data, 'file');
+ }
+ $.add($('tbody', section), rows);
+ return $.get('selectedArchives', Conf['selectedArchives'], function(_arg) {
+ var option, selectedArchives, type;
+
+ selectedArchives = _arg.selectedArchives;
+ for (boardID in selectedArchives) {
+ data = selectedArchives[boardID];
+ for (type in data) {
+ name = data[type];
+ if (option = $("select[data-boardid='" + boardID + "'][data-type='" + type + "'] > option[value='" + name + "']", section)) {
+ option.selected = true;
+ }
+ }
+ }
+ });
+ },
+ addArchiveCell: function(row, boardID, data, type) {
+ var archive, length, options, select, td, _i, _len, _ref;
+
+ options = [];
+ _ref = data[type];
+ for (_i = 0, _len = _ref.length; _i < _len; _i++) {
+ archive = _ref[_i];
+ options.push($.el('option', {
+ textContent: archive,
+ value: archive
+ }));
+ }
+ td = $.el('td');
+ length = options.length;
+ if (length) {
+ td.innerHTML = '';
+ select = td.firstElementChild;
+ if (!(select.disabled = length === 1)) {
+ select.setAttribute('data-boardid', boardID);
+ select.setAttribute('data-type', type);
+ $.on(select, 'change', Settings.saveSelectedArchive);
+ }
+ $.add(select, options);
+ } else {
+ td.textContent = 'N/A';
+ }
+ return $.add(row, td);
+ },
+ saveSelectedArchive: function() {
+ var _this = this;
+
+ return $.get('selectedArchives', Conf['selectedArchives'], function(_arg) {
+ var selectedArchives, _name;
+
+ selectedArchives = _arg.selectedArchives;
+ (selectedArchives[_name = _this.dataset.boardid] || (selectedArchives[_name] = {}))[_this.dataset.type] = _this.value;
+ return $.set('selectedArchives', selectedArchives);
+ });
+ },
keybinds: function(section) {
var arr, input, inputs, items, key, tbody, tr, _ref;
@@ -9898,7 +10006,7 @@
boards: {}
};
}
- Conf['archivers'] = {};
+ Conf['selectedArchives'] = {};
$.get(Conf, Main.initFeatures);
return $.asap((function() {
var _ref;
@@ -9936,7 +10044,11 @@
var url;
if (Conf['404 Redirect'] && d.title === '4chan - 404 Not Found') {
- url = Redirect.image(pathname[1], pathname[3]);
+ Redirect.init();
+ url = Redirect.to('file', {
+ boardID: pathname[1],
+ filename: pathname[3]
+ });
if (url) {
return location.href = url;
}
@@ -10073,7 +10185,7 @@
if (d.title === '4chan - 404 Not Found') {
if (Conf['404 Redirect'] && g.VIEW === 'thread') {
- href = Redirect.to({
+ href = Redirect.to('thread', {
boardID: g.BOARD.ID,
threadID: g.THREADID,
postID: +location.hash.match(/\d+/)
diff --git a/json/archives.json b/json/archives.json
new file mode 100644
index 000000000..d5f527798
--- /dev/null
+++ b/json/archives.json
@@ -0,0 +1,109 @@
+[{
+ "uid": 0,
+ "name": "Foolz",
+ "domain": "archive.foolz.us",
+ "http": true,
+ "https": true,
+ "software": "foolfuuka",
+ "boards": ["a", "co", "gd", "jp", "m", "q", "sp", "tg", "tv", "vp", "vr", "wsg"],
+ "files": ["a", "gd", "jp", "m", "q", "tg", "vp", "vr", "wsg"]
+}, {
+ "uid": 1,
+ "name": "NSFW Foolz",
+ "domain": "nsfw.foolz.us",
+ "http": true,
+ "https": true,
+ "software": "foolfuuka",
+ "boards": ["u"],
+ "files": ["u"]
+}, {
+ "uid": 2,
+ "name": "The Dark Cave",
+ "domain": "archive.thedarkcave.org",
+ "http": true,
+ "https": true,
+ "software": "foolfuuka",
+ "boards": ["c", "int", "out", "po"],
+ "files": ["c", "po"]
+}, {
+ "uid": 3,
+ "name": "4plebs",
+ "domain": "archive.4plebs.org",
+ "http": true,
+ "https": false,
+ "software": "foolfuuka",
+ "boards": ["hr", "tg", "tv", "x"],
+ "files": ["hr", "tg", "tv", "x"]
+}, {
+ "uid": 4,
+ "name": "Nyafuu",
+ "domain": "archive.nyafuu.org",
+ "http": true,
+ "https": true,
+ "software": "foolfuuka",
+ "boards": ["c", "w", "wg"],
+ "files": ["c", "w", "wg"]
+}, {
+ "uid": 5,
+ "name": "Love is Over",
+ "domain": "loveisover.me",
+ "http": true,
+ "https": true,
+ "software": "foolfuuka",
+ "boards": ["d", "h", "v"],
+ "files": ["d", "h", "v"]
+}, {
+ "uid": 6,
+ "name": "nth-chan",
+ "domain": "nth.pensivenonsen.se",
+ "http": true,
+ "https": false,
+ "software": "foolfuuka",
+ "boards": ["vg"],
+ "files": ["vg"]
+}, {
+ "uid": 11,
+ "name": "Foolz a Shit",
+ "domain": "archive.foolzashit.com",
+ "http": true,
+ "https": true,
+ "software": "foolfuuka",
+ "boards": ["adv", "asp", "cm", "e", "i", "lgbt", "n", "o", "p", "s", "s4s", "t", "trv", "y"],
+ "files": ["adv", "asp", "cm", "e", "i", "lgbt", "n", "o", "p", "s", "s4s", "t", "trv", "y"]
+}, {
+ "uid": 7,
+ "name": "Install Gentoo",
+ "domain": "archive.installgentoo.net",
+ "http": true,
+ "https": true,
+ "software": "fuuka",
+ "boards": ["diy", "g", "sci"],
+ "files": []
+}, {
+ "uid": 8,
+ "name": "Rebecca Black Tech",
+ "domain": "rbt.asia",
+ "http": true,
+ "https": true,
+ "software": "fuuka",
+ "boards": ["cgl", "g", "mu", "w"],
+ "files": ["cgl", "g", "mu", "w"]
+}, {
+ "uid": 9,
+ "name": "Heinessen",
+ "domain": "archive.heinessen.com",
+ "http": true,
+ "https": false,
+ "software": "fuuka",
+ "boards": ["an", "fit", "k", "mlp", "r9k", "toy", "x"],
+ "files": ["an", "k", "toy", "x"]
+}, {
+ "uid": 10,
+ "name": "warosu",
+ "domain": "fuuka.warosu.org",
+ "http": true,
+ "https": true,
+ "software": "fuuka",
+ "boards": ["3", "cgl", "ck", "fa", "ic", "jp", "lit", "q", "s4s", "tg", "vr"],
+ "files": ["3", "cgl", "ck", "fa", "ic", "jp", "lit", "q", "s4s", "vr"]
+}]
diff --git a/src/Archive/Redirect.coffee b/src/Archive/Redirect.coffee
index d3bbcb09f..5d26adb35 100644
--- a/src/Archive/Redirect.coffee
+++ b/src/Archive/Redirect.coffee
@@ -1,159 +1,170 @@
Redirect =
+ thread: {}
+ post: {}
+ file: {}
+
init: ->
- $.sync 'archivers', @updateArchives
+ for boardID, data of Conf['selectedArchives']
+ for type, id of data
+ for name, archive of Redirect.archives
+ continue if name isnt id or type is 'post' and archive.software isnt 'foolfuuka'
+ arr = if type is 'file'
+ archive.files
+ else
+ archive.boards
+ Redirect[type][boardID] = archive if arr.contains boardID
+ for name, archive of Redirect.archives
+ for boardID in archive.boards
+ unless boardID of Redirect.thread
+ Redirect.thread[boardID] = archive
+ unless boardID of Redirect.post or archive.software isnt 'foolfuuka'
+ Redirect.post[boardID] = archive
+ unless boardID of Redirect.file or !archive.files.contains boardID
+ Redirect.file[boardID] = archive
+ return
- updateArchives: ->
- $.get 'archivers', {}, ({archivers}) ->
- Conf['archivers'] = archivers
-
- imageArchives: do ->
- o =
- a: "//archive.foolz.us/"
- ck: "//fuuka.warosu.org/"
- an: "http://archive.heinessen.com/"
- cgl: "//rbt.asia/"
- c: "//archive.nyafuu.org/"
- d: "//loveisover.me/"
- e: "http://archive.foolzashit.com"
- hr: "http://archive.4plebs.org/"
- u: "//nsfw.foolz.us/"
- po: "//archive.thedarkcave.org/"
- vg: "http://nth.pensivenonsen.se/"
- c: "//archive.nyafuu.org/"
-
- o.adv = o.asp = o.cm = o.i = o.n = o.o = o.p = o.s = o.t = o.trv = o.y = o.lgbt = o.s4s = o.e
- o.gd = o.jp = o.m = o.q = o.tg = o.vp = o.vr = o.wsg = o.a
- o.fa = o.lit = o.ck
- o.k = o.toy = o.x = o.an
- o.g = o.mu = o.cgl
- o.w = o.wg = o.c
- o.h = o.v = o.d
- o.tv = o.hr
-
- return o
-
- image: (boardID, filename) ->
- # Do not use g.BOARD, the image url can originate from a cross-quote.
- # Fuck. Your. Shit.
- "#{Redirect.imageArchives[boardID]}#{boardID}/full_image/#{filename}"
-
- post: (boardID, postID) ->
- unless Redirect.post[boardID]?
- for name, archive of @archiver
- if archive.type is 'foolfuuka' and archive.boards.contains boardID
- Redirect.post[boardID] = archive.base
- break
- Redirect.post[boardID] or= false
-
- return if Redirect.post[boardID]
- "#{Redirect.post[boardID]}/_/api/chan/post/?board=#{boardID}&num=#{postID}"
- else
- null
-
- select: (board) ->
- for name, archive of @archiver
- continue unless archive.boards.contains board
- name
-
- to: (data) ->
- {boardID} = data
-
- unless (arch = Conf.archivers[boardID])?
- Conf.archivers[boardID] = arch = @select(boardID)[0]
- $.set 'archivers', Conf.archivers
-
- return (if arch and archive = @archiver[arch]
- Redirect.path archive.base, archive.type, data
- else if data.threadID
- "//boards.4chan.org/#{boardID}/"
- else
- null)
-
- unless archive.boards.contains g.BOARD.ID
- Conf['archivers'] = archive
-
- archiver:
+ archives:
'Foolz':
- base: 'https://archive.foolz.us'
- boards: ['a', 'co', 'gd', 'jp', 'm', 'q', 'sp', 'tg', 'tv', 'vp', 'vr', 'wsg']
- type: 'foolfuuka'
- 'NSFWFoolz':
- base: 'https://nsfw.foolz.us'
- boards: ['u']
- type: 'foolfuuka'
- 'TheDarkCave':
- base: 'http://archive.thedarkcave.org'
- boards: ['c', 'int', 'out', 'po']
- type: 'foolfuuka'
+ 'domain': 'archive.foolz.us'
+ 'http': true
+ 'https': true
+ 'software': 'foolfuuka'
+ 'boards': ['a', 'co', 'gd', 'jp', 'm', 'q', 'sp', 'tg', 'tv', 'vp', 'vr', 'wsg']
+ 'files': ['a', 'gd', 'jp', 'm', 'q', 'tg', 'vp', 'vr', 'wsg']
+
+ 'NSFW Foolz':
+ 'domain': 'nsfw.foolz.us'
+ 'http': true
+ 'https': true
+ 'software': 'foolfuuka'
+ 'boards': ['u']
+ 'files': ['u']
+
+ 'The Dark Cave':
+ 'domain': 'archive.thedarkcave.org'
+ 'http': true
+ 'https': true
+ 'software': 'foolfuuka'
+ 'boards': ['c', 'int', 'out', 'po']
+ 'files': ['c', 'po']
+
'4plebs':
- base: 'http://archive.4plebs.org'
- boards: ['hr', 'tg', 'tv', 'x']
- base: 'foolfuuka'
- 'NyaFuu':
- base: '//archive.nyafuu.org'
- boards: ['c', 'w', 'wg']
- type: 'foolfuuka'
- 'LoveIsOver':
- base: '//loveisover.me'
- boards: ['d', 'h', 'v']
- type: 'foolfuuka'
- 'PensiveNonsen':
- base: 'http://nth.pensivenonsen.se'
- boards: ['vg']
- type: 'foolfuuka'
- 'FoolzaShit':
- base: 'http://archive.foolzashit.com'
- boards: ["adv", "asp", "cm", "e", "i", "lgbt", "n", "o", "p", "s", "s4s", "t", "trv", "y"]
- type: 'foolfuuka'
- 'Warosu':
- base: '//fuuka.warosu.org'
- boards: ['cgl', 'ck', 'fa', 'jp', 'lit', 's4s', 'q', 'tg', 'vr']
- type: 'fuuka'
- 'InstallGentoo':
- base: '//archive.installgentoo.net'
- boards: ['diy', 'g', 'sci']
- type: 'fuuka'
- 'RebeccaBlackTech':
- base: '//rbt.asia'
- boards: ['cgl', 'g', 'mu', 'w']
- type: 'fuuka_mail'
+ 'domain': 'archive.4plebs.org'
+ 'http': true
+ 'software': 'foolfuuka'
+ 'boards': ['hr', 'tg', 'tv', 'x']
+ 'files': ['hr', 'tg', 'tv', 'x']
+
+ 'Nyafuu':
+ 'http': true
+ 'https': true
+ 'software': 'foolfuuka'
+ 'boards': ['c', 'w', 'wg']
+ 'files': ['c', 'w', 'wg']
+
+ 'Love is Over':
+ 'domain': 'loveisover.me'
+ 'http': true
+ 'https': true
+ 'software': 'foolfuuka'
+ 'boards': ['d', 'h', 'v']
+ 'files': ['d', 'h', 'v']
+
+ 'nth-chan':
+ 'domain': 'nth.pensivenonsen.se'
+ 'http': true
+ 'software': 'foolfuuka'
+ 'boards': ['vg']
+ 'files': ['vg']
+
+ 'Foolz a Shit':
+ 'domain': 'archive.foolzashit.com'
+ 'http': true
+ 'https': true
+ 'software': 'foolfuuka'
+ 'boards': ['adv', 'asp', 'cm', 'e', 'i', 'lgbt', 'n', 'o', 'p', 's', 's4s', 't', 'trv', 'y']
+ 'files': ['adv', 'asp', 'cm', 'e', 'i', 'lgbt', 'n', 'o', 'p', 's', 's4s', 't', 'trv', 'y']
+
+ 'Install Gentoo':
+ 'domain': 'archive.installgentoo.net'
+ 'http': true
+ 'https': true
+ 'software': 'fuuka'
+ 'boards': ['diy', 'g', 'sci']
+ 'files': []
+
+ 'Rebecca Black Tech':
+ 'domain': 'rbt.asia'
+ 'http': true
+ 'https': true
+ 'software': 'fuuka'
+ 'boards': ['cgl', 'g', 'mu', 'w']
+ 'files': ['cgl', 'g', 'mu', 'w']
+
'Heinessen':
- base: 'http://archive.heinessen.com'
- boards: ['an', 'fit', 'k', 'mlp', 'r9k', 'toy', 'x']
- type: 'fuuka'
- 'Cliche':
- base: '//www.cliché.net/4chan/cgi-board.pl'
- boards: ['e']
- type: 'fuuka'
+ 'domain': 'archive.heinessen.com'
+ 'http': true
+ 'software': 'fuuka'
+ 'boards': ['an', 'fit', 'k', 'mlp', 'r9k', 'toy', 'x']
+ 'files': ['an', 'k', 'toy', 'x']
- path: (base, archiver, data) ->
- if data.isSearch
- {boardID, type, value} = data
- type = if type is 'name'
- 'username'
- else if type is 'MD5'
- 'image'
- else
- type
- value = encodeURIComponent value
- return if archiver is 'foolfuuka'
- "#{base}/#{boardID}/search/#{type}/#{value}"
- else if type is 'image'
- "#{base}/#{boardID}/?task=search2&search_media_hash=#{value}"
- else
- "#{base}/#{boardID}/?task=search2&search_#{type}=#{value}"
+ 'warosu':
+ 'domain': 'fuuka.warosu.org'
+ 'http': true
+ 'https': true
+ 'software': 'fuuka'
+ 'boards': ['3', 'cgl', 'ck', 'fa', 'ic', 'jp', 'lit', 'q', 's4s', 'tg', 'vr']
+ 'files': ['3', 'cgl', 'ck', 'fa', 'ic', 'jp', 'lit', 'q', 's4s', 'vr']
- {boardID, threadID, postID} = data
- # keep the number only if the location.hash was sent f.e.
+ to: (dest, data) ->
+ archive = (if dest is 'search' then Redirect.thread else Redirect[dest])[data.boardID]
+ return '' unless archive
+ Redirect[dest] archive, data
+
+ protocol: (archive) ->
+ protocol = location.protocol
+ unless archive[protocol[0...-1]]
+ protocol = if protocol is 'https:' then 'http:' else 'https:'
+ "#{protocol}//"
+
+ thread: (archive, {boardID, threadID, postID}) ->
+ # Keep the post number only if the location.hash was sent f.e.
path = if threadID
"#{boardID}/thread/#{threadID}"
else
"#{boardID}/post/#{postID}"
- if archiver is 'foolfuuka'
+ if archive.software is 'foolfuuka'
path += '/'
if threadID and postID
- path += if archiver is 'foolfuuka'
+ path += if archive.software is 'foolfuuka'
"##{postID}"
else
"#p#{postID}"
- "#{base}/#{path}"
+ "#{Redirect.protocol archive}#{archive.domain}/#{path}"
+
+ post: (archive, {boardID, postID}) ->
+ # For fuuka-based archives:
+ # https://github.com/eksopl/fuuka/issues/27
+ protocol = Redirect.protocol archive
+ # XXX foolz had HSTS set for 120 days, which broke XHR+CORS+Redirection when on HTTP.
+ # Remove necessary HTTPS procotol in September 2013.
+ if ['Foolz', 'NSFW Foolz'].contains archive.name
+ protocol = 'https://'
+ "#{protocol}#{archive.domain}/_/api/chan/post/?board=#{boardID}&num=#{postID}"
+
+ file: (archive, {boardID, filename}) ->
+ "#{Redirect.protocol archive}#{archive.domain}/#{boardID}/full_image/#{filename}"
+
+ search: (archive, {boardID, type, value}) ->
+ type = if type is 'name'
+ 'username'
+ else if type is 'MD5'
+ 'image'
+ else
+ type
+ value = encodeURIComponent value
+ path = if archive.software is 'foolfuuka'
+ "#{boardID}/search/#{type}/#{value}"
+ else
+ "#{boardID}/?task=search2&search_#{if type is 'image' then 'media_hash' else type}=#{value}"
+ "#{Redirect.protocol archive}#{archive.domain}/#{path}"
diff --git a/src/General/Get.coffee b/src/General/Get.coffee
index dd5d591d6..b7332e5f6 100644
--- a/src/General/Get.coffee
+++ b/src/General/Get.coffee
@@ -71,7 +71,7 @@ Get =
if threadID
$.cache "//api.4chan.org/#{boardID}/res/#{threadID}.json", ->
Get.fetchedPost @, boardID, threadID, postID, root, context
- else if url = Redirect.post boardID, postID
+ else if url = Redirect.to 'post', {boardID, postID}
$.cache url, ->
Get.archivedPost @, boardID, postID, root, context
insert: (post, root, context) ->
@@ -97,7 +97,7 @@ Get =
{status} = req
unless [200, 304].contains status
# The thread can die by the time we check a quote.
- if url = Redirect.post boardID, postID
+ if url = Redirect.to 'post', {boardID, postID}
$.cache url, ->
Get.archivedPost @, boardID, postID, root, context
else
@@ -115,7 +115,7 @@ Get =
break if post.no is postID # we found it!
if post.no > postID
# The post can be deleted by the time we check a quote.
- if url = Redirect.post boardID, postID
+ if url = Redirect.to 'post', {boardID, postID}
$.cache url, ->
Get.archivedPost @, boardID, postID, root, context
else
diff --git a/src/General/Main.coffee b/src/General/Main.coffee
index a057f03e0..0cfd6544a 100644
--- a/src/General/Main.coffee
+++ b/src/General/Main.coffee
@@ -14,7 +14,8 @@ Main =
flatten null, Config
for db in DataBoards
Conf[db] = boards: {}
- Conf['archivers'] = {}
+ Conf['selectedArchives'] = {}
+
$.get Conf, Main.initFeatures
$.asap (-> d.head and $('link[rel="shortcut icon"]', d.head) or d.readyState in ['interactive', 'complete']),\
@@ -45,7 +46,10 @@ Main =
when 'images.4chan.org'
$.ready ->
if Conf['404 Redirect'] and d.title is '4chan - 404 Not Found'
- url = Redirect.image pathname[1], pathname[3]
+ Redirect.init()
+ url = Redirect.to 'file',
+ boardID: pathname[1]
+ filename: pathname[3]
location.href = url if url
return
@@ -170,7 +174,7 @@ Main =
initReady: ->
if d.title is '4chan - 404 Not Found'
if Conf['404 Redirect'] and g.VIEW is 'thread'
- href = Redirect.to
+ href = Redirect.to 'thread',
boardID: g.BOARD.ID
threadID: g.THREADID
postID: +location.hash.match /\d+/ # post number or 0
diff --git a/src/General/Settings.coffee b/src/General/Settings.coffee
index 218e61118..f71a46f54 100644
--- a/src/General/Settings.coffee
+++ b/src/General/Settings.coffee
@@ -27,6 +27,7 @@ Settings =
Settings.addSection 'Filter', Settings.filter
Settings.addSection 'Sauce', Settings.sauce
Settings.addSection 'Advanced', Settings.advanced
+ Settings.addSection 'Archives', Settings.archives
Settings.addSection 'Keybinds', Settings.keybinds
$.on d, 'AddSettingsSection', Settings.addSection
@@ -329,23 +330,9 @@ Settings =
ta.value = item['QR.personas']
$.on ta, 'change', $.cb.value
- # Archiver
- archiver = $ 'select[name=archiver]', section
- toSelect = Redirect.select g.BOARD.ID
- toSelect = ['No Archive Available'] unless toSelect[0]
-
- $.add archiver, $.el('option', {textContent: name}) for name in toSelect
-
- if toSelect[1]
- Conf['archivers'][g.BOARD]
- archiver.value = Conf['archivers'][g.BOARD] or toSelect[0]
- $.on archiver, 'change', ->
- Conf['archivers'][g.BOARD] = @value
- $.set 'archivers', Conf.archivers
-
$.get items, (items) ->
for key, val of items
- continue if ['emojiPos', 'archiver'].contains key
+ continue if ['emojiPos'].contains key
input = inputs[key]
input.value = val
continue if key is 'usercss'
@@ -398,6 +385,69 @@ Settings =
usercss: ->
CustomCSS.update()
+ archives: (section) ->
+ section.innerHTML = """
+<%= grunt.file.read('src/General/html/Settings/Archives.html').replace(/>\s+<').trim() %>
+"""
+
+ boards = {}
+ for name, archive of Redirect.archives
+ for boardID in archive.boards
+ data = boards[boardID] or= {
+ thread: []
+ post: []
+ file: []
+ }
+ data.thread.push name
+ if archive.software is 'foolfuuka'
+ data.post.push name
+ if archive.files.contains boardID
+ data.file.push name
+
+ rows = []
+ for boardID in Object.keys(boards).sort() # Alphabetical order
+ row = $.el 'tr'
+ rows.push row
+ $.add row, $.el 'th',
+ textContent: "/#{boardID}/"
+ className: if boardID is g.BOARD.ID then 'warning' else ''
+
+ data = boards[boardID]
+ Settings.addArchiveCell row, boardID, data, 'thread'
+ Settings.addArchiveCell row, boardID, data, 'post'
+ Settings.addArchiveCell row, boardID, data, 'file'
+ $.add $('tbody', section), rows
+ $.get 'selectedArchives', Conf['selectedArchives'], ({selectedArchives}) ->
+ for boardID, data of selectedArchives
+ for type, name of data
+ if option = $ "select[data-boardid='#{boardID}'][data-type='#{type}'] > option[value='#{name}']", section
+ option.selected = true
+ return
+ addArchiveCell: (row, boardID, data, type) ->
+ options = []
+ for archive in data[type]
+ options.push $.el 'option',
+ textContent: archive
+ value: archive
+ td = $.el 'td'
+ {length} = options
+ if length
+ td.innerHTML = ''
+ select = td.firstElementChild
+ unless select.disabled = length is 1
+ # XXX GM can't into datasets
+ select.setAttribute 'data-boardid', boardID
+ select.setAttribute 'data-type', type
+ $.on select, 'change', Settings.saveSelectedArchive
+ $.add select, options
+ else
+ td.textContent = 'N/A'
+ $.add row, td
+ saveSelectedArchive: ->
+ $.get 'selectedArchives', Conf['selectedArchives'], ({selectedArchives}) =>
+ (selectedArchives[@dataset.boardid] or= {})[@dataset.type] = @value
+ $.set 'selectedArchives', selectedArchives
+
keybinds: (section) ->
section.innerHTML = """
<%= grunt.file.read('src/General/html/Settings/Keybinds.html').replace(/>\s+<').trim() %>
diff --git a/src/General/html/Settings/Advanced.html b/src/General/html/Settings/Advanced.html
index 6251d7b7c..37a22355e 100644
--- a/src/General/html/Settings/Advanced.html
+++ b/src/General/html/Settings/Advanced.html
@@ -1,8 +1,3 @@
-