mirror of
https://github.com/FrankerFaceZ/FrankerFaceZ.git
synced 2025-09-17 10:16:57 +00:00
BetterTTV Integration
This commit is contained in:
parent
cc71863800
commit
4e6942e2f3
11 changed files with 576 additions and 100 deletions
|
@ -34,6 +34,62 @@ var badge_css = function(badge) {
|
|||
// Render Badge
|
||||
// --------------------
|
||||
|
||||
FFZ.prototype.bttv_badges = function(data) {
|
||||
var user_id = data.sender,
|
||||
user = this.users[user_id],
|
||||
badges_out = [],
|
||||
insert_at = -1;
|
||||
|
||||
if ( ! user || ! user.badges )
|
||||
return;
|
||||
|
||||
// Determine where in the list to insert these badges.
|
||||
for(var i=0; i < data.badges.length; i++) {
|
||||
var badge = data.badges[i];
|
||||
if ( badge.type == "subscriber" || badge.type == "turbo" ) {
|
||||
insert_at = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
for (var slot in user.badges) {
|
||||
if ( ! user.badges.hasOwnProperty(slot) )
|
||||
continue;
|
||||
|
||||
var badge = user.badges[slot],
|
||||
full_badge = this.badges[badge.id] || {},
|
||||
desc = badge.title || full_badge.title,
|
||||
style = "",
|
||||
alpha = BetterTTV.settings.get('alphaTags');
|
||||
|
||||
if ( badge.image )
|
||||
style += 'background-image: url(\\"' + badge.image + '\\"); ';
|
||||
|
||||
if ( badge.color && ! alpha )
|
||||
style += 'background-color: ' + badge.color + '; ';
|
||||
|
||||
if ( badge.extra_css )
|
||||
style += badge.extra_css;
|
||||
|
||||
if ( style )
|
||||
desc += '" style="' + style;
|
||||
|
||||
badges_out.push([(insert_at == -1 ? 1 : -1) * slot, {type: "ffz-badge-" + badge.id + (alpha ? " alpha" : ""), name: "", description: desc}]);
|
||||
}
|
||||
|
||||
badges_out.sort(function(a,b){return a[0] - b[0]});
|
||||
|
||||
if ( insert_at == -1 ) {
|
||||
while(badges_out.length)
|
||||
data.badges.push(badges_out.shift()[1]);
|
||||
} else {
|
||||
while(badges_out.length)
|
||||
data.badges.insertAt(insert_at, badges_out.shift()[1]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
FFZ.prototype.render_badge = function(view) {
|
||||
var user = view.get('context.model.from'),
|
||||
room_id = view.get('context.parentController.content.id'),
|
||||
|
|
132
src/betterttv.js
Normal file
132
src/betterttv.js
Normal file
|
@ -0,0 +1,132 @@
|
|||
var FFZ = window.FrankerFaceZ,
|
||||
SENDER_REGEX = /(\sdata-sender="[^"]*"(?=>))/;
|
||||
|
||||
|
||||
// --------------------
|
||||
// Initialization
|
||||
// --------------------
|
||||
|
||||
FFZ.prototype.find_bttv = function(increment, delay) {
|
||||
this.has_bttv = false;
|
||||
if ( window.BTTVLOADED )
|
||||
return this.setup_bttv();
|
||||
|
||||
if ( delay >= 60000 )
|
||||
this.log("BetterTTV was not detected after 60 seconds.");
|
||||
else
|
||||
setTimeout(this.find_bttv.bind(this, increment, (delay||0) + increment),
|
||||
increment);
|
||||
}
|
||||
|
||||
|
||||
FFZ.prototype.setup_bttv = function() {
|
||||
this.log("BetterTTV was detected. Hooking.");
|
||||
this.has_bttv = true;
|
||||
|
||||
|
||||
// Send Message Behavior
|
||||
var original_send = BetterTTV.chat.helpers.sendMessage, f = this;
|
||||
BetterTTV.chat.helpers.sendMessage = function(message) {
|
||||
var cmd = message.split(' ', 1)[0].toLowerCase();
|
||||
|
||||
if ( cmd === "/ffz" )
|
||||
f.run_command(message.substr(5), BetterTTV.chat.store.currentRoom);
|
||||
else
|
||||
return original_send(message);
|
||||
}
|
||||
|
||||
|
||||
// Ugly Hack for Current Room
|
||||
var original_handler = BetterTTV.chat.handlers.privmsg,
|
||||
received_room;
|
||||
BetterTTV.chat.handlers.privmsg = function(room, data) {
|
||||
received_room = room;
|
||||
var output = original_handler(room, data);
|
||||
received_room = null;
|
||||
return output;
|
||||
}
|
||||
|
||||
|
||||
// Message Display Behavior
|
||||
var original_privmsg = BetterTTV.chat.templates.privmsg;
|
||||
BetterTTV.chat.templates.privmsg = function(highlight, action, server, isMod, data) {
|
||||
// Handle badges.
|
||||
f.bttv_badges(data);
|
||||
|
||||
var output = original_privmsg(highlight, action, server, isMod, data);
|
||||
return output.replace(SENDER_REGEX, '$1 data-room="' + received_room + '"');
|
||||
}
|
||||
|
||||
|
||||
// Ugly Hack for Current Sender
|
||||
var original_template = BetterTTV.chat.templates.message,
|
||||
received_sender;
|
||||
BetterTTV.chat.templates.message = function(sender, message, emotes, colored) {
|
||||
received_sender = sender;
|
||||
var output = original_template(sender, message, emotes, colored);
|
||||
received_sender = null;
|
||||
return output;
|
||||
}
|
||||
|
||||
|
||||
// Emoticonize
|
||||
var original_emoticonize = BetterTTV.chat.templates.emoticonize;
|
||||
BetterTTV.chat.templates.emoticonize = function(message, emotes) {
|
||||
var tokens = original_emoticonize(message, emotes),
|
||||
user = f.users[received_sender],
|
||||
room = f.rooms[received_room];
|
||||
|
||||
// Get our sets.
|
||||
var sets = _.union(user && user.sets || [], room && room.sets || [], f.global_sets),
|
||||
emotes = [];
|
||||
|
||||
// Build a list of emotes that match.
|
||||
_.each(sets, function(set_id) {
|
||||
var set = f.emote_sets[set_id];
|
||||
if ( ! set )
|
||||
return;
|
||||
|
||||
_.each(set.emotes, function(emote) {
|
||||
_.any(tokens, function(token) {
|
||||
return _.isString(token) && token.match(emote.regex);
|
||||
}) && emotes.push(emote);
|
||||
});
|
||||
});
|
||||
|
||||
// Don't bother proceeding if we have no emotes.
|
||||
if ( ! emotes.length )
|
||||
return tokens;
|
||||
|
||||
// Why is emote parsing so bad? ;_;
|
||||
_.each(emotes, function(emote) {
|
||||
var eo = ['<img class="emoticon" src="' + emote.url + '" alt="' + emote.title + '" />'],
|
||||
old_tokens = tokens;
|
||||
|
||||
tokens = [];
|
||||
|
||||
if ( ! old_tokens || ! old_tokens.length )
|
||||
return tokens;
|
||||
|
||||
for(var i=0; i < old_tokens.length; i++) {
|
||||
var token = old_tokens[i];
|
||||
if ( typeof token != "string" ) {
|
||||
tokens.push(token);
|
||||
continue;
|
||||
}
|
||||
|
||||
var tbits = token.split(emote.regex);
|
||||
tbits.forEach(function(val, ind) {
|
||||
if ( val && val.length )
|
||||
tokens.push(val);
|
||||
|
||||
if ( ind !== tbits.length - 1 )
|
||||
tokens.push(eo);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return tokens;
|
||||
}
|
||||
|
||||
this.update_ui_link();
|
||||
}
|
|
@ -14,8 +14,6 @@ FFZ.prototype.setup_line = function() {
|
|||
Line.reopen({
|
||||
tokenizedMessage: function() {
|
||||
// Add our own step to the tokenization procedure.
|
||||
var tokens = f._emoticonize(this, this._super());
|
||||
f.log("Chat Tokens", tokens);
|
||||
return f._emoticonize(this, this._super());
|
||||
|
||||
}.property("model.message", "isModeratorOrHigher", "controllers.emoticons.emoticons.[]")
|
||||
|
@ -30,16 +28,45 @@ FFZ.prototype.setup_line = function() {
|
|||
didInsertElement: function() {
|
||||
this._super();
|
||||
|
||||
var el = this.get('element');
|
||||
var el = this.get('element'),
|
||||
user = this.get('context.model.from');
|
||||
|
||||
el.setAttribute('data-room', this.get('context.parentController.content.id'));
|
||||
el.setAttribute('data-sender', this.get('context.model.from'));
|
||||
el.setAttribute('data-sender', user);
|
||||
|
||||
f.render_badge(this);
|
||||
f.capitalize(this, user);
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// ---------------------
|
||||
// Capitalization
|
||||
// ---------------------
|
||||
|
||||
FFZ.capitalization = {};
|
||||
|
||||
FFZ.prototype.capitalize = function(view, user) {
|
||||
if ( FFZ.capitalization[user] )
|
||||
return view.$('.from').text(FFZ.capitalization[user]);
|
||||
|
||||
var f = this;
|
||||
jQuery.getJSON("https://api.twitch.tv/kraken/channels/" + user + "?callback=?")
|
||||
.always(function(data) {
|
||||
if ( data.display_name == undefined )
|
||||
FFZ.capitalization[user] = user;
|
||||
else
|
||||
FFZ.capitalization[user] = data.display_name;
|
||||
|
||||
f.capitalize(view, user);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// ---------------------
|
||||
// Emoticon Replacement
|
||||
// ---------------------
|
||||
|
@ -83,7 +110,7 @@ FFZ.prototype._emoticonize = function(controller, tokens) {
|
|||
// emoticon.
|
||||
_.each(emotes, function(emote) {
|
||||
//var eo = {isEmoticon:true, cls: emote.klass};
|
||||
var eo = {emoticonSrc: emote.url, altText: emote.name};
|
||||
var eo = {isEmoticon:true, cls: emote.klass, emoticonSrc: emote.url, altText: emote.name};
|
||||
|
||||
tokens = _.compact(_.flatten(_.map(tokens, function(token) {
|
||||
if ( _.isObject(token) )
|
||||
|
|
|
@ -54,8 +54,14 @@ FFZ.chat_commands = {};
|
|||
|
||||
FFZ.prototype.room_message = function(room, text) {
|
||||
var lines = text.split("\n");
|
||||
for(var i=0; i < lines.length; i++)
|
||||
room.room.addMessage({style: 'ffz admin', from: 'FFZ', message: lines[i]});
|
||||
if ( this.has_bttv ) {
|
||||
for(var i=0; i < lines.length; i++)
|
||||
BetterTTV.chat.handlers.onPrivmsg(room.id, {style: 'admin', date: new Date(), from: 'jtv', message: lines[i]});
|
||||
|
||||
} else {
|
||||
for(var i=0; i < lines.length; i++)
|
||||
room.room.addMessage({style: 'ffz admin', date: new Date(), from: 'FFZ', message: lines[i]});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -192,22 +198,6 @@ FFZ.prototype._load_room_json = function(room_id, callback, data) {
|
|||
}
|
||||
|
||||
|
||||
/*FFZ.ws_commands.sets_for_room = function(data) {
|
||||
var room = this.rooms[data.room];
|
||||
if ( ! room )
|
||||
return;
|
||||
|
||||
for(var i=0; i < data.sets.length; i++) {
|
||||
var set = data.sets[i];
|
||||
if ( room.sets.contains(set) )
|
||||
continue;
|
||||
|
||||
room.sets.push(set);
|
||||
this.load_set(set);
|
||||
}
|
||||
}*/
|
||||
|
||||
|
||||
// --------------------
|
||||
// Ember Modifications
|
||||
// --------------------
|
||||
|
|
|
@ -80,13 +80,15 @@ var build_legacy_css = function(emote) {
|
|||
return ".ffz-emote-" + emote.id + ' { background-image: url("' + emote.url + '"); height: ' + emote.height + "px; width: " + emote.width + "px; margin: " + margin + (emote.extra_css ? "; " + emote.extra_css : "") + "}\n";
|
||||
}
|
||||
|
||||
var build_css = function(emote) {
|
||||
var build_new_css = function(emote) {
|
||||
if ( ! emote.margins && ! emote.extra_css )
|
||||
return "";
|
||||
return build_legacy_css(emote);
|
||||
|
||||
return 'img[src="' + emote.url + '"] { ' + (emote.margins ? "margin: " + emote.margins + ";" : "") + (emote.extra_css || "") + " }\n";
|
||||
return build_legacy_css(emote) + 'img[src="' + emote.url + '"] { ' + (emote.margins ? "margin: " + emote.margins + ";" : "") + (emote.extra_css || "") + " }\n";
|
||||
}
|
||||
|
||||
var build_css = build_new_css;
|
||||
|
||||
|
||||
|
||||
FFZ.prototype._load_set_json = function(set_id, callback, data) {
|
||||
|
@ -94,6 +96,7 @@ FFZ.prototype._load_set_json = function(set_id, callback, data) {
|
|||
this.emote_sets[set_id] = data;
|
||||
data.users = [];
|
||||
data.global = false;
|
||||
data.count = 0;
|
||||
|
||||
// Iterate through all the emoticons, building CSS and regex objects as appropriate.
|
||||
var output_css = "";
|
||||
|
@ -111,10 +114,12 @@ FFZ.prototype._load_set_json = function(set_id, callback, data) {
|
|||
emote.regex = new RegExp("\\b" + emote.name + "\\b", "g");
|
||||
|
||||
output_css += build_css(emote);
|
||||
data.count++;
|
||||
}
|
||||
|
||||
utils.update_css(this._emote_style, set_id, output_css + (data.extra_css || ""));
|
||||
this.log("Updated emoticons for set: " + set_id, data);
|
||||
this.update_ui_link();
|
||||
|
||||
if ( callback )
|
||||
callback(true, data);
|
||||
|
|
|
@ -67,6 +67,8 @@ require('./ember/chatview');
|
|||
|
||||
require('./debug');
|
||||
|
||||
require('./betterttv');
|
||||
|
||||
require('./ui/styles');
|
||||
require('./ui/notifications');
|
||||
require('./ui/viewer_count');
|
||||
|
@ -74,6 +76,7 @@ require('./ui/viewer_count');
|
|||
require('./ui/menu_button');
|
||||
require('./ui/menu');
|
||||
|
||||
|
||||
// ---------------
|
||||
// Initialization
|
||||
// ---------------
|
||||
|
@ -119,6 +122,9 @@ FFZ.prototype.setup = function(delay) {
|
|||
this.setup_css();
|
||||
this.setup_menu();
|
||||
|
||||
this.find_bttv(10);
|
||||
|
||||
|
||||
} catch(err) {
|
||||
this.log("An error occurred while starting FrankerFaceZ: " + err);
|
||||
return;
|
||||
|
|
|
@ -100,15 +100,20 @@ FFZ.prototype._emotes_for_sets = function(parent, view, sets, header, btn) {
|
|||
|
||||
for(var i=0; i < sets.length; i++) {
|
||||
var set = this.emote_sets[sets[i]];
|
||||
if ( ! set || ! set.emotes )
|
||||
continue;
|
||||
|
||||
for(var eid in set.emotes) {
|
||||
var emote = set.emotes[eid];
|
||||
if ( !set.emotes.hasOwnProperty(eid) || emote.hidden )
|
||||
continue;
|
||||
|
||||
c++;
|
||||
var s = document.createElement('img');
|
||||
s.src = emote.url;
|
||||
//s.className = 'emoticon ' + emote.klass + ' tooltip';
|
||||
var s = document.createElement('span');
|
||||
s.className = 'emoticon tooltip';
|
||||
s.style.backgroundImage = 'url("' + emote.url + '")';
|
||||
s.style.width = emote.width + "px";
|
||||
s.style.height = emote.height + "px";
|
||||
s.title = emote.name;
|
||||
s.addEventListener('click', this._add_emote.bind(this, view, emote.name));
|
||||
grid.appendChild(s);
|
||||
|
|
|
@ -6,8 +6,6 @@ var FFZ = window.FrankerFaceZ,
|
|||
// --------------------
|
||||
|
||||
FFZ.prototype.build_ui_link = function(view) {
|
||||
// TODO: Detect dark mode from BTTV.
|
||||
|
||||
var link = document.createElement('a');
|
||||
link.className = 'ffz-ui-toggle';
|
||||
link.innerHTML = constants.CHAT_BUTTON;
|
||||
|
@ -22,14 +20,28 @@ FFZ.prototype.build_ui_link = function(view) {
|
|||
FFZ.prototype.update_ui_link = function(link) {
|
||||
var controller = App.__container__.lookup('controller:chat');
|
||||
link = link || document.querySelector('a.ffz-ui-toggle');
|
||||
if ( !link || !controller ) return;
|
||||
if ( !link || !controller ) return this.log("No button.");
|
||||
|
||||
var room_id = controller.get('currentRoom.id'),
|
||||
room = this.rooms[room_id],
|
||||
has_emotes = room && room.sets.length > 0;
|
||||
has_emotes = false,
|
||||
|
||||
if ( has_emotes )
|
||||
link.classList.remove('no-emotes');
|
||||
else
|
||||
link.classList.add('no-emotes');
|
||||
dark = (this.has_bttv ? BetterTTV.settings.get('darkenedMode') : false),
|
||||
blue = (this.has_bttv ? BetterTTV.settings.get('showBlueButtons') : false);
|
||||
|
||||
|
||||
// Check for emoticons.
|
||||
if ( room && room.sets.length ) {
|
||||
for(var i=0; i < room.sets.length; i++) {
|
||||
var set = this.emote_sets[room.sets[i]];
|
||||
if ( set && set.count > 0 ) {
|
||||
has_emotes = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
link.classList.toggle('no-emotes', ! has_emotes);
|
||||
link.classList.toggle('dark', dark);
|
||||
link.classList.toggle('blue', blue);
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue