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 = "
Archiver\nSelect an Archiver for this board:\n
Custom Board Navigation
New lines will be converted into spaces.

In the following, board can translate to a board ID (a, b, etc...), the current board (current), or the Status/Twitter link (status, @).
\n For example:
[ toggle-all ] [current-title] [g-title / a-title / jp-title] [x / wsg / h] [t-text:\"Piracy\"]
\n will give you
[ + ] [Technology] [Technology / Anime & Manga / Otaku Culture] [x / wsg / h] [Piracy]
\n if you are on /g/.\n
Board link: board
Title link: board-title
Board link (Replace with title when on that board): board-replace
Full text link: board-full
Custom text link: board-text:\"VIP Board\"
Index-only link: board-index
Catalog-only link: board-catalog
External link: external-text:\"Google\",\"http://www.google.com\"
Combinations are possible: board-index-text:\"VIP Index\"
Full board list toggle: toggle-all
Time Formatting is disabled.
:
Supported format specifiers:
Day: %a, %A, %d, %e
Month: %m, %b, %B
Year: %y, %Y
Hour: %k, %H, %l, %I, %p, %P
Minute: %M
Second: %S
Quote Backlinks formatting is disabled.
:
File Info Formatting is disabled.
:
Link: %l (truncated), %L (untruncated), %T (Unix timestamp)
Original file name: %n (truncated), %N (untruncated), %t (Unix timestamp)
Spoiler indicator: %p
Size: %B (Bytes), %K (KB), %M (MB), %s (4chan default)
Resolution: %r (Displays 'PDF' for PDF files)
Quick Reply Personas is disabled.

\n One item per line.
\n Items will be added in the relevant input's auto-completion list.
\n Password items will always be used, since there is no password input.
\n Lines starting with a # will be ignored.\n

Unread Favicon is disabled.
Emoji is disabled.
\n Sage Icon:
\n Position:
Thread Updater is disabled.
\n Interval:
"; + section.innerHTML = "
Custom Board Navigation
New lines will be converted into spaces.

In the following, board can translate to a board ID (a, b, etc...), the current board (current), or the Status/Twitter link (status, @).
\n For example:
[ toggle-all ] [current-title] [g-title / a-title / jp-title] [x / wsg / h] [t-text:\"Piracy\"]
\n will give you
[ + ] [Technology] [Technology / Anime & Manga / Otaku Culture] [x / wsg / h] [Piracy]
\n if you are on /g/.\n
Board link: board
Title link: board-title
Board link (Replace with title when on that board): board-replace
Full text link: board-full
Custom text link: board-text:\"VIP Board\"
Index-only link: board-index
Catalog-only link: board-catalog
External link: external-text:\"Google\",\"http://www.google.com\"
Combinations are possible: board-index-text:\"VIP Index\"
Full board list toggle: toggle-all
Time Formatting is disabled.
:
Supported format specifiers:
Day: %a, %A, %d, %e
Month: %m, %b, %B
Year: %y, %Y
Hour: %k, %H, %l, %I, %p, %P
Minute: %M
Second: %S
Quote Backlinks formatting is disabled.
:
File Info Formatting is disabled.
:
Link: %l (truncated), %L (untruncated), %T (Unix timestamp)
Original file name: %n (truncated), %N (untruncated), %t (Unix timestamp)
Spoiler indicator: %p
Size: %B (Bytes), %K (KB), %M (MB), %s (4chan default)
Resolution: %r (Displays 'PDF' for PDF files)
Quick Reply Personas is disabled.

\n One item per line.
\n Items will be added in the relevant input's auto-completion list.
\n Password items will always be used, since there is no password input.
\n Lines starting with a # will be ignored.\n

Unread Favicon is disabled.
Emoji is disabled.
\n Sage Icon:
\n Position:
Thread Updater is disabled.
\n Interval:
"; 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
BoardThread redirectionPost fetchingFile 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 = "
Archiver\nSelect an Archiver for this board:\n
Custom Board Navigation
New lines will be converted into spaces.

In the following, board can translate to a board ID (a, b, etc...), the current board (current), or the Status/Twitter link (status, @).
\n For example:
[ toggle-all ] [current-title] [g-title / a-title / jp-title] [x / wsg / h] [t-text:\"Piracy\"]
\n will give you
[ + ] [Technology] [Technology / Anime & Manga / Otaku Culture] [x / wsg / h] [Piracy]
\n if you are on /g/.\n
Board link: board
Title link: board-title
Board link (Replace with title when on that board): board-replace
Full text link: board-full
Custom text link: board-text:\"VIP Board\"
Index-only link: board-index
Catalog-only link: board-catalog
External link: external-text:\"Google\",\"http://www.google.com\"
Combinations are possible: board-index-text:\"VIP Index\"
Full board list toggle: toggle-all
Time Formatting is disabled.
:
Supported format specifiers:
Day: %a, %A, %d, %e
Month: %m, %b, %B
Year: %y, %Y
Hour: %k, %H, %l, %I, %p, %P
Minute: %M
Second: %S
Quote Backlinks formatting is disabled.
:
File Info Formatting is disabled.
:
Link: %l (truncated), %L (untruncated), %T (Unix timestamp)
Original file name: %n (truncated), %N (untruncated), %t (Unix timestamp)
Spoiler indicator: %p
Size: %B (Bytes), %K (KB), %M (MB), %s (4chan default)
Resolution: %r (Displays 'PDF' for PDF files)
Quick Reply Personas is disabled.

\n One item per line.
\n Items will be added in the relevant input's auto-completion list.
\n Password items will always be used, since there is no password input.
\n Lines starting with a # will be ignored.\n

Unread Favicon is disabled.
Emoji is disabled.
\n Sage Icon:
\n Position:
Thread Updater is disabled.
\n Interval:
"; + section.innerHTML = "
Custom Board Navigation
New lines will be converted into spaces.

In the following, board can translate to a board ID (a, b, etc...), the current board (current), or the Status/Twitter link (status, @).
\n For example:
[ toggle-all ] [current-title] [g-title / a-title / jp-title] [x / wsg / h] [t-text:\"Piracy\"]
\n will give you
[ + ] [Technology] [Technology / Anime & Manga / Otaku Culture] [x / wsg / h] [Piracy]
\n if you are on /g/.\n
Board link: board
Title link: board-title
Board link (Replace with title when on that board): board-replace
Full text link: board-full
Custom text link: board-text:\"VIP Board\"
Index-only link: board-index
Catalog-only link: board-catalog
External link: external-text:\"Google\",\"http://www.google.com\"
Combinations are possible: board-index-text:\"VIP Index\"
Full board list toggle: toggle-all
Time Formatting is disabled.
:
Supported format specifiers:
Day: %a, %A, %d, %e
Month: %m, %b, %B
Year: %y, %Y
Hour: %k, %H, %l, %I, %p, %P
Minute: %M
Second: %S
Quote Backlinks formatting is disabled.
:
File Info Formatting is disabled.
:
Link: %l (truncated), %L (untruncated), %T (Unix timestamp)
Original file name: %n (truncated), %N (untruncated), %t (Unix timestamp)
Spoiler indicator: %p
Size: %B (Bytes), %K (KB), %M (MB), %s (4chan default)
Resolution: %r (Displays 'PDF' for PDF files)
Quick Reply Personas is disabled.

\n One item per line.
\n Items will be added in the relevant input's auto-completion list.
\n Password items will always be used, since there is no password input.
\n Lines starting with a # will be ignored.\n

Unread Favicon is disabled.
Emoji is disabled.
\n Sage Icon:
\n Position:
Thread Updater is disabled.
\n Interval:
"; 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
BoardThread redirectionPost fetchingFile 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 = "
Archiver\nSelect an Archiver for this board:\n
Custom Board Navigation
New lines will be converted into spaces.

In the following, board can translate to a board ID (a, b, etc...), the current board (current), or the Status/Twitter link (status, @).
\n For example:
[ toggle-all ] [current-title] [g-title / a-title / jp-title] [x / wsg / h] [t-text:\"Piracy\"]
\n will give you
[ + ] [Technology] [Technology / Anime & Manga / Otaku Culture] [x / wsg / h] [Piracy]
\n if you are on /g/.\n
Board link: board
Title link: board-title
Board link (Replace with title when on that board): board-replace
Full text link: board-full
Custom text link: board-text:\"VIP Board\"
Index-only link: board-index
Catalog-only link: board-catalog
External link: external-text:\"Google\",\"http://www.google.com\"
Combinations are possible: board-index-text:\"VIP Index\"
Full board list toggle: toggle-all
Time Formatting is disabled.
:
Supported format specifiers:
Day: %a, %A, %d, %e
Month: %m, %b, %B
Year: %y, %Y
Hour: %k, %H, %l, %I, %p, %P
Minute: %M
Second: %S
Quote Backlinks formatting is disabled.
:
File Info Formatting is disabled.
:
Link: %l (truncated), %L (untruncated), %T (Unix timestamp)
Original file name: %n (truncated), %N (untruncated), %t (Unix timestamp)
Spoiler indicator: %p
Size: %B (Bytes), %K (KB), %M (MB), %s (4chan default)
Resolution: %r (Displays 'PDF' for PDF files)
Quick Reply Personas is disabled.

\n One item per line.
\n Items will be added in the relevant input's auto-completion list.
\n Password items will always be used, since there is no password input.
\n Lines starting with a # will be ignored.\n

Unread Favicon is disabled.
Emoji is disabled.
\n Sage Icon:
\n Position:
Thread Updater is disabled.
\n Interval:
"; + section.innerHTML = "
Custom Board Navigation
New lines will be converted into spaces.

In the following, board can translate to a board ID (a, b, etc...), the current board (current), or the Status/Twitter link (status, @).
\n For example:
[ toggle-all ] [current-title] [g-title / a-title / jp-title] [x / wsg / h] [t-text:\"Piracy\"]
\n will give you
[ + ] [Technology] [Technology / Anime & Manga / Otaku Culture] [x / wsg / h] [Piracy]
\n if you are on /g/.\n
Board link: board
Title link: board-title
Board link (Replace with title when on that board): board-replace
Full text link: board-full
Custom text link: board-text:\"VIP Board\"
Index-only link: board-index
Catalog-only link: board-catalog
External link: external-text:\"Google\",\"http://www.google.com\"
Combinations are possible: board-index-text:\"VIP Index\"
Full board list toggle: toggle-all
Time Formatting is disabled.
:
Supported format specifiers:
Day: %a, %A, %d, %e
Month: %m, %b, %B
Year: %y, %Y
Hour: %k, %H, %l, %I, %p, %P
Minute: %M
Second: %S
Quote Backlinks formatting is disabled.
:
File Info Formatting is disabled.
:
Link: %l (truncated), %L (untruncated), %T (Unix timestamp)
Original file name: %n (truncated), %N (untruncated), %t (Unix timestamp)
Spoiler indicator: %p
Size: %B (Bytes), %K (KB), %M (MB), %s (4chan default)
Resolution: %r (Displays 'PDF' for PDF files)
Quick Reply Personas is disabled.

\n One item per line.
\n Items will be added in the relevant input's auto-completion list.
\n Password items will always be used, since there is no password input.
\n Lines starting with a # will be ignored.\n

Unread Favicon is disabled.
Emoji is disabled.
\n Sage Icon:
\n Position:
Thread Updater is disabled.
\n Interval:
"; 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
BoardThread redirectionPost fetchingFile 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 @@ -
- Archiver - Select an Archiver for this board: - -
Custom Board Navigation
diff --git a/src/General/html/Settings/Archives.html b/src/General/html/Settings/Archives.html new file mode 100644 index 000000000..086b33d92 --- /dev/null +++ b/src/General/html/Settings/Archives.html @@ -0,0 +1,12 @@ +
404 Redirect is disabled.
+

Disabled selections indicate that only one archive is available for that board and redirection type.

+ + + + + + + + + +
Archived boards
BoardThread redirectionPost fetchingFile redirection
diff --git a/src/Images/ImageExpand.coffee b/src/Images/ImageExpand.coffee index 87eb99755..a2427365a 100644 --- a/src/Images/ImageExpand.coffee +++ b/src/Images/ImageExpand.coffee @@ -137,7 +137,10 @@ ImageExpand = src = @src.split '/' if src[2] is '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 if g.DEAD or post.isDead or post.file.isDead diff --git a/src/Images/ImageHover.coffee b/src/Images/ImageHover.coffee index 639f37e0a..082aa4625 100644 --- a/src/Images/ImageHover.coffee +++ b/src/Images/ImageHover.coffee @@ -28,7 +28,10 @@ ImageHover = src = @src.split '/' if src[2] is '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 @src = URL return if g.DEAD or post.isDead or post.file.isDead diff --git a/src/Menu/ArchiveLink.coffee b/src/Menu/ArchiveLink.coffee index daa67bb9e..12b6e507d 100644 --- a/src/Menu/ArchiveLink.coffee +++ b/src/Menu/ArchiveLink.coffee @@ -10,8 +10,7 @@ ArchiveLink = el: div order: 90 open: ({ID, thread, board}) -> - redirect = Redirect.to {postID: ID, threadID: thread.ID, boardID: board.ID} - redirect isnt "//boards.4chan.org/#{board}/" + !!Redirect.to 'thread', {postID: ID, threadID: thread.ID, boardID: board.ID} subEntries: [] for type in [ @@ -35,14 +34,14 @@ ArchiveLink = open = if type is 'post' ({ID, thread, board}) -> - el.href = Redirect.to {postID: ID, threadID: thread.ID, boardID: board.ID} + el.href = Redirect.to 'thread', {postID: ID, threadID: thread.ID, boardID: board.ID} true else (post) -> value = Filter[type] post # We want to parse the exact same stuff as the filter does already. return false unless value - el.href = Redirect.to + el.href = Redirect.to 'search', boardID: post.board.ID type: type value: value diff --git a/src/Miscellaneous/ExpandThread.coffee b/src/Miscellaneous/ExpandThread.coffee index 06174fd89..b384ffecf 100644 --- a/src/Miscellaneous/ExpandThread.coffee +++ b/src/Miscellaneous/ExpandThread.coffee @@ -94,4 +94,4 @@ ExpandThread = Main.callbackNodes Post, posts $.after a, nodes - Fourchan.parseThread thread.ID, 1, nodes.length \ No newline at end of file + Fourchan.parseThread thread.ID, 1, nodes.length diff --git a/src/Quotelinks/Quotify.coffee b/src/Quotelinks/Quotify.coffee index 182561de8..b537a7ae2 100644 --- a/src/Quotelinks/Quotify.coffee +++ b/src/Quotelinks/Quotify.coffee @@ -51,14 +51,14 @@ Quotify = a.setAttribute 'data-boardid', boardID a.setAttribute 'data-threadid', post.thread.ID a.setAttribute 'data-postid', postID - else if redirect = Redirect.to {boardID, threadID: 0, postID} + else if redirect = Redirect.to 'thread', {boardID, threadID: 0, postID} # Replace the .deadlink span if we can redirect. a = $.el 'a', href: redirect className: 'deadlink' target: '_blank' textContent: "#{quote}\u00A0(Dead)" - if Redirect.post boardID, postID + if Redirect.to 'post', {boardID, postID} # Make it function as a normal quote if we can fetch the post. $.addClass a, 'quotelink' a.setAttribute 'data-boardid', boardID