Merge branch 'master' of https://github.com/seaweedchan/4chan-x into v3
Conflicts: LICENSE builds/4chan-X.user.js builds/crx/script.js
This commit is contained in:
commit
8ba58ee12e
22
CHANGELOG.md
22
CHANGELOG.md
@ -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*
|
||||||
|
|
||||||
|
|||||||
2
LICENSE
2
LICENSE
@ -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
|
||||||
|
|||||||
@ -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
@ -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
@ -1 +1 @@
|
|||||||
postMessage({version:'1.2.36'},'*')
|
postMessage({version:'1.2.39'},'*')
|
||||||
|
|||||||
@ -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",
|
||||||
|
|||||||
@ -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
|
|
||||||
@ -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'
|
||||||
|
|||||||
@ -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})"
|
||||||
|
|||||||
@ -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>>>#{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 ''
|
|
||||||
]
|
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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}
|
#{subject}
|
||||||
<span class='nameBlock#{capcodeClass}'>
|
<span class='nameBlock#{capcodeClass}'>
|
||||||
#{emailStart}
|
#{emailStart}
|
||||||
<span class=name>#{name or ''}</span>
|
<span class=name>#{name or ''}</span>
|
||||||
|
|||||||
@ -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]}"
|
||||||
|
|||||||
@ -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'
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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}"
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user