var twitter = {}; var accounts = store.get("accounts") || []; twitter.version = 4; twitter.consumerKey = "JPRtaafuUN3zcqFjxXCbJQ"; twitter.consumerSecret = "VOT7yrQ5AZ57QzqljTRRjwylf5KPUfWoUujibZMEw"; twitter.growlId = "bmnmjejkpblabmgiehpgjpiglmnhocoi"; twitter.setup = function () { localStorage.removeItem("timelineCache"); var a = $.get("https://api.twitter.com/1/help/test.json", function (c) { OAuth.correctTimestamp(new Date(a.getResponseHeader("Date")).getTime() / 1000); for (var b in accounts) { if (!accounts[b].accessToken) { accounts.splice(b, 1); updateAccounts(); document.location.reload() } else { if (accounts.length == 1) { accounts[b]["default"] = true } twitter.loadAccount(accounts[b]) } } }); twitter.messagesDB = window.webkitIndexedDB.open("messagesDB"); twitter.messagesDB.onsuccess = function () { twitter.messagesDB = twitter.messagesDB.result; if (twitter.messagesDB.version == "") { var b = twitter.messagesDB.setVersion(1); b.onsuccess = function (f) { for (var d in accounts) { var c = twitter.messagesDB.createObjectStore(accounts[d].id, { keyPath: "id_str" }); c.createIndex("sender_id", "sender_id", { unique: false }); c.createIndex("recipient_id", "recipient_id", { unique: false }) } } } } }; twitter.oauthRequest = function (d) { accessor = { consumerSecret: twitter.consumerSecret }; message = { action: d.url, method: d.method || "GET", parameters: [ ["oauth_consumer_key", twitter.consumerKey], ["oauth_signature_method", "HMAC-SHA1"], ["oauth_version", "1.0"] ] }; d.token = d.token || d.account.accessToken; d.tokenSecret = d.tokenSecret || d.account.accessTokenSecret; if (d.token != true) { message.parameters.push(["oauth_token", d.token]) } if (d.tokenSecret != true) { accessor.tokenSecret = d.tokenSecret } for (var a in d.parameters) { if (d.parameters[a][0] == "oauth_callback") { d.parameters[a][1] = unescape(d.parameters[a][1]) } message.parameters.push(d.parameters[a]) } OAuth.setTimestampAndNonce(message); OAuth.SignatureMethod.sign(message, accessor); if (d.stream) { console.log("Opening user stream for user " + d.account.screenName); $.ajax({ url: message.action, type: message.method, data: OAuth.getParameterMap(message.parameters), dataType: d.type || "json", xhr: function () { d.account.stream.connection = new XMLHttpRequest(); d.account.stream.connection.addEventListener("progress", function () { processResponse(d.account) }, false); return d.account.stream.connection }, complete: function (f, g) { streamComplete(f.status, d.account) } }); setInterval(function () { checkStream(d.account) }, 45000) } else { var e = true; if (d.media) { e = false; var c = new FormData(); c.append("media[]", d.media); c.append("status", d.status); if (d.replyID) { c.append("in_reply_to_status_id", d.replyID) } var b = function (f) { f.setRequestHeader("Authorization", OAuth.getAuthorizationHeader("", message.parameters)) } } $.ajax({ url: message.action, type: message.method, data: c || OAuth.getParameterMap(message.parameters), dataType: d.type || "json", contentType: (d.media) ? false : "application/x-www-form-urlencoded", processData: e, beforeSend: b || function () {}, xhr: d.xhr, success: function (g, f, i) { if (d.success) { d.success(g) } }, error: function (g, f, i) { console.log(g.responseText); if (d.error) { d.error(g.responseText, d.parameters, g) } } }) } }; function processResponse(f) { f.stream.response = f.stream.connection.responseText.split("\r"); while (f.stream.response[f.stream.index + 1]) { if (f.stream.response[f.stream.index].length > 1) { var e; if (e = jQuery.parseJSON(f.stream.response[f.stream.index])) { if (e.text) { f.stream.timeline.unshift(e); if (e.entities.user_mentions) { var b = false; for (var c in e.entities.user_mentions) { if (e.entities.user_mentions[c].screen_name == f.screenName) { b = true; f.stream.mentions.unshift(e); var d = false; var c = 0; while (f.stream.friends[c] && !d) { if (f.stream.friends[c] == e.user.id) { d = true } c++ } if (!d) { f.stream.timeline.splice(0, 1) } } } } if (e.user.id == f.id) { f.stream.userTimeline.unshift(e) } if (f.notifyTweet || (f.notifyMention && b)) { twitter.notify(f, f.stream.index) } while (f.stream.timeline.length > 100) { f.stream.timeline.pop() } while (f.stream.mentions.length > 100) { f.stream.mentions.pop() } while (f.stream.userTimeline.length > 100) { f.stream.mentions.pop() } var a = chrome.extension.getViews({}); for (var c in a) { if (a[c].updateTimeline) { a[c].updateTimeline("home", f); if (b) { a[c].updateTimeline("mentions", f) } if (e.user.id == f.id) { a[c].updateTimeline("userTimeline", f) } } } } else { if (e.direct_message) { twitter.messagesDB.transaction([f.id], webkitIDBTransaction.READ_WRITE).objectStore(f.id).add(e.direct_message); if (f.notifyDm) { twitter.notify(f, f.stream.index) } var a = chrome.extension.getViews({}); for (var c in a) { if (a[c].updateMessage) { a[c].updateMessage(f.id, e.direct_message) } } } else { if (e["delete"]) { var c = 0; if (f.stream.timeline[c]) { while (f.stream.timeline[c].id_str > e["delete"].status.id_str || f.stream.timeline[c].retweeted_by && f.stream.timeline[c].id_str != e["delete"].status.id_str) { c++; if (!f.stream.timeline[c]) { break } } } if (f.stream.timeline[c]) { if (f.stream.timeline[c].id_str == e["delete"].status.id_str) { f.stream.timeline.splice(c, 1) } } var a = chrome.extension.getViews({}); for (var c in a) { if (a[c].deleteStatus) { a[c].deleteStatus(f.id, e["delete"].status.id_str) } } } else { if (e.friends) { f.stream.friends = e.friends } } } } } else { f.stream.connection.abort() } } f.stream.index++ } } function checkStream(a) { console.log("Checking stream activity..."); if (a.stream.connection) { if (a.stream.connection.responseText.length > 5000000 || a.stream.lastIndex == a.stream.index) { a.stream.connection.abort() } a.stream.lastIndex = a.stream.index } } function updateAccounts() { var a = []; for (var b in accounts) { a[b] = jQuery.extend({}, accounts[b]); delete a[b].stream } if (a.length == 0) { store.set("accounts", "") } else { store.set("accounts", a) } } twitter.stream = function (a) { this.response = ""; this.timeline = []; this.mentions = []; this.userTimeline = []; this.connection = ""; this.index = 0; this.lastIndex = 0; this.wait = a || 0; this.start = function (e) { console.log("Fetching timelines..."); twitter.getTimeline({ accountId: e.id, type: "home", success: function (f) { e.stream.timeline = f; console.log("Fetched home") } }); twitter.getUserTimeline({ accountId: e.id, success: function (f) { e.stream.userTimeline = f; console.log("Fetched user") } }); twitter.getMentions({ accountId: e.id, success: function (f) { e.stream.mentions = f; console.log("Fetched mentions") } }); var c = 0; while (twitter.messagesDB.objectStoreNames[c] && twitter.messagesDB.objectStoreNames[c] != e.id) { c++ } function b(f) { twitter.messagesDB.transaction([f]).objectStore(f).openCursor(null, webkitIDBCursor.PREV).onsuccess = function (j) { console.log("Loaded messages DB cursor"); var k = j.target.result; if (k) { var i = k.key; var g = [ ["since_id", twitter.decrementID(k.key)] ] } if (!i) { var g = [ ["count", 200] ] } twitter.getMessages({ accountId: f, parameters: g, success: function (n) { var m = twitter.messagesDB.transaction([e.id], webkitIDBTransaction.READ_WRITE).objectStore(e.id); var l = function () { for (var o in n) { m.add(n[o]) } }; if (n.length) { if (n[n.length - 1].id_str != i) { m.openCursor().onsuccess = function (o) { var p = o.target.result; if (p) { p["delete"](); p["continue"]() } else { l() } } } else { n.pop(); l() } } console.log("Fetched messages") } }) } } if (!twitter.messagesDB.objectStoreNames[c]) { console.log("Creating object store"); var d = twitter.messagesDB.setVersion(parseInt(twitter.messagesDB.version) + 1).onsuccess = function (g) { var f = chrome.extension.getBackgroundPage().twitter.messagesDB.createObjectStore(e.id, { keyPath: "id_str" }); f.createIndex("sender_id", "sender_id", { unique: false }); f.createIndex("recipient_id", "recipient_id", { unique: false }); b(e.id) } } else { b(e.id) } twitter.oauthRequest({ url: "https://userstream.twitter.com/2/user.json", stream: true, account: e }) } }; function streamComplete(a, b) { console.log(b.screenName + " stream complete"); delete b.stream.connection; if (!b.disabled) { if (a > 200) { if (b.stream.wait < 240000) { setTimeout(function () { b.stream = new twitter.stream(b.stream.wait); b.stream.start(b) }, b.stream.wait); if (b.stream.wait == 0) { b.stream.wait = 5000 } b.stream.wait *= 2 } else { notif = webkitNotifications.createNotification("images/48.png", "Twitter Error", "Twitter Notifier couldn't connect to Twitter - maybe Twitter's down, or maybe you aren't logged in properly. Go to the options page to logout and in again."); notif.show(); setTimeout(function () { b.stream = new twitter.stream(b.stream.wait); b.stream.start(b) }, 10000) } } else { if (b.stream.wait < 30000) { setTimeout(function () { b.stream = new twitter.stream(b.stream.wait); b.stream.start(b) }, b.stream.wait); b.stream.wait += 10000 } else { connectionError() } } b.waitReset = setTimeout(function () { b.wait = 0 }, 320000) } } function connectionError() { var a = webkitNotifications.createNotification("images/48.png", "Connection Error", "Twitter Notifier couldn't connect to Twitter - are you sure you're connected to the internet? Connection will be tried again in 1 minute."); if (store.get("connectionErrors")) { a.show() } setTimeout(function () { a.cancel(); document.location.reload() }, 60000) } twitter.requestToken = function () { var a = Date.now(); twitter.oauthRequest({ url: "https://api.twitter.com/oauth/request_token", type: "text", method: "POST", token: true, tokenSecret: true, parameters: [ ["oauth_callback", escape(window.top.location + "?t=" + a)] ], success: function (d) { d = d.split("&"); var b = []; for (var c in d) { var e = d[c].split("="); b[e[0]] = e[1] } accounts.push({ requestToken: b.oauth_token, requestTokenSecret: b.oauth_token_secret, timestamp: a }); updateAccounts(); if (b.oauth_token) { chrome.tabs.create({ url: "https://api.twitter.com/oauth/authorize?oauth_token=" + b.oauth_token }) } else { setTimeout(function () { alert("An error occurred! Please check you have internet access and your clock is set correctly and try again.") }, 5000) } }, error: function (d, c) { webkitNotifications.createNotification("images/error.png", "Failed to authenticate with Twitter", "Check you have internet access and your computer's clock is set correctly (common cause of error) and try again.").show() } }) }; twitter.accessToken = function (a, e) { accounts = chrome.extension.getBackgroundPage().accounts; for (var b in accounts) { if (accounts[b].timestamp == e) { var d = accounts[b]; var c = b } } twitter.oauthRequest({ url: "https://api.twitter.com/oauth/access_token", type: "text", method: "POST", token: d.requestToken, tokenSecret: d.requestTokenSecret, parameters: [ ["oauth_verifier", a] ], success: function (j) { j = j.split("&"); var f = []; for (var g in j) { var k = j[g].split("="); f[k[0]] = k[1] } for (var g in accounts) { if (accounts[g].accessToken == f.oauth_token) { accounts.splice(c, 1); c = false } } if (c) { delete d.timestamp; delete d.requestToken; delete d.requestTokenSecret; d.accessToken = f.oauth_token; d.accessTokenSecret = f.oauth_token_secret; d.notifyDm = true; d.notifyTweet = true; d.notifyMention = true; chrome.extension.getBackgroundPage().twitter.loadNewAccount(d); webkitNotifications.createNotification("images/48.png", "Authorised!", "Twitter Notifier is now authorised and running.").show() } else { webkitNotifications.createNotification("images/48.png", "Not Authorised", "That account has already been connected to Twitter Notifier.").show() } updateAccounts(); chrome.tabs.getCurrent(function (i) { chrome.tabs.remove(i.id) }) } }) }; twitter.loadAccount = function (a) { console.log("Loading account " + a.screenName); twitter.oauthRequest({ url: "https://api.twitter.com/1/account/verify_credentials.json", account: a, success: function (c) { try { a.id = c.id; a.name = c.name; a.screenName = c.screen_name; a.image = c.profile_image_url; a.stream = new twitter.stream(); console.log("Updating accounts store"); updateAccounts(); if (!a.disabled) { a.stream.start(a) } } catch (b) { connectionError() } }, error: function (c, b) { webkitNotifications.createNotification("images/48.png", "Could not authenticate user @" + a.screenName, "Twitter Notifier failed to authorise this account with Twitter. Try logging out and logging in of this account on the accounts page.").show() } }) }; twitter.loadNewAccount = function (b) { for (var a in accounts) { if (accounts[a].accessToken == b.accessToken) { twitter.loadAccount(accounts[a]) } } }; twitter.getAccountById = function (b) { for (var a in accounts) { if (accounts[a].id == b) { return accounts[a] } } }; twitter.favourite = function (d, c, b) { var a = twitter.getAccountById(c); twitter.oauthRequest({ method: "POST", url: "https://api.twitter.com/1/favorites/create/" + d + ".json", account: a, success: b || function () {}, error: function (e) { e = jQuery.parseJSON(e); webkitNotifications.createNotification("images/error.png", "Could not favourite", "Error: " + e.error).show() } }) }; twitter.unfavourite = function (d, c, b) { var a = twitter.getAccountById(c); twitter.oauthRequest({ method: "POST", url: "https://api.twitter.com/1/favorites/destroy/" + d + ".json", account: a, success: b || function () {}, error: function (e) { e = jQuery.parseJSON(e); webkitNotifications.createNotification("images/error.png", "Could not unfavourite", "Error: " + e.error).show() } }) }; twitter.retweet = function (d, c, b) { var a = twitter.getAccountById(c); twitter.oauthRequest({ method: "POST", url: "https://api.twitter.com/1/statuses/retweet/" + d + ".json", account: a, success: b || function () {}, error: function (e) { e = jQuery.parseJSON(e); webkitNotifications.createNotification("images/error.png", "Retweet failed", "Error: " + e.error).show() } }) }; twitter.deleteStatus = function (d, c, b) { var a = twitter.getAccountById(c); twitter.oauthRequest({ method: "POST", url: "https://api.twitter.com/1/statuses/destroy/" + d + ".json", account: a, success: b || function () {}, error: function (e) { e = jQuery.parseJSON(e); webkitNotifications.createNotification("images/error.png", "Retweet failed", "Error: " + e.error).show() } }) }; twitter.update = function (f, c, e, d) { var b = twitter.getAccountById(f); var a = [ ["status", c] ]; if (e) { a.push(["in_reply_to_status_id", e]) } twitter.oauthRequest({ method: "POST", url: "https://api.twitter.com/1/statuses/update.json", parameters: a, account: b, success: d || function () {}, error: function (g, k) { g = jQuery.parseJSON(g); console.log(g); webkitNotifications.createNotification("images/error.png", "Status could not be sent", "Error: " + g.error).show(); for (var j in k) { if (k[j][0] == "status") { k = k[j][1] } } chrome.tabs.create({ url: "http://twitter.com/?status=" + k }) } }) }; twitter.updateWithMedia = function (i, e, d, g, f, a) { var c = twitter.getAccountById(i); var b = []; twitter.oauthRequest({ method: "POST", url: "https://upload.twitter.com/1/statuses/update_with_media.json", parameters: b, account: c, media: d, status: e, replyID: g || false, xhr: function () { var j = new XMLHttpRequest(); j.upload.addEventListener("progress", a || function () {}, false); return j }, success: f || function () {}, error: function (j, l) { j = jQuery.parseJSON(j); console.log(j); webkitNotifications.createNotification("images/error.png", "Status could not be sent", "Error: " + j.error).show(); for (var k in l) { if (l[k][0] == "status") { l = l[k][1] } } chrome.tabs.create({ url: "http://twitter.com/?status=" + l }) } }) }; twitter.dm = function (e, b, d, c) { var a = twitter.getAccountById(e); twitter.oauthRequest({ method: "POST", url: "https://api.twitter.com/1/direct_messages/new.json", parameters: [ ["text", b], ["user_id", d] ], account: a, error: function (f) { webkitNotifications.createNotification("images/error.png", "DM Could not be sent", "Error: " + jQuery.parseJSON(f)["error"]).show() }, success: c || function () {} }) }; twitter.getTimeline = function (c) { var b = twitter.getAccountById(c.accountId); var a = [ ["include_rts", "true"], ["include_entities", "true"], ["include_my_retweet", "true"] ]; if (c.parameters) { a = a.concat(c.parameters) } twitter.oauthRequest({ method: "GET", url: "https://api.twitter.com/1/statuses/home_timeline.json", account: b, parameters: a, success: c.success || function () {}, error: c.error || function () {} }) }; twitter.getUserTimeline = function (c) { var b = twitter.getAccountById(c.accountId); var a = [ ["include_rts", "true"], ["include_entities", "true"], ["include_my_retweet", "true"] ]; if (c.parameters) { a = a.concat(c.parameters) } twitter.oauthRequest({ method: "GET", url: "https://api.twitter.com/1/statuses/user_timeline.json", account: b, parameters: a, success: c.success || function () {}, error: c.error || function () {} }) }; twitter.getMentions = function (c) { var b = twitter.getAccountById(c.accountId); var a = [ ["include_rts", "true"], ["include_entities", "true"] ]; if (c.parameters) { a = a.concat(c.parameters) } twitter.oauthRequest({ method: "GET", url: "https://api.twitter.com/1/statuses/mentions.json", account: b, parameters: a, success: c.success || function () {}, error: c.error || function () {} }) }; twitter.getMessages = function (d) { var c = twitter.getAccountById(d.accountId); var b = [ ["skip_status", "true"] ]; if (d.parameters) { b = b.concat(d.parameters) } if (b.sent) { var a = "https://api.twitter.com/1/direct_messages/sent.json"; delete b.sent } twitter.oauthRequest({ method: "GET", url: "https://api.twitter.com/1/direct_messages.json", account: c, parameters: b, success: function (e) { twitter.oauthRequest({ method: "GET", url: "https://api.twitter.com/1/direct_messages/sent.json", account: c, parameters: b, success: function (f) { e = e.concat(f); e.sort(function (i, g) { return new Date(g.created_at) - new Date(i.created_at) }); d.success(e); console.log(e) }, error: d.error || function () {} }) }, error: d.error || function () {} }) }; twitter.getUsers = function (b) { var a = twitter.getAccountById(b.accountId); twitter.oauthRequest({ method: "POST", url: "https://api.twitter.com/1/users/lookup.json", account: a, parameters: b.parameters, success: b.success || function () {}, error: b.error || function () {} }) }; twitter.getFriendships = function (b) { var a = twitter.getAccountById(b.accountId); twitter.oauthRequest({ method: "GET", url: "https://api.twitter.com/1/friendships/show.json", account: a, parameters: b.parameters, success: b.success || function () {}, error: b.error || function () {} }) }; twitter.openReplyWindow = function (a) { if (navigator.appVersion.indexOf("Mac") != -1) { w = 449; h = 90 } else { w = 463; h = 126 } chrome.windows.create({ url: "reply.html" + a, width: w, height: h, type: "popup", focused: true }) }; twitter.notify = function (b, a) { var c = {}; if (store.get("growl")) { var d = jQuery.parseJSON(b.stream.response[a]); if (d.direct_message) { if (d.direct_message.sender.id == b.id) { c.title = "Message to " + d.direct_message.recipient.name } else { c.title = "Message from " + d.direct_message.sender.name } c.text = $("
").html(d.direct_message.text).text(); c.url = "http://twitter.com/messages"; c.image = d.direct_message.sender.profile_image_url } else { if (d.retweeted_status) { d = d.retweeted_status } c.title = d.user.name; c.text = $("
").html(d.text).text(); c.url = "http://twitter.com/" + d.user.screen_name + "/status/" + d.id_str; c.image = d.user.profile_image_url } chrome.extension.sendRequest(twitter.growlId, c, function (e) { webkitNotifications.createHTMLNotification("notification.html?account=" + b.id + "&id=" + a).show() }) } else { webkitNotifications.createHTMLNotification("notification.html?account=" + b.id + "&id=" + a).show() } }; twitter.decrementID = function (b) { var a = -1; while (b.substr(a, 1) == "0") { a-- } return b.slice(0, a) + (b.substr(a) - 1) }; function removeObjectStore(b) { var a = twitter.messagesDB.setVersion(parseInt(twitter.messagesDB.version) + 1); a.onsuccess = function (c) { twitter.messagesDB.deleteObjectStore(b) } } $(document).ready(function () { var d = window.location.href.split("?"); if (d[1]) { d = d[1].split("&") || null; for (var b in d) { d[b] = d[b].split("="); if (d[b][0] == "oauth_verifier") { var a = d[b][1] } if (d[b][0] == "t") { var c = d[b][1] } } } if (a) { twitter.accessToken(a, c) } else { if (!localStorage.firstRun) { if (!localStorage.version) { chrome.tabs.create({ url: "options/index.html" }); localStorage.timeout = 10; localStorage.fontSize = 13; localStorage.version = twitter.version } else { accounts = [{ accessToken: localStorage.accessToken, accessTokenSecret: localStorage.accessTokenSecret, id: parseInt(localStorage.id), image: localStorage.image, name: localStorage.name, notifyDm: localStorage.notifyDm, notifyMention: localStorage.notifyMention, notifyTweet: localStorage.notifyTweet, screenName: localStorage.screenName }]; for (var b in accounts[0]) { if (accounts[0][b] == "true") { accounts[0][b] = true } if (accounts[0][b] == "false") { accounts[0][b] = false } } localStorage.removeItem("screenName"); localStorage.removeItem("id"); localStorage.removeItem("accessToken"); localStorage.removeItem("accessTokenSecret"); localStorage.removeItem("image"); localStorage.removeItem("name"); localStorage.removeItem("notifyDm"); localStorage.removeItem("notifyTweet"); localStorage.removeItem("notifyMention"); updateAccounts() } localStorage.firstRun = true } if (localStorage.version < twitter.version) { localStorage.version = twitter.version; webkitNotifications.createNotification("images/48.png", "Twitter Notifier Updated!", "Twitter Notifier has been updated to the latest and greatest version!").show() } twitter.setup() } });