QR.cooldown = seconds: 0 delays: thread: 0 reply: 0 image: 0 reply_intra: 0 image_intra: 0 deletion: 60 # cooldown for deleting posts/files thread_global: 300 # inter-board thread cooldown # Called from Main init: -> return unless Conf['Quick Reply'] and Conf['Cooldown'] @data = Conf['cooldowns'] $.sync 'cooldowns', @sync # Called from QR setup: -> return unless Conf['Cooldown'] # Read cooldown times if m = Get.scriptData().match /\bcooldowns *= *({[^}]+})/ $.extend QR.cooldown.delays, JSON.parse m[1] # The longest reply cooldown, for use in pruning old reply data QR.cooldown.maxDelay = 0 for type, delay of QR.cooldown.delays when type not in ['thread', 'thread_global'] QR.cooldown.maxDelay = Math.max QR.cooldown.maxDelay, delay QR.cooldown.isSetup = true QR.cooldown.start() start: -> {data} = QR.cooldown return unless ( QR.cooldown.isSetup and !QR.cooldown.isCounting and Object.keys(data[g.BOARD.ID] or {}).length + Object.keys(data.global or {}).length > 0 ) QR.cooldown.isCounting = true QR.cooldown.count() sync: (data) -> QR.cooldown.data = data or {} QR.cooldown.start() add: (threadID, postID) -> return unless Conf['Cooldown'] start = Date.now() boardID = g.BOARD.ID QR.cooldown.set boardID, start, {threadID, postID} QR.cooldown.set 'global', start, {boardID, threadID, postID} if threadID is postID QR.cooldown.start() addDelay: (post, delay) -> return unless Conf['Cooldown'] cooldown = QR.cooldown.categorize post cooldown.delay = delay QR.cooldown.set g.BOARD.ID, Date.now(), cooldown QR.cooldown.start() addMute: (delay) -> return unless Conf['Cooldown'] QR.cooldown.set g.BOARD.ID, Date.now(), {type: 'mute', delay} QR.cooldown.start() delete: (post) -> return unless Conf['Cooldown'] $.forceSync 'cooldowns' cooldowns = (QR.cooldown.data[post.board.ID] or= {}) for id, cooldown of cooldowns if !cooldown.delay? and cooldown.threadID is post.thread.ID and cooldown.postID is post.ID delete cooldowns[id] QR.cooldown.save [post.board.ID] secondsDeletion: (post) -> return 0 unless Conf['Quick Reply'] and Conf['Cooldown'] cooldowns = QR.cooldown.data[post.board.ID] or {} for start, cooldown of cooldowns if !cooldown.delay? and cooldown.threadID is post.thread.ID and cooldown.postID is post.ID seconds = QR.cooldown.delays.deletion - (Date.now() - start) // $.SECOND return Math.max seconds, 0 0 categorize: (post) -> if post.thread is 'new' type: 'thread' else type: if !!post.file then 'image' else 'reply' threadID: +post.thread set: (scope, id, value) -> $.forceSync 'cooldowns' cooldowns = (QR.cooldown.data[scope] or= {}) cooldowns[id] = value $.set 'cooldowns', QR.cooldown.data save: (scopes) -> {data} = QR.cooldown for scope in scopes when scope of data and !Object.keys(data[scope]).length delete data[scope] $.set 'cooldowns', data count: -> $.forceSync 'cooldowns' save = [] nCooldowns = 0 now = Date.now() {type, threadID} = QR.cooldown.categorize QR.posts[0] seconds = 0 for scope in [g.BOARD.ID, 'global'] cooldowns = (QR.cooldown.data[scope] or= {}) for start, cooldown of cooldowns start = +start elapsed = (now - start) // $.SECOND if elapsed < 0 # clock changed since then? delete cooldowns[start] save.push scope continue # Explicit delays from error messages if cooldown.delay? if cooldown.delay <= elapsed delete cooldowns[start] save.push scope else if (cooldown.type is type and cooldown.threadID is threadID) or cooldown.type is 'mute' # Delays only apply to the given post type and thread. seconds = Math.max seconds, cooldown.delay - elapsed continue # Clean up expired cooldowns maxDelay = if cooldown.threadID isnt cooldown.postID QR.cooldown.maxDelay else QR.cooldown.delays[if scope is 'global' then 'thread_global' else 'thread'] if QR.cooldown.customCooldown maxDelay = Math.max maxDelay, parseInt(Conf['customCooldown'], 10) if maxDelay <= elapsed delete cooldowns[start] save.push scope continue if (type is 'thread') is (cooldown.threadID is cooldown.postID) and cooldown.boardID isnt g.BOARD.ID # Only cooldowns relevant to this post can set the seconds variable: # reply cooldown with a reply, thread cooldown with a thread. # Inter-board thread cooldowns only apply on boards other than the one they were posted on. suffix = if scope is 'global' '_global' else if type isnt 'thread' and threadID is cooldown.threadID '_intra' else '' seconds = Math.max seconds, QR.cooldown.delays[type + suffix] - elapsed # If additional cooldown is enabled, add the configured seconds to the count. if QR.cooldown.customCooldown seconds = Math.max seconds, parseInt(Conf['customCooldown'], 10) - elapsed nCooldowns += Object.keys(cooldowns).length QR.cooldown.save save if save.length if nCooldowns clearTimeout QR.cooldown.timeout QR.cooldown.timeout = setTimeout QR.cooldown.count, $.SECOND else delete QR.cooldown.isCounting # Update the status when we change posting type. # Don't get stuck at some random number. # Don't interfere with progress status updates. update = seconds isnt QR.cooldown.seconds QR.cooldown.seconds = seconds QR.status() if update QR.submit() if seconds is 0 and QR.cooldown.auto and !QR.req