1
0
Fork 0
mirror of https://github.com/FrankerFaceZ/FrankerFaceZ.git synced 2025-08-08 07:10:54 +00:00
* Changed: Show the verified badge on rich chat embeds for Twitch partner channels.
* API Added: More flexible support for tokens when building chat embeds.
* API Added: Experiment for using the API to look-up links, rather than the socket cluster.
This commit is contained in:
SirStendec 2020-07-26 21:26:42 -04:00
parent a4fa1d1491
commit 05e8428a4a
7 changed files with 96 additions and 12 deletions

View file

@ -1,7 +1,7 @@
{
"name": "frankerfacez",
"author": "Dan Salvato LLC",
"version": "4.20.19",
"version": "4.20.20",
"description": "FrankerFaceZ is a Twitch enhancement suite.",
"license": "Apache-2.0",
"scripts": {

View file

@ -7,12 +7,20 @@
{"value": false, "weight": 100}
]
},
"all_points": {
"name": "Override Channel Points Rendering",
"description": "Override rendering for all channel points messages, even when no message is present.",
"api_links": {
"name": "API-Based Link Lookups",
"description": "Use the new API to look up links instead of the socket cluster.",
"groups": [
{"value": true, "weight": 50},
{"value": false, "weight": 50}
]
},
"all_points": {
"name": "Override Channel Points Rendering",
"description": "Override rendering for all channel points messages, even when no message is present.",
"groups": [
{"value": true, "weight": 100},
{"value": false, "weight": 0}
]
}
}

View file

@ -1,6 +1,7 @@
<script>
import {has, timeout} from 'utilities/object';
import {ALLOWED_ATTRIBUTES, ALLOWED_TAGS} from 'utilities/constants';
const ERROR_IMAGE = 'https://static-cdn.jtvnw.net/emoticons/v1/58765/2.0';
@ -95,9 +96,34 @@ export default {
else if ( typeof token !== 'object' )
out.push(token);
else {
const el = h(token.tag || 'span', {
else if ( token.type === 't') {
const content = {};
if ( token.content )
for(const [key,val] of Object.entries(token.content))
content[key] = this.renderTokens(val, h);
out = out.concat(this.tList(token.key, token.phrase, content));
} else {
const tag = token.tag || 'span';
if ( ! ALLOWED_TAGS.includes(tag) ) {
console.log('Skipping disallowed tag', tag);
continue;
}
const attrs = {};
if ( token.attrs ) {
for(const [key,val] of Object.entries(token.attrs)) {
if ( ! ALLOWED_ATTRIBUTES.includes(key) && ! key.startsWith('data-') )
console.log('Skipping disallowed attribute', key);
else
attrs[key] = val;
}
}
const el = h(tag, {
class: token.class,
attrs
}, this.renderTokens(token.content, h));
out.push(el);

View file

@ -1536,7 +1536,12 @@ export default class Chat extends Module {
cbs[success ? 0 : 1](data);
}
if ( this.experiments.getAssignment('api_links') )
timeout(fetch(`https://api-test.frankerfacez.com/v2/link?url=${encodeURIComponent(url)}`).then(r => r.json()), 15000)
.then(data => handle(true, data))
.catch(err => handle(false, err));
else
timeout(this.socket.call('get_link', url), 15000)
.then(data => handle(true, data))
.catch(err => handle(false, err));

View file

@ -143,6 +143,16 @@ export const Users = {
];
}
if ( user.roles?.isPartner ) {
if ( ! title_tokens )
title_tokens = [title];
title_tokens = {tag: 'div', class: 'tw-flex tw-align-items-center', content: [
{tag: 'div', content: title_tokens},
{tag: 'figure', class: 'tw-mg-l-05 ffz-i-verified tw-c-text-link', content: []}
]};
}
return {
url: token.url,
accent: user.primaryColorHex ? `#${user.primaryColorHex}` : null,

View file

@ -6,6 +6,7 @@
import Module from 'utilities/module';
import {timeout, has} from 'utilities/object';
import {ALLOWED_ATTRIBUTES, ALLOWED_TAGS} from 'utilities/constants';
const ERROR_IMAGE = 'https://static-cdn.jtvnw.net/emoticons/v1/58765/2.0';
@ -104,9 +105,34 @@ export default class RichContent extends Module {
else if ( typeof token !== 'object' )
out.push(token);
else {
const el = createElement(token.tag || 'span', {
className: token.class
else if ( token.type === 't' ) {
const content = {};
if ( token.content )
for(const [key,val] of Object.entries(token.content))
content[key] = this.renderTokens(val);
out = out.concat(t.i18n.tList(token.key, token.phrase, content));
} else {
const tag = token.tag || 'span';
if ( ! ALLOWED_TAGS.includes(tag) ) {
console.log('Skipping disallowed tag', tag);
continue;
}
const attrs = {};
if ( token.attrs ) {
for(const [key,val] of Object.entries(token.attrs)) {
if ( ! ALLOWED_ATTRIBUTES.includes(key) && ! key.startsWith('data-') )
console.log('Skipping disallowed attribute', key);
else
attrs[key] = val;
}
}
const el = createElement(tag, {
className: token.class,
...attrs
}, this.renderTokens(token.content));
out.push(el);

View file

@ -18,6 +18,15 @@ export const LV_SERVER = 'https://cbenni.com/api';
export const LV_SOCKET_SERVER = 'wss://cbenni.com/socket.io/';
export const ALLOWED_TAGS = [
'strong', 'em', 'i', 'b', 'time', 'br', 'hr', 'div', 'span', 'img', 'figure', 'p', 'a', 'video', 'audio', 'blockquote', 'heading', 'section', 'nav', 'footer', 'aside', 'article', 'source', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6'
];
export const ALLOWED_ATTRIBUTES = [
'datetime', 'src', 'href', 'style', 'alt', 'title', 'height', 'width', 'srcset', 'autoplay', 'volume', 'muted', 'loop', 'poster', 'type'
];
export const KEYS = {
Enter: 13,
Escape: 27,