1
0
Fork 0
mirror of https://github.com/FrankerFaceZ/FrankerFaceZ.git synced 2025-08-03 16:38:31 +00:00
FrankerFaceZ/src/badges.js

844 lines
No EOL
25 KiB
JavaScript

var FFZ = window.FrankerFaceZ,
constants = require('./constants'),
utils = require('./utils'),
SPECIAL_BADGES = ['staff', 'admin', 'global_mod'],
OTHER_KNOWN = ['turbo', 'bits', 'premium'],
CSS_BADGES = {
staff: { 1: { color: "#200f33", use_svg: true } },
admin: { 1: { color: "#faaf19", use_svg: true } },
global_mod: { 1: { color: "#0c6f20", use_svg: true } },
broadcaster: { 1: { color: "#e71818", use_svg: true } },
moderator: { 1: { color: "#34ae0a", use_svg: true } },
twitchbot: { 1: { color: "#34ae0a" } },
turbo: { 1: { color: "#6441a5", use_svg: true } },
premium: { 1: { color: "#009cdc" } },
bits: {
1: { color: "#cbc8d0" },
100: { color: "#ca7eff" },
1000: { color: "#3ed8b3" },
5000: { color: "#49acff" },
10000: { color: "#ff271e" },
25000: { color: "#f560ab" },
50000: { color: "#ff881f" },
75000: { color: "#16d03d" },
100000: { color: "#ffcb13" },
200000: { color: "#cbc8d0" },
300000: { color: "#c97ffd" },
400000: { color: "#3dd8b3" },
500000: { color: "#48acfe" },
600000: { color: "#ff281f" },
700000: { color: "#f560ab" },
800000: { color: "#ff881f" },
900000: { color: "#16d03d" },
1000000: { color: "#fecb11" }
}
},
NO_INVERT_BADGES = ['subscriber', 'ffz-badge-1'],
INVERT_INVERT_BADGES = ['bits'],
TRANSPARENT_BADGES = ['subscriber'],
BTTV_TYPE_REPLACEMENTS = {
'global-moderator': 'global_mod'
},
BADGE_POSITIONS = {
'broadcaster': 0,
'staff': 0,
'admin': 0,
'global_mod': 0,
'mod': 1,
'moderator': 1,
'twitchbot': 1,
'subscriber': 10,
},
BADGE_NAMES = {
'global_mod': 'Global Moderator'
},
BADGE_KLASSES = {
'global_mod': 'global-moderator'
};
// --------------------
// Settings
// --------------------
FFZ.settings_info.show_badges = {
type: "boolean",
value: true,
category: "Chat Appearance",
name: "Additional Badges",
help: "Show additional badges for bots, FrankerFaceZ donors, and other special users."
};
FFZ.settings_info.loyalty_badges = {
type: "boolean",
value: true,
category: "Chat Appearance",
name: "Display Subscriber Loyalty Badges",
help: "Show different badge images for users that have been subscribed 3, 6, 12, and 24 months in supported channels.",
on_update: function(val) {
utils.toggle_cls('ffz-no-loyalty')(!val);
}
};
FFZ.settings_info.hidden_badges = {
type: "button",
value: [],
category: "Chat Appearance",
name: "Hidden Badges",
help: "Any badges added to this list will not be displayed in chat.",
on_update: function(val) {
if ( this.has_bttv_6 )
return;
var controller = utils.ember_lookup('controller:chat'),
messages = controller && controller.get('currentRoom.messages');
if ( ! messages )
return;
for(var i=0; i < messages.length; i++)
messages[i]._line && messages[i]._line.ffzUpdateBadges();
},
method: function() {
var f = this,
service = utils.ember_lookup('service:badges'),
badgeCollection = service && service.badgeCollection,
old_val = f.settings.hidden_badges.join(", "),
values = [];
if ( badgeCollection ) {
if ( badgeCollection.global )
for(var badge in badgeCollection.global)
if ( badgeCollection.global.hasOwnProperty(badge) && badge !== 'broadcasterName' ) {
var badge_data = badgeCollection.global[badge] || {},
version = badge_data.versions && Object.keys(badge_data.versions)[0];
if ( version )
values.push([badge, f.render_badges(f.get_twitch_badges(badge + "/" + version))]);
}
if ( badgeCollection.channel )
for(var badge in badgeCollection.channel)
if ( badgeCollection.channel.hasOwnProperty(badge) && badge !== 'broadcasterName' ) {
var badge_data = badgeCollection.channel[badge] || {},
version = badge_data.versions && Object.keys(badge_data.versions)[0];
if ( version )
values.push([badge, f.render_badges(f.get_twitch_badges(badge + "/" + version))]);
}
}
for(var badge_id in f.badges) {
if ( ! f.badges.hasOwnProperty(badge_id) )
continue;
var badge = f.badges[badge_id],
hide_key = (badge.source_ext ? f._apis[badge.source_ext].name_key : 'ffz') + '-' + (badge.name || badge.id),
render_badge = {};
render_badge[badge.slot] = f._get_badge_object({}, badge);
values.push([hide_key, f.render_badges(render_badge)]);
}
if ( this.has_bttv_6 && window.BetterTTV ) {
try {
for(var badge_id in BetterTTV.chat.store.__badgeTypes)
values.push(['bttv-' + badge_id, null]);
values.push(['bot', null]);
} catch(err) {
this.error("Unable to load known BetterTTV badges.", err);
}
}
var already_used = [],
output = [];
for(var i=0; i < values.length; i++) {
var badge = values[i];
if ( already_used.indexOf(badge[0]) !== -1 )
continue;
already_used.push(badge[0]);
output.push((badge[1] ? '<div class="ffz-hidden-badges badges">' + badge[1] + '</div>' : '') + '<code>' + badge[0] + '</code>');
}
utils.prompt(
"Hidden Badges",
"Please enter a comma-separated list of badges that you would like to be hidden in chat. You can use the special value <code>game</code> to hide all the game-specific badges at once.</p><p><b>Possible Values:</b> " + output.join(", "),
old_val,
function(new_val) {
if ( new_val === null || new_val === undefined )
return;
f.settings.set("hidden_badges", _.unique(new_val.trim().toLowerCase().split(/\s*,\s*/)).without(""));
}, 600
)
}
};
FFZ.settings_info.sub_notice_badges = {
type: "boolean",
value: false,
category: "Chat Appearance",
name: "Old-Style Subscriber Notice Badges",
no_bttv: true,
help: "Display a subscriber badge on old-style chat messages about new subscribers.",
on_update: function(val) {
this.toggle_style('badges-sub-notice', ! this.has_bttv && ! val);
this.toggle_style('badges-sub-notice-on', ! this.has_bttv && val);
}
};
FFZ.settings_info.legacy_badges = {
type: "select",
options: {
0: "Default",
1: "Moderator Only",
2: "Mod + Turbo",
3: "All Legacy Badges"
},
value: 0,
category: "Chat Appearance",
name: "Legacy Badges",
help: "Use the old, pre-vector chat badges from Twitch in place of the new.",
process_value: utils.process_int(0, 0, 3),
on_update: function(val) {
this.toggle_style('badges-legacy', val === 3);
this.toggle_style('badges-legacy-mod', val !== 0);
this.toggle_style('badges-legacy-turbo', val > 1);
}
};
FFZ.settings_info.transparent_badges = {
type: "select",
options: {
0: "Default",
1: "Rounded",
2: "Circular",
3: "Circular (Color Only)",
4: "Circular (Color Only, Small)",
5: "Transparent" //,
//6: "Transparent (Colored)"
},
value: 0,
category: "Chat Appearance",
no_bttv: 6,
name: "Badge Style",
help: "Make badges appear rounded, completely circular, or transparent with no background at all.",
process_value: utils.process_int(0, 0, 5),
on_update: function(val) {
if ( this.has_bttv_6 )
return;
this.toggle_style('badges-rounded', val === 1);
this.toggle_style('badges-circular', val === 2 || val === 3 || val === 4);
this.toggle_style('badges-blank', val === 3 || val === 4);
this.toggle_style('badges-circular-small', val === 4);
this.toggle_style('badges-transparent', val >= 5);
document.body.classList.toggle('ffz-transparent-badges', val >= 5);
// Update existing chat lines.
var CL = utils.ember_resolve('component:chat/chat-line'),
CW = utils.ember_resolve('component:twitch-conversations/conversation-window'),
DP = utils.ember_resolve('component:chat/from-display-preview'),
views = (CL || CW || DP) ? utils.ember_views() : [];
for(var vid in views) {
var view = views[vid];
if ( CL && view instanceof CL && view.buildBadgesHTML )
view.$('.badges').replaceWith(view.buildBadgesHTML());
else if ( DP && view instanceof DP && view.ffzRenderBadges )
view.ffzRenderBadges();
else if ( CW && view instanceof CW && view.ffzReplaceBadges )
view.ffzReplaceBadges();
}
}
};
// This requires -webkit-mask-image which isn't working in non-WebKit browsers.
if ( constants.IS_WEBKIT )
FFZ.settings_info.transparent_badges.options[6] = "Transparent (Colored)";
// --------------------
// Initialization
// --------------------
FFZ.prototype.setup_badges = function() {
this.log("Preparing badge system.");
if ( ! this.has_bttv_6 ) {
var val = this.settings.transparent_badges;
this.toggle_style('badges-rounded', val === 1);
this.toggle_style('badges-circular', val === 2 || val === 3 || val === 4);
this.toggle_style('badges-blank', val === 3 || val === 4);
this.toggle_style('badges-circular-small', val === 4);
this.toggle_style('badges-transparent', val >= 5);
utils.toggle_cls('ffz-transparent-badges')(val >= 5);
utils.toggle_cls('ffz-no-loyalty')(!this.settings.loyalty_badges);
}
if ( ! this.has_bttv ) {
this.toggle_style('badges-sub-notice', ! this.settings.sub_notice_badges);
this.toggle_style('badges-sub-notice-on', this.settings.sub_notice_badges);
}
this.toggle_style('badges-legacy', this.settings.legacy_badges === 3);
this.toggle_style('badges-legacy-mod', this.settings.legacy_badges !== 0);
this.toggle_style('badges-legacy-turbo', this.settings.legacy_badges > 1);
this.log("Creating badge style element.");
var s = this._badge_style = document.createElement('style');
s.id = "ffz-badge-css";
document.head.appendChild(s);
this.log("Generating CSS for existing API badges.");
for(var badge_id in this.badges)
if ( this.badges.hasOwnProperty(badge_id) )
utils.update_css(s, badge_id, utils.badge_css(this.badges[badge_id]));
this.log("Generating CSS for existing Twitch badges.");
for(var badge_id in CSS_BADGES) {
var badge_data = CSS_BADGES[badge_id],
klass = BADGE_KLASSES[badge_id] || badge_id;
for(var version in badge_data)
utils.update_css(s, 'twitch-' + badge_id + '-' + version, utils.cdn_badge_css(klass, version, badge_data[version]));
}
this.log("Loading badges.");
this.load_badges();
}
// --------------------
// Reloading Badges
// --------------------
FFZ.ws_commands.reload_badges = function() {
this.load_badges();
}
FFZ.ws_commands.set_badge = function(data) {
var user_id = data[0],
slot = data[1],
badge = data[2],
user = this.users[user_id] = this.users[user_id] || {},
badges = user.badges = user.badges || {};
if ( typeof badge === "number" )
badge = {id: badge};
if ( badge === undefined || badge === null )
badges[slot] = null;
else
badges[slot] = badge;
}
// --------------------
// Badge Selection
// --------------------
FFZ.prototype.get_badges = function(user, room_id, badges, msg) {
var data = this.users[user],
room = this.rooms[room_id],
room_data = room && room.users && room.users[user],
hidden_badges = this.settings.hidden_badges,
badge_data = data && data.badges || {};
if ( room_data && room_data.badges )
badge_data = _.extend({}, badge_data, room_data.badges);
if ( ! badge_data || ! this.settings.show_badges )
return badges;
for(var slot in badge_data) {
var badge = badge_data[slot];
if ( ! badge_data.hasOwnProperty(slot) || ! badge )
continue;
var badge_id = badge.real_id || badge.id,
full_badge = this.badges[badge_id] || {},
full_badge_id = full_badge.real_id || full_badge.id,
old_badge = badges[slot],
hide_key = (full_badge.source_ext ? this._apis[full_badge.source_ext].name_key : 'ffz') + '-' + (full_badge.name || full_badge.id);
if ( hidden_badges.indexOf(hide_key) !== -1 )
continue;
if ( full_badge.visible !== undefined ) {
var visible = full_badge.visible;
if ( typeof visible === "function" )
visible = visible.call(this, room_id, user, msg, badges);
if ( ! visible )
continue;
}
if ( old_badge ) {
var replaces = badge.hasOwnProperty('replaces') ? badge.replaces : full_badge.replaces,
replace_mode = badge.replace_mode || full_badge.replace_mode || 'merge';
if ( ! replaces )
continue;
if ( replace_mode === 'merge' ) {
old_badge.image = badge.image || null;
old_badge.klass += ' ffz-badge-replacement ffz-replacer-ffz-badge-' + (badge_id || full_badge_id);
old_badge.title += ', ' + (badge.title || full_badge.title);
continue;
} else if ( replace_mode === 'keep_title' ) {
var b = badges[slot] = this._get_badge_object(badge, full_badge);
b.title = old_badge.title + ', ' + b.title;
continue;
} else if ( replace_mode === 'title_only' ) {
old_badge.title += ', ' + (badge.title || full_badge.title);
continue;
}
}
badges[slot] = this._get_badge_object(badge, full_badge);
}
return badges;
}
FFZ.prototype._get_badge_object = function(badge, full_badge) {
var id = badge.real_id || badge.id || full_badge.real_id || full_badge.id;
return {
id: id,
klass: 'ffz-badge-' + id,
title: badge.title || full_badge.title || ('Unknown FFZ Badge\nID: ' + id),
image: badge.image,
full_image: full_badge.image,
color: badge.color,
no_tooltip: badge.no_tooltip || full_badge.no_tooltip,
click_action: badge.click_action || full_badge.click_action,
click_url: badge.click_url || full_badge.click_url,
no_invert: badge.no_invert || full_badge.no_invert,
no_color: badge.no_color || full_badge.no_color,
invert_invert: badge.invert_invert || full_badge.invert_invert,
transparent: badge.transparent || full_badge.transparent || (badge.color || full_badge.color) === "transparent",
extra_css: (badge.extra_css || full_badge.extra_css)
}
}
FFZ.prototype.get_line_badges = function(msg) {
var room = msg.get && msg.get('room') || msg.room,
from = msg.get && msg.get('from') || msg.from,
tags = msg.get && msg.get('tags') || msg.tags || {},
badge_tag = tags.badges || {};
// Twitch Badges
var badges = this.get_twitch_badges(badge_tag, room);
// FFZ Badges
return this.get_badges(from, room, badges, msg);
}
FFZ.prototype.get_twitch_badges = function(badge_tag, room_id) {
var badges = {},
hidden_badges = this.settings.hidden_badges,
last_id = -1,
had_last = false,
service = utils.ember_lookup('service:badges'),
badgeCollection = service && service.badgeCollection,
globals = badgeCollection && badgeCollection.global || {},
channel = badgeCollection && badgeCollection.channel || {};
// Is this the right channel?
if ( room_id && room_id !== channel.broadcasterName ) {
var ffz_room = this.rooms && this.rooms[room_id];
channel = ffz_room && ffz_room.badges || {};
}
// Whisper Chat Lines have a non-associative array for some reason.
if ( Array.isArray(badge_tag) ) {
var val = badge_tag;
badge_tag = {};
for(var i=0; i < val.length; i++)
badge_tag[val[i].id] = val[i].version;
}
// VoD Chat lines don't have the badges pre-parsed for some reason.
else if ( typeof badge_tag === 'string' )
badge_tag = utils.parse_badge_tag(badge_tag);
for(var badge in badge_tag) {
var version = badge_tag[badge];
if ( ! badge_tag.hasOwnProperty(badge) || version === undefined || version === null )
continue;
var versions = channel[badge] || globals[badge],
binfo = versions && versions.versions && versions.versions[version],
is_game = badge.substr(-2) === '_1';
if ( hidden_badges.indexOf(badge) !== -1 || (is_game && hidden_badges.indexOf('game') !== -1) )
continue;
if ( BADGE_POSITIONS.hasOwnProperty(badge) )
last_id = BADGE_POSITIONS[badge];
else {
last_id = had_last ? last_id + 1 : 15;
had_last = true;
}
var is_known = BADGE_POSITIONS.hasOwnProperty(badge) || OTHER_KNOWN.indexOf(badge) !== -1;
badges[last_id] = {
klass: (BADGE_KLASSES[badge] || badge) + (is_known ? '' : ' unknown-badge') + ' version-' + version,
title: binfo && binfo.title || BADGE_NAMES[badge] || badge.capitalize(),
click_url: binfo && binfo.click_action === 'visit_url' && binfo.click_url,
no_invert: ! (versions && versions.allow_invert) && NO_INVERT_BADGES.indexOf(badge) !== -1,
no_color: ! CSS_BADGES.hasOwnProperty(badge),
invert_invert: (versions && versions.invert_invert) || INVERT_INVERT_BADGES.indexOf(badge) !== -1,
transparent: TRANSPARENT_BADGES.indexOf(badge) !== -1
};
if ( ! is_known && binfo ) {
badges[last_id].image = binfo.image_url_1x;
if ( binfo.image_url_2x || binfo.image_url_4x )
badges[last_id].srcSet = 'url("' + binfo.image_url_1x + '") 1x' + (binfo.image_url_2x ? ', url("' + binfo.image_url_2x + '") 2x' : '') + (binfo.image_url_4x ? ', url("' + binfo.image_url_4x + '") 4x' : '');
}
}
return badges;
}
// --------------------
// Render Badge
// --------------------
FFZ.prototype.render_badges = function(badges) {
var out = [],
setting = this.settings.transparent_badges;
for(var key in badges) {
var badge = badges[key],
klass = badge.klass,
css = '',
is_colored = !(badge.no_color !== undefined ? badge.no_color : badge.transparent);
if ( badge.image )
if ( is_colored && setting === 6 )
css += (constants.IS_WEBKIT ? '-webkit-' : '') + 'mask-image:url("' + utils.quote_attr(badge.image) + '");';
else
css += 'background-image:url("' + utils.quote_attr(badge.image) + '");';
if ( badge.srcSet )
if ( is_colored && setting === 6 )
css += (constants.IS_WEBKIT ? '-webkit-mask-image:-webkit-' : 'mask-image:') + 'image-set(' + badge.srcSet + ');';
else
css += 'background-image:' + (constants.IS_WEBKIT ? '-webkit-' : '') + 'image-set(' + badge.srcSet + ');';
if ( badge.color )
if ( is_colored && setting === 6 )
css += 'background: linear-gradient(' + badge.color + ',' + badge.color + ');';
else
css += 'background-color:' + badge.color + ';'
if ( badge.extra_css )
css += badge.extra_css;
if ( badge.click_url )
klass += ' click_url';
if ( badge.click_action )
klass += ' click_action';
if ( badge.no_invert )
klass += ' no-invert';
if ( badge.invert_invert )
klass += ' invert-invert';
if ( is_colored && setting === 6 )
klass += ' colored';
if ( badge.transparent )
klass += ' transparent';
out.push('<div class="badge ' + (badge.no_tooltip ? '' : 'html-tooltip ') + utils.quote_attr(klass) + '"' + (badge.id ? ' data-badge-id="' + badge.id + '"' : '') + (badge.click_url ? ' data-url="' + utils.quote_attr(badge.click_url) + '"' : '') + (css ? ' style="' + utils.quote_attr(css) + '"' : '') + ' title="' + utils.quote_attr(badge.title) + '"></div>');
}
return out.join("");
}
// --------------------
// Extension Support
// --------------------
FFZ.prototype.bttv_badges = function(data) {
if ( ! this.settings.show_badges )
return;
var user_id = data.sender,
user = this.users[user_id],
room = this.rooms[data.room],
room_data = room && room.users && room.users[user_id],
badges_out = [],
insert_at = -1,
hidden_badges = this.settings.hidden_badges,
alpha = BetterTTV.settings.get('alphaTags');
if ( ! data.badges )
data.badges = [];
// Determine where in the list to insert these badges.
// Also, strip out banned badges while we're at it.
for(var i=0; i < data.badges.length; i++) {
var badge = data.badges[i],
space_ind = badge.type.indexOf(' '),
hidden_key = space_ind !== -1 ? badge.type.substr(0, space_ind) : badge.type;
if ( hidden_key.indexOf('twitch-') === 0 )
hidden_key = hidden_key.substr(7);
if ( BTTV_TYPE_REPLACEMENTS.hasOwnProperty(hidden_key) )
hidden_key = BTTV_TYPE_REPLACEMENTS[hidden_key];
else {
var ind = hidden_key.indexOf('-');
if ( ind !== -1 )
hidden_key = hidden_key.substr(0, ind);
}
var is_game = hidden_key.substr(-2) === '_1';
if ( hidden_badges.indexOf(hidden_key) !== -1 || (is_game && hidden_badges.indexOf('game') !== -1) ) {
data.badges.splice(i, 1);
i--;
continue;
}
if ( insert_at === -1 && (badge.type === "subscriber" || badge.type === "turbo" || badge.type.substr(0, 7) === 'twitch-') )
insert_at = i;
}
var badge_data = user && user.badges || {};
if ( room_data && room_data.badges )
badge_data = _.extend({}, badge_data, room_data.badges);
// If there's no user, we're done now.
if ( ! badge_data )
return;
// We have a user. Start replacing badges.
for (var slot in badge_data) {
var badge = badge_data[slot];
if ( ! badge_data.hasOwnProperty(slot) || ! badge )
continue;
var badge_id = badge.real_id || badge.id,
full_badge = this.badges[badge_id] || {},
full_badge_id = full_badge.real_id || full_badge.id,
desc = badge.title || full_badge.title,
style = "",
klass = 'ffz-badge-' + badge_id + (alpha ? ' alpha' : ''),
hide_key = (full_badge.source_ext ? this._apis[full_badge.source_ext].name_key : 'ffz') + '-' + (full_badge.name || full_badge.id);
if ( hidden_badges.indexOf(hide_key) !== -1 )
continue;
if ( full_badge.visible !== undefined ) {
var visible = full_badge.visible;
if ( typeof visible === "function" )
visible = visible.call(this, data.room, user_id);
if ( ! visible )
continue;
}
if ( alpha && badge.transparent_image )
style += 'background-image: url("' + badge.transparent_image + '");';
else 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="' + utils.quote_attr(style);
var replaces = badge.hasOwnProperty('replaces') ? badge.replaces : full_badge.replaces,
replace_mode = badge.replace_mode || full_badge.replace_mode || 'merge';
if ( replaces ) {
var replaced = false;
for(var i=0; i < data.badges.length; i++) {
var b = data.badges[i];
if ( b.type === full_badge.replaces_type ) {
if ( replace_mode === 'merge' ) {
b.type += " ffz-badge-replacement ffz-replacer-ffz-badge-" + (badge_id || full_badge_id);
b.description += ", " + (badge.title || full_badge.title) +
(badge.image ? '" style="background-image: url(' + utils.quote_attr('"' + badge.image + '"') + ')' : '');
} else if ( replace_mode === 'keep_title' ) {
data.badges[i] = {
type: klass,
name: '',
description: b.description + ', ' + desc
};
} else if ( replace_mode === 'title_only' ) {
b.description += ', ' + (badge.title || full_badge.title);
} else {
data.badges[i] = {type: klass, name: '', description: desc};
}
replaced = true;
break;
}
}
if ( replaced )
continue;
}
badges_out.push([(insert_at == -1 ? 1 : -1) * slot, {type: klass, 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]);
}
}
// --------------------
// Badge Loading
// --------------------
FFZ.bttv_known_bots = ["nightbot","moobot","sourbot","xanbot","manabot","mtgbot","ackbot","baconrobot","tardisbot","deejbot","valuebot","stahpbot"];
FFZ.prototype.load_badges = function(callback, tries) {
var f = this;
jQuery.getJSON(constants.API_SERVER + "v1/badges")
.done(function(data) {
var badge_total = 0,
badge_count = 0,
badge_data = {};
for(var i=0; i < data.badges.length; i++) {
var badge = data.badges[i];
if ( badge && badge.name ) {
f._load_badge_json(badge.id, badge);
badge_total++;
}
}
if ( data.users )
for(var badge_id in data.users)
if ( data.users.hasOwnProperty(badge_id) && f.badges[badge_id] ) {
var badge = f.badges[badge_id],
users = data.users[badge_id];
badge_data[badge.name] = users.length;
for(var i=0; i < users.length; i++) {
var user = users[i],
ud = f.users[user] = f.users[user] || {},
badges = ud.badges = ud.badges || {};
badge_count++;
badges[badge.slot] = {id: badge.id};
}
f.log('Added "' + badge.name + '" badge to ' + utils.number_commas(users.length) + ' users.');
}
// Special Badges
var zw = f.users.zenwan = f.users.zenwan || {},
badges = zw.badges = zw.badges || {};
if ( ! badges[1] )
badge_count++;
badges[1] = {id: 2, image: "//cdn.frankerfacez.com/script/momiglee_badge.png", title: "WAN"};
f.log("Loaded " + utils.number_commas(badge_count) + " total badges across " + badge_total + " types.");
typeof callback === "function" && callback(true, badge_count, badge_total, badge_data);
}).fail(function(data) {
if ( data.status === 404 )
return typeof callback === "function" && callback(false);
tries = (tries || 0) + 1;
if ( tries < 10 )
return setTimeout(f.load_badges.bind(f, callback, tries), 500 + 500*tries);
f.error("Unable to load badge data. [HTTP Status " + data.status + "]", data);
typeof callback === "function" && callback(false);
});
}
FFZ.prototype._load_badge_json = function(badge_id, data) {
this.badges[badge_id] = data;
if ( data.replaces ) {
data.replaces_type = data.replaces;
data.replaces = true;
}
if ( data.name === 'bot' )
data.visible = function(r,user) { return !(this.has_bttv && FFZ.bttv_known_bots.indexOf(user)!==-1); };
if ( data.name === 'developer' || data.name === 'supporter' )
data.click_url = 'https://www.frankerfacez.com/donate';
utils.update_css(this._badge_style, badge_id, utils.badge_css(data));
}