Conflicts:
	LICENSE
	builds/4chan-X.user.js
	builds/crx/script.js
This commit is contained in:
Zixaphir 2013-09-20 04:45:46 -07:00
commit 8ba58ee12e
20 changed files with 200 additions and 335 deletions

View File

@ -1,3 +1,25 @@
### v1.2.39
*2013-09-19*
**seaweedchan**:
- Fix thread updater bug introduced in last version
### v1.2.38
*2013-09-19*
**MayhemYDG**:
- Update posting cooldown timers to match 4chan settings:
- Cooldown may vary between inter-thread and intra-thread replies.
- Cooldown may vary when posting a file or not.
- Cooldown does not take sageing into account anymore.
- Timers vary across boards.
### v1.2.37
*2013-09-12*
**seaweedchan**:
- Just some small fixes.
### v1.2.36 ### v1.2.36
*2013-08-26* *2013-08-26*

View File

@ -1,5 +1,5 @@
/* /*
* 4chan X - Version 1.2.36 - 2013-09-03 * 4chan X - Version 1.2.39 - 2013-09-20
* *
* Licensed under the MIT license. * Licensed under the MIT license.
* https://github.com/seaweedchan/4chan-x/blob/master/LICENSE * https://github.com/seaweedchan/4chan-x/blob/master/LICENSE

View File

@ -1,6 +1,6 @@
// ==UserScript== // ==UserScript==
// @name 4chan X // @name 4chan X
// @version 1.2.36 // @version 1.2.39
// @minGMVer 1.13 // @minGMVer 1.13
// @minFFVer 22 // @minFFVer 22
// @namespace 4chan-X // @namespace 4chan-X

File diff suppressed because one or more lines are too long

View File

@ -1,6 +1,6 @@
{ {
"name": "4chan X", "name": "4chan X",
"version": "1.2.36", "version": "1.2.39",
"manifest_version": 2, "manifest_version": 2,
"description": "Cross-browser userscript for maximum lurking on 4chan.", "description": "Cross-browser userscript for maximum lurking on 4chan.",
"icons": { "icons": {

File diff suppressed because one or more lines are too long

View File

@ -1 +1 @@
postMessage({version:'1.2.36'},'*') postMessage({version:'1.2.39'},'*')

View File

@ -1,6 +1,6 @@
{ {
"name": "4chan-X", "name": "4chan-X",
"version": "1.2.36", "version": "1.2.39",
"description": "Cross-browser userscript for maximum lurking on 4chan.", "description": "Cross-browser userscript for maximum lurking on 4chan.",
"meta": { "meta": {
"name": "4chan X", "name": "4chan X",

View File

@ -14,8 +14,5 @@ Anonymize =
$.rm tripcode $.rm tripcode
delete @nodes.tripcode delete @nodes.tripcode
if @info.email if @info.email
if /sage/i.test @info.email $.replace email, name
email.href = 'mailto:sage' delete @nodes.email
else
$.replace email, name
delete @nodes.email

View File

@ -182,7 +182,7 @@ PostHiding =
if Conf['Anonymize'] if Conf['Anonymize']
'Anonymous' 'Anonymous'
else else
post.info.name $('.nameBlock', post.nodes.info).textContent
$.add a, $.tn " #{postInfo}" $.add a, $.tn " #{postInfo}"
post.nodes.stub = $.el 'div', post.nodes.stub = $.el 'div',
className: 'stub' className: 'stub'

View File

@ -185,7 +185,7 @@ ThreadHiding =
if Conf['Anonymize'] if Conf['Anonymize']
'Anonymous' 'Anonymous'
else else
OP.info.name $('.nameBlock', OP.nodes.info).textContent
a = ThreadHiding.makeButton thread, 'show' a = ThreadHiding.makeButton thread, 'show'
$.add a, $.tn " #{opInfo} (#{numReplies})" $.add a, $.tn " #{opInfo} (#{numReplies})"

View File

@ -27,7 +27,6 @@ Build =
date: data.now date: data.now
dateUTC: data.time dateUTC: data.time
comment: data.com comment: data.com
capcodeReplies: data.capcode_replies
# thread status # thread status
isSticky: !!data.sticky isSticky: !!data.sticky
isClosed: !!data.closed isClosed: !!data.closed
@ -59,7 +58,7 @@ Build =
postID, threadID, boardID postID, threadID, boardID
name, capcode, tripcode, uniqueID, email, subject, flagCode, flagName, date, dateUTC name, capcode, tripcode, uniqueID, email, subject, flagCode, flagName, date, dateUTC
isSticky, isClosed isSticky, isClosed
comment, capcodeReplies comment
file file
} = o } = o
isOP = postID is threadID isOP = postID is threadID
@ -201,36 +200,4 @@ Build =
continue if href[0] is '/' # Cross-board quote, or board link continue if href[0] is '/' # Cross-board quote, or board link
quote.href = "/#{boardID}/res/#{href}" # Fix pathnames quote.href = "/#{boardID}/res/#{href}" # Fix pathnames
Build.capcodeReplies {boardID, threadID, root: container, capcodeReplies}
container container
capcodeReplies: ({boardID, threadID, bq, root, capcodeReplies}) ->
return unless capcodeReplies
generateCapcodeReplies = (capcodeType, array) ->
"<span class=smaller><span class=bold>#{
switch capcodeType
when 'admin'
'Administrator'
when 'mod'
'Moderator'
when 'developer'
'Developer'
} Repl#{if array.length > 1 then 'ies' else 'y'}:</span> #{
array.map (ID) ->
"<a href='/#{boardID}/res/#{threadID}#p#{ID}' class=quotelink>&gt;&gt;#{ID}</a>"
.join ' '
}</span><br>"
html = []
for capcodeType, array of capcodeReplies
html.push generateCapcodeReplies capcodeType, array
bq or= $ 'blockquote', root
$.add bq, [
$.el 'br'
$.el 'br'
$.el 'span',
className: 'capcodeReplies'
innerHTML: html.join ''
]

View File

@ -455,10 +455,7 @@ Config =
#/Admin$/;highlight:moot;op:yes #/Admin$/;highlight:moot;op:yes
""" """
email: """ email: ""
# Filter any e-mails that are not `sage` on /a/ and /jp/:
#/^(?!sage$)/;boards:a,jp
"""
subject: """ subject: """
# Filter Generals on /v/: # Filter Generals on /v/:
#/general/i;boards:v;op:only #/general/i;boards:v;op:only

View File

@ -995,6 +995,7 @@ a:only-of-type > .remove {
position: relative; position: relative;
text-decoration: none; text-decoration: none;
white-space: nowrap; white-space: nowrap;
min-width: 70px;
} }
.left>.entry.has-submenu { .left>.entry.has-submenu {
padding-right: 17px !important; padding-right: 17px !important;

View File

@ -34,7 +34,7 @@
<div class='postInfo desktop' id=pi#{postID}> <div class='postInfo desktop' id=pi#{postID}>
<input type=checkbox name=#{postID} value=delete> <input type=checkbox name=#{postID} value=delete>
#{subject}&nbsp; &nbsp;#{subject}&nbsp;
<span class='nameBlock#{capcodeClass}'> <span class='nameBlock#{capcodeClass}'>
#{emailStart} #{emailStart}
<span class=name>#{name or ''}</span> <span class=name>#{name or ''}</span>

View File

@ -68,13 +68,12 @@ class Post
# <br> -> \n # <br> -> \n
# Remove: # Remove:
# 'Comment too long'... # 'Comment too long'...
# Admin/Mod/Dev replies. (/q/)
# EXIF data. (/p/) # EXIF data. (/p/)
# Rolls. (/tg/) # Rolls. (/tg/)
# Preceding and following new lines. # Preceding and following new lines.
# Trailing spaces. # Trailing spaces.
bq = @nodes.comment.cloneNode true bq = @nodes.comment.cloneNode true
nodes = $$ '.abbr, .capcodeReplies, .exif, b', bq nodes = $$ '.abbr, .exif, b', bq
i = 0 i = 0
while node = nodes[i++] while node = nodes[i++]
$.rm node $.rm node
@ -108,8 +107,7 @@ class Post
@nodes.quotelinks.push quotelink @nodes.quotelinks.push quotelink
# Don't count capcode replies as quotes in OPs. (Admin/Mod/Dev Replies: ...) return if @isClone
return if @isClone or !@isReply and $.hasClass quotelink.parentNode.parentNode, 'capcodeReplies'
# ES6 Set when? # ES6 Set when?
fullID = "#{match[1]}.#{match[2]}" fullID = "#{match[1]}.#{match[2]}"

View File

@ -31,7 +31,7 @@ DeleteLink =
el: div el: div
order: 40 order: 40
open: (post) -> open: (post) ->
return false if post.isDead or post.board.ID is 'q' return false if post.isDead
DeleteLink.post = post DeleteLink.post = post
node = div.firstChild node = div.firstChild
node.textContent = 'Delete' node.textContent = 'Delete'

View File

@ -54,11 +54,6 @@ ExpandComment =
href = quote.getAttribute 'href' href = quote.getAttribute 'href'
continue if href[0] is '/' # Cross-board quote, or board link continue if href[0] is '/' # Cross-board quote, or board link
quote.href = "/#{post.board}/res/#{href}" # Fix pathnames quote.href = "/#{post.board}/res/#{href}" # Fix pathnames
Build.capcodeReplies
boardID: post.board.ID
threadID: post.thread.ID
bq: clone
capcodeReplies: postObj.capcode_replies
post.nodes.shortComment = comment post.nodes.shortComment = comment
$.replace comment, clone $.replace comment, clone
post.nodes.comment = post.nodes.longComment = clone post.nodes.comment = post.nodes.longComment = clone

View File

@ -54,7 +54,7 @@ ExpandThread =
1 1
else switch g.BOARD.ID else switch g.BOARD.ID
# XXX boards config # XXX boards config
when 'b', 'vg', 'q' then 3 when 'b', 'vg' then 3
when 't' then 1 when 't' then 1
else 5 else 5
posts = $$ ".thread > .replyContainer", threadRoot posts = $$ ".thread > .replyContainer", threadRoot

View File

@ -273,22 +273,20 @@ QR =
cooldown: cooldown:
init: -> init: ->
return unless Conf['Cooldown'] return unless Conf['Cooldown']
board = g.BOARD.ID setTimers = (e) => QR.cooldown.types = e.detail
QR.cooldown.types = $.on window, 'cooldown:timers', setTimers
thread: switch board $.globalEval 'window.dispatchEvent(new CustomEvent("cooldown:timers", {detail: cooldowns}))'
when 'q' then 86400 QR.cooldown.types or= {} # XXX tmp workaround until all pages and the catalogs get the cooldowns var.
when 'b', 'soc', 'r9k' then 600 $.off window, 'cooldown:timers', setTimers
else 300 for type of QR.cooldown.types
sage: if board is 'q' then 600 else 60 QR.cooldown.types[type] = +QR.cooldown.types[type]
file: if board is 'q' then 300 else 30
post: if board is 'q' then 150 else 30
QR.cooldown.upSpd = 0 QR.cooldown.upSpd = 0
QR.cooldown.upSpdAccuracy = .5 QR.cooldown.upSpdAccuracy = .5
$.get "cooldown.#{board}", {}, (item) -> key = "cooldown.#{g.BOARD}"
QR.cooldown.cooldowns = item["cooldown.#{board}"] $.get key, {}, (item) ->
QR.cooldown.cooldowns = item[key]
QR.cooldown.start() QR.cooldown.start()
$.sync "cooldown.#{board}", QR.cooldown.sync $.sync key, QR.cooldown.sync
start: -> start: ->
return unless Conf['Cooldown'] return unless Conf['Cooldown']
return if QR.cooldown.isCounting return if QR.cooldown.isCounting
@ -304,30 +302,17 @@ QR =
set: (data) -> set: (data) ->
return unless Conf['Cooldown'] return unless Conf['Cooldown']
{req, post, isReply, delay} = data {req, post, isReply, threadID, delay} = data
start = if req then req.uploadEndTime else Date.now() start = if req then req.uploadEndTime else Date.now()
if delay if delay
cooldown = {delay} cooldown = {delay}
else else
if post.file if post.file
upSpd = post.file.size / ((req.uploadEndTime - req.uploadStartTime) / $.SECOND) upSpd = post.file.size / ((start - req.uploadStartTime) / $.SECOND)
QR.cooldown.upSpdAccuracy = ((upSpd > QR.cooldown.upSpd * .9) + QR.cooldown.upSpdAccuracy) / 2 QR.cooldown.upSpdAccuracy = ((upSpd > QR.cooldown.upSpd * .9) + QR.cooldown.upSpdAccuracy) / 2
QR.cooldown.upSpd = upSpd QR.cooldown.upSpd = upSpd
isSage = /sage/i.test post.email
hasFile = !!post.file hasFile = !!post.file
type = unless isReply cooldown = {isReply, hasFile, threadID}
'thread'
else if isSage
'sage'
else if hasFile
'file'
else
'post'
cooldown =
isReply: isReply
isSage: isSage
hasFile: hasFile
timeout: start + QR.cooldown.types[type] * $.SECOND
QR.cooldown.cooldowns[start] = cooldown QR.cooldown.cooldowns[start] = cooldown
$.set "cooldown.#{g.BOARD}", QR.cooldown.cooldowns $.set "cooldown.#{g.BOARD}", QR.cooldown.cooldowns
QR.cooldown.start() QR.cooldown.start()
@ -347,12 +332,12 @@ QR =
QR.status() QR.status()
return return
setTimeout QR.cooldown.count, $.SECOND clearTimeout QR.cooldown.timeout
QR.cooldown.timeout = setTimeout QR.cooldown.count, $.SECOND
now = Date.now() now = Date.now()
post = QR.posts[0] post = QR.posts[0]
isReply = post.thread isnt 'new' isReply = post.thread isnt 'new'
isSage = /sage/i.test post.email
hasFile = !!post.file hasFile = !!post.file
seconds = null seconds = null
{types, cooldowns, upSpd, upSpdAccuracy} = QR.cooldown {types, cooldowns, upSpd, upSpdAccuracy} = QR.cooldown
@ -366,26 +351,31 @@ QR =
QR.cooldown.unset start QR.cooldown.unset start
continue continue
if 'timeout' of cooldown
# XXX tmp conversion from previous cooldowns
QR.cooldown.unset start
continue
if isReply is cooldown.isReply if isReply is cooldown.isReply
# Only cooldowns relevant to this post can set the seconds value. # Only cooldowns relevant to this post can set the seconds variable:
# Unset outdated cooldowns that can no longer impact us. # reply cooldown with a reply, thread cooldown with a thread
elapsed = Math.floor (now - start) / $.SECOND
continue if elapsed < 0 # clock changed since then?
type = unless isReply type = unless isReply
'thread' 'thread'
else if isSage and cooldown.isSage else if hasFile
'sage' 'image'
else if hasFile and cooldown.hasFile
'file'
else else
'post' 'reply'
elapsed = Math.floor (now - start) / $.SECOND maxTimer = Math.max types[type] or 0, types[type + '_intra'] or 0
if elapsed >= 0 # clock changed since then? unless start <= now <= start + maxTimer * $.SECOND
seconds = Math.max seconds, types[type] - elapsed QR.cooldown.unset start
if Conf['Cooldown Prediction'] and hasFile and upSpd type += '_intra' if isReply and +post.thread is cooldown.threadID
seconds -= Math.floor post.file.size / upSpd * upSpdAccuracy seconds = Math.max seconds, types[type] - elapsed
seconds = Math.max seconds, 0
unless start <= now <= cooldown.timeout
QR.cooldown.unset start
if seconds and Conf['Cooldown Prediction'] and hasFile and upSpd
seconds -= Math.floor post.file.size / upSpd * upSpdAccuracy
seconds = Math.max seconds, 0
# Update the status when we change posting type. # Update the status when we change posting type.
# Don't get stuck at some random number. # Don't get stuck at some random number.
# Don't interfere with progress status updates. # Don't interfere with progress status updates.
@ -1039,7 +1029,7 @@ QR =
# prevent errors # prevent errors
if threadID is 'new' if threadID is 'new'
threadID = null threadID = null
if ['vg', 'q'].contains(g.BOARD.ID) and !post.sub if g.BOARD.ID is 'vg' and !post.sub
err = 'New threads require a subject.' err = 'New threads require a subject.'
else unless post.file or textOnly = !!$ 'input[name=textonly]', $.id 'postForm' else unless post.file or textOnly = !!$ 'input[name=textonly]', $.id 'postForm'
err = 'No file selected.' err = 'No file selected.'
@ -1233,7 +1223,7 @@ QR =
else else
post.rm() post.rm()
QR.cooldown.set {req, post, isReply} QR.cooldown.set {req, post, isReply, threadID}
URL = if threadID is postID # new thread URL = if threadID is postID # new thread
"/#{g.BOARD}/res/#{threadID}" "/#{g.BOARD}/res/#{threadID}"