NOTICE: By continued use of this site you understand and agree to the binding Terms of Service and Privacy Policy.
// ==UserScript== // @name Thread Watcher // @namespace com.kongregate.resterman // @author resterman // @version 0.2.3 // @include http://www.kongregate.com/community* // @include http://www.kongregate.com/forums/* // @description Watch threads for new posts. // ==/UserScript== function Thread(threadId, threadTitle, lastPostId, lastPostAuthor, forumId) { this.threadId = threadId; this.threadTitle = threadTitle; this.lastPostId = lastPostId; this.lastPostAuthor = lastPostAuthor; this.forumId = forumId; } Thread.prototype = { THREADS_KEY: "thread", save: function () { var threadsWatched = localStorage.getItem(this.THREADS_KEY); if (threadsWatched === null) threadsWatched = {}; else threadsWatched = JSON.parse(threadsWatched); threadsWatched[this.threadId] = { threadId: this.threadId, forumId: this.forumId, lastPostId: this.lastPostId, threadTitle: this.threadTitle, lastPostAuthor: this.lastPostAuthor }; localStorage.setItem(this.THREADS_KEY, JSON.stringify(threadsWatched)); }, watch: function () { this.save(); }, unwatch: function () { var threadsWatched = JSON.parse(localStorage.getItem(this.THREADS_KEY)); if (threadsWatched === null || !this.isWatched()) return; delete threadsWatched[this.threadId]; localStorage.setItem(this.THREADS_KEY, JSON.stringify(threadsWatched)); }, wasUpdated: function () { if (!this.isWatched()) return false; var storedThread = Thread.get(this.threadId); return storedThread ? storedThread.lastPostId < this.lastPostId : false; }, isOlder: function (aThread) { return this.lastPostId < aThread.lastPostId; }, isWatched: function () { return !!Thread.get(this.threadId); }, getUrl: function () { return '/forums/'+ this.forumId +'/topics/'+ this.threadId; }, createWatchButton: function () { var link = new Element('a', {href: 'javascript:void(0);'}) .update(this.isWatched() ? Thread.UNWATCH : Thread.WATCH); link.setAttribute('class', this.isWatched() ? 'unwatch-btn' : 'watch-btn'); var self = this; link.observe('click', function (e) { e.stop(); if (self.isWatched()) { self.unwatch(); link.update(Thread.WATCH) .setAttribute('class', 'watch-btn'); } else { self.watch(); link.update(Thread.UNWATCH) .setAttribute('class', 'unwatch-btn'); } }); return link; } }; Thread.WATCH = 'watch'; Thread.UNWATCH = 'unwatch'; Thread.getPostIdFromUrl = function (url) { var matches = url.match(/posts-([0-9]+)-row/); return matches !== null ? parseInt(matches[1]) : null; }; Thread.getThreadIdFromUrl = function (url) { var matches = url.match(/topics\/([0-9]+)-/); return matches !== null ? parseInt(matches[1]) : null; }; Thread.getForumIdFromUrl = function (url) { var matches = url.match(/forums\/([0-9]+)-/); return matches !== null ? parseInt(matches[1]) : null; }; Thread.create = function (threadId, threadTitle, lastPostId, lastPostAuthor, forumId) { return new Thread(threadId, threadTitle, lastPostId, lastPostAuthor, forumId); }; Thread.createFromUrl = function (url) { return Thread.create( Thread.getThreadIdFromUrl(url), null, Thread.getPostIdFromUrl(url), null, Thread.getForumIdFromUrl(url) ); }; Thread.get = function (threadId) { var threadsWatched = Thread.getAllWatched(); if (threadsWatched === null) return null; return threadsWatched[threadId]; }; Thread.getAllWatched = function () { var threadsWatched = localStorage.getItem(Thread.prototype.THREADS_KEY); if (threadsWatched === null) return null; threadsWatched = JSON.parse(threadsWatched); for (var i in threadsWatched) { var obj = threadsWatched[i]; threadsWatched[i] = Thread.create( obj.threadId, obj.threadTitle, obj.lastPostId, obj.lastPostAuthor, obj.forumId ); } return threadsWatched; }; /* url: http://www.kongregate.com/forums/ */ function threads(){ var css = document.createElement('style'); css.innerHTML = 'td.lp span a.unwatch-btn { color: #336699; } td.lp span a.unwatch-btn { color: #900; }'; document.head.appendChild(css); var threads = $$('.hentry'); threads.each(function (thread) { var links = thread.select('a'); var url = links[links.length - 1].href; var t = Thread.createFromUrl(url); t.threadTitle = thread.select('.entry-title')[0].innerText; t.lastPostAuthor = thread.select('.author')[0].firstChild.innerText; var actionLink = t.createWatchButton(); actionLink.setStyle({ 'margin-left': '2px' }); thread.select('.lp')[0] .insert(new Element('span').insert(actionLink)); if (t.isWatched() && t.wasUpdated()) { thread.select('.icon')[0].setStyle({ transition: 'all ease 0.5s', backgroundColor: 'deepskyblue' }); } }); } // url: http://www.kongregate.com/forums/*/topics/* function thread() { var id = Thread.getThreadIdFromUrl(location.href), thread = Thread.get(id); if (!thread) { thread = Thread.createFromUrl(location.href); // Avoid fetching real last id, setting to negative id thread.lastPostId = -1; thread.lastPostAuthor = null; // Doesn't matter $('topic_mod').remove(); // Remove thread controls to avoid innerText considering it thread.threadTitle = $$('.forum_header h1')[0].innerText.match(/(.*?)(\s+page\s+[0-9]+|$)/)[1] } var lastPost = $$('.post:last')[0]; if (!lastPost) return; var lastId = lastPost.getAttribute('id').match(/posts-([0-9]+)-row/)[1]; if (thread.isWatched() && lastId > thread.lastPostId) { thread.lastPostId = lastId; thread.save(); } var watchButton = thread.createWatchButton().setStyle({ marginLeft: '10px' }); $$('.media.mbs').each(function (i) { i.select('.utility').each(function (j) { j.insert({ after: watchButton }); }); }); } /* url: http://www.kongregate.com/community/ */ function community() { var containerTitle = new Element('h3', { id: 'watched_threads_title', class: 'forum_group_title h2 mtl' }).update('Watched Threads'); var threadsTable = new Element('table'); $('forums_title').insert({ after: threadsTable }); $('forums_title').insert({ after: containerTitle }); var threadsTableBody = new Element('tbody'); threadsTable.insert(threadsTableBody); var onUnwatchClick = function (thread, row) { return function(e) { e.stop(); thread.unwatch(); row.remove(); }; }; var threads = Thread.getAllWatched(); for (var i in threads) { var t = threads[i]; var row = new Element('tr'); threadsTableBody.insert(row); var titleContainer = new Element('td', { class: 'c2 pts' }); row.insert(titleContainer); var title = new Element('a', { class: 'title h3', href: t.getUrl() }).update(t.threadTitle); titleContainer.insert(title); var unwatchButton = new Element('a', { href: 'javascript:void(0);' }).update('unwatch') .setStyle({ 'float': 'right' }); unwatchButton.observe('click', onUnwatchClick(t, row)); titleContainer.insert(unwatchButton); } } (function() { 'use strict'; if (/\.com\/forums\/.*\/topics/.test(location.href)) thread(); else if (/\.com\/forums/.test(location.href)) threads(); else if (/\.com\/community/.test(location.href)) community(); })();