1
0
Fork 0
mirror of https://github.com/FrankerFaceZ/FrankerFaceZ.git synced 2025-06-28 05:15:54 +00:00
FrankerFaceZ/src/main.js

607 lines
16 KiB
JavaScript
Raw Normal View History

// ----------------
// The Constructor
// ----------------
var FFZ = window.FrankerFaceZ = function() {
FFZ.instance = this;
// Logging
this._log_data = [];
this._apis = {};
// Data structures
this.badges = {};
this.users = {};
this.rooms = {};
this.emoji_data = {};
this.emoji_names = {};
this.emote_sets = {};
this.global_sets = [];
this.default_sets = [];
this._last_emote_id = 0;
// Error Logging
var t = this;
window.addEventListener('error', function(event) {
if ( ! event.error )
return;
//var has_stack = event.error && event.error.stack;
t.error("Uncaught JavaScript Error", event.error);
//t.log("JavaScript Error: " + event.message + " [" + event.filename + ":" + event.lineno + ":" + event.colno + "]", has_stack ? event.error.stack : undefined, false, has_stack);
});
// Initialize settings as early as possible.
this.load_settings();
// Detect if we need to polyfill
if ( ! window.fetch ) {
this.log("Fetch is not detected. Requesting polyfill.");
var script = document.createElement('script');
script.id = 'ffz-polyfill';
script.type = 'text/javascript';
script.src = FrankerFaceZ.constants.SERVER + 'script/fetch.polyfill.' + (FrankerFaceZ.constants.DEBUG ? '' : 'min.') + 'js?_=' + Date.now();
document.head.appendChild(script);
} else
// Get things started.
this.initialize();
}
FFZ.get = function() { return FFZ.instance; }
// TODO: This should be in a module.
FFZ.msg_commands = {};
FFZ.channel_metadata = {};
// Version
var VER = FFZ.version_info = {
major: 3, minor: 5, revision: 373,
toString: function() {
return [VER.major, VER.minor, VER.revision].join(".") + (VER.extra || "");
}
}
// Logging
FFZ.prototype.log = function(msg, data, to_json, log_json) {
if ( to_json )
msg = msg + ' -- ' + JSON.stringify(data);
this._log_data.push(msg + ((!to_json && log_json) ? " -- " + JSON.stringify(data) : ""));
if ( data !== undefined && console.groupCollapsed && console.dir ) {
console.groupCollapsed("%cFFZ:%c " + msg, "color:#755000; font-weight: bold", "color:black; font-weight: normal");
if ( typeof data === "string" || navigator.userAgent.indexOf("Firefox/") !== -1 )
console.log(data);
else
console.dir(data);
console.groupEnd("%cFFZ:%c " + msg, "color:#755000; font-weight: bold", "color:black; font-weight: normal");
} else
console.log("%cFFZ:%c " + msg, "color:#755000; font-weight: bold", "color:black; font-weight: normal");
}
FFZ.prototype.error = function(msg, error, to_json, log_json) {
var data = error && error.stack || error;
msg = "Error: " + msg + " [" + error + "]" + (to_json ? " -- " + JSON.stringify(data) : "");
this._log_data.push(msg + ((!to_json && log_json) ? " -- " + JSON.stringify(data) : ""));
if ( data === undefined ) {
var err = new Error();
data = err.stack;
}
if ( data !== undefined && console.groupCollapsed && console.dir ) {
console.groupCollapsed("%cFFZ " + msg, "color:red");
if ( typeof data === "string" || navigator.userAgent.indexOf("Firefox/") !== -1 )
console.log(data);
else
console.dir(data);
console.groupEnd("%cFFZ " + msg, "color:red");
} else
console.log("%cFFZ " + msg, "color:red");
}
FFZ.prototype.paste_logs = function() {
var f = this,
output = function(result) {
f._pastebin(result).then(function(url) {
f.log("Your FrankerFaceZ logs have been uploaded to: " + url);
}).catch(function() {
f.error("An error occured uploading the logs to a pastebin.");
});
}
this.get_debugging_info().then(function(data) {
output(data);
}).catch(function(err) {
f.error("Error building debugging information.", err);
output(f._log_data.join("\n"));
});
}
FFZ.prototype._pastebin = function(data) {
return new Promise(function(succeed, fail) {
jQuery.ajax({url: "https://putco.de/", type: "PUT", data: data})
.success(function(e) { succeed(e.trim() + ".log"); })
.fail(function(e) { fail(null); });
});
}
// -------------------
// User Data
// -------------------
2016-05-13 23:56:59 -04:00
FFZ.prototype.get_user = function(force_reload) {
if ( ! force_reload && this.__user )
return this.__user;
var LC = FFZ.utils.ember_lookup('service:login'),
user = LC ? LC.get('userData') : undefined;
if ( ! user && window.PP && PP.login )
user = PP;
if ( user )
this.__user = user;
return user;
}
FFZ.prototype._editor_of = null;
2016-05-24 19:24:45 -04:00
FFZ.prototype.get_user_editor_of = function() {
var f = this;
return new Promise(function(succeed,fail) {
var user = f.get_user();
if ( ! user || ! user.login )
return fail();
2016-05-24 19:24:45 -04:00
jQuery.get("/" + user.login + "/dashboard/permissions").done(function(data) {
try {
var dom = new DOMParser().parseFromString(data, 'text/html'),
links = dom.querySelectorAll('#editable .label');
2016-05-24 19:24:45 -04:00
f._editor_of = _.map(links, function(e) {
var href = e.getAttribute('href');
return href && href.substr(href.lastIndexOf('/') + 1);
});
succeed(f._editor_of);
} catch(err) {
f.error("Failed to parse User Editor State", err);
fail();
}
2016-05-24 19:24:45 -04:00
}).fail(function(e) {
f.error("Failed to load User Editor State", e);
fail();
2016-05-24 19:24:45 -04:00
});
});
}
// -------------------
// Import Everything!
// -------------------
// Import these first to set up data structures
require('./localization');
require('./ui/menu');
require('./settings');
require('./socket');
require('./colors');
require('./emoticons');
require('./badges');
2015-06-05 03:59:28 -04:00
require('./tokenize');
//require('./filtering');
2015-06-05 03:59:28 -04:00
require('./ember/wrapper');
require('./ember/router');
require('./ember/bits');
require('./ember/channel');
require('./ember/player');
require('./ember/room');
require('./ember/vod-chat');
require('./ember/layout');
require('./ember/line');
require('./ember/chatview');
require('./ember/conversations');
require('./ember/viewers');
require('./ember/moderation-card');
require('./ember/chat-input');
//require('./ember/teams');
require('./ember/directory');
require('./ember/following');
require('./ember/feed-card');
require('./ember/sidebar');
require('./debug');
require('./ext/betterttv');
require('./ext/emote_menu');
require('./featurefriday');
require('./ui/channel_stats');
2016-10-05 01:31:10 -04:00
require('./ui/logviewer');
//require('./ui/chatpane');
require('./ui/popups');
require('./ui/styles');
2015-02-24 02:48:29 -05:00
require('./ui/dark');
require('./ui/tooltips');
require('./ui/notifications');
//require('./ui/viewer_count');
2015-06-05 03:59:28 -04:00
require('./ui/sub_count');
require('./ui/dash_stats');
require('./ui/dash_feed');
require('./ui/menu_button');
2015-07-04 17:06:36 -04:00
require('./ui/following');
require('./ui/following-count');
require('./ui/races');
require('./ui/my_emotes');
require('./ui/about_page');
require('./commands');
require('./ext/api');
require('./ext/warpworld');
// ---------------
// Initialization
// ---------------
FFZ.prototype.initialized = false;
FFZ.prototype.initialize = function(increment, delay) {
// Make sure that FrankerFaceZ doesn't start setting itself up until the
// Twitch ember application is ready.
// Pages we don't want to interact with at all.
if ( location.hostname === 'passport.twitch.tv' || /^\/user\/two_factor/.test(location.pathname) )
return this.log("Found authentication sub-page. Not initializing.");
if ( ['im.twitch.tv', 'api.twitch.tv'].indexOf(location.hostname) !== -1 || /^\/products\//.test(location.pathname) || /^\/pr\//.test(location.pathname) )
return this.log("Found banned sub-domain. Not initializing.");
// Check for the player
if ( location.hostname === 'player.twitch.tv' )
return this.init_player(delay);
// Clips~
if ( location.hostname === 'clips.twitch.tv' )
return this.init_clips(delay);
// Check for special non-ember pages.
2016-09-30 13:09:03 -04:00
if ( /^\/(?:team\/|user\/|p\/|settings|m\/|messages?\/)/.test(location.pathname) )
return this.init_normal(delay);
// Check for the dashboard.
if ( /\/[^\/]+\/dashboard/.test(location.pathname) && !/bookmarks$/.test(location.pathname) )
return this.init_dashboard(delay);
var loaded = FFZ.utils.ember_resolve('model:room');
if ( !loaded ) {
increment = increment || 10;
if ( delay >= 60000 )
this.log("Twitch application not detected in \"" + location.toString() + "\". Aborting.");
else
setTimeout(this.initialize.bind(this, increment, (delay||0) + increment),
increment);
return;
}
this.init_ember(delay);
}
FFZ.prototype.init_clips = function(delay) {
var start = (window.performance && performance.now) ? performance.now() : Date.now();
this.log("Found Twitch Clips after " + (delay||0) + " ms at: " + location);
this.log("Initializing FrankerFaceZ version " + FFZ.version_info);
this.is_dashboard = false;
this.embed_in_dash = false;
this.is_clips = true;
try {
this.embed_in_clips = window.top !== window && window.top.location.hostname === 'clips.twitch.tv';
} catch(err) { this.embed_in_clips = false; }
this.setup_dark();
this.setup_css();
this.add_clips_darken_button();
this.initialized = true;
this.api_trigger('initialized');
var end = (window.performance && performance.now) ? performance.now() : Date.now(),
duration = end - start;
this.log("Initialization complete in " + duration + "ms");
}
FFZ.prototype.init_player = function(delay) {
var start = (window.performance && performance.now) ? performance.now() : Date.now();
this.log("Found Twitch Player after " + (delay||0) + " ms at: " + location);
this.log("Initializing FrankerFaceZ version " + FFZ.version_info);
this.is_dashboard = false;
try {
this.embed_in_dash = window.top !== window && /\/[^\/]+\/dashboard/.test(window.top.location.pathname) && !/bookmarks$/.test(window.top.location.pathname);
} catch(err) { this.embed_in_dash = false; }
// Literally only make it dark.
this.setup_dark();
this.setup_css();
this.setup_player();
this.initialized = true;
this.api_trigger('initialized');
var end = (window.performance && performance.now) ? performance.now() : Date.now(),
duration = end - start;
this.log("Initialization complete in " + duration + "ms");
}
FFZ.prototype.init_normal = function(delay, no_socket) {
var start = (window.performance && performance.now) ? performance.now() : Date.now();
this.log("Found non-Ember Twitch after " + (delay||0) + " ms at: " + location);
this.log("Initializing FrankerFaceZ version " + FFZ.version_info);
2015-07-04 17:06:36 -04:00
this.is_dashboard = false;
try {
this.embed_in_dash = window.top !== window && /\/[^\/]+\/dashboard/.test(window.top.location.pathname) && !/bookmarks$/.test(window.top.location.pathname);
} catch(err) { this.embed_in_dash = false; }
// Initialize all the modules.
this.setup_ember_wrapper();
// Start this early, for quick loading.
this.setup_dark();
this.setup_css();
this.setup_popups();
this.setup_following_link();
if ( ! no_socket ) {
this.setup_time();
this.ws_create();
}
this.setup_colors();
this.setup_emoticons();
this.setup_badges();
this.setup_sidebar();
this.setup_notifications();
this.setup_following_count(false);
2015-06-05 03:59:28 -04:00
this.setup_menu();
this.finalize_ember_wrapper();
this.setup_message_event();
this.fix_tooltips();
this.find_bttv(10);
this.initialized = true;
this.api_trigger('initialized');
var end = (window.performance && performance.now) ? performance.now() : Date.now(),
duration = end - start;
this.log("Initialization complete in " + duration + "ms");
}
FFZ.prototype.is_dashboard = false;
FFZ.prototype.init_dashboard = function(delay) {
var start = (window.performance && performance.now) ? performance.now() : Date.now();
this.log("Found Twitch Dashboard after " + (delay||0) + " ms at: " + location);
this.log("Initializing FrankerFaceZ version " + FFZ.version_info);
var match = location.pathname.match(/\/([^\/]+)/);
this.dashboard_channel = match && match[1] || undefined;
this.is_dashboard = true;
2015-07-04 17:06:36 -04:00
this.embed_in_dash = false;
// Initialize all the modules.
this.setup_ember_wrapper();
// Start this early, for quick loading.
this.setup_dark();
this.setup_css();
this.setup_popups();
this.setup_following_link();
this.setup_time();
this.ws_create();
this.setup_colors();
this.setup_emoticons();
this.setup_badges();
this.setup_tokenization();
this.setup_notifications();
this.setup_following_count(false);
this.setup_menu();
this.setup_dash_stats();
this.setup_dash_feed();
this.finalize_ember_wrapper();
2015-06-05 03:59:28 -04:00
this._update_subscribers();
// Set up the FFZ message passer.
this.setup_message_event();
2016-09-30 13:09:03 -04:00
this.cache_command_aliases();
this.fix_tooltips();
this.find_bttv(10);
this.initialized = true;
this.api_trigger('initialized');
var end = (window.performance && performance.now) ? performance.now() : Date.now(),
duration = end - start;
this.log("Initialization complete in " + duration + "ms");
}
FFZ.prototype.init_ember = function(delay) {
var start = (window.performance && performance.now) ? performance.now() : Date.now();
this.log("Found Twitch application after " + (delay||0) + " ms at: " + location);
this.log("Initializing FrankerFaceZ version " + FFZ.version_info);
2015-07-04 17:06:36 -04:00
this.is_dashboard = false;
2015-07-04 17:06:36 -04:00
try {
this.embed_in_dash = window.top !== window && /\/[^\/]+\/dashboard/.test(window.top.location.pathname) && !/bookmarks$/.test(window.top.location.pathname);
} catch(err) { this.embed_in_dash = false; }
// Is debug mode enabled? Scratch that, everyone gets error handlers!
if ( true ) { //this.settings.developer_mode ) {
// Set up an error listener for RSVP.
var f = this;
if ( Ember.RSVP && Ember.RSVP.on )
Ember.RSVP.on('error', function(error) {
2016-09-30 13:09:03 -04:00
// We want to ignore errors that are just 4xx HTTP responses.
if ( error && error.responseJSON && typeof error.responseJSON.status === "number" && error.responseJSON.status >= 400 )
return;
f.error("There was an error within an Ember RSVP.", error);
});
Ember.onerror = function(error) {
2016-09-30 13:09:03 -04:00
// We want to ignore errors that are just 4xx HTTP responses.
if ( error && error.responseJSON && typeof error.responseJSON.status === "number" && error.responseJSON.status >= 400 )
return;
f.error("There was an unknown error within Ember.", error);
}
}
// Set up all the everything.
this.setup_ember_wrapper();
// Start this early, for quick loading.
2015-02-24 02:48:29 -05:00
this.setup_dark();
this.setup_css();
this.setup_popups();
this.setup_time();
this.ws_create();
this.setup_emoticons();
this.setup_badges();
this.setup_router();
this.setup_colors();
this.setup_tokenization();
//this.setup_filtering();
this.setup_player();
this.setup_channel();
this.setup_room();
this.setup_vod_chat();
this.setup_line();
this.setup_bits();
this.setup_layout();
this.setup_chatview();
this.setup_conversations();
this.setup_viewers();
this.setup_mod_card();
this.setup_chat_input();
this.setup_directory();
this.setup_profile_following();
this.setup_feed_cards();
this.setup_sidebar();
//this.setup_teams();
this.setup_notifications();
this.setup_menu();
this.setup_my_emotes();
2015-07-04 17:06:36 -04:00
this.setup_following();
this.setup_following_count(true);
this.setup_races();
2015-06-05 03:59:28 -04:00
// Do all Ember modification before this point.
this.finalize_ember_wrapper();
2016-09-30 13:09:03 -04:00
this.cache_command_aliases();
this.fix_tooltips();
this.fix_scroll();
2015-06-05 03:59:28 -04:00
this.connect_extra_chat();
this.setup_message_event();
this.find_bttv(10);
this.find_emote_menu(10);
setTimeout(this.check_badware.bind(this), 10000);
//this.check_news();
this.check_ff();
this.refresh_chat();
this.initialized = true;
this.api_trigger('initialized');
var end = (window.performance && performance.now) ? performance.now() : Date.now(),
duration = end - start;
this.log("Initialization complete in " + duration + "ms");
2015-06-05 03:59:28 -04:00
}
// ------------------------
// Dashboard Message Event
// ------------------------
FFZ.prototype.setup_message_event = function() {
this.log("Listening for Window Messages.");
window.addEventListener("message", this._on_window_message.bind(this), false);
}
FFZ.prototype._on_window_message = function(e) {
var msg = e.data;
if ( typeof msg === "string" )
try {
msg = JSON.parse(msg);
} catch(err) {
// Not JSON? We don't care.
return;
}
if ( ! msg || ! msg.from_ffz )
2015-06-05 03:59:28 -04:00
return;
var handler = FFZ.msg_commands[msg.command];
if ( handler )
handler.call(this, msg.data);
else
this.log("Invalid Message: " + msg.command, msg.data, false, true);
}