1
0
Fork 0
mirror of https://github.com/FrankerFaceZ/FrankerFaceZ.git synced 2025-06-28 05:15:54 +00:00
* Added: Option to only adjust the player volume by scrolling when holding the right-mouse button. (Closes #954)
* API Added: Support for rendering badges with non-image content.
This commit is contained in:
SirStendec 2021-02-17 02:08:21 -05:00
parent ccef06ef7b
commit 165e17c014
5 changed files with 139 additions and 41 deletions

View file

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

View file

@ -581,8 +581,14 @@ export class TranslationManager extends Module {
return; return;
} }
if ( typeof ast === 'object' && ast.v ) if ( typeof ast === 'object' && ast.v ) {
out[ast.v] = shallow_copy(get(ast.v, options)); const val = get(ast.v, options);
// Skip React objects.
if ( val && val['$$typeof'] )
return;
out[ast.v] = shallow_copy(val);
}
} }

View file

@ -7,7 +7,7 @@
import {NEW_API, SERVER, API_SERVER, IS_WEBKIT, IS_FIREFOX, WEBKIT_CSS as WEBKIT} from 'utilities/constants'; import {NEW_API, SERVER, API_SERVER, IS_WEBKIT, IS_FIREFOX, WEBKIT_CSS as WEBKIT} from 'utilities/constants';
import {createElement, ManagedStyle} from 'utilities/dom'; import {createElement, ManagedStyle} from 'utilities/dom';
import {has} from 'utilities/object'; import {has, maybe_call} from 'utilities/object';
import Module from 'utilities/module'; import Module from 'utilities/module';
import { ColorAdjuster } from 'src/utilities/color'; import { ColorAdjuster } from 'src/utilities/color';
@ -66,10 +66,10 @@ const NO_REPEAT = 'background-repeat:no-repeat;background-position:center;',
CSS_MASK_IMAGE = IS_WEBKIT ? 'webkitMaskImage' : 'maskImage', CSS_MASK_IMAGE = IS_WEBKIT ? 'webkitMaskImage' : 'maskImage',
CSS_TEMPLATES = { CSS_TEMPLATES = {
0: data => `background:${data.image} ${data.color};background-size:${data.scale*1.8}rem;${data.svg ? '' : `background-image:${data.image_set};`}${NO_REPEAT}`, 0: data => `${data.fore ? `color:${data.fore};` : ''}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;`, 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;`, 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;`, 3: data => `${data.fore ? `color:${data.fore};` : ''}background:${data.color};border-radius:${data.scale*.9}rem;`,
4: data => `${CSS_TEMPLATES[3](data)}height:${data.scale}rem;min-width:${data.scale}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}`, 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};`}` 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};`}`
@ -91,14 +91,15 @@ export function generateOverrideCSS(data, style) {
} }
export function generateBadgeCSS(badge, version, data, style, is_dark, badge_version = 2, color_fixer, scale = 1, clickable = false) { export function generateBadgeCSS(badge, version, data, style, is_dark, badge_version = 2, color_fixer, fg_fixer, scale = 1, clickable = false) {
let color = data.color || 'transparent', let color = data.color || 'transparent',
base_image = data.image || `${BASE_IMAGE}${badge_version}/${badge}${data.svg ? '.svg' : `/${version}/`}`, fore = data.fore || '#fff',
base_image = data.image || (data.addon ? null : `${BASE_IMAGE}${badge_version}/${badge}${data.svg ? '.svg' : `/${version}/`}`),
trans = false, trans = false,
invert = false, invert = false,
svg, image, image_set; svg, image, image_set;
if ( style > 4 ) { if ( base_image && style > 4 ) {
const td = data.trans || {}; const td = data.trans || {};
color = td.color || color; color = td.color || color;
@ -106,7 +107,6 @@ export function generateBadgeCSS(badge, version, data, style, is_dark, badge_ver
trans = true; trans = true;
if ( td.image !== true ) if ( td.image !== true )
base_image = td.image; base_image = td.image;
} }
if ( has(td, 'invert') ) if ( has(td, 'invert') )
@ -123,7 +123,7 @@ export function generateBadgeCSS(badge, version, data, style, is_dark, badge_ver
if ( color === 'transparent' ) if ( color === 'transparent' )
style = 0; style = 0;
if ( style !== 3 && style !== 4 ) { if ( base_image && style !== 3 && style !== 4 ) {
svg = base_image.endsWith('.svg'); svg = base_image.endsWith('.svg');
if ( data.urls ) if ( data.urls )
image = `url("${data.urls[scale]}")`; image = `url("${data.urls[scale]}")`;
@ -147,10 +147,18 @@ export function generateBadgeCSS(badge, version, data, style, is_dark, badge_ver
if ( color_fixer && color && color !== 'transparent' ) if ( color_fixer && color && color !== 'transparent' )
color = color_fixer.process(color) || color; color = color_fixer.process(color) || color;
// TODO: Fix the click_url name once we actually support badge clicking. if ( fg_fixer && fore && fore !== 'transparent' && color !== 'transparent' ) {
fg_fixer.base = color;
fore = fg_fixer.process(fore) || fore;
}
if ( ! base_image && style > 3 )
style = 1;
return `${clickable && (data.click_url || data.click_action) ? 'cursor:pointer;' : ''}${invert ? 'filter:invert(100%);' : ''}${CSS_TEMPLATES[style]({ return `${clickable && (data.click_url || data.click_action) ? 'cursor:pointer;' : ''}${invert ? 'filter:invert(100%);' : ''}${CSS_TEMPLATES[style]({
scale: 1, scale: 1,
color, color,
fore,
image, image,
image_set, image_set,
svg svg
@ -419,7 +427,7 @@ export default class Badges extends Module {
} else if ( p === 'ffz' ) { } else if ( p === 'ffz' ) {
out.push(<div class="ffz-badge-tip"> out.push(<div class="ffz-badge-tip">
{show_previews && <div {show_previews && d.image && <div
class="preview-image ffz-badge" class="preview-image ffz-badge"
style={{ style={{
backgroundColor: d.color, backgroundColor: d.color,
@ -611,7 +619,7 @@ export default class Badges extends Module {
provider: 'ffz', provider: 'ffz',
image: bu[4] || bu[2] || bu[1], image: bu[4] || bu[2] || bu[1],
color: badge.color || full_badge.color, color: badge.color || full_badge.color,
title: badge.title || full_badge.title title: badge.title || full_badge.title,
}; };
// Hacky nonsense. // Hacky nonsense.
@ -627,9 +635,10 @@ export default class Badges extends Module {
const replaces = has(badge, 'replaces') ? badge.replaces : full_badge.replaces, const replaces = has(badge, 'replaces') ? badge.replaces : full_badge.replaces,
replaces_type = badge.replaces_type || full_badge.replaces_type; replaces_type = badge.replaces_type || full_badge.replaces_type;
if ( replaces && (!replaces_type || replaces_type === old_badge.id) ) if ( replaces && (!replaces_type || replaces_type === old_badge.id) ) {
old_badge.replaced = badge.id; old_badge.replaced = badge.id;
else old_badge.content = badge.content || full_badge.content || old_badge.content;
} else
continue; continue;
style = old_badge.props.style; style = old_badge.props.style;
@ -647,7 +656,12 @@ export default class Badges extends Module {
style style
}; };
slotted[slot] = {id: badge.id, props, badges: [bd]} slotted[slot] = {
id: badge.id,
props,
badges: [bd],
content: badge.content || full_badge.content
}
} }
if (no_invert) { if (no_invert) {
@ -683,7 +697,11 @@ export default class Badges extends Module {
const data = slotted[slot], const data = slotted[slot],
props = data.props; props = data.props;
props.className = `ffz-tooltip ffz-badge${data.full_size ? ' ffz-full-size' : ''}${data.no_invert ? ' ffz-no-invert' : ''}`; let content = maybe_call(data.content, this, data, msg, createElement);
if ( content && ! Array.isArray(content) )
content = [content];
props.className = `ffz-tooltip ffz-badge${content ? ' tw-pd-x-05' : ''}${data.full_size ? ' ffz-full-size' : ''}${data.no_invert ? ' ffz-no-invert' : ''}`;
props.key = `${props['data-provider']}-${props['data-badge']}`; props.key = `${props['data-provider']}-${props['data-badge']}`;
props['data-tooltip-type'] = 'badge'; props['data-tooltip-type'] = 'badge';
props['data-badge-data'] = JSON.stringify(data.badges); props['data-badge-data'] = JSON.stringify(data.badges);
@ -693,7 +711,7 @@ export default class Badges extends Module {
if ( data.replaced ) if ( data.replaced )
props['data-replaced'] = data.replaced; props['data-replaced'] = data.replaced;
out.push(createElement('span', props)); out.push(createElement('span', props, content || undefined));
} }
return out; return out;
@ -702,14 +720,17 @@ export default class Badges extends Module {
rebuildColor() { rebuildColor() {
if ( this.parent.context.get('chat.badges.fix-colors') ) { if ( this.parent.context.get('chat.badges.fix-colors') ) {
this.fg_fixer = new ColorAdjuster('#fff', 1, 4.5);
this.color_fixer = new ColorAdjuster( this.color_fixer = new ColorAdjuster(
this.parent.context.get('theme.is-dark') ? '#181818' : '#FFFFFF', this.parent.context.get('theme.is-dark') ? '#181818' : '#FFFFFF',
1, 1,
2.5 2.5
); );
} else } else {
this.fg_fixer = null;
this.color_fixer = null; this.color_fixer = null;
} }
}
rebuildColoredBadges() { rebuildColoredBadges() {
@ -824,6 +845,7 @@ export default class Badges extends Module {
loadBadgeData(badge_id, data, generate_css = true) { loadBadgeData(badge_id, data, generate_css = true) {
this.badges[badge_id] = data; this.badges[badge_id] = data;
if ( data ) {
if ( data.addon === undefined ) if ( data.addon === undefined )
data.addon =/^addon/.test(badge_id); data.addon =/^addon/.test(badge_id);
@ -834,6 +856,7 @@ export default class Badges extends Module {
if ( ! data.addon && (data.name === 'developer' || data.name === 'supporter') ) if ( ! data.addon && (data.name === 'developer' || data.name === 'supporter') )
data.click_url = 'https://www.frankerfacez.com/donate'; data.click_url = 'https://www.frankerfacez.com/donate';
}
if ( generate_css ) if ( generate_css )
this.buildBadgeCSS(); this.buildBadgeCSS();
@ -855,11 +878,11 @@ export default class Badges extends Module {
out.push(`.ffz-badge[data-replaced="${key}"]{${generateOverrideCSS(data, style, is_dark)}}`); out.push(`.ffz-badge[data-replaced="${key}"]{${generateOverrideCSS(data, style, is_dark)}}`);
if ( use_media ) { if ( use_media ) {
out.push(`@media (max-resolution: 99dpi) {${selector}{${generateBadgeCSS(key, 0, data, style, is_dark, 0, this.color_fixer, 1, can_click)}}}`); out.push(`@media (max-resolution: 99dpi) {${selector}{${generateBadgeCSS(key, 0, data, style, is_dark, 0, this.color_fixer, this.fg_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: 100dpi) and (max-resolution:199dpi) {${selector}{${generateBadgeCSS(key, 0, data, style, is_dark, 0, this.color_fixer, this.fg_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)}}}`); out.push(`@media (min-resolution: 200dpi) {${selector}{${generateBadgeCSS(key, 0, data, style, is_dark, 0, this.color_fixer, this.fg_fixer, 4, can_click)}}}`);
} else } else
out.push(`${selector}{${generateBadgeCSS(key, 0, data, style, is_dark, 0, this.color_fixer, undefined, can_click)}}`); out.push(`${selector}{${generateBadgeCSS(key, 0, data, style, is_dark, 0, this.color_fixer, this.fg_fixer, undefined, can_click)}}`);
} }
this.style.set('ext-badges', out.join('\n')); this.style.set('ext-badges', out.join('\n'));
@ -953,11 +976,11 @@ export default class Badges extends Module {
d.click_action = td.click_action; d.click_action = td.click_action;
if ( use_media ) { if ( use_media ) {
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 (max-resolution: 99dpi) {${selector}{${generateBadgeCSS(key, version, d, style, is_dark, badge_version, this.color_fixer, this.fg_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: 100dpi) and (max-resolution:199dpi) {${selector}{${generateBadgeCSS(key, version, d, style, is_dark, badge_version, this.color_fixer, this.fg_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)}}}`); out.push(`@media (min-resolution: 200dpi) {${selector}{${generateBadgeCSS(key, version, d, style, is_dark, badge_version, this.color_fixer, this.fg_fixer, 4, can_click)}}}`);
} else } else
out.push(`${selector}{${generateBadgeCSS(key, version, d, style, is_dark, badge_version, this.color_fixer, undefined, can_click)}}`); out.push(`${selector}{${generateBadgeCSS(key, version, d, style, is_dark, badge_version, this.color_fixer, this.fg_fixer, undefined, can_click)}}`);
} }
} }

View file

@ -359,8 +359,12 @@ export default class Player extends Module {
if ( ! this._ffz_click_handler ) if ( ! this._ffz_click_handler )
this._ffz_click_handler = this.ffzClickHandler.bind(this); this._ffz_click_handler = this.ffzClickHandler.bind(this);
if ( ! this._ffz_menu_handler )
this._ffz_menu_handler = this.ffzMenuHandler.bind(this);
on(cont, 'wheel', this._ffz_scroll_handler); on(cont, 'wheel', this._ffz_scroll_handler);
on(cont, 'mousedown', this._ffz_click_handler); on(cont, 'mousedown', this._ffz_click_handler);
on(cont, 'contextmenu', this._ffz_menu_handler);
} }
cls.prototype.ffzRemoveListeners = function() { cls.prototype.ffzRemoveListeners = function() {
@ -378,11 +382,24 @@ export default class Player extends Module {
this._ffz_click_handler = null; this._ffz_click_handler = null;
} }
if ( this._ffz_menu_handler ) {
off(cont, 'contextmenu', this._ffz_menu_handler);
this._ffz_menu_handler = null;
}
this._ffz_listeners = false; this._ffz_listeners = false;
} }
cls.prototype.ffzClickHandler = function(event) { cls.prototype.ffzClickHandler = function(event) {
if ( ! t.settings.get('player.mute-click') || ! event || event.button !== 1 ) if ( ! event )
return;
if ( t.settings.get('player.volume-scroll') === 2 && event.button === 2 ) {
this.ffz_rmb = true;
this.ffz_scrolled = false;
}
if ( ! t.settings.get('player.mute-click') || event.button !== 1 )
return; return;
const player = this.props?.mediaPlayerInstance; const player = this.props?.mediaPlayerInstance;
@ -396,8 +413,20 @@ export default class Player extends Module {
return false; return false;
} }
cls.prototype.ffzMenuHandler = function(event) {
this.ffz_rmb = false;
if ( this.ffz_scrolled ) {
event.preventDefault();
event.stopPropagation();
}
}
cls.prototype.ffzScrollHandler = function(event) { cls.prototype.ffzScrollHandler = function(event) {
if ( ! t.settings.get('player.volume-scroll') ) const setting = t.settings.get('player.volume-scroll');
if ( ! setting )
return;
if ( setting === 2 && ! this.ffz_rmb )
return; return;
const delta = event.wheelDelta || -(event.deltaY || event.detail || 0), const delta = event.wheelDelta || -(event.deltaY || event.detail || 0),
@ -407,6 +436,9 @@ export default class Player extends Module {
if ( ! player?.getVolume ) if ( ! player?.getVolume )
return; return;
if ( setting === 2 )
this.ffz_scrolled = true;
const amount = t.settings.get('player.volume-scroll-steps'), const amount = t.settings.get('player.volume-scroll-steps'),
old_volume = video?.volume ?? player.getVolume(), old_volume = video?.volume ?? player.getVolume(),
volume = Math.max(0, Math.min(1, old_volume + (delta > 0 ? amount : -amount))); volume = Math.max(0, Math.min(1, old_volume + (delta > 0 ? amount : -amount)));

View file

@ -258,7 +258,12 @@ export default class Player extends Module {
path: 'Player > General >> Volume', path: 'Player > General >> Volume',
title: 'Adjust volume by scrolling with the mouse wheel.', title: 'Adjust volume by scrolling with the mouse wheel.',
description: '*This setting will not work properly on streams with visible extensions when mouse interaction with extensions is allowed.*', description: '*This setting will not work properly on streams with visible extensions when mouse interaction with extensions is allowed.*',
component: 'setting-check-box' component: 'setting-select-box',
data: [
{value: false, title: 'Disabled'},
{value: true, title: 'Enabled'},
{value: 2, title: 'Enabled with Right-Click'}
]
} }
}); });
@ -713,8 +718,12 @@ export default class Player extends Module {
if ( ! this._ffz_click_handler ) if ( ! this._ffz_click_handler )
this._ffz_click_handler = this.ffzClickHandler.bind(this); this._ffz_click_handler = this.ffzClickHandler.bind(this);
if ( ! this._ffz_menu_handler )
this._ffz_menu_handler = this.ffzMenuHandler.bind(this);
on(cont, 'wheel', this._ffz_scroll_handler); on(cont, 'wheel', this._ffz_scroll_handler);
on(cont, 'mousedown', this._ffz_click_handler); on(cont, 'mousedown', this._ffz_click_handler);
on(cont, 'contextmenu', this._ffz_menu_handler);
} }
cls.prototype.ffzRemoveListeners = function() { cls.prototype.ffzRemoveListeners = function() {
@ -732,11 +741,24 @@ export default class Player extends Module {
this._ffz_click_handler = null; this._ffz_click_handler = null;
} }
if ( this._ffz_menu_handler ) {
off(cont, 'contextmenu', this._ffz_menu_handler);
this._ffz_menu_handler = null;
}
this._ffz_listeners = false; this._ffz_listeners = false;
} }
cls.prototype.ffzClickHandler = function(event) { cls.prototype.ffzClickHandler = function(event) {
if ( ! t.settings.get('player.mute-click') || ! event || event.button !== 1 ) if ( ! event )
return;
if ( t.settings.get('player.volume-scroll') === 2 && event.button === 2 ) {
this.ffz_rmb = true;
this.ffz_scrolled = false;
}
if ( ! t.settings.get('player.mute-click') || event.button !== 1 )
return; return;
const player = this.props?.mediaPlayerInstance; const player = this.props?.mediaPlayerInstance;
@ -750,8 +772,20 @@ export default class Player extends Module {
return false; return false;
} }
cls.prototype.ffzMenuHandler = function(event) {
this.ffz_rmb = false;
if ( this.ffz_scrolled ) {
event.preventDefault();
event.stopPropagation();
}
}
cls.prototype.ffzScrollHandler = function(event) { cls.prototype.ffzScrollHandler = function(event) {
if ( ! t.settings.get('player.volume-scroll') ) const setting = t.settings.get('player.volume-scroll');
if ( ! setting )
return;
if ( setting === 2 && ! this.ffz_rmb )
return; return;
const delta = event.wheelDelta || -(event.deltaY || event.detail || 0), const delta = event.wheelDelta || -(event.deltaY || event.detail || 0),
@ -761,6 +795,9 @@ export default class Player extends Module {
if ( ! player?.getVolume ) if ( ! player?.getVolume )
return; return;
if ( setting === 2 )
this.ffz_scrolled = true;
const amount = t.settings.get('player.volume-scroll-steps'), const amount = t.settings.get('player.volume-scroll-steps'),
old_volume = video?.volume ?? player.getVolume(), old_volume = video?.volume ?? player.getVolume(),
volume = Math.max(0, Math.min(1, old_volume + (delta > 0 ? amount : -amount))); volume = Math.max(0, Math.min(1, old_volume + (delta > 0 ? amount : -amount)));