1
0
Fork 0
mirror of https://github.com/FrankerFaceZ/FrankerFaceZ.git synced 2025-06-27 21:05:53 +00:00
* Added: Changelog for Add-Ons.
* Added: Option to disable the player running at a faster rate to reduce the buffer size.
* Changed: Stream Latency metadata now shows you when the player is running at a faster rate.
* Fixed: Formatting of tool-tips for metadata.
* Fixed: Metadata tool-tips not supporting rich children when updating.
* Fixed: Metadata icons not updating when changed dynamically.
* Fixed: The current channel's accent color not being detected in pop-out chat.
* Fixed: Styles not being applied correctly to deleted messages that are part of a channel points reward or part of a re-subscription notice.
* Removed: Support for Rooms messages.
* API Added: Settings now have an `onUIChanged` method that is called when a setting is changed by a UI control, allowing for immediate feedback.
* API Added: Built-in settings components now accept a `buttons` component that is rendered before the reset and profile override buttons.
This commit is contained in:
SirStendec 2019-11-14 19:52:35 -05:00
parent 8ac1b2ce91
commit 347919c51a
28 changed files with 335 additions and 83 deletions

View file

@ -139,7 +139,7 @@ module.exports = {
"react/jsx-first-prop-new-line": ["error", "multiline-multiprop"],
"react/jsx-indent": ["warn", "tab"],
"react/jsx-indent-props": ["warn", "tab"],
"react/jsx-key": "warn",
//"react/jsx-key": "warn",
"react/jsx-no-bind": "error",
"react/jsx-no-comment-textnodes": "error",
"react/jsx-no-duplicate-props": "error",

View file

@ -669,6 +669,12 @@
"search": [
"channel-points"
]
},
{
"uid": "4e511190b60f329d08301eb6869c5130",
"css": "fast-fw",
"code": 59453,
"src": "fontawesome"
}
]
}

View file

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

Binary file not shown.

View file

@ -128,6 +128,8 @@
<glyph glyph-name="channel-points" unicode="&#xe83c;" d="M500 550a200 200 0 0 0 200-200h-100a100 100 0 0 1-100 100z m12 200a400 400 0 0 1-412-400 400 400 0 0 1 800 0 400 400 0 0 1-388 400z m-3-100a300 300 0 0 0 291-300 300 300 0 0 0-600 0 300 300 0 0 0 309 300z" horiz-adv-x="1000" />
<glyph glyph-name="fast-fw" unicode="&#xe83d;" d="M25-71q-10-11-18-8t-7 18v822q0 14 7 18t18-8l396-396q5-5 8-10v396q0 14 7 18t18-8l396-396q11-10 11-25t-11-25l-396-396q-11-11-18-8t-7 18v397q-3-6-8-11z" horiz-adv-x="928.6" />
<glyph glyph-name="link-ext" unicode="&#xf08e;" d="M786 332v-178q0-67-47-114t-114-47h-464q-67 0-114 47t-47 114v464q0 66 47 113t114 48h393q7 0 12-5t5-13v-36q0-8-5-13t-12-5h-393q-37 0-63-26t-27-63v-464q0-37 27-63t63-27h464q37 0 63 27t26 63v178q0 8 5 13t13 5h36q8 0 13-5t5-13z m214 482v-285q0-15-11-25t-25-11-25 11l-98 98-364-364q-5-6-13-6t-12 6l-64 64q-6 5-6 12t6 13l364 364-98 98q-11 11-11 25t11 25 25 11h285q15 0 25-11t11-25z" horiz-adv-x="1000" />
<glyph glyph-name="twitter" unicode="&#xf099;" d="M904 622q-37-54-90-93 0-8 0-23 0-73-21-145t-64-139-103-117-144-82-181-30q-151 0-276 81 19-2 43-2 126 0 224 77-59 1-105 36t-64 89q19-3 34-3 24 0 48 6-63 13-104 62t-41 115v2q38-21 82-23-37 25-59 64t-22 86q0 49 25 91 68-83 164-133t208-55q-5 21-5 41 0 75 53 127t127 53q79 0 132-57 61 12 115 44-21-64-80-100 52 6 104 28z" horiz-adv-x="928.6" />

Before

Width:  |  Height:  |  Size: 36 KiB

After

Width:  |  Height:  |  Size: 37 KiB

