This commit is contained in:
Jordan Bates 2013-05-13 06:13:36 -07:00
commit c9858fe863
15 changed files with 1254 additions and 732 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

109
json/archives.json Normal file
View File

@ -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"]
}]

View File

@ -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}"

View File

@ -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

View File

@ -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

View File

@ -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+</g, '><').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></select>'
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+</g, '><').trim() %>

View File

@ -1,8 +1,3 @@
<fieldset>
<legend>Archiver</legend>
Select an Archiver for this board:
<select name=archiver></select>
</fieldset>
<fieldset>
<legend>Custom Board Navigation</span></legend>
<div><textarea name=boardnav class=field spellcheck=false></textarea></div>

View File

@ -0,0 +1,12 @@
<div class="warning" #{if Conf['404 Redirect'] then 'hidden' else ''}><code>404 Redirect</code> is disabled.</div>
<p>Disabled selections indicate that only one archive is available for that board and redirection type.</p>
<table>
<caption>Archived boards</caption>
<thead>
<th>Board</th>
<th>Thread redirection</th>
<th>Post fetching</th>
<th>File redirection</th>
</thead>
<tbody></tbody>
</table>

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -94,4 +94,4 @@ ExpandThread =
Main.callbackNodes Post, posts
$.after a, nodes
Fourchan.parseThread thread.ID, 1, nodes.length
Fourchan.parseThread thread.ID, 1, nodes.length

View File

@ -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