mirror of
https://github.com/FrankerFaceZ/FrankerFaceZ.git
synced 2025-06-27 21:05:53 +00:00
4.20.76
* Fixed: Color picker for chat filtering opening up and going out of view. (Can still go *down* out of view, but it's a start.) * Fixed: Square Avatar and hide LIVE indicator not working on the channel page. * Fixed: Modify `webmunch` and `switchboard` to better handle the latest webpack update, adding checks to make sure we don't accidentally break state by requiring an unloaded module.
This commit is contained in:
parent
16ab515b4b
commit
a91907c869
12 changed files with 402 additions and 62 deletions
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "frankerfacez",
|
||||
"author": "Dan Salvato LLC",
|
||||
"version": "4.20.75",
|
||||
"version": "4.20.76",
|
||||
"description": "FrankerFaceZ is a Twitch enhancement suite.",
|
||||
"license": "Apache-2.0",
|
||||
"scripts": {
|
||||
|
|
157
src/clips.js
Normal file
157
src/clips.js
Normal file
|
@ -0,0 +1,157 @@
|
|||
'use strict';
|
||||
|
||||
import dayjs from 'dayjs';
|
||||
import RavenLogger from './raven';
|
||||
|
||||
import Logger from 'utilities/logging';
|
||||
import Module from 'utilities/module';
|
||||
|
||||
import {DEBUG} from 'utilities/constants';
|
||||
import {timeout} from 'utilities/object';
|
||||
|
||||
import SettingsManager from './settings/index';
|
||||
import AddonManager from './addons';
|
||||
import ExperimentManager from './experiments';
|
||||
import {TranslationManager} from './i18n';
|
||||
|
||||
import Site from './sites/clips';
|
||||
import Tooltips from 'src/modules/tooltips';
|
||||
import Chat from 'src/modules/chat';
|
||||
|
||||
class FrankerFaceZ extends Module {
|
||||
constructor() {
|
||||
super();
|
||||
const start_time = performance.now(),
|
||||
VER = FrankerFaceZ.version_info;
|
||||
|
||||
FrankerFaceZ.instance = this;
|
||||
|
||||
this.flavor = 'clips';
|
||||
this.name = 'ffz_clips';
|
||||
this.__state = 0;
|
||||
this.__modules.core = this;
|
||||
|
||||
// ========================================================================
|
||||
// Error Reporting and Logging
|
||||
// ========================================================================
|
||||
|
||||
this.inject('raven', RavenLogger);
|
||||
|
||||
this.log = new Logger(null, null, null, this.raven);
|
||||
this.log.label = 'FFZClips';
|
||||
this.log.init = true;
|
||||
|
||||
this.core_log = this.log.get('core');
|
||||
|
||||
this.log.info(`FrankerFaceZ Standalone Clips v${VER} (build ${VER.build}${VER.commit ? ` - commit ${VER.commit}` : ''})`);
|
||||
|
||||
|
||||
// ========================================================================
|
||||
// Core Systems
|
||||
// ========================================================================
|
||||
|
||||
this.inject('settings', SettingsManager);
|
||||
this.inject('experiments', ExperimentManager);
|
||||
this.inject('i18n', TranslationManager);
|
||||
this.inject('site', Site);
|
||||
this.inject('addons', AddonManager);
|
||||
|
||||
// ========================================================================
|
||||
// Startup
|
||||
// ========================================================================
|
||||
|
||||
this.inject('tooltips', Tooltips);
|
||||
this.register('chat', Chat);
|
||||
|
||||
this.enable().then(() => {
|
||||
const duration = performance.now() - start_time;
|
||||
this.core_log.info(`Initialization complete in ${duration.toFixed(5)}ms.`);
|
||||
this.log.init = false;
|
||||
}).catch(err => {
|
||||
this.core_log.error(`An error occurred during initialization.`, err);
|
||||
this.log.init = false;
|
||||
});
|
||||
}
|
||||
|
||||
static get() {
|
||||
return FrankerFaceZ.instance;
|
||||
}
|
||||
|
||||
// ========================================================================
|
||||
// Generate Log
|
||||
// ========================================================================
|
||||
|
||||
async generateLog() {
|
||||
const promises = [];
|
||||
for(const key in this.__modules) { // eslint-disable-line guard-for-in
|
||||
const module = this.__modules[key];
|
||||
if ( module instanceof Module && module.generateLog && module != this )
|
||||
promises.push((async () => {
|
||||
try {
|
||||
return [
|
||||
key,
|
||||
await timeout(Promise.resolve(module.generateLog()), 5000)
|
||||
];
|
||||
} catch(err) {
|
||||
return [
|
||||
key,
|
||||
`Error: ${err}`
|
||||
]
|
||||
}
|
||||
})());
|
||||
}
|
||||
|
||||
const out = await Promise.all(promises);
|
||||
|
||||
if ( this.log.captured_init && this.log.captured_init.length > 0 ) {
|
||||
const logs = [];
|
||||
for(const msg of this.log.captured_init) {
|
||||
const time = dayjs(msg.time).locale('en').format('H:mm:ss');
|
||||
logs.push(`[${time}] ${msg.level} | ${msg.category || 'core'}: ${msg.message}`);
|
||||
}
|
||||
|
||||
out.unshift(['initialization', logs.join('\n')]);
|
||||
}
|
||||
|
||||
return out.map(x => `${x[0]}
|
||||
-------------------------------------------------------------------------------
|
||||
${typeof x[1] === 'string' ? x[1] : JSON.stringify(x[1], null, 4)}`).join('\n\n');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
FrankerFaceZ.Logger = Logger;
|
||||
|
||||
const VER = FrankerFaceZ.version_info = {
|
||||
major: __version_major__,
|
||||
minor: __version_minor__,
|
||||
revision: __version_patch__,
|
||||
extra: __version_prerelease__?.length && __version_prerelease__[0],
|
||||
commit: __git_commit__,
|
||||
build: __webpack_hash__,
|
||||
toString: () =>
|
||||
`${VER.major}.${VER.minor}.${VER.revision}${VER.extra || ''}${DEBUG ? '-dev' : ''}`
|
||||
}
|
||||
|
||||
// We don't support addons in the player right now, so
|
||||
FrankerFaceZ.utilities = {
|
||||
addon: require('utilities/addon'),
|
||||
color: require('utilities/color'),
|
||||
constants: require('utilities/constants'),
|
||||
dom: require('utilities/dom'),
|
||||
events: require('utilities/events'),
|
||||
//fontAwesome: require('utilities/font-awesome'),
|
||||
//graphql: require('utilities/graphql'),
|
||||
logging: require('utilities/logging'),
|
||||
module: require('utilities/module'),
|
||||
object: require('utilities/object'),
|
||||
time: require('utilities/time'),
|
||||
tooltip: require('utilities/tooltip'),
|
||||
i18n: require('utilities/translation-core'),
|
||||
dayjs: require('dayjs'),
|
||||
popper: require('popper.js').default
|
||||
}
|
||||
|
||||
|
||||
window.FrankerFaceZ = FrankerFaceZ;
|
||||
window.ffz = new FrankerFaceZ();
|
|
@ -43,7 +43,7 @@
|
|||
</select>
|
||||
</div>
|
||||
<div v-if="colored" class="tw-flex-shrink-0 tw-mg-r-05">
|
||||
<color-picker v-if="editing" v-model="edit_data.c" :nullable="true" :show-input="false" :open-up="true" />
|
||||
<color-picker v-if="editing" v-model="edit_data.c" :nullable="true" :show-input="false" />
|
||||
<div v-else-if="term.c" class="ffz-color-preview">
|
||||
<figure :style="`background-color: ${term.c}`">
|
||||
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
>
|
||||
</div>
|
||||
<div v-if="colored" class="tw-flex-shrink-0 tw-mg-l-05">
|
||||
<color-picker v-if="editing" v-model="edit_data.c" :nullable="true" :show-input="false" :open-up="true" />
|
||||
<color-picker v-if="editing" v-model="edit_data.c" :nullable="true" :show-input="false" />
|
||||
<div v-else-if="term.c" class="ffz-color-preview">
|
||||
<figure :style="`background-color: ${term.c}`">
|
||||
|
||||
|
|
|
@ -40,7 +40,7 @@ const CLASSES = {
|
|||
'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',
|
||||
'not-live-bar': 'div[data-test-selector="non-live-video-banner-layout"]',
|
||||
'channel-live-ind': '.channel-header__user .tw-channel-status-text-indicator,.channel-info-content .user-avatar-animated__live',
|
||||
'channel-live-ind': '.channel-header__user .tw-channel-status-text-indicator,.channel-info-content .tw-halo__indicator',
|
||||
'celebration': 'body .celebration__overlay',
|
||||
'mod-view': '.chat-input__buttons-container .tw-core-button[href*="/moderator"]'
|
||||
};
|
||||
|
|
|
@ -6,7 +6,9 @@
|
|||
}
|
||||
|
||||
.user-avatar-card__halo,
|
||||
.player-streaminfo__picture img[src] {
|
||||
.player-streaminfo__picture img[src],
|
||||
.channel-info-content .tw-halo,
|
||||
.channel-info-content .tw-halo:before {
|
||||
border-radius: 0 !important;
|
||||
}
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
import Module from 'utilities/module';
|
||||
import pathToRegexp from 'path-to-regexp';
|
||||
import { sleep } from 'src/utilities/object';
|
||||
|
||||
|
||||
export default class Switchboard extends Module {
|
||||
|
@ -21,7 +22,7 @@ export default class Switchboard extends Module {
|
|||
}
|
||||
|
||||
|
||||
awaitRouter() {
|
||||
awaitRouter(count = 0) {
|
||||
const router = this.fine.searchTree(null,
|
||||
n => (n.logger && n.logger.category === 'default-root-router') ||
|
||||
(n.onHistoryChange && n.reportInteractive) ||
|
||||
|
@ -31,7 +32,51 @@ export default class Switchboard extends Module {
|
|||
if ( router )
|
||||
return Promise.resolve(router);
|
||||
|
||||
return new Promise(r => setTimeout(r, 50)).then(() => this.awaitRouter());
|
||||
if ( count > 50 )
|
||||
return Promise.resolve(null);
|
||||
|
||||
return sleep(50).then(() => this.awaitRouter(count + 1));
|
||||
}
|
||||
|
||||
|
||||
awaitRoutes(count = 0) {
|
||||
const routes = this.fine.searchTree(null,
|
||||
n => n.props?.component && n.props.path,
|
||||
100, 0, false, true);
|
||||
|
||||
if ( routes?.size )
|
||||
return Promise.resolve(routes);
|
||||
|
||||
if ( count > 50 )
|
||||
return Promise.resolve(null);
|
||||
|
||||
return sleep(50).then(() => this.awaitRoutes(count + 1));
|
||||
}
|
||||
|
||||
|
||||
getSwitches(routes) {
|
||||
const switches = new Set;
|
||||
for(const route of routes) {
|
||||
const switchy = this.fine.searchParent(route, n => n.props?.children);
|
||||
if ( switchy )
|
||||
switches.add(switchy);
|
||||
}
|
||||
|
||||
return switches;
|
||||
}
|
||||
|
||||
|
||||
getPossibleRoutes(switches) { // eslint-disable-line class-methods-use-this
|
||||
const routes = new Set;
|
||||
for(const switchy of switches) {
|
||||
if ( Array.isArray(switchy?.props?.children) )
|
||||
for(const child of switchy.props.children) {
|
||||
if ( child?.props?.component )
|
||||
routes.add(child);
|
||||
}
|
||||
}
|
||||
|
||||
return routes;
|
||||
}
|
||||
|
||||
|
||||
|
@ -46,7 +91,7 @@ export default class Switchboard extends Module {
|
|||
if ( count > 50 )
|
||||
return Promise.resolve(null);
|
||||
|
||||
return new Promise(r => setTimeout(r, 50)).then(() => this.awaitRoute(count + 1));
|
||||
return sleep(50).then(() => this.awaitRoute(count + 1));
|
||||
}
|
||||
|
||||
|
||||
|
@ -57,16 +102,16 @@ export default class Switchboard extends Module {
|
|||
|
||||
// Find the current route.
|
||||
const route = await this.awaitRoute(),
|
||||
da_switch = route && this.fine.searchParent(route, n => n.props && n.props.children);
|
||||
da_switch = route && this.fine.searchParent(route, n => n.props?.children);
|
||||
|
||||
if ( ! da_switch )
|
||||
return new Promise(r => setTimeout(r, 50)).then(() => this.onEnable());
|
||||
return sleep(50).then(() => this.onEnable());
|
||||
|
||||
// Identify Router
|
||||
const router = await this.awaitRouter();
|
||||
|
||||
this.log.info(`Found Route and Switch with ${da_switch.props.children.length} routes.`);
|
||||
this.da_switch = da_switch;
|
||||
this.possible = da_switch.props.children;
|
||||
this.location = router.props.location.pathname;
|
||||
//const location = router.props.location.pathname;
|
||||
|
||||
|
@ -78,9 +123,31 @@ export default class Switchboard extends Module {
|
|||
});
|
||||
}
|
||||
|
||||
async startMultiRouter() {
|
||||
this.multi_router = true;
|
||||
|
||||
const routes = await this.awaitRoutes();
|
||||
if ( ! routes?.size )
|
||||
return this.log.info(`Unable to find any <Route/>s for multi-router.`);
|
||||
|
||||
const switches = this.getSwitches(routes);
|
||||
if ( ! switches?.size )
|
||||
return this.log.info(`Unable to find any switches for multi-router.`);
|
||||
|
||||
this.possible = this.getPossibleRoutes(switches);
|
||||
this.log.info(`Found ${routes.size} Routes with ${switches.size} Switches and ${this.possible.size} routes.`);
|
||||
|
||||
this.loadOne();
|
||||
}
|
||||
|
||||
loadOne() {
|
||||
if ( ! this.loadRoute(false) )
|
||||
this.loadRoute(true);
|
||||
if ( ! this.loadRoute(true) ) {
|
||||
if ( ! this.multi_router )
|
||||
this.startMultiRouter();
|
||||
else
|
||||
this.log.info(`There are no routes that can be used to load a chunk. Tried ${this.tried.size} routes.`);
|
||||
}
|
||||
}
|
||||
|
||||
waitAndSee() {
|
||||
|
@ -88,13 +155,13 @@ export default class Switchboard extends Module {
|
|||
if ( this.web_munch._require )
|
||||
return;
|
||||
|
||||
this.log.info('We still need require(). Trying again.');
|
||||
this.log.debug('We still need require(). Trying again.');
|
||||
this.loadOne();
|
||||
});
|
||||
}
|
||||
|
||||
loadRoute(with_params) {
|
||||
for(const route of this.da_switch.props.children) {
|
||||
for(const route of this.possible) {
|
||||
if ( ! route.props || ! route.props.component )
|
||||
continue;
|
||||
|
||||
|
@ -114,7 +181,7 @@ export default class Switchboard extends Module {
|
|||
}
|
||||
|
||||
this.tried.add(route.props.path);
|
||||
this.log.info('Found Non-Matching Route', route.props.path);
|
||||
this.log.debug('Found Non-Matching Route', route.props.path);
|
||||
|
||||
const component_class = route.props.component;
|
||||
|
||||
|
@ -124,7 +191,8 @@ export default class Switchboard extends Module {
|
|||
try {
|
||||
component = component_class.Preload({priority: 1});
|
||||
} catch(err) {
|
||||
this.log.warn('Error instantiating preloader for forced chunk loading.', err);
|
||||
this.log.warn('Error instantiating preloader for forced chunk loading.');
|
||||
this.log.debug('Captured Error', err);
|
||||
component = null;
|
||||
}
|
||||
|
||||
|
@ -133,18 +201,19 @@ export default class Switchboard extends Module {
|
|||
|
||||
try {
|
||||
component.props.loader().then(() => {
|
||||
this.log.info('Successfully forced a chunk to load using route', route.props.path)
|
||||
this.log.debug('Successfully loaded route', route.props.path)
|
||||
this.waitAndSee();
|
||||
});
|
||||
} catch(err) {
|
||||
this.log.warn('Unexpected result trying to use component pre-loader to force loading of another chunk.');
|
||||
this.log.warn('Unexpected result trying to use component pre-loader.');
|
||||
}
|
||||
|
||||
} else {
|
||||
try {
|
||||
component = new route.props.component;
|
||||
} catch(err) {
|
||||
this.log.warn('Error instantiating component for forced chunk loading.', err);
|
||||
this.log.warn('Error instantiating component for forced chunk loading.');
|
||||
this.log.debug('Captured Error', err);
|
||||
component = null;
|
||||
}
|
||||
|
||||
|
@ -153,11 +222,11 @@ export default class Switchboard extends Module {
|
|||
|
||||
try {
|
||||
component.props.children.props.loader().then(() => {
|
||||
this.log.info('Successfully forced a chunk to load using route', route.props.path)
|
||||
this.log.debug('Successfully loaded route', route.props.path)
|
||||
this.waitAndSee();
|
||||
});
|
||||
} catch(err) {
|
||||
this.log.warn('Unexpected result trying to use component loader to force loading of another chunk.');
|
||||
this.log.warn('Unexpected result trying to use component loader.');
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -47,7 +47,7 @@
|
|||
v-if="open"
|
||||
v-on-clickaway="closePicker"
|
||||
:class="{'ffz-bottom-100': openUp}"
|
||||
class="tw-absolute tw-z-above ffz-balloon--up ffz-balloon--right"
|
||||
class="tw-absolute tw-z-above tw-tooltip--down tw-tooltip--align-right"
|
||||
>
|
||||
<chrome-picker :disable-alpha="! alpha" :value="colors" @input="onPick" />
|
||||
</div>
|
||||
|
|
|
@ -246,7 +246,7 @@ export default class Fine extends Module {
|
|||
}
|
||||
}
|
||||
|
||||
searchTree(node, criteria, max_depth=15, depth=0, traverse_roots = true) {
|
||||
searchTree(node, criteria, max_depth=15, depth=0, traverse_roots = true, multi = false) {
|
||||
if ( ! node )
|
||||
node = this.react;
|
||||
else if ( node._reactInternalFiber )
|
||||
|
@ -254,8 +254,16 @@ export default class Fine extends Module {
|
|||
else if ( node instanceof Node )
|
||||
node = this.getReactInstance(node);
|
||||
|
||||
if ( multi ) {
|
||||
if ( !(multi instanceof Set) )
|
||||
multi = new Set;
|
||||
}
|
||||
|
||||
if ( multi && ! (multi instanceof Set) )
|
||||
multi = new Set;
|
||||
|
||||
if ( ! node || node._ffz_no_scan || depth > max_depth )
|
||||
return null;
|
||||
return multi ? multi : null;
|
||||
|
||||
if ( typeof criteria === 'string' ) {
|
||||
const wrapper = this._wrappers.get(criteria);
|
||||
|
@ -263,20 +271,24 @@ export default class Fine extends Module {
|
|||
throw new Error('invalid critera');
|
||||
|
||||
if ( ! wrapper._class )
|
||||
return null;
|
||||
return multi ? multi : null;
|
||||
|
||||
criteria = n => n && n.constructor === wrapper._class;
|
||||
}
|
||||
|
||||
const inst = node.stateNode;
|
||||
if ( inst && criteria(inst, node) )
|
||||
return inst;
|
||||
if ( inst && criteria(inst, node) ) {
|
||||
if ( multi )
|
||||
multi.add(inst);
|
||||
else
|
||||
return inst;
|
||||
}
|
||||
|
||||
if ( node.child ) {
|
||||
let child = node.child;
|
||||
while(child) {
|
||||
const result = this.searchTree(child, criteria, max_depth, depth+1, traverse_roots);
|
||||
if ( result )
|
||||
const result = this.searchTree(child, criteria, max_depth, depth+1, traverse_roots, multi);
|
||||
if ( result && ! multi )
|
||||
return result;
|
||||
child = child.sibling;
|
||||
}
|
||||
|
@ -287,14 +299,17 @@ export default class Fine extends Module {
|
|||
if ( root ) {
|
||||
let child = root._internalRoot && root._internalRoot.current || root.current;
|
||||
while(child) {
|
||||
const result = this.searchTree(child, criteria, max_depth, depth+1, traverse_roots);
|
||||
if ( result )
|
||||
const result = this.searchTree(child, criteria, max_depth, depth+1, traverse_roots, multi);
|
||||
if ( result && ! multi )
|
||||
return result;
|
||||
|
||||
child = child.sibling;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( multi )
|
||||
return multi;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -55,7 +55,7 @@ export default class Subpump extends Module {
|
|||
return;
|
||||
}
|
||||
|
||||
for(const [key, val] of Object.entries(instances))
|
||||
for(const val of Object.values(instances))
|
||||
if ( val?._client ) {
|
||||
if ( this.instance ) {
|
||||
this.log.warn('Multiple PubSub instances detected. Things might act weird.');
|
||||
|
|
|
@ -6,8 +6,20 @@
|
|||
// ============================================================================
|
||||
|
||||
import Module from 'utilities/module';
|
||||
import {has, sleep} from 'utilities/object';
|
||||
import { DEBUG } from '../constants';
|
||||
import {has} from 'utilities/object';
|
||||
import { DEBUG } from 'utilities/constants';
|
||||
|
||||
|
||||
const Requires = Symbol('FFZRequires');
|
||||
|
||||
const regex_cache = {};
|
||||
|
||||
function getRequireRegex(name) {
|
||||
if ( ! regex_cache[name] )
|
||||
regex_cache[name] = new RegExp(`\\b${name}\\(([0-9a-zA-Z_+]+)\\)`, 'g');
|
||||
|
||||
return regex_cache[name];
|
||||
}
|
||||
|
||||
const NAMES = [
|
||||
'webpackJsonp',
|
||||
|
@ -34,8 +46,11 @@ export default class WebMunch extends Module {
|
|||
this._chunk_names = {};
|
||||
this._mod_cache = {};
|
||||
|
||||
this._checked_module = {};
|
||||
this._required_ids = new Set;
|
||||
this._known_ids = new Set;
|
||||
|
||||
this.Requires = Requires;
|
||||
this.v4 = null;
|
||||
|
||||
this.hookLoader();
|
||||
|
@ -107,12 +122,9 @@ export default class WebMunch extends Module {
|
|||
this._original_loader = thing.push;
|
||||
|
||||
// Wrap all existing modules in case any of them haven't been required yet.
|
||||
// However, there's an issue with this causing loading issues on the
|
||||
// dashboard. Somehow. Not sure, so just don't do it on that page.
|
||||
if ( ! location.hostname.includes('dashboard') )
|
||||
for(const chunk of thing)
|
||||
if ( chunk && chunk[1] )
|
||||
this.processModulesV4(chunk[1]);
|
||||
for(const chunk of thing)
|
||||
if ( chunk && chunk[1] )
|
||||
this.processModulesV4(chunk[1], true);
|
||||
|
||||
try {
|
||||
thing.push = this.webpackJsonpv4.bind(this);
|
||||
|
@ -146,29 +158,40 @@ export default class WebMunch extends Module {
|
|||
}
|
||||
|
||||
|
||||
_resolveRequire(require) {
|
||||
if ( this._require )
|
||||
return;
|
||||
|
||||
this._require = require;
|
||||
if ( this._resolve_require ) {
|
||||
for(const fn of this._resolve_require)
|
||||
fn(require);
|
||||
|
||||
this._resolve_require = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
processModulesV4(modules) {
|
||||
const t = this;
|
||||
|
||||
for(const [mod_id, original_module] of Object.entries(modules)) {
|
||||
this._known_ids.add(mod_id);
|
||||
|
||||
modules[mod_id] = function(module, exports, require, ...args) {
|
||||
if ( ! t._require && typeof require === 'function' ) {
|
||||
t.log.info(`require() grabbed from invocation of module ${mod_id}`);
|
||||
t._require = require;
|
||||
if ( t._resolve_require ) {
|
||||
try {
|
||||
for(const fn of t._resolve_require)
|
||||
fn(require);
|
||||
} catch(err) {
|
||||
t.log.error('An error occurred running require callbacks.', err);
|
||||
}
|
||||
|
||||
t._resolve_require = null;
|
||||
t.log.debug(`require() grabbed from invocation of module ${mod_id}`);
|
||||
try {
|
||||
t._resolveRequire(require);
|
||||
} catch(err) {
|
||||
t.log.error('An error occurred running require callbacks.', err);
|
||||
}
|
||||
}
|
||||
|
||||
return original_module.call(this, module, exports, require, ...args);
|
||||
}
|
||||
|
||||
modules[mod_id].original = original_module;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -176,14 +199,15 @@ export default class WebMunch extends Module {
|
|||
webpackJsonpv4(data) {
|
||||
const chunk_ids = data[0],
|
||||
modules = data[1],
|
||||
names = Array.isArray(chunk_ids) && chunk_ids.map(x => this._chunk_names[x] || x).join(', ');
|
||||
names = Array.isArray(chunk_ids) && chunk_ids.map(x => this._chunk_names[x] || x);
|
||||
|
||||
this.log.verbose(`Twitch Chunk Loaded: ${chunk_ids} (${names})`);
|
||||
this.log.verbose(`Twitch Chunk Loaded: ${chunk_ids} (${names.join(', ')})`);
|
||||
this.log.verbose(`Modules: ${Object.keys(modules)}`);
|
||||
|
||||
if ( modules )
|
||||
this.processModulesV4(modules);
|
||||
this.processModulesV4(modules, false);
|
||||
|
||||
this._checked_module = {};
|
||||
const res = this._original_loader.apply(this._original_store, arguments); // eslint-disable-line prefer-rest-params
|
||||
this.emit(':loaded', chunk_ids, names, modules);
|
||||
return res;
|
||||
|
@ -296,10 +320,16 @@ export default class WebMunch extends Module {
|
|||
if ( ! this._original_store )
|
||||
return null;
|
||||
|
||||
const out = new Set;
|
||||
|
||||
for(const [chunks, modules] of this._original_store) {
|
||||
if ( modules[id] )
|
||||
return chunks;
|
||||
if ( modules[id] ) {
|
||||
for(const chunk of chunks)
|
||||
out.add(chunk);
|
||||
}
|
||||
}
|
||||
|
||||
return [...out];
|
||||
}
|
||||
|
||||
chunkNameForModule(id) {
|
||||
|
@ -316,6 +346,14 @@ export default class WebMunch extends Module {
|
|||
return null;
|
||||
}
|
||||
|
||||
chunkNamesForModule(id) {
|
||||
const chunks = this._chunksForModule(id);
|
||||
if ( ! chunks )
|
||||
return null;
|
||||
|
||||
return chunks.map(id => this._chunk_names[id] || id);
|
||||
}
|
||||
|
||||
|
||||
_oldGetModule(key, predicate, require) {
|
||||
if ( ! require || ! require.c )
|
||||
|
@ -358,7 +396,7 @@ export default class WebMunch extends Module {
|
|||
if ( mod ) {
|
||||
const ret = predicate(mod);
|
||||
if ( ret ) {
|
||||
this.log.debug(`Located module "${key}" in module ${k}${DEBUG ? ` (${this.chunkNameForModule(k)})` : ''} after ${checked} tries`);
|
||||
this.log.debug(`[Old] Located module "${key}" in module ${k}${DEBUG ? ` (${this.chunkNameForModule(k)})` : ''} after ${checked} tries`);
|
||||
const out = predicate.use_result ? ret : mod;
|
||||
if ( key )
|
||||
this._mod_cache[key] = out;
|
||||
|
@ -367,7 +405,7 @@ export default class WebMunch extends Module {
|
|||
}
|
||||
}
|
||||
|
||||
this.log.debug(`Unable to locate module "${key}"`);
|
||||
this.log.debug(`[Old] Unable to locate module "${key}" despite checking ${checked} modules`);
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -405,6 +443,22 @@ export default class WebMunch extends Module {
|
|||
for(const id of ids) {
|
||||
try {
|
||||
checked++;
|
||||
|
||||
// If we have not previously required this module, check to see
|
||||
// if we CAN require this module. We want to avoid requiring a
|
||||
// module that doesn't yet have a constructor because that will
|
||||
// break webpack's internal state.
|
||||
if ( ! this._required_ids.has(id) ) {
|
||||
let check = this._checked_module[id];
|
||||
if ( check == null )
|
||||
check = this._checkModule(id);
|
||||
|
||||
if ( check )
|
||||
continue;
|
||||
}
|
||||
|
||||
this._required_ids.add(id);
|
||||
|
||||
const mod = require(id);
|
||||
if ( mod ) {
|
||||
const ret = predicate(mod);
|
||||
|
@ -421,11 +475,50 @@ export default class WebMunch extends Module {
|
|||
}
|
||||
}
|
||||
|
||||
this.log.debug(`Unable to locate module "${key}"`);
|
||||
this.log.debug(`Unable to locate module "${key}" despite checking ${checked} modules`);
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
_checkModule(id) {
|
||||
const fn = this._require?.m?.[id];
|
||||
if ( fn ) {
|
||||
let reqs = fn[Requires],
|
||||
banned = false;
|
||||
|
||||
if ( reqs == null ) {
|
||||
const str = fn.toString(),
|
||||
name_match = /^function\([^,)]+,[^,)]+,([^,)]+)/.exec(str);
|
||||
|
||||
if ( name_match ) {
|
||||
const regex = getRequireRegex(name_match[1]);
|
||||
reqs = fn[Requires] = new Set;
|
||||
|
||||
regex.lastIndex = 0;
|
||||
let match;
|
||||
|
||||
while((match = regex.exec(str))) {
|
||||
const mod_id = match[1];
|
||||
reqs.add(mod_id);
|
||||
|
||||
if ( ! this._require.m[mod_id] )
|
||||
banned = true;
|
||||
}
|
||||
|
||||
} else
|
||||
fn[Requires] = false;
|
||||
|
||||
} else if ( reqs ) {
|
||||
for(const mod_id of reqs)
|
||||
if ( ! this._require.m[mod_id] )
|
||||
banned = true;
|
||||
}
|
||||
|
||||
return this._checked_module[id] = banned;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ========================================================================
|
||||
// Grabbing Require
|
||||
// ========================================================================
|
||||
|
@ -515,9 +608,11 @@ export default class WebMunch extends Module {
|
|||
}
|
||||
|
||||
this._chunk_names = modules;
|
||||
this.log.info(`Loaded names for ${Object.keys(modules).length} chunks from require().`)
|
||||
this.log.debug(`Loaded names for ${Object.keys(modules).length} chunks from require().`)
|
||||
} else
|
||||
this.log.warn(`Unable to find chunk names in require().`);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
WebMunch.Requires = Requires;
|
|
@ -1,5 +1,7 @@
|
|||
'use strict';
|
||||
|
||||
import { has } from 'utilities/object';
|
||||
|
||||
const RAVEN_LEVELS = {
|
||||
1: 'debug',
|
||||
2: 'info',
|
||||
|
@ -14,7 +16,7 @@ function readLSLevel() {
|
|||
return null;
|
||||
|
||||
const upper = level.toUpperCase();
|
||||
if ( Logger[upper] )
|
||||
if ( has(Logger, upper) )
|
||||
return Logger[upper];
|
||||
|
||||
if ( /^\d+$/.test(level) )
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue