diff --git a/Firefox/@betterdiscord-0.0.1.xpi b/Firefox/@betterdiscord-0.0.1.xpi
new file mode 100644
index 0000000..6fbd52d
Binary files /dev/null and b/Firefox/@betterdiscord-0.0.1.xpi differ
diff --git a/Firefox/data/css/main.css b/Firefox/data/css/main.css
new file mode 100644
index 0000000..b76d867
--- /dev/null
+++ b/Firefox/data/css/main.css
@@ -0,0 +1,3 @@
+.guilds {
+ background:red !important;
+}
\ No newline at end of file
diff --git a/Firefox/data/js/main.js b/Firefox/data/js/main.js
new file mode 100644
index 0000000..bce3fc3
--- /dev/null
+++ b/Firefox/data/js/main.js
@@ -0,0 +1,199 @@
+var emotesTwitch = null, emotesTwitchSub = null, emotesFfz = null, emotesBttv = null, emotesBttv2 = null;
+
+var twitchEmoteUrlStart = "https://static-cdn.jtvnw.net/emoticons/v1/";
+var twitchEmoteUrlEnd = "/1.0";
+var ffzEmoteUrlStart = "https://cdn.frankerfacez.com/emoticon/";
+var ffzEmoteUrlEnd = "/1";
+var bttvEmoteUrlStart = "https://cdn.betterttv.net/emote/";
+var bttvEmoteUrlEnd = "/1x";
+
+var _emoteModule;
+function EmoteModule() {
+
+}
+
+EmoteModule.prototype.init = function() {
+ _emoteModule.loadEmoteData();
+};
+
+EmoteModule.prototype.obsCallback = function(mutation) {
+ var self = this;
+ for(var i = 0 ; i < mutation.addedNodes.length ; ++i) {
+ var next = mutation.addedNodes.item(i);
+ if (next) {
+ var nodes = self.getNodes(next);
+ for(var node in nodes) {
+ if (nodes.hasOwnProperty(node)) {
+ self.injectEmote(nodes[node]);
+ }
+ }
+ }
+ }
+};
+
+EmoteModule.prototype.getNodes = function(node) {
+ var next;
+ var nodes = [];
+ var treeWalker = document.createTreeWalker(node, NodeFilter.SHOW_TEXT, null, false);
+
+ while((next = treeWalker.nextNode()) != null) {
+ nodes.push(next);
+ }
+ return nodes;
+};
+
+EmoteModule.prototype.injectEmote = function(node) {
+
+ if (!node.parentElement) {
+ return;
+ }
+
+ var parent = node.parentElement;
+ if (parent.tagName != "SPAN") {
+ return;
+ }
+ if(!$(parent.parentElement).hasClass("markup") && !$(parent.parentElement).hasClass("message-content")) { return; }
+
+ var parentInnerHTML = parent.innerHTML;
+ var words = parentInnerHTML.split(/\s+/g);
+ if (!words) {
+ return;
+ }
+
+ words.some(function(word) {
+ if (word.length < 4) {
+ return;
+ }
+ if(emotesTwitch != null) {
+ if (emotesTwitch.emotes.hasOwnProperty(word)) {
+ var len = Math.round(word.length / 4);
+ parentInnerHTML = parentInnerHTML.replace(word, '');
+ return;
+ }
+ }
+ if(emotesTwitchSub != null) {
+ if (emotesTwitchSub.hasOwnProperty(word)) {
+ var len = Math.round(word.length / 4);
+ parentInnerHTML = parentInnerHTML.replace(word, '');
+ return;
+ }
+ }
+ if(emotesFfz != null) {
+ if(emotesFfz.hasOwnProperty(word)) {
+ var len = Math.round(word.length / 4);
+ parentInnerHTML = parentInnerHTML.replace(word, '');
+ return;
+ }
+ }
+ if(emotesBttv != null) {
+ if(emotesBttv.hasOwnProperty(word)) {
+ var len = Math.round(word.length / 4);
+ parentInnerHTML = parentInnerHTML.replace(word, '');
+ return;
+ }
+ }
+ if(emotesBttv2 != null) {
+ if(emotesBttv2.hasOwnProperty(word)) {
+ var len = Math.round(word.length / 4);
+ parentInnerHTML = parentInnerHTML.replace(word, '');
+ return;
+ }
+ }
+ });
+
+ parent.innerHTML = parentInnerHTML.replace(new RegExp("\uFDD9", "g"), "");
+};
+
+EmoteModule.prototype.loadEmoteData = function(type) {
+ if(_hash == null) {
+ _utils.getHash(this.loadEmoteData);
+ return;
+ }
+
+ switch(type) {
+ default:
+ _emoteModule.loadEmoteData("twitch");
+ break;
+ case "twitch":
+ _utils.log("Loading twitch global emotes");
+ $.getJSON('https://twitchemotes.com/api_cache/v2/global.json', function(data) {
+ _utils.log("Loaded twitch global emotes");
+ emotesTwitch = data;
+ _emoteModule.loadEmoteData("twitch-sub");
+ });
+ break;
+ case "twitch-sub":
+ emotesTwitchSub = {};
+ _utils.log("Loading twitch subscriber emotes");
+ $.getJSON('https://twitchemotes.com/api_cache/v2/subscriber.json', function(data) {
+ $.each(data.channels, function(key, val){
+ $.each(val.emotes, function(key, val) {
+ emotesTwitchSub[val.code] = val.image_id;
+ });
+ });
+
+ _emoteModule.loadEmoteData("ffz");
+ });
+ break;
+ case "ffz":
+ emotesFfz = {};
+ _utils.log("Loading FFZ emotes");
+ $.getJSON('https://cdn.rawgit.com/Jiiks/BetterDiscordApp/'+_hash+'/data/emotedata_ffz.json', function(data) {
+ emotesFfz = data;
+ _emoteModule.loadEmoteData("bttv");
+ });
+ break;
+ case "bttv":
+ emotesBttv = {};
+ _utils.log("Loading Basic BTTV emotes");
+ $.getJSON('https://api.betterttv.net/2/emotes', function(data) {
+ $.each(data.emotes, function(key, val) {
+ emotesBttv[val.code] = val.id;
+ });
+ _emoteModule.loadEmoteData("bttv2");
+ });
+ break;
+ case "bttv2":
+ emotesBttv2 = {};
+ _utils.log("Loading BTTV emotes");
+ $.getJSON('https://cdn.rawgit.com/Jiiks/BetterDiscordApp/'+_hash+'/data/emotedata_bttv.json', function(data) {
+ emotesBttv2 = data;
+ });
+ break;
+ }
+};
+
+var _utils;
+
+var _hash = null;
+function Utils() {}
+
+Utils.prototype.getHash = function(callback) {
+ _utils.log("Getting HASH");
+ $.getJSON("https://api.github.com/repos/Jiiks/BetterDiscordApp/commits/master", function(data){
+ _hash = data.sha;
+ _utils.log("HASH = " + _hash);
+ callback();
+ });
+};
+
+Utils.prototype.log = function(message) {
+ console.log("[BetterDiscord] - " + message);
+};
+
+(function() {
+
+ _utils = new Utils();
+
+ _emoteModule = new EmoteModule();
+ _emoteModule.init();
+
+ var mainObserver = new MutationObserver(function(mutations) {
+ mutations.forEach(function(mutation) {
+ _emoteModule.obsCallback(mutation);
+ });
+ });
+
+ mainObserver.observe(document, { childList: true, subtree: true });
+
+})();
\ No newline at end of file
diff --git a/Firefox/icon.png b/Firefox/icon.png
new file mode 100644
index 0000000..5587df6
Binary files /dev/null and b/Firefox/icon.png differ
diff --git a/Firefox/index.js b/Firefox/index.js
deleted file mode 100644
index 3bbc578..0000000
--- a/Firefox/index.js
+++ /dev/null
@@ -1,9 +0,0 @@
-var self = require('sdk/self');
-
-// a dummy function, to show how tests work.
-// to see how to test this function, look at test/test-index.js
-function dummy(text, callback) {
- callback(text);
-}
-
-exports.dummy = dummy;
diff --git a/Firefox/lib/BdPageMod.js b/Firefox/lib/BdPageMod.js
new file mode 100644
index 0000000..4a34339
--- /dev/null
+++ b/Firefox/lib/BdPageMod.js
@@ -0,0 +1,14 @@
+"use sctrict"
+
+var pageMod = require('sdk/page-mod');
+var data = require("sdk/self").data;
+
+function BdPageMod(options, callbacks) {
+ pageMod.PageMod({
+ include: '*.discordapp.com',
+ contentScriptFile: [data.url('../data/js/jquery-2.1.4.min.js'), data.url('../data/js/main.js')],
+ contentStyleFile: []
+ });
+}
+
+exports.BdPageMod = BdPageMod;
\ No newline at end of file
diff --git a/Firefox/lib/BetterDiscord.js b/Firefox/lib/BetterDiscord.js
new file mode 100644
index 0000000..2933e39
--- /dev/null
+++ b/Firefox/lib/BetterDiscord.js
@@ -0,0 +1,9 @@
+"use strict"
+
+var _bdPagemod = require('./BdPageMod.js');
+
+function BetterDiscord(args) {
+ _bdPagemod = new _bdPagemod.BdPageMod();
+}
+
+exports.BetterDiscord = BetterDiscord;
\ No newline at end of file
diff --git a/Firefox/lib/main.js b/Firefox/lib/main.js
new file mode 100644
index 0000000..555d28f
--- /dev/null
+++ b/Firefox/lib/main.js
@@ -0,0 +1,9 @@
+"use strict";
+
+var _betterDiscord = require("./BetterDiscord.js");
+
+function main(options, callbacks) {
+ _betterDiscord = new _betterDiscord.BetterDiscord();
+}
+
+exports.main = main;
\ No newline at end of file
diff --git a/Firefox/package.json b/Firefox/package.json
index 70181b3..fdf4ad1 100644
--- a/Firefox/package.json
+++ b/Firefox/package.json
@@ -3,10 +3,10 @@
"name": "betterdiscord",
"version": "0.0.1",
"description": "BetterDiscord enhances Discord with several features",
- "main": "index.js",
- "author": "Jiiks",
+ "main": "lib/main",
+ "author": "JiCode",
"engines": {
- "firefox": ">=38.0a1"
+ "firefox": ">=30"
},
"license": "MIT",
"keywords": [