Before After
Before After

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -1,10 +1,15 @@
<template lang="html">
<div class="ffz--changelog tw-border-t tw-pd-t-1">
<div class="tw-align-center">
<h2>{{ t('home.changelog', 'Changelog') }}</h2>
<h2 v-if="addons">
{{ t('setting.add_ons.changelog.title', 'Add-Ons Changelog') }}
</h2>
<h2 v-else>
{{ t('home.changelog', 'Changelog') }}
</h2>
</div>
<div class="tw-mg-b-1 tw-flex tw-align-items-center">
<div v-if=" ! addons" class="tw-mg-b-1 tw-flex tw-align-items-center">
<div class="tw-flex-grow-1" />
<div class="tw-checkbox tw-relative tw-tooltip-wrapper">
<input
@ -28,12 +33,43 @@
<ul>
<li v-for="commit of display" :key="commit.sha" class="tw-mg-b-2">
<div class="tw-flex tw-align-items-center tw-border-b tw-mg-b-05">
<div v-if="commit.active" class="tw-pill tw-mg-r-05">
<div v-if="! addons && commit.active" class="tw-pill tw-mg-r-05">
{{ t('home.changelog.current', 'Current Version') }}
</div>
<div class="tw-font-size-4">
<div v-if="commit.title" class="tw-font-size-4">
{{ commit.title }}
</div>
<div v-if="commit.author">
<t-list
phrase="home.changelog.by-line"
default="By: {user}"
class="tw-inline-flex tw-align-items-center"
>
<template #user>
<a
v-if="commit.author.html_url"
:href="commit.author.html_url"
target="_blank"
rel="noopener noreferrer"
class="tw-inline-flex tw-align-items-center tw-link tw-link--inherit tw-mg-x-05"
>
<figure
v-if="commit.author.avatar_url"
class="tw-avatar tw-avatar--size-20 tw-mg-r-05"
>
<img
:src="commit.author.avatar_url"
class="tw-block tw-border-radius-rounded tw-image tw-image-avatar"
>
</figure>
{{ commit.author.login }}
</a>
<strong v-else class="tw-mg-x-05">
{{ commit.author.login || commit.author.name }}
</strong>
</template>
</t-list>
</div>
<div
v-if="commit.hash"
class="tw-font-size-8 tw-c-text-alt-2"
@ -81,6 +117,7 @@ export default {
data() {
return {
error: false,
addons: this.item.addons,
nonversioned: false,
loading: false,
more: true,
@ -95,21 +132,29 @@ export default {
for(const commit of this.commits) {
let message = commit.commit.message,
author = null,
title = old_commit;
const match = TITLE_MATCH.exec(message);
if ( this.addons ) {
title = null;
author = commit.author;
if ( match ) {
title = match[1];
message = message.slice(match[0].length);
} else if ( ! this.nonversioned )
continue;
} else {
const match = TITLE_MATCH.exec(message);
if ( match ) {
title = match[1];
message = message.slice(match[0].length);
} else if ( ! this.nonversioned )
continue;
}
const date = new Date(commit.commit.author.date),
active = commit.sha === window.FrankerFaceZ.version_info.commit;
out.push({
title,
author,
message,
active,
hash: commit.sha && commit.sha.slice(0,7),
@ -150,7 +195,7 @@ export default {
this.loading = true;
try {
const resp = await fetch(`https://api.github.com/repos/frankerfacez/frankerfacez/commits${until ? `?until=${until}` : ''}`),
const resp = await fetch(`https://api.github.com/repos/frankerfacez/${this.addons ? 'add-ons' : 'frankerfacez'}/commits${until ? `?until=${until}` : ''}`),
data = resp.ok ? await resp.json() : null;
if ( ! data || ! Array.isArray(data) ) {
@ -158,14 +203,20 @@ export default {
return;
}
let added = false;
for(const commit of data) {
if ( this.commit_ids.has(commit.sha) )
continue;
this.commit_ids.add(commit.sha)
this.commits.push(commit);
added = true;
}
if ( ! added )
this.more = false;
this.loading = false;
} catch(err) {

View file

@ -18,6 +18,14 @@
<span v-if="unseen" class="tw-pill">{{ t('setting.new', 'New') }}</span>
</label>
<component
:is="item.buttons"
v-if="item.buttons"
:context="context"
:item="item"
:value="value"
/>
<button
v-if="source && source !== profile"
class="tw-mg-l-05 tw-button tw-button--text"

View file

@ -18,6 +18,14 @@
@input="onInput"
/>
<component
:is="item.buttons"
v-if="item.buttons"
:context="context"
:item="item"
:value="value"
/>
<button
v-if="source && source !== profile"
class="tw-mg-l-05 tw-button tw-button--text"

View file

@ -13,7 +13,7 @@
<select
:id="item.full_key"
ref="control"
class="tw-border-radius-medium tw-font-size-6 tw-select tw-pd-l-1 tw-pd-r-3 tw-pd-y-05"
class="tw-border-top-left-radius-medium tw-border-top-right-radius-medium tw-font-size-6 tw-select tw-pd-l-1 tw-pd-r-3 tw-pd-y-05"
@change="onChange"
>
<option
@ -31,11 +31,19 @@
ref="text"
:value="value"
:disabled="! isCustom"
class="tw-border-radius-medium tw-font-size-6 tw-pd-x-1 tw-pd-y-05 tw-input"
class="ffz-mg-t-1p tw-border-bottom-left-radius-medium tw-border-bottom-right-radius-medium tw-font-size-6 tw-pd-x-1 tw-pd-y-05 tw-input"
@change="onTextChange"
>
</div>
<component
:is="item.buttons"
v-if="item.buttons"
:context="context"
:item="item"
:value="value"
/>
<button
v-if="source && source !== profile"
class="tw-mg-l-05 tw-mg-y-05 tw-button tw-button--text"

View file

@ -24,6 +24,14 @@
</option>
</select>
<component
:is="item.buttons"
v-if="item.buttons"
:context="context"
:item="item"
:value="value"
/>
<button
v-if="source && source !== profile"
class="tw-mg-l-05 tw-button tw-button--text"

View file

@ -17,6 +17,14 @@
@change="onChange"
>
<component
:is="item.buttons"
v-if="item.buttons"
:context="context"
:item="item"
:value="value"
/>
<button
v-if="source && source !== profile"
class="tw-mg-l-05 tw-button tw-button--text"

View file

@ -87,6 +87,13 @@ export default class MainMenu extends Module {
component: 'changelog'
});
this.settings.addUI('addon-changelog', {
path: 'Add-Ons > Changelog @{"sort": -1000, "profile_warning": false}',
component: 'changelog',
force_seen: true,
addons: true
});
this.settings.addUI('legal', {
path: 'Home > Legal @{"sort": 1000}',
component: 'legal-page',

View file

@ -184,10 +184,16 @@ export default {
value = this.item.process(value);
this.profile.set(this.item.setting, value);
if ( this.item.onUIChange )
this.item.onUIChange(value);
},
clear() {
this.profile.delete(this.item.setting);
if ( this.item.onUIChange )
this.item.onUIChange(this.value);
}
}
}

View file

@ -1,4 +1,4 @@
'use strict';
'use strict';
// ============================================================================
// Channel Metadata
@ -114,14 +114,19 @@ export default class Metadata extends Module {
if ( ! data.created )
return null;
return `${this.i18n.t(
'metadata.uptime.tooltip',
'Stream Uptime'
)}<div class="pd-t-05">${this.i18n.t(
'metadata.uptime.since',
'(since {since,datetime})',
{since: data.created}
)}</div>`;
return [
this.i18n.t(
'metadata.uptime.tooltip',
'Stream Uptime'
),
<div class="tw-pd-t-05">
{this.i18n.t(
'metadata.uptime.since',
'(since {since,datetime})',
{since: data.created}
)}
</div>
];
},
async popup(data, tip) {
@ -210,6 +215,7 @@ export default class Metadata extends Module {
hlsLatencyBroadcaster: temp.hls_latency_broadcaster / 1000,
hlsLatencyEncoder: temp.hls_latency_encoder / 1000,
memoryUsage: `${temp.totalMemoryNumber} MB`,
rate: maybe_call(player.getPlaybackRate, player) || 1,
playbackRate: temp.current_bitrate,
skippedFrames: temp.dropped_frames,
videoResolution: `${temp.vid_width}x${temp.vid_height}`
@ -229,6 +235,7 @@ export default class Metadata extends Module {
videoWidth,
displayHeight,
displayWidth,
rate: maybe_call(player.getPlaybackRate, player),
fps: Math.floor(maybe_call(player.getVideoFrameRate, player) || 0),
hlsLatencyBroadcaster: player.stats?.broadcasterLatency,
hlsLatencyEncoder: player.stats?.transcoderLatency,
@ -248,13 +255,20 @@ export default class Metadata extends Module {
return {
stats,
drift,
rate: stats.rate == null ? 1 : stats.rate,
delay: stats.hlsLatencyBroadcaster,
old: stats.hlsLatencyBroadcaster > 180
}
},
order: 3,
icon: 'ffz-i-gauge',
icon(data) {
if ( data.rate > 1 )
return 'ffz-i-fast-fw';
return 'ffz-i-gauge'
},
subtitle: () => this.i18n.t('metadata.player-stats.subtitle', 'Latency'),
@ -293,16 +307,28 @@ export default class Metadata extends Module {
},
tooltip(data) {
const delayed = data.drift > 5000 ?
`${this.i18n.t(
const delayed = data.drift > 5000 && (<div class="tw-border-b tw-mg-b-05 tw-pd-b-05">
{this.i18n.t(
'metadata.player-stats.delay-warning',
'Your local clock seems to be off by roughly {count,number} seconds, which could make this inaccurate.',
Math.round(data.drift / 10) / 100
)}<hr>` :
'';
)}
</div>);
const ff = data.rate > 1 && (<div class="tw-border-b tw-mg-b-05 tw-pd-b-05">
{this.i18n.t(
'metadata.player-stats.rate-warning',
'Playing at {rate,number}x speed to reduce delay.',
{rate: data.rate.toFixed(2)}
)}
</div>);
if ( ! data.stats || ! data.delay )
return delayed + this.i18n.t('metadata.player-stats.latency-tip', 'Stream Latency');
return [
delayed,
ff,
this.i18n.t('metadata.player-stats.latency-tip', 'Stream Latency')
];
const stats = data.stats,
video_info = this.i18n.t(
@ -312,19 +338,34 @@ export default class Metadata extends Module {
);
if ( data.old )
return `${delayed}${this.i18n.t(
'metadata.player-stats.video-tip',
'Video Information'
)}<div class="pd-t-05">${this.i18n.t(
'metadata.player-stats.broadcast-ago',
'Broadcast {count,number}s Ago',
data.delay
)}</div><div class="pd-t-05">${video_info}</div>`;
return [
delayed,
this.i18n.t(
'metadata.player-stats.video-tip',
'Video Information'
),
<div class="tw-pd-t-05">
{this.i18n.t(
'metadata.player-stats.broadcast-ago',
'Broadcast {count,number}s Ago',
data.delay
)}
</div>,
<div class="tw-pd-t-05">
{video_info}
</div>
];
return `${delayed}${this.i18n.t(
'metadata.player-stats.latency-tip',
'Stream Latency'
)}<div class="pd-t-05">${video_info}</div>`;
return [
delayed, ff,
this.i18n.t(
'metadata.player-stats.latency-tip',
'Stream Latency'
),
<div class="tw-pd-t-05">
{video_info}
</div>
];
}
}
}
@ -396,7 +437,7 @@ export default class Metadata extends Module {
// Grab the element again in case it changed, somehow.
el = container.querySelector(`.ffz-stat[data-key="${key}"]`);
let stat, old_color;
let stat, old_color, old_icon;
const label = maybe_call(def.label, this, data);
@ -408,7 +449,7 @@ export default class Metadata extends Module {
color = maybe_call(def.color, this, data) || '';
if ( ! el ) {
let icon = maybe_call(def.icon, this, data);
let icon = old_icon = maybe_call(def.icon, this, data);
let button = false;
if ( def.button !== false && (def.popup || def.click) ) {
@ -608,6 +649,7 @@ export default class Metadata extends Module {
if ( ! stat )
return destroy();
old_icon = el.dataset.icon || '';
old_color = el.dataset.color || '';
if ( el._ffz_order !== order )
@ -616,7 +658,17 @@ export default class Metadata extends Module {
if ( el.tip_content !== tooltip ) {
el.tip_content = tooltip;
if ( el.tip )
el.tip.element.innerHTML = tooltip;
setChildren(el.tip.element, tooltip);
}
}
if ( typeof def.icon === 'function' ) {
const icon = maybe_call(def.icon, this, data);
if ( typeof icon === 'string' && icon !== old_icon ) {
el.dataset.icon = icon;
const figure = el.querySelector('figure');
if ( figure )
figure.className = icon;
}
}

View file

@ -65,6 +65,12 @@ export default class Channel extends Module {
Twilight.CHAT_ROUTES
);
this.ChannelContext = this.fine.define(
'channel-context',
n => n.resetPrivateVariables && n.fetchChannel && n.clearBroadcastSettingsUpdateInterval,
['popout', 'embed-chat']
);
/*this.SquadController = this.fine.define(
'squad-controller',
n => n.onSquadPage && n.isValidSquad && n.handleLeaveSquad,
@ -74,7 +80,10 @@ export default class Channel extends Module {
updateChannelColor(color) {
const parsed = color && Color.RGBA.fromHex(color);
let parsed = color && Color.RGBA.fromHex(color);
if ( ! parsed )
parsed = Color.RGBA.fromHex('9147FF');
if ( parsed ) {
this.css_tweaks.setVariable('channel-color', parsed.toCSS());
this.css_tweaks.setVariable('channel-color-20', parsed._a(0.2).toCSS());
@ -95,6 +104,14 @@ export default class Channel extends Module {
//this.SquadController.on('mount', this.noAutoSquads, this);
//this.SquadController.on('update', this.noAutoSquads, this);
this.ChannelContext.on('mount', this.onChannelContext, this);
this.ChannelContext.on('update', this.onChannelContext, this);
this.ChannelContext.on('unmount', this.offChannelContext, this);
this.ChannelContext.ready((cls, instances) => {
for(const inst of instances)
this.onChannelContext(inst);
});
this.RaidController.ready((cls, instances) => {
for(const inst of instances)
this.wrapRaidController(inst);
@ -148,6 +165,41 @@ export default class Channel extends Module {
});
}
onChannelContext(inst) {
if ( ! inst.state || inst.state.loading )
return;
const channel = inst.state.channel,
clip = inst.state.clip,
video = inst.state.video,
category = video?.game || clip?.game || channel?.stream?.game || channel?.broadcastSettings?.game;
const color = inst.state?.primaryColorHex;
this.updateChannelColor(color);
this.settings.updateContext({
channel: inst.state.channel?.login,
channelID: inst.state.channel?.id,
channelColor: color,
category: category?.name,
categoryID: category?.id
});
}
offChannelContext() {
this.updateChannelColor(null);
this.settings.updateContext({
channel: null,
channelID: null,
category: null,
categoryID: null,
channelColor: null
});
}
onChannelMounted(inst) {
this.wrapChannelPage(inst);

View file

@ -47,11 +47,11 @@ export default class ChatLine extends Module {
Twilight.CHAT_ROUTES
);
this.ChatRoomLine = this.fine.define(
/*this.ChatRoomLine = this.fine.define(
'chat-room-line',
n => n.renderMessageBody && n.props && ! n.onExtensionNameClick && has(n.props, 'hasModPermissions'),
Twilight.CHAT_ROUTES
);
);*/
/*this.ChatRoomContainer = this.fine.define(
'chat-room-container',
@ -100,7 +100,7 @@ export default class ChatLine extends Module {
FFZRichContent = this.rich_content && this.rich_content.RichContent;
this.ChatRoomLine.ready(cls => {
/*this.ChatRoomLine.ready(cls => {
const old_render = cls.prototype.render;
cls.prototype.render = function() { try {
@ -212,7 +212,7 @@ export default class ChatLine extends Module {
// Do this after a short delay to hopefully reduce the chance of React
// freaking out on us.
setTimeout(() => this.ChatRoomLine.forceUpdate());
});
});*/
this.WhisperLine.ready(cls => {
@ -527,7 +527,7 @@ other {# messages were deleted by a moderator.}
}, the_list);
}
cls = 'user-notice-line tw-pd-y-05 ffz--subscribe-line';
cls = `user-notice-line tw-pd-y-05 ffz--subscribe-line${show_class ? ' ffz--deleted-message' : ''}`;
out = [
e('div', {
className: 'tw-flex tw-c-text-alt-2',
@ -590,7 +590,7 @@ other {# messages were deleted by a moderator.}
count: msg.sub_total
}));
cls = 'user-notice-line tw-pd-y-05 tw-pd-r-2 ffz--subscribe-line';
cls = `user-notice-line tw-pd-y-05 tw-pd-r-2 ffz--subscribe-line${show_class ? ' ffz--deleted-message' : ''}`;
out = [
e('div', {className: 'tw-flex tw-c-text-alt-2'}, [
t.chat.context.get('chat.subs.compact') ? null :
@ -652,7 +652,7 @@ other {# messages were deleted by a moderator.}
));
}
cls = 'user-notice-line tw-pd-y-05 tw-pd-r-2 ffz--subscribe-line';
cls = `user-notice-line tw-pd-y-05 tw-pd-r-2 ffz--subscribe-line${show_class ? ' ffz--deleted-message' : ''}`;
out = [
e('div', {className: 'tw-flex tw-c-text-alt-2'}, [
t.chat.context.get('chat.subs.compact') ? null :
@ -690,7 +690,7 @@ other {# messages were deleted by a moderator.}
]);
if ( system_msg ) {
cls = 'user-notice-line tw-pd-y-05 tw-pd-r-2 ffz--ritual-line';
cls = `user-notice-line tw-pd-y-05 tw-pd-r-2 ffz--ritual-line${show_class ? ' ffz--deleted-message' : ''}`;
out = [
system_msg,
out && e('div', {
@ -710,7 +710,7 @@ other {# messages were deleted by a moderator.}
t.i18n.formatNumber(getRewardCost(msg.ffz_reward))
]);
cls = `ffz--points-line tw-pd-l-1 tw-pd-y-05 tw-pd-r-2${isHighlightedReward(msg.ffz_reward) ? ' ffz--points-highlight' : ''}`;
cls = `ffz--points-line tw-pd-l-1 tw-pd-y-05 tw-pd-r-2${isHighlightedReward(msg.ffz_reward) ? ' ffz--points-highlight' : ''}${show_class ? ' ffz--deleted-message' : ''}`;
out = [
e('div', {className: 'tw-c-text-alt-2'}, [
out ? null : t.actions.renderInline(msg, this.props.showModerationIcons, u, r, e),
@ -872,13 +872,13 @@ other {# messages were deleted by a moderator.}
}
}
for(const inst of this.ChatRoomLine.instances) {
/*for(const inst of this.ChatRoomLine.instances) {
const msg = inst.props.message;
if ( msg ) {
msg.ffz_tokens = null;
msg.mentioned = msg.mention_color = null;
}
}
}*/
for(const inst of this.WhisperLine.instances) {
const msg = inst.props.message;
@ -888,7 +888,7 @@ other {# messages were deleted by a moderator.}
this.ChatLine.forceUpdate();
this.ExtensionLine.forceUpdate();
this.ChatRoomLine.forceUpdate();
//this.ChatRoomLine.forceUpdate();
this.WhisperLine.forceUpdate();
this.emit('chat:updated-lines');

View file

@ -20,10 +20,10 @@ export default class Layout extends Module {
this.inject('site.fine');
this.inject('site.css_tweaks');
this.TopNav = this.fine.define(
/*this.TopNav = this.fine.define(
'top-nav',
n => n.computeStyles && n.navigationLinkSize
);
);*/
/*this.RightColumn = this.fine.define(
'tw-rightcolumn',
@ -239,10 +239,7 @@ export default class Layout extends Module {
}
updateNavLinks() {
for(const inst of this.TopNav.instances)
try {
inst.computeStyles();
} catch(err) { /* no-op */ }
}
updatePortraitMode() {

View file

@ -73,6 +73,21 @@ export default class Player extends Module {
// Settings
this.settings.add('player.allow-catchup', {
default: true,
ui: {
path: 'Player > General >> General',
title: 'Allow the player to speed up to reduce delay.',
description: 'Twitch, by default, will apply a minor speed up to live video when you have a large delay to the broadcaster in order to catch back up with the live broadcast. This may result in audio distortion. Disable this to prevent the automatic speed changes.',
component: 'setting-check-box'
},
changed: val => {
for(const inst of this.Player.instances)
this.updateAutoPlaybackRate(inst, val);
}
});
this.settings.add('player.volume-scroll', {
default: false,
ui: {
@ -80,11 +95,6 @@ export default class Player extends Module {
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.*',
component: 'setting-check-box'
},
changed: val => {
for(const inst of this.Player.instances)
this.updateVolumeScroll(inst, val);
}
});
@ -647,6 +657,19 @@ export default class Player extends Module {
}
updateAutoPlaybackRate(inst, val) {
const player = inst.props?.mediaPlayerInstance;
if ( ! player )
return;
if ( val == null )
val = this.settings.get('player.allow-catchup');
if ( player.setLiveSpeedUpRate )
player.setLiveSpeedUpRate(val ? 1.05 : 1);
}
updateHideExtensions(val) {
if ( val === undefined )
val = this.settings.get('player.ext-hide');
@ -762,6 +785,12 @@ export default class Player extends Module {
updateGUI(inst) {
this.addPiPButton(inst);
this.addResetButton(inst);
const player = inst?.props?.mediaPlayerInstance;
if ( player && ! this.settings.get('player.allow-catchup') ) {
if ( player.setLiveSpeedUpRate )
player.setLiveSpeedUpRate(1);
}
}

View file

@ -90,5 +90,6 @@ export default [
"t-reset",
"whispers",
"cake",
"channel-points"
"channel-points",
"fast-fw"
];

View file

@ -60,6 +60,7 @@
.ffz-i-t-reset:before { content: '\e83a'; } /* '' */
.ffz-i-whispers:before { content: '\e83b'; } /* '' */
.ffz-i-channel-points:before { content: '\e83c'; } /* '' */
.ffz-i-fast-fw:before { content: '\e83d'; } /* '' */
.ffz-i-link-ext:before { content: '\f08e'; } /* '' */
.ffz-i-twitter:before { content: '\f099'; } /* '' */
.ffz-i-github:before { content: '\f09b'; } /* '' */

File diff suppressed because one or more lines are too long

View file

@ -60,6 +60,7 @@
.ffz-i-t-reset { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe83a;&nbsp;'); }
.ffz-i-whispers { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe83b;&nbsp;'); }
.ffz-i-channel-points { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe83c;&nbsp;'); }
.ffz-i-fast-fw { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe83d;&nbsp;'); }
.ffz-i-link-ext { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf08e;&nbsp;'); }
.ffz-i-twitter { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf099;&nbsp;'); }
.ffz-i-github { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf09b;&nbsp;'); }

View file

@ -71,6 +71,7 @@
.ffz-i-t-reset { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe83a;&nbsp;'); }
.ffz-i-whispers { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe83b;&nbsp;'); }
.ffz-i-channel-points { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe83c;&nbsp;'); }
.ffz-i-fast-fw { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xe83d;&nbsp;'); }
.ffz-i-link-ext { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf08e;&nbsp;'); }
.ffz-i-twitter { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf099;&nbsp;'); }
.ffz-i-github { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = '&#xf09b;&nbsp;'); }

View file

@ -1,11 +1,11 @@
@font-face {
font-family: 'ffz-fontello';
src: url('../font/ffz-fontello.eot?90039340');
src: url('../font/ffz-fontello.eot?90039340#iefix') format('embedded-opentype'),
url('../font/ffz-fontello.woff2?90039340') format('woff2'),
url('../font/ffz-fontello.woff?90039340') format('woff'),
url('../font/ffz-fontello.ttf?90039340') format('truetype'),
url('../font/ffz-fontello.svg?90039340#ffz-fontello') format('svg');
src: url('../font/ffz-fontello.eot?37997143');
src: url('../font/ffz-fontello.eot?37997143#iefix') format('embedded-opentype'),
url('../font/ffz-fontello.woff2?37997143') format('woff2'),
url('../font/ffz-fontello.woff?37997143') format('woff'),
url('../font/ffz-fontello.ttf?37997143') format('truetype'),
url('../font/ffz-fontello.svg?37997143#ffz-fontello') format('svg');
font-weight: normal;
font-style: normal;
}
@ -15,7 +15,7 @@
@media screen and (-webkit-min-device-pixel-ratio:0) {
@font-face {
font-family: 'ffz-fontello';
src: url('../font/ffz-fontello.svg?90039340#ffz-fontello') format('svg');
src: url('../font/ffz-fontello.svg?37997143#ffz-fontello') format('svg');
}
}
*/
@ -116,6 +116,7 @@
.ffz-i-t-reset:before { content: '\e83a'; } /* '' */
.ffz-i-whispers:before { content: '\e83b'; } /* '' */
.ffz-i-channel-points:before { content: '\e83c'; } /* '' */
.ffz-i-fast-fw:before { content: '\e83d'; } /* '' */
.ffz-i-link-ext:before { content: '\f08e'; } /* '' */
.ffz-i-twitter:before { content: '\f099'; } /* '' */
.ffz-i-github:before { content: '\f09b'; } /* '' */

View file

@ -27,6 +27,10 @@
margin-right: -0.5rem !important;
}
.ffz-mg-t-1p {
margin-top: 1px !important;
}
.ffz-mg-l--05 {
margin-left: -0.5rem !important;
}