1
0
Fork 0
mirror of https://github.com/FrankerFaceZ/FrankerFaceZ.git synced 2025-09-15 17:46:55 +00:00
* Fixed: Emotes not appearing in Chat on Videos.
* Fixed: Extra, unnecessary `Pause Chat` section appearing in the Twitch chat settings menu.
* Fixed: Hide the number of unread whispers when hiding the whispers button.
* Fixed: The alternative live viewer display sometimes incorrectly displaying zero when loading the page.
* Fixed: Precision issue when displaying localized numbers in some cases.
This commit is contained in:
SirStendec 2020-09-15 19:17:29 -04:00
parent 943e0fdc18
commit 472f9472ee
8 changed files with 93 additions and 14 deletions

View file

@ -1,7 +1,7 @@
{ {
"name": "frankerfacez", "name": "frankerfacez",
"author": "Dan Salvato LLC", "author": "Dan Salvato LLC",
"version": "4.20.37", "version": "4.20.38",
"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

@ -1388,9 +1388,15 @@ export default class Chat extends Module {
ret = `${content.alt}${content.cheerAmount}`; ret = `${content.alt}${content.cheerAmount}`;
} else if ( content.images ) { } else if ( content.images ) {
const url = (content.images.themed ? content.images.dark : content.images.sources), const url = (content.images.themed ? content.images.dark : content.images.sources);
match = url && /\/emoticons\/v1\/(\d+)\/[\d.]+$/.exec(url['1x']), let id = content.emoteID;
if ( ! id ) {
const match = url && (
/\/emoticons\/v1\/(\d+)\/[\d.]+$/.exec(url['1x']) ||
/\/emoticons\/v2\/(\d+)\//.exec(url['1x'])
);
id = match && match[1]; id = match && match[1];
}
ret = content.alt; ret = content.alt;

View file

@ -369,6 +369,24 @@ export default class Channel extends Module {
return; return;
} }
// TODO: See if we can read this data directly from Apollo's cache.
// Also, test how it works with videos and clips.
/*const raw_game = el.querySelector('a[data-a-target="stream-game-link"]')?.textContent;
if ( ! el._ffz_game_cache_updating && el._ffz_game_cache !== raw_game ) {
el._ffz_game_cache_updating = true;
el._ffz_game_cache = raw_game;
this.twitch_data.getUserGame(props.channelID, props.channelLogin).then(game => {
el._ffz_game_cache_updating = false;
this.settings.updateContext({
category: game?.displayName,
categoryID: game?.id
})
}).catch(() => {
el._ffz_game_cache_updating = false;
});
}*/
const other_props = react.child.child?.child?.child?.child?.child?.child?.child?.child?.child?.memoizedProps, const other_props = react.child.child?.child?.child?.child?.child?.child?.child?.child?.child?.memoizedProps,
title = other_props?.title; title = other_props?.title;
@ -438,8 +456,19 @@ export default class Channel extends Module {
getViewerCount: () => { getViewerCount: () => {
const thing = cont.querySelector('p[data-a-target="animated-channel-viewers-count"]'), const thing = cont.querySelector('p[data-a-target="animated-channel-viewers-count"]'),
r = thing && this.fine.getReactInstance(thing), r = thing && this.fine.getReactInstance(thing),
p = r?.memoizedProps?.children?.props; c = r?.memoizedProps?.children;
// Sometimes, on early loads, the animated element
// is actually a static string.
if ( typeof c === 'string' && /^[0-9,.]+$/.test(c) ) {
try {
const val = parseInt(c.replace(/,/, ''), 10);
if ( ! isNaN(val) && isFinite(val) && val > 0 )
return val;
} catch(err) { /* no-op */ }
}
const p = c?.props;
if ( p && p.value != null ) if ( p && p.value != null )
return p.value; return p.value;

View file

@ -25,11 +25,11 @@ export default class SettingsMenu extends Module {
Twilight.CHAT_ROUTES Twilight.CHAT_ROUTES
); );
this.ModSettingsMenu = this.fine.define( /*this.ModSettingsMenu = this.fine.define(
'chat-mod-settings', 'chat-mod-settings',
n => n.renderModerationSettingsLink && n.onChatClear, n => n.renderModerationSettingsLink && n.onChatClear,
Twilight.CHAT_ROUTES Twilight.CHAT_ROUTES
); );*/
} }
async onEnable() { async onEnable() {
@ -71,7 +71,7 @@ export default class SettingsMenu extends Module {
</div>} </div>}
</div>); </div>);
const f = t.chat.context.get('chat.scroller.freeze'), /*const f = t.chat.context.get('chat.scroller.freeze'),
reason = f === 2 ? t.i18n.t('key.ctrl', 'Ctrl Key') : reason = f === 2 ? t.i18n.t('key.ctrl', 'Ctrl Key') :
f === 3 ? t.i18n.t('key.meta', 'Meta Key') : f === 3 ? t.i18n.t('key.meta', 'Meta Key') :
f === 4 ? t.i18n.t('key.alt', 'Alt Key') : f === 4 ? t.i18n.t('key.alt', 'Alt Key') :
@ -96,7 +96,7 @@ export default class SettingsMenu extends Module {
<figure class="tw-svg ffz-i-right-dir" /> <figure class="tw-svg ffz-i-right-dir" />
</div> </div>
</button> </button>
</div>); </div>);*/
return val; return val;
} }
@ -171,7 +171,7 @@ export default class SettingsMenu extends Module {
this.SettingsMenu.forceUpdate(); this.SettingsMenu.forceUpdate();
}); });
this.ModSettingsMenu.ready(cls => { /*this.ModSettingsMenu.ready(cls => {
const old_render = cls.prototype.render; const old_render = cls.prototype.render;
cls.prototype.render = function() { cls.prototype.render = function() {
@ -193,7 +193,7 @@ export default class SettingsMenu extends Module {
} }
this.ModSettingsMenu.forceUpdate(); this.ModSettingsMenu.forceUpdate();
}) })*/
this.SettingsMenu.on('unmount', inst => { this.SettingsMenu.on('unmount', inst => {
inst.ffzSettingsClick = null; inst.ffzSettingsClick = null;

View file

@ -33,7 +33,7 @@ const CLASSES = {
'player-rerun-bar': '.channel-root__player-container div.tw-c-text-overlay:not([data-a-target="hosting-ui-header"])', 'player-rerun-bar': '.channel-root__player-container div.tw-c-text-overlay:not([data-a-target="hosting-ui-header"])',
'pinned-cheer': '.pinned-cheer,.pinned-cheer-v2,.channel-leaderboard', 'pinned-cheer': '.pinned-cheer,.pinned-cheer-v2,.channel-leaderboard',
'whispers': 'body .whispers-open-threads,.tw-core-button[data-a-target="whisper-box-button"]', 'whispers': 'body .whispers-open-threads,.tw-core-button[data-a-target="whisper-box-button"],.whispers__pill',
'dir-live-ind': '.live-channel-card[data-ffz-type="live"] .tw-channel-status-text-indicator, article[data-ffz-type="live"] .tw-channel-status-text-indicator', 'dir-live-ind': '.live-channel-card[data-ffz-type="live"] .tw-channel-status-text-indicator, article[data-ffz-type="live"] .tw-channel-status-text-indicator',
'profile-hover': '.preview-card .tw-relative:hover .ffz-channel-avatar', 'profile-hover': '.preview-card .tw-relative:hover .ffz-channel-avatar',

View file

@ -0,0 +1,12 @@
query FFZ_UserGame($id: ID, $login: String) {
user(id: $id, login: $login) {
id
broadcastSettings {
id
game {
id
displayName
}
}
}
}

View file

@ -51,9 +51,9 @@ export const DEFAULT_TYPES = {
number(val, node) { number(val, node) {
if ( typeof val !== 'number' ) { if ( typeof val !== 'number' ) {
let new_val = parseInt(val, 10); let new_val = parseFloat(val);
if ( isNaN(new_val) || ! isFinite(new_val) ) if ( isNaN(new_val) || ! isFinite(new_val) )
new_val = parseFloat(val); new_val = parseInt(val, 10);
if ( isNaN(new_val) || ! isFinite(new_val) ) if ( isNaN(new_val) || ! isFinite(new_val) )
return val; return val;
@ -254,7 +254,16 @@ export default class TranslationCore {
formatNumber(value, format) { formatNumber(value, format) {
let formatter = this.numberFormats.get(format); let formatter = this.numberFormats.get(format);
if ( ! formatter ) { if ( ! formatter ) {
if ( this.formats.number[format] )
formatter = new Intl.NumberFormat(this.locale, this.formats.number[format]); formatter = new Intl.NumberFormat(this.locale, this.formats.number[format]);
else if ( typeof format === 'number' )
formatter = new Intl.NumberFormat(this.locale, {
minimumFractionDigits: format,
maximumFractionDigits: format
});
else
formatter = new Intl.NumberFormat(this.locale);
this.numberFormats.set(format, formatter); this.numberFormats.set(format, formatter);
} }

View file

@ -265,6 +265,29 @@ export default class TwitchData extends Module {
return get('data.user', data); return get('data.user', data);
} }
/**
* Queries Apollo for the user's current game, details given the user id or name. One of (id, login) MUST be specified
* @function getUserGame
* @memberof TwitchData
* @async
*
* @param {int|string|null|undefined} id - the user id number (can be an integer string)
* @param {string|null|undefined} login - the username
* @returns {Object} information about the requested user
*
* @example
*
* console.log(this.twitch_data.getUserGame(19571641, null));
*/
async getUserGame(id, login) {
const data = await this.queryApollo(
await import(/* webpackChunkName: 'queries' */ './data/user-game.gql'),
{ id, login }
);
return get('data.user.broadcastSettings.game', data);
}
/** /**
* Queries Apollo for the logged in user's relationship to the channel with given the id or name. One of (id, login) MUST be specified * Queries Apollo for the logged in user's relationship to the channel with given the id or name. One of (id, login) MUST be specified
* @function getUserSelf * @function getUserSelf