2017-11-13 01:23:39 -05:00
'use strict' ;
// ============================================================================
// Badge Handling
// ============================================================================
2019-12-10 20:46:33 -05:00
import { NEW _API , SERVER , API _SERVER , IS _WEBKIT , IS _FIREFOX , WEBKIT _CSS as WEBKIT } from 'utilities/constants' ;
2017-11-28 02:03:59 -05:00
2018-04-01 18:24:08 -04:00
import { createElement , ManagedStyle } from 'utilities/dom' ;
2017-11-28 02:03:59 -05:00
import { has } from 'utilities/object' ;
2017-11-13 01:23:39 -05:00
import Module from 'utilities/module' ;
2019-12-05 23:13:27 -05:00
import { ColorAdjuster } from 'src/utilities/color' ;
const CSS _BADGES = {
1 : {
staff : { 1 : { color : '#200f33' , svg : true , trans : { color : '#6441a5' } } } ,
admin : { 1 : { color : '#faaf19' , svg : true } } ,
global _mod : { 1 : { color : '#0c6f20' , svg : true } } ,
broadcaster : { 1 : { color : '#e71818' , svg : true } } ,
moderator : { 1 : { color : '#34ae0a' , svg : true } } ,
twitchbot : { 1 : { color : '#34ae0a' } } ,
partner : { 1 : { color : 'transparent' , trans : { image : true , color : '#6441a5' } } } ,
'clip-champ' : { 1 : { color : '#6441a5' } } ,
vip : { 1 : { color : '#b33ff0' , trans : { color : 'transparent' , invert : false } } } ,
turbo : { 1 : { color : '#6441a5' , svg : true } } ,
premium : { 1 : { color : '#009cdc' } } ,
subscriber : { 0 : { color : '#6441a5' } , 1 : { color : '#6441a5' } } ,
} ,
2 : {
staff : { 1 : { color : '#000' } } ,
2019-12-06 15:56:58 -05:00
admin : { 1 : { color : '#DB7600' } } ,
2019-12-05 23:13:27 -05:00
broadcaster : { 1 : { color : '#E91916' } } ,
2019-12-06 15:56:58 -05:00
moderator : { 1 : { color : '#00AD03' } } ,
2019-12-05 23:13:27 -05:00
global _mod : { 1 : { color : '#006441' } } ,
2019-12-06 15:56:58 -05:00
twitchbot : { 1 : { color : '#00AD03' } } ,
2019-12-05 23:13:27 -05:00
partner : { 1 : { color : '#9146FF' } } ,
subscriber : { 0 : { color : '#8205B4' } , 1 : { color : '#8205B4' } } ,
2019-12-06 15:56:58 -05:00
vip : { 1 : { color : '#E005B9' } } ,
2019-12-05 23:13:27 -05:00
turbo : { 1 : { color : '#59399A' } } ,
2019-12-06 15:56:58 -05:00
premium : { 1 : { color : '#00A0D6' } } ,
2019-12-05 23:13:27 -05:00
'anonymous-cheerer' : { 1 : { color : '#4B367C' } } ,
'clip-champ' : { 1 : { color : '#9146FF' } }
}
2017-11-13 01:23:39 -05:00
}
2018-01-16 17:36:56 -05:00
export const BADGE _POSITIONS = {
broadcaster : 0 ,
staff : 0 ,
admin : 0 ,
global _mod : 0 ,
mod : 1 ,
moderator : 1 ,
twitchbot : 1 ,
2018-11-14 18:33:57 -05:00
vip : 2 ,
2018-01-16 17:36:56 -05:00
subscriber : 25
} ;
2017-11-13 01:23:39 -05:00
2017-11-28 02:03:59 -05:00
const NO _REPEAT = 'background-repeat:no-repeat;background-position:center;' ,
2019-12-05 23:13:27 -05:00
BASE _IMAGE = ` ${ SERVER } /static/badges/twitch/ ` ,
2018-02-02 16:00:01 -05:00
CSS _MASK _IMAGE = IS _WEBKIT ? 'webkitMaskImage' : 'maskImage' ,
2017-11-28 02:03:59 -05:00
CSS _TEMPLATES = {
2018-01-16 17:36:56 -05:00
0 : data => ` background: ${ data . image } ${ data . color } ;background-size: ${ data . scale * 1.8 } rem; ${ data . svg ? '' : ` background-image: ${ data . image _set } ; ` } ${ NO _REPEAT } ` ,
1 : data => ` ${ CSS _TEMPLATES [ 0 ] ( data ) } border-radius: ${ data . scale * .2 } rem; ` ,
2 : data => ` ${ CSS _TEMPLATES [ 0 ] ( data ) } border-radius: ${ data . scale * .9 } rem;background-size: ${ data . scale * 1.6 } rem; ` ,
3 : data => ` background: ${ data . color } ;border-radius: ${ data . scale * .9 } rem; ` ,
4 : data => ` ${ CSS _TEMPLATES [ 3 ] ( data ) } height: ${ data . scale } rem;min-width: ${ data . scale } rem; ` ,
5 : data => ` background: ${ data . image } ;background-size: ${ data . scale * 1.8 } rem; ${ data . svg ? ` ` : ` background-image: ${ data . image _set } ; ` } ${ NO _REPEAT } ` ,
6 : data => ` background:linear-gradient( ${ data . color } , ${ data . color } ); ${ WEBKIT } mask-image: ${ data . image } ; ${ WEBKIT } mask-size: ${ data . scale * 1.8 } rem ${ data . scale * 1.8 } rem; ${ data . svg ? ` ` : ` ${ WEBKIT } mask-image: ${ data . image _set } ; ` } `
2017-11-28 02:03:59 -05:00
} ;
2018-02-02 16:18:03 -05:00
export function generateOverrideCSS ( data , style ) {
2018-04-02 03:30:22 -04:00
const urls = data . urls || { 1 : data . image } ,
image = ` url(" ${ urls [ 1 ] } ") ` ,
2018-02-02 16:18:03 -05:00
image _set = ` ${ WEBKIT } image-set( ${ image } 1x ${ urls [ 2 ] ? ` , url(" ${ urls [ 2 ] } ") 2x ` : '' } ${ urls [ 4 ] ? ` , url(" ${ urls [ 4 ] } ") 4x ` : '' } ) ` ;
2018-01-16 17:36:56 -05:00
if ( style === 3 || style === 4 )
return '' ;
if ( style === 6 )
return ` ${ WEBKIT } mask-image: ${ image } !important; ${ WEBKIT } mask-image: ${ image _set } !important; ` ;
else
return ` background-image: ${ image } !important;background-image: ${ image _set } !important; ` ;
}
2020-08-17 13:33:30 -04:00
export function generateBadgeCSS ( badge , version , data , style , is _dark , badge _version = 2 , color _fixer , scale = 1 , clickable = false ) {
2017-11-28 02:03:59 -05:00
let color = data . color || 'transparent' ,
2019-12-05 23:13:27 -05:00
base _image = data . image || ` ${ BASE _IMAGE } ${ badge _version } / ${ badge } ${ data . svg ? '.svg' : ` / ${ version } / ` } ` ,
2017-11-28 02:03:59 -05:00
trans = false ,
invert = false ,
svg , image , image _set ;
if ( style > 4 ) {
const td = data . trans || { } ;
color = td . color || color ;
if ( td . image ) {
trans = true ;
if ( td . image !== true )
base _image = td . image ;
}
if ( has ( td , 'invert' ) )
invert = td . invert && ! is _dark ;
else
invert = style === 5 && ! is _dark ;
}
if ( style === 3 || style === 4 ) {
if ( color === 'transparent' && data . trans )
color = data . trans . color || color ;
2018-02-02 16:29:41 -05:00
}
2017-11-28 02:03:59 -05:00
2018-02-02 16:29:41 -05:00
if ( color === 'transparent' )
style = 0 ;
2017-11-28 02:03:59 -05:00
2018-02-02 16:29:41 -05:00
if ( style !== 3 && style !== 4 ) {
2017-11-28 02:03:59 -05:00
svg = base _image . endsWith ( '.svg' ) ;
2018-01-16 17:36:56 -05:00
if ( data . urls )
2019-12-10 20:46:33 -05:00
image = ` url(" ${ data . urls [ scale ] } ") ` ;
2018-01-16 17:36:56 -05:00
else
image = ` url(" ${ svg ? base _image : ` ${ base _image } ${ scale } ${ trans ? '_trans' : '' } .png ` } ") ` ;
2019-12-10 20:46:33 -05:00
if ( data . urls && scale === 1 ) {
2018-02-02 16:00:01 -05:00
image _set = ` ${ WEBKIT } image-set( ${ image } 1x ${ data . urls [ 2 ] ? ` , url(" ${ data . urls [ 2 ] } ") 2x ` : '' } ${ data . urls [ 4 ] ? ` , url(" ${ data . urls [ 4 ] } ") 4x ` : '' } ) `
2017-11-28 02:03:59 -05:00
2018-01-16 17:36:56 -05:00
} else if ( ! svg && scale < 4 ) {
2017-11-28 02:03:59 -05:00
if ( scale === 1 )
image _set = ` ${ WEBKIT } image-set( ${ image } 1x, url(" ${ base _image } 2 ${ trans ? '_trans' : '' } .png") 2x, url(" ${ base _image } 4 ${ trans ? '_trans' : '' } .png") 4x) ` ;
else if ( scale === 2 )
image _set = ` ${ WEBKIT } image-set( ${ image } 1x, url(" ${ base _image } 4 ${ trans ? '_trans' : '' } .png") 2x) ` ;
} else
2019-12-10 20:46:33 -05:00
image _set = image ;
2017-11-28 02:03:59 -05:00
}
2019-12-05 23:13:27 -05:00
if ( color _fixer && color && color !== 'transparent' )
color = color _fixer . process ( color ) || color ;
2018-01-16 17:36:56 -05:00
// TODO: Fix the click_url name once we actually support badge clicking.
2020-08-17 13:33:30 -04:00
return ` ${ clickable && ( data . click _url || data . click _action ) ? 'cursor:pointer;' : '' } ${ invert ? 'filter:invert(100%);' : '' } ${ CSS _TEMPLATES [ style ] ( {
2019-12-10 20:46:33 -05:00
scale : 1 ,
2017-11-28 02:03:59 -05:00
color ,
image ,
image _set ,
svg
} ) } ` ;
}
2017-11-13 01:23:39 -05:00
export default class Badges extends Module {
2017-11-28 02:03:59 -05:00
constructor ( ... args ) {
super ( ... args ) ;
this . inject ( 'i18n' ) ;
this . inject ( 'settings' ) ;
this . inject ( 'socket' ) ;
this . inject ( 'tooltips' ) ;
2018-04-12 02:29:43 -04:00
this . inject ( 'experiments' ) ;
2017-11-28 02:03:59 -05:00
this . style = new ManagedStyle ( 'badges' ) ;
2020-07-14 21:24:07 -04:00
// Special data structure for supporters to greatly reduce
// memory usage and speed things up for people who only have
// a supporter badge.
this . supporter _id = null ;
this . supporters = new Set ;
2017-11-28 02:03:59 -05:00
this . badges = { } ;
2018-02-22 18:23:44 -05:00
this . twitch _badges = { } ;
2019-12-10 20:46:33 -05:00
if ( IS _FIREFOX )
this . settings . add ( 'chat.badges.media-queries' , {
default : true ,
ui : {
path : 'Chat > Badges >> tabs ~> Appearance' ,
title : 'Use @media queries to support High-DPI Badge images in Mozilla Firefox.' ,
description : 'This is required to see high-DPI badges on Firefox because Firefox still has yet to support `image-set()` after more than five years. It may be less reliable.' ,
component : 'setting-check-box'
}
} ) ;
2019-12-05 23:13:27 -05:00
this . settings . add ( 'chat.badges.version' , {
default : 2 ,
ui : {
path : 'Chat > Badges >> tabs ~> Appearance' ,
title : 'Version' ,
component : 'setting-select-box' ,
data : [
{ value : 1 , title : '1 (Pre December 2019)' } ,
{ value : 2 , title : '2 (Current)' }
]
}
} ) ;
2020-08-17 13:33:30 -04:00
this . settings . add ( 'chat.badges.clickable' , {
default : true ,
ui : {
path : 'Chat > Badges >> Behavior' ,
title : 'Allow clicking badges.' ,
description : 'Certain badges, such as Prime Gaming, act as links when this is enabled.' ,
component : 'setting-check-box'
}
} ) ;
2019-12-05 23:13:27 -05:00
this . settings . add ( 'chat.badges.fix-colors' , {
default : true ,
ui : {
path : 'Chat > Badges >> tabs ~> Appearance' ,
title : 'Adjust badge colors for visibility.' ,
description : 'Ensures that badges are visible against the current background.\n\n**Note:** Only affects badges with custom rendering. Subscriber badges, bit badges, etc. are not affected.' ,
component : 'setting-check-box'
}
} ) ;
2018-02-22 18:23:44 -05:00
this . settings . add ( 'chat.badges.hidden' , {
2018-03-22 22:39:27 -04:00
default : { } ,
type : 'object_merge' ,
ui : {
2018-02-22 18:23:44 -05:00
path : 'Chat > Badges >> tabs ~> Visibility' ,
2018-07-05 20:27:17 -04:00
title : 'Visibility' ,
2018-02-22 18:23:44 -05:00
component : 'badge-visibility' ,
2019-04-28 17:28:16 -04:00
data : ( ) => this . getSettingsBadges ( true )
2018-02-22 18:23:44 -05:00
}
} ) ;
2017-11-28 02:03:59 -05:00
2018-03-15 03:31:30 -04:00
this . settings . add ( 'chat.badges.custom-mod' , {
default : true ,
ui : {
path : 'Chat > Badges >> tabs ~> Appearance' ,
title : 'Use custom moderator badges where available.' ,
component : 'setting-check-box'
}
} )
2017-11-28 02:03:59 -05:00
this . settings . add ( 'chat.badges.style' , {
2019-12-05 23:13:27 -05:00
default : 1 ,
2017-11-28 02:03:59 -05:00
ui : {
2018-02-22 18:23:44 -05:00
path : 'Chat > Badges >> tabs ~> Appearance' ,
2017-11-28 02:03:59 -05:00
title : 'Style' ,
component : 'setting-select-box' ,
data : [
2019-12-05 23:13:27 -05:00
{ value : 0 , title : 'Square' } ,
2017-11-28 02:03:59 -05:00
{ value : 1 , title : 'Rounded' } ,
{ value : 2 , title : 'Circular' } ,
{ value : 3 , title : 'Circular (Color Only)' } ,
{ value : 4 , title : 'Circular (Color Only, Small)' } ,
{ value : 5 , title : 'Transparent' } ,
{ value : 6 , title : 'Transparent (Colored)' }
]
}
} ) ;
2020-08-17 13:33:30 -04:00
this . handleClick = this . handleClick . bind ( this ) ;
2017-11-28 02:03:59 -05:00
}
2019-04-28 17:28:16 -04:00
getSettingsBadges ( include _addons ) {
const twitch = [ ] ,
2020-01-24 19:02:06 -05:00
owl = [ ] ,
tcon = [ ] ,
2019-04-28 17:28:16 -04:00
game = [ ] ,
ffz = [ ] ,
addon = [ ] ;
for ( const key in this . twitch _badges )
if ( has ( this . twitch _badges , key ) ) {
const badge = this . twitch _badges [ key ] ,
vs = [ ] ;
let v = badge && ( badge [ 1 ] || badge [ 0 ] ) ;
for ( const key in badge )
2020-01-24 19:02:06 -05:00
if ( key !== '__cat' && has ( badge , key ) ) {
2019-04-28 17:28:16 -04:00
const version = badge [ key ] ;
if ( ! v )
v = version ;
if ( version && version . image1x )
vs . push ( {
version : key ,
name : version . title ,
image : version . image1x ,
styleImage : ` url(" ${ version . image1x } ") `
} ) ;
}
2020-01-24 19:02:06 -05:00
if ( v ) {
let cat ;
if ( badge . _ _cat === 'm-owl' )
cat = owl ;
else if ( badge . _ _cat === 'm-tcon' )
cat = tcon ;
else if ( badge . _ _cat === 'm-game' )
cat = game ;
else
cat = twitch ;
cat . push ( {
2019-04-28 17:28:16 -04:00
id : key ,
provider : 'twitch' ,
name : v . title ,
color : 'transparent' ,
image : v . image2x ,
versions : vs ,
styleImage : ` url(" ${ v . image2x } ") `
} ) ;
2020-01-24 19:02:06 -05:00
}
2019-04-28 17:28:16 -04:00
}
if ( include _addons )
for ( const key in this . badges )
if ( has ( this . badges , key ) ) {
const badge = this . badges [ key ] ,
image = badge . urls ? ( badge . urls [ 2 ] || badge . urls [ 1 ] ) : badge . image ;
2019-12-18 13:25:14 -05:00
( badge . addon ? addon : ffz ) . push ( {
2019-04-28 17:28:16 -04:00
id : key ,
provider : 'ffz' ,
name : badge . title ,
color : badge . color || 'transparent' ,
image ,
styleImage : ` url(" ${ image } ") `
} ) ;
}
return [
2019-12-18 13:25:14 -05:00
{ title : 'Twitch' , id : 'm-twitch' , badges : twitch } ,
2020-01-24 19:02:06 -05:00
{ title : 'Twitch: TwitchCon' , id : 'm-tcon' , badges : tcon } ,
{ title : 'Twitch: Overwatch League' , id : 'm-owl' , badges : owl } ,
2019-12-18 13:25:14 -05:00
{ title : 'Twitch: Game' , id : 'm-game' , key : 'game' , badges : game } ,
{ title : 'FrankerFaceZ' , id : 'm-ffz' , badges : ffz } ,
{ title : 'Add-on' , id : 'm-addon' , badges : addon }
2019-04-28 17:28:16 -04:00
] ;
}
2017-11-28 02:03:59 -05:00
onEnable ( ) {
2018-03-15 03:31:30 -04:00
this . parent . context . on ( 'changed:chat.badges.custom-mod' , this . rebuildAllCSS , this ) ;
2017-11-28 02:03:59 -05:00
this . parent . context . on ( 'changed:chat.badges.style' , this . rebuildAllCSS , this ) ;
this . parent . context . on ( 'changed:theme.is-dark' , this . rebuildAllCSS , this ) ;
this . parent . context . on ( 'changed:theme.tooltips-dark' , this . rebuildAllCSS , this ) ;
2019-12-05 23:13:27 -05:00
this . parent . context . on ( 'changed:chat.badges.version' , this . rebuildAllCSS , this ) ;
2019-12-10 20:46:33 -05:00
this . parent . context . on ( 'changed:chat.badges.media-queries' , this . rebuildAllCSS , this ) ;
2019-12-05 23:13:27 -05:00
this . parent . context . on ( 'changed:chat.badges.fix-colors' , this . rebuildColoredBadges , this ) ;
2020-08-17 13:33:30 -04:00
this . parent . context . on ( 'changed:chat.badges.clickable' , this . rebuildAllCSS , this ) ;
2017-11-28 02:03:59 -05:00
this . rebuildAllCSS ( ) ;
this . loadGlobalBadges ( ) ;
this . tooltips . types . badge = ( target , tip ) => {
2018-02-02 18:51:38 -05:00
tip . add _class = 'ffz__tooltip--badges' ;
2020-08-14 17:17:24 -04:00
const show _previews = this . parent . context . get ( 'tooltip.badge-images' ) ;
let container = target . parentElement . parentElement ;
if ( ! container . dataset . roomId )
container = target . closest ( '[data-room-id]' ) ;
2020-08-29 13:06:17 -04:00
const room _id = container ? . dataset ? . roomId ,
room _login = container ? . dataset ? . room ,
2018-02-02 16:00:01 -05:00
data = JSON . parse ( target . dataset . badgeData ) ,
out = [ ] ;
2018-12-03 18:08:32 -05:00
if ( data == null )
return out ;
2018-02-02 16:00:01 -05:00
for ( const d of data ) {
const p = d . provider ;
if ( p === 'twitch' ) {
2018-07-20 18:42:17 -04:00
const bd = this . getTwitchBadge ( d . badge , d . version , room _id , room _login ) ,
2019-05-08 22:47:38 -04:00
global _badge = this . getTwitchBadge ( d . badge , d . version , null , null , true ) || { } ;
2018-02-02 16:00:01 -05:00
if ( ! bd )
continue ;
2019-04-28 17:28:16 -04:00
let title = bd . title || global _badge . title ;
2020-06-30 19:48:46 -04:00
const tier = bd . tier || global _badge . tier ;
2019-04-28 17:28:16 -04:00
if ( d . data ) {
if ( d . badge === 'subscriber' ) {
2020-06-30 19:48:46 -04:00
if ( tier > 0 )
title = this . i18n . t ( 'badges.subscriber.tier-months' , '{title}\n(Tier {tier}, {months,number} Month{months,en_plural})' , {
title ,
tier ,
months : d . data
} ) ;
else
title = this . i18n . t ( 'badges.subscriber.months' , '{title}\n({count,number} Month{count,en_plural})' , {
title ,
count : d . data
} ) ;
2019-10-28 01:06:02 -04:00
} else if ( d . badge === 'founder' ) {
title = this . i18n . t ( 'badges.founder.months' , '{title}\n(Subscribed for {count,number} Month{count,en_plural})' , {
title ,
count : d . data
} ) ;
2019-04-28 17:28:16 -04:00
}
}
2018-04-01 18:24:08 -04:00
out . push ( < div class = "ffz-badge-tip" >
{ show _previews && < img class = "preview-image ffz-badge" src = { bd . image4x } / > }
2019-04-28 17:28:16 -04:00
{ title }
2018-04-01 18:24:08 -04:00
< / div > ) ;
/ * o u t . p u s h ( e ( ' d i v ' , { c l a s s N a m e : ' f f z - b a d g e - t i p ' } , [
2018-02-02 16:00:01 -05:00
show _previews && e ( 'img' , {
2017-11-28 02:03:59 -05:00
className : 'preview-image ffz-badge' ,
2018-02-02 16:00:01 -05:00
src : bd . image4x
} ) ,
bd . title
2018-04-01 18:24:08 -04:00
] ) ) ; * /
2018-02-02 16:00:01 -05:00
} else if ( p === 'ffz' ) {
2018-04-01 18:24:08 -04:00
out . push ( < div class = "ffz-badge-tip" >
{ show _previews && < div
class = "preview-image ffz-badge"
style = { {
backgroundColor : d . color ,
backgroundImage : ` url(" ${ d . image } ") `
} }
/ > }
{ d . title }
< / div > ) ;
/ * o u t . p u s h ( e ( ' d i v ' , { c l a s s N a m e : ' f f z - b a d g e - t i p ' } , [
2018-02-02 16:29:41 -05:00
show _previews && e ( 'div' , {
2018-02-02 16:00:01 -05:00
className : 'preview-image ffz-badge' ,
style : {
backgroundColor : d . color ,
backgroundImage : ` url(" ${ d . image } ") `
}
} ) ,
d . title
2018-04-01 18:24:08 -04:00
] ) ) ; * /
2018-02-02 16:00:01 -05:00
}
}
2017-11-28 02:03:59 -05:00
2018-02-02 16:00:01 -05:00
return out ;
}
2017-11-28 02:03:59 -05:00
}
2020-08-17 13:33:30 -04:00
handleClick ( event ) {
if ( ! this . parent . context . get ( 'chat.badges.clickable' ) )
return ;
const target = event . target ;
let container = target . parentElement . parentElement ;
if ( ! container . dataset . roomId )
container = target . closest ( '[data-room-id]' ) ;
2020-08-29 13:06:17 -04:00
const room _id = container ? . dataset ? . roomId ,
room _login = container ? . dataset ? . room ,
2020-08-17 13:33:30 -04:00
data = JSON . parse ( target . dataset . badgeData ) ;
if ( data == null )
return ;
let url = null ;
for ( const d of data ) {
const p = d . provider ;
if ( p === 'twitch' ) {
const bd = this . getTwitchBadge ( d . badge , d . version , room _id , room _login ) ,
global _badge = this . getTwitchBadge ( d . badge , d . version , null , null , true ) || { } ;
if ( ! bd )
continue ;
if ( bd . click _url )
url = bd . click _url ;
else if ( global _badge . click _url )
url = global _badge . click _url ;
else if ( ( bd . click _action === 'sub' || global _badge . click _action === 'sub' ) && room _login )
url = ` https://www.twitch.tv/subs/ ${ room _login } ` ;
else
continue ;
break ;
} else if ( p === 'ffz' ) {
const badge = this . badges [ target . dataset . badge ] ;
if ( badge ? . click _url ) {
url = badge . click _url ;
break ;
}
}
}
this . log . info ( 'badge-click' , event . target ) ;
if ( url ) {
const link = createElement ( 'a' , {
target : '_blank' ,
rel : 'noopener noreferrer' ,
href : url
} ) ;
link . click ( ) ;
}
event . preventDefault ( ) ;
}
2018-04-01 18:24:08 -04:00
render ( msg , createElement ) { // eslint-disable-line class-methods-use-this
2018-03-22 22:39:27 -04:00
const hidden _badges = this . parent . context . get ( 'chat.badges.hidden' ) || { } ,
2018-02-02 16:00:01 -05:00
badge _style = this . parent . context . get ( 'chat.badges.style' ) ,
2018-03-15 03:31:30 -04:00
custom _mod = this . parent . context . get ( 'chat.badges.custom-mod' ) ,
is _mask = badge _style > 5 ,
2018-02-02 16:00:01 -05:00
is _colored = badge _style !== 5 ,
has _image = badge _style !== 3 && badge _style !== 4 ,
2019-12-18 13:25:14 -05:00
ffz _hidden = hidden _badges [ 'm-ffz' ] ,
addon _hidden = hidden _badges [ 'm-addon' ] ,
2020-01-24 19:02:06 -05:00
tb = this . twitch _badges ,
2018-01-16 17:36:56 -05:00
out = [ ] ,
slotted = { } ,
twitch _badges = msg . badges || { } ,
2019-04-28 17:28:16 -04:00
dynamic _data = msg . badgeDynamicData || { } ,
2017-11-28 02:03:59 -05:00
2018-01-16 17:36:56 -05:00
user = msg . user || { } ,
2018-07-19 22:16:00 -04:00
user _id = user . id ,
user _login = user . login ,
2017-11-28 02:03:59 -05:00
room _id = msg . roomID ,
room _login = msg . roomLogin ,
2018-03-15 03:31:30 -04:00
room = this . parent . getRoom ( room _id , room _login , true ) ,
2018-01-16 17:36:56 -05:00
badges = this . getBadges ( user _id , user _login , room _id , room _login ) ;
let last _slot = 50 , slot ;
2017-11-28 02:03:59 -05:00
for ( const badge _id in twitch _badges )
if ( has ( twitch _badges , badge _id ) ) {
2018-01-16 17:36:56 -05:00
const version = twitch _badges [ badge _id ] ,
2019-12-18 13:25:14 -05:00
is _hidden = hidden _badges [ badge _id ] ,
2020-01-24 19:02:06 -05:00
bdata = tb && tb [ badge _id ] ,
cat = bdata && bdata . _ _cat || 'm-twitch' ;
2018-01-16 17:36:56 -05:00
2020-01-24 19:02:06 -05:00
if ( is _hidden || ( is _hidden == null && hidden _badges [ cat ] ) )
2018-01-16 17:36:56 -05:00
continue ;
if ( has ( BADGE _POSITIONS , badge _id ) )
slot = BADGE _POSITIONS [ badge _id ] ;
else
slot = last _slot ++ ;
2019-10-28 01:06:02 -04:00
const data = dynamic _data [ badge _id ] || ( badge _id === 'founder' && dynamic _data [ 'subscriber' ] ) ,
2019-04-28 17:28:16 -04:00
urls = badge _id === 'moderator' && custom _mod && room && room . data && room . data . mod _urls ,
2018-03-15 03:31:30 -04:00
badges = [ ] ;
if ( urls ) {
const bd = this . getTwitchBadge ( badge _id , version , room _id , room _login ) ;
badges . push ( {
provider : 'ffz' ,
image : urls [ 4 ] || urls [ 2 ] || urls [ 1 ] ,
color : '#34ae0a' ,
2019-04-28 17:28:16 -04:00
title : bd ? bd . title : 'Moderator' ,
data
2018-03-15 03:31:30 -04:00
} ) ;
} else
badges . push ( {
provider : 'twitch' ,
badge : badge _id ,
2019-04-28 17:28:16 -04:00
version ,
data
2018-03-15 03:31:30 -04:00
} ) ;
2018-02-02 16:00:01 -05:00
2018-01-16 17:36:56 -05:00
slotted [ slot ] = {
id : badge _id ,
props : {
'data-provider' : 'twitch' ,
'data-badge' : badge _id ,
2018-02-08 18:28:30 -05:00
'data-version' : version ,
style : { }
2018-02-02 16:00:01 -05:00
} ,
badges
2018-01-16 17:36:56 -05:00
} ;
2017-11-28 02:03:59 -05:00
}
2018-01-16 17:36:56 -05:00
for ( const badge of badges )
2019-05-29 16:35:09 -04:00
if ( badge && badge . id != null ) {
2019-12-18 13:25:14 -05:00
const full _badge = this . badges [ badge . id ] || { } ,
is _hidden = hidden _badges [ badge . id ] ;
if ( is _hidden || ( is _hidden == null && ( full _badge . addon ? addon _hidden : ffz _hidden ) ) )
2018-01-16 17:36:56 -05:00
continue ;
2019-12-18 13:25:14 -05:00
const slot = has ( badge , 'slot' ) ? badge . slot : full _badge . slot ,
2018-02-02 16:00:01 -05:00
old _badge = slotted [ slot ] ,
urls = badge . urls || ( badge . image ? { 1 : badge . image } : null ) ,
2018-02-02 18:51:38 -05:00
color = badge . color || full _badge . color || 'transparent' ,
2018-09-24 18:49:03 +02:00
no _invert = badge . no _invert ,
2018-02-02 18:51:38 -05:00
masked = color !== 'transparent' && is _mask ,
2018-02-02 16:00:01 -05:00
bu = ( urls || full _badge . urls || { 1 : full _badge . image } ) ,
bd = {
provider : 'ffz' ,
image : bu [ 4 ] || bu [ 2 ] || bu [ 1 ] ,
color : badge . color || full _badge . color ,
title : badge . title || full _badge . title
} ;
2018-01-16 17:36:56 -05:00
2018-02-02 18:51:38 -05:00
let style ;
2018-01-16 17:36:56 -05:00
if ( old _badge ) {
2018-02-02 18:51:38 -05:00
old _badge . badges . push ( bd ) ;
2018-01-16 17:36:56 -05:00
const replaces = has ( badge , 'replaces' ) ? badge . replaces : full _badge . replaces ,
replaces _type = badge . replaces _type || full _badge . replaces _type ;
if ( replaces && ( ! replaces _type || replaces _type === old _badge . id ) )
old _badge . replaced = badge . id ;
2018-02-02 18:51:38 -05:00
else
continue ;
2018-01-16 17:36:56 -05:00
2018-02-02 18:51:38 -05:00
style = old _badge . props . style ;
2018-01-16 17:36:56 -05:00
2019-05-29 16:35:09 -04:00
} else if ( slot == null )
2018-01-16 17:36:56 -05:00
continue ;
2018-02-02 18:51:38 -05:00
else {
style = { } ;
const props = {
2017-11-28 02:03:59 -05:00
className : 'ffz-tooltip ffz-badge' ,
'data-tooltip-type' : 'badge' ,
'data-provider' : 'ffz' ,
'data-badge' : badge . id ,
style
} ;
2018-02-02 18:51:38 -05:00
slotted [ slot ] = { id : badge . id , props , badges : [ bd ] }
}
2018-09-24 18:49:03 +02:00
if ( no _invert ) {
2018-11-12 13:34:53 -05:00
slotted [ slot ] . full _size = true ;
2018-12-09 15:09:18 -05:00
slotted [ slot ] . no _invert = true ;
2018-11-12 13:34:53 -05:00
2018-09-24 18:49:03 +02:00
style . background = 'unset' ;
style . backgroundSize = 'unset' ;
style [ CSS _MASK _IMAGE ] = 'unset' ;
}
2018-11-12 13:34:53 -05:00
if ( ( has _image || color === 'transparent' ) && urls ) {
2018-04-02 03:30:22 -04:00
const image = ` url(" ${ urls [ 1 ] } ") ` ;
let image _set ;
2018-02-02 16:00:01 -05:00
if ( urls [ 2 ] || urls [ 4 ] )
image _set = ` ${ WEBKIT } image-set( ${ image } 1x ${ urls [ 2 ] ? ` , url(" ${ urls [ 2 ] } ") 2x ` : '' } ${ urls [ 4 ] ? ` , url(" ${ urls [ 4 ] } ") 4x ` : '' } ) ` ;
2018-09-24 18:49:03 +02:00
style [ masked && ! no _invert ? CSS _MASK _IMAGE : 'backgroundImage' ] = image ;
2018-02-02 16:00:01 -05:00
if ( image _set )
2018-09-24 18:49:03 +02:00
style [ masked && ! no _invert ? CSS _MASK _IMAGE : 'backgroundImage' ] = image _set ;
2018-02-02 16:00:01 -05:00
}
if ( is _colored && badge . color ) {
2018-09-24 18:49:03 +02:00
if ( masked && ! no _invert )
2018-02-02 16:00:01 -05:00
style . backgroundImage = ` linear-gradient( ${ badge . color } , ${ badge . color } ) ` ;
else
style . backgroundColor = badge . color ;
}
2018-01-16 17:36:56 -05:00
}
for ( const slot in slotted )
if ( has ( slotted , slot ) ) {
const data = slotted [ slot ] ,
props = data . props ;
2018-12-09 15:09:18 -05:00
props . className = ` ffz-tooltip ffz-badge ${ data . full _size ? ' ffz-full-size' : '' } ${ data . no _invert ? ' ffz-no-invert' : '' } ` ;
2018-07-20 18:42:17 -04:00
props . key = ` ${ props [ 'data-provider' ] } - ${ props [ 'data-badge' ] } ` ;
2018-01-16 17:36:56 -05:00
props [ 'data-tooltip-type' ] = 'badge' ;
2018-02-02 16:00:01 -05:00
props [ 'data-badge-data' ] = JSON . stringify ( data . badges ) ;
2017-11-28 02:03:59 -05:00
2020-08-17 13:33:30 -04:00
props . onClick = this . handleClick ;
2018-01-16 17:36:56 -05:00
if ( data . replaced )
props [ 'data-replaced' ] = data . replaced ;
2017-11-28 02:03:59 -05:00
2018-04-01 18:24:08 -04:00
out . push ( createElement ( 'span' , props ) ) ;
2018-01-16 17:36:56 -05:00
}
2017-11-28 02:03:59 -05:00
return out ;
}
2019-12-05 23:13:27 -05:00
rebuildColor ( ) {
if ( this . parent . context . get ( 'chat.badges.fix-colors' ) ) {
this . color _fixer = new ColorAdjuster (
this . parent . context . get ( 'theme.is-dark' ) ? '#181818' : '#FFFFFF' ,
1 ,
2.5
) ;
} else
this . color _fixer = null ;
}
rebuildColoredBadges ( ) {
this . rebuildColor ( ) ;
this . buildBadgeCSS ( ) ;
this . buildTwitchCSSBadgeCSS ( ) ;
}
2017-11-28 02:03:59 -05:00
rebuildAllCSS ( ) {
2019-12-05 23:13:27 -05:00
this . rebuildColor ( ) ;
2018-03-15 03:31:30 -04:00
for ( const room of this . parent . iterateRooms ( ) ) {
2017-11-28 02:03:59 -05:00
room . buildBadgeCSS ( ) ;
2018-03-15 03:31:30 -04:00
room . buildModBadgeCSS ( ) ;
}
2017-11-28 02:03:59 -05:00
2018-01-16 17:36:56 -05:00
this . buildBadgeCSS ( ) ;
2017-11-28 02:03:59 -05:00
this . buildTwitchBadgeCSS ( ) ;
this . buildTwitchCSSBadgeCSS ( ) ;
}
// ========================================================================
// Extension Badges
// ========================================================================
getBadges ( user _id , user _login , room _id , room _login ) {
const room = this . parent . getRoom ( room _id , room _login , true ) ,
global _user = this . parent . getUser ( user _id , user _login , true ) ,
room _user = room && room . getUser ( user _id , user _login , true ) ;
2020-07-14 21:24:07 -04:00
const out = ( global _user ? global _user . badges . _cache : [ ] ) . concat (
2017-11-28 02:03:59 -05:00
room _user ? room _user . badges . _cache : [ ] ) ;
2020-07-14 21:24:07 -04:00
if ( this . supporter _id && this . supporters . has ( ` ${ user _id } ` ) )
out . push ( { id : this . supporter _id } ) ;
return out ;
2017-11-28 02:03:59 -05:00
}
async loadGlobalBadges ( tries = 0 ) {
let response , data ;
2018-04-12 02:29:43 -04:00
2020-03-05 18:21:11 -05:00
if ( this . experiments . getAssignment ( 'api_load' ) && tries < 1 )
2018-04-12 02:29:43 -04:00
try {
2020-11-12 17:02:04 -05:00
fetch ( ` ${ NEW _API } /v1/badges/ids ` ) . catch ( ( ) => { } ) ;
2018-04-12 02:29:43 -04:00
} catch ( err ) { /* do nothing */ }
2017-11-28 02:03:59 -05:00
try {
2020-07-14 21:24:07 -04:00
response = await fetch ( ` ${ API _SERVER } /v1/badges/ids ` ) ;
2017-11-28 02:03:59 -05:00
} catch ( err ) {
tries ++ ;
if ( tries < 10 )
return setTimeout ( ( ) => this . loadGlobalBadges ( tries ) , 500 * tries ) ;
this . log . error ( 'Error loading global badge data.' , err ) ;
return false ;
}
if ( ! response . ok )
return false ;
try {
data = await response . json ( ) ;
} catch ( err ) {
this . log . error ( 'Error parsing global badge data.' , err ) ;
return false ;
}
let badges = 0 , users = 0 ;
if ( data . badges )
for ( const badge of data . badges )
if ( badge && badge . id ) {
2018-02-02 16:00:01 -05:00
this . loadBadgeData ( badge . id , badge , false ) ;
2017-11-28 02:03:59 -05:00
badges ++ ;
}
if ( data . users )
for ( const badge _id in data . users )
if ( has ( data . users , badge _id ) ) {
const badge = this . badges [ badge _id ] ;
let c = 0 ;
2020-07-14 21:24:07 -04:00
if ( badge ? . name === 'supporter' ) {
this . supporter _id = badge _id ;
for ( const user _id of data . users [ badge _id ] )
this . supporters . add ( ` ${ user _id } ` ) ;
c = this . supporters . size ;
} else
for ( const user _id of data . users [ badge _id ] ) {
const user = this . parent . getUser ( user _id , undefined ) ;
if ( user . addBadge ( 'ffz-global' , badge _id ) ) {
c ++ ;
users ++ ;
}
2017-11-28 02:03:59 -05:00
}
if ( c > 0 )
this . log . info ( ` Added " ${ badge ? badge . name : ` # ${ badge _id } ` } " to ${ c } users. ` ) ;
}
this . log . info ( ` Loaded ${ badges } badges and assigned them to ${ users } users. ` ) ;
2018-01-16 17:36:56 -05:00
this . buildBadgeCSS ( ) ;
2017-11-28 02:03:59 -05:00
}
2018-02-02 16:00:01 -05:00
loadBadgeData ( badge _id , data , generate _css = true ) {
2017-11-28 02:03:59 -05:00
this . badges [ badge _id ] = data ;
2019-12-18 13:25:14 -05:00
if ( data . addon === undefined )
data . addon = /^addon/ . test ( badge _id ) ;
2017-11-28 02:03:59 -05:00
if ( data . replaces && ! data . replaces _type ) {
data . replaces _type = data . replaces ;
data . replaces = true ;
}
if ( data . name === 'developer' || data . name === 'supporter' )
data . click _url = 'https://www.frankerfacez.com/donate' ;
2018-02-02 16:00:01 -05:00
if ( generate _css )
this . buildBadgeCSS ( ) ;
2017-11-28 02:03:59 -05:00
}
2018-01-16 17:36:56 -05:00
buildBadgeCSS ( ) {
const style = this . parent . context . get ( 'chat.badges.style' ) ,
2019-12-10 20:46:33 -05:00
is _dark = this . parent . context . get ( 'theme.is-dark' ) ,
2020-08-17 13:33:30 -04:00
can _click = this . parent . context . get ( 'chat.badges.clickable' ) ,
2019-12-10 20:46:33 -05:00
use _media = IS _FIREFOX && this . parent . context . get ( 'chat.badges.media-queries' ) ;
2018-01-16 17:36:56 -05:00
const out = [ ] ;
for ( const key in this . badges )
if ( has ( this . badges , key ) ) {
const data = this . badges [ key ] ,
selector = ` .ffz-badge[data-badge=" ${ key } "] ` ;
out . push ( ` .ffz-badge[data-replaced=" ${ key } "]{ ${ generateOverrideCSS ( data , style , is _dark ) } } ` ) ;
2019-12-10 20:46:33 -05:00
if ( use _media ) {
2020-08-17 13:33:30 -04:00
out . push ( ` @media (max-resolution: 99dpi) { ${ selector } { ${ generateBadgeCSS ( key , 0 , data , style , is _dark , 0 , this . color _fixer , 1 , can _click ) } }} ` ) ;
out . push ( ` @media (min-resolution: 100dpi) and (max-resolution:199dpi) { ${ selector } { ${ generateBadgeCSS ( key , 0 , data , style , is _dark , 0 , this . color _fixer , 2 , can _click ) } }} ` ) ;
out . push ( ` @media (min-resolution: 200dpi) { ${ selector } { ${ generateBadgeCSS ( key , 0 , data , style , is _dark , 0 , this . color _fixer , 4 , can _click ) } }} ` ) ;
2019-12-10 20:46:33 -05:00
} else
2020-08-17 13:33:30 -04:00
out . push ( ` ${ selector } { ${ generateBadgeCSS ( key , 0 , data , style , is _dark , 0 , this . color _fixer , undefined , can _click ) } } ` ) ;
2018-01-16 17:36:56 -05:00
}
this . style . set ( 'ext-badges' , out . join ( '\n' ) ) ;
}
2017-11-28 02:03:59 -05:00
// ========================================================================
// Twitch Badges
// ========================================================================
2019-05-08 22:47:38 -04:00
getTwitchBadge ( badge , version , room _id , room _login , retried = false ) {
2017-11-28 02:03:59 -05:00
const room = this . parent . getRoom ( room _id , room _login , true ) ;
let b ;
if ( room ) {
2018-01-19 17:17:16 -05:00
const versions = room . badges && room . badges [ badge ] ;
b = versions && versions [ version ] ;
2017-11-28 02:03:59 -05:00
}
if ( ! b ) {
2018-01-19 17:17:16 -05:00
const versions = this . twitch _badges && this . twitch _badges [ badge ] ;
b = versions && versions [ version ] ;
2017-11-28 02:03:59 -05:00
}
2019-05-08 22:47:38 -04:00
if ( ! b && ! retried ) {
const chat = this . resolve ( 'site.chat' ) ;
if ( chat && chat . tryUpdateBadges )
chat . tryUpdateBadges ( ) ;
}
2017-11-28 02:03:59 -05:00
return b ;
}
2019-05-08 22:47:38 -04:00
getTwitchBadgeCount ( ) {
return this . twitch _badge _count || 0 ;
2019-05-03 19:30:46 -04:00
}
2017-11-28 02:03:59 -05:00
updateTwitchBadges ( badges ) {
2019-05-08 22:47:38 -04:00
this . twitch _badge _count = 0 ;
2019-05-03 19:30:46 -04:00
if ( ! Array . isArray ( badges ) )
2018-01-19 17:17:16 -05:00
this . twitch _badges = badges ;
else {
2019-05-03 19:30:46 -04:00
let b = null ;
if ( badges . length ) {
b = { } ;
for ( const data of badges ) {
const sid = data . setID ,
2020-01-24 19:02:06 -05:00
bs = b [ sid ] = b [ sid ] || {
_ _cat : getBadgeCategory ( sid )
} ;
2019-05-03 19:30:46 -04:00
2020-08-17 13:33:30 -04:00
fixBadgeData ( data ) ;
2019-05-08 22:47:38 -04:00
this . twitch _badge _count ++ ;
2019-05-03 19:30:46 -04:00
bs [ data . version ] = data ;
}
2018-01-19 17:17:16 -05:00
}
this . twitch _badges = b ;
}
2017-11-28 02:03:59 -05:00
this . buildTwitchBadgeCSS ( ) ;
2020-08-17 13:33:30 -04:00
this . buildTwitchCSSBadgeCSS ( ) ;
2017-11-28 02:03:59 -05:00
}
buildTwitchCSSBadgeCSS ( ) {
const style = this . parent . context . get ( 'chat.badges.style' ) ,
2019-12-05 23:13:27 -05:00
is _dark = this . parent . context . get ( 'theme.is-dark' ) ,
2020-08-17 13:33:30 -04:00
can _click = this . parent . context . get ( 'chat.badges.clickable' ) ,
2019-12-10 20:46:33 -05:00
use _media = IS _FIREFOX && this . parent . context . get ( 'chat.badges.media-queries' ) ,
2019-12-05 23:13:27 -05:00
badge _version = this . parent . context . get ( 'chat.badges.version' ) ,
2020-08-17 13:33:30 -04:00
versioned = CSS _BADGES [ badge _version ] || { } ,
twitch _data = this . twitch _badges || { } ;
2017-11-28 02:03:59 -05:00
const out = [ ] ;
2019-12-05 23:13:27 -05:00
for ( const key in versioned )
if ( has ( versioned , key ) ) {
2020-08-17 13:33:30 -04:00
const data = versioned [ key ] ,
twitch = twitch _data [ key ] ;
2017-11-28 02:03:59 -05:00
for ( const version in data )
if ( has ( data , version ) ) {
const d = data [ version ] ,
2020-08-17 13:33:30 -04:00
td = twitch ? . [ version ] ,
2017-11-28 02:03:59 -05:00
selector = ` .ffz-badge[data-badge=" ${ key } "][data-version=" ${ version } "] ` ;
2020-08-17 13:33:30 -04:00
if ( td && td . click _url )
d . click _url = td . click _url ;
if ( td && td . click _action )
d . click _action = td . click _action ;
2019-12-10 20:46:33 -05:00
if ( use _media ) {
2020-08-17 13:33:30 -04:00
out . push ( ` @media (max-resolution: 99dpi) { ${ selector } { ${ generateBadgeCSS ( key , version , d , style , is _dark , badge _version , this . color _fixer , 1 , can _click ) } }} ` ) ;
out . push ( ` @media (min-resolution: 100dpi) and (max-resolution:199dpi) { ${ selector } { ${ generateBadgeCSS ( key , version , d , style , is _dark , badge _version , this . color _fixer , 2 , can _click ) } }} ` ) ;
out . push ( ` @media (min-resolution: 200dpi) { ${ selector } { ${ generateBadgeCSS ( key , version , d , style , is _dark , badge _version , this . color _fixer , 4 , can _click ) } }} ` ) ;
2019-12-10 20:46:33 -05:00
} else
2020-08-17 13:33:30 -04:00
out . push ( ` ${ selector } { ${ generateBadgeCSS ( key , version , d , style , is _dark , badge _version , this . color _fixer , undefined , can _click ) } } ` ) ;
2017-11-28 02:03:59 -05:00
}
}
this . style . set ( 'css-badges' , out . join ( '\n' ) ) ;
}
buildTwitchBadgeCSS ( ) {
if ( ! this . twitch _badges )
this . style . delete ( 'twitch-badges' ) ;
2019-12-05 23:13:27 -05:00
const badge _version = this . parent . context . get ( 'chat.badges.version' ) ,
2019-12-10 20:46:33 -05:00
use _media = IS _FIREFOX && this . parent . context . get ( 'chat.badges.media-queries' ) ,
2020-08-17 13:33:30 -04:00
can _click = this . parent . context . get ( 'chat.badges.clickable' ) ,
2019-12-05 23:13:27 -05:00
versioned = CSS _BADGES [ badge _version ] || { } ;
2017-11-28 02:03:59 -05:00
const out = [ ] ;
2018-01-19 17:17:16 -05:00
for ( const key in this . twitch _badges )
if ( has ( this . twitch _badges , key ) ) {
2019-12-05 23:13:27 -05:00
if ( has ( versioned , key ) )
2018-01-19 17:17:16 -05:00
continue ;
const versions = this . twitch _badges [ key ] ;
for ( const version in versions )
if ( has ( versions , version ) ) {
2019-12-10 20:46:33 -05:00
const data = versions [ version ] ,
selector = ` .ffz-badge[data-badge=" ${ key } "][data-version=" ${ version } "] ` ;
2018-01-19 17:17:16 -05:00
2019-12-10 20:46:33 -05:00
out . push ( ` ${ selector } {
2020-08-17 13:33:30 -04:00
$ { can _click && ( data . click _action || data . click _url ) ? 'cursor:pointer;' : '' }
2018-01-19 17:17:16 -05:00
background - color : transparent ;
filter : none ;
$ { WEBKIT } mask - image : none ;
background - size : 1.8 rem ;
background - image : url ( "${data.image1x}" ) ;
background - image : $ { WEBKIT } image - set (
url ( "${data.image1x}" ) 1 x ,
url ( "${data.image2x}" ) 2 x ,
url ( "${data.image4x}" ) 4 x
) ;
2019-12-10 20:46:33 -05:00
} ` );
if ( use _media ) {
out . push ( ` @media (min-resolution: 100dpi) and (max-resolution:199dpi) { ${ selector } {
2019-12-10 22:07:48 -05:00
background - image : url ( "${data.image2x}" ) ;
2019-12-10 20:46:33 -05:00
} } ` );
out . push ( ` @media (min-resolution: 200dpi) { ${ selector } {
2019-12-10 22:07:48 -05:00
background - image : url ( "${data.image4x}" ) ;
2019-12-10 20:46:33 -05:00
} } ` );
}
2018-01-19 17:17:16 -05:00
}
2017-11-28 02:03:59 -05:00
}
2017-11-13 01:23:39 -05:00
2017-11-28 02:03:59 -05:00
if ( out . length )
this . style . set ( 'twitch-badges' , out . join ( '\n' ) ) ;
else
this . style . delete ( 'twitch-badges' ) ;
}
2020-01-24 19:02:06 -05:00
}
2020-08-17 13:33:30 -04:00
export function getBadgeCategory ( key ) {
2020-01-24 19:02:06 -05:00
if ( key . startsWith ( 'overwatch-league' ) )
return 'm-owl' ;
else if ( key . startsWith ( 'twitchcon' ) )
return 'm-tcon' ;
else if ( /_\d+$/ . test ( key ) )
return 'm-game' ;
return 'm-twitch' ;
2020-08-17 13:33:30 -04:00
}
export function fixBadgeData ( badge ) {
if ( ! badge )
return badge ;
// Click Behavior
if ( badge . clickAction === 'VISIT_URL' && badge . clickURL )
badge . click _url = badge . clickURL ;
if ( badge . clickAction === 'TURBO' )
badge . click _url = 'https://www.twitch.tv/products/turbo?ref=chat_badge' ;
if ( badge . clickAction === 'SUBSCRIBE' && badge . channelName )
badge . click _url = ` https://www.twitch.tv/subs/ ${ badge . channelName } ` ;
else if ( badge . clickAction )
badge . click _action = 'sub' ;
// Subscriber Tier
if ( badge . setID === 'subscriber' ) {
const id = parseInt ( badge . version , 10 ) ;
if ( ! isNaN ( id ) && isFinite ( id ) ) {
badge . tier = ( id - ( id % 1000 ) ) / 1000 ;
if ( badge . tier < 0 )
badge . tier = 0 ;
} else
badge . tier = 0 ;
}
return badge ;
2017-11-13 01:23:39 -05:00
}