mirror of
https://github.com/FrankerFaceZ/FrankerFaceZ.git
synced 2025-06-27 21:05:53 +00:00
4.5.5
* Added: Synchronize applicable settings to `clips.twitch.tv` pages using an iframe. * Fixed: Issue with chat replay disappearing on `clips.twitch.tv` pages. * Changed: Pull the FFZ version number from `package.json`.
This commit is contained in:
parent
04aa1789a2
commit
f1c527b721
14 changed files with 314 additions and 23 deletions
|
@ -29,6 +29,10 @@ module.exports = {
|
|||
"require": false,
|
||||
"__webpack_hash__": false,
|
||||
"__git_commit__": false,
|
||||
"__version_major__": false,
|
||||
"__version_minor__": false,
|
||||
"__version_patch__": false,
|
||||
"__version_prerelease__": false,
|
||||
"FrankerFaceZ": false
|
||||
},
|
||||
"rules": {
|
||||
|
|
48
package-lock.json
generated
48
package-lock.json
generated
|
@ -58,6 +58,12 @@
|
|||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
||||
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
|
||||
"dev": true
|
||||
},
|
||||
"semver": {
|
||||
"version": "5.7.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz",
|
||||
"integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -1738,6 +1744,14 @@
|
|||
"semver": "^5.5.0",
|
||||
"shebang-command": "^1.2.0",
|
||||
"which": "^1.2.9"
|
||||
},
|
||||
"dependencies": {
|
||||
"semver": {
|
||||
"version": "5.7.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz",
|
||||
"integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"crypto-browserify": {
|
||||
|
@ -2285,6 +2299,12 @@
|
|||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
||||
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
|
||||
"dev": true
|
||||
},
|
||||
"semver": {
|
||||
"version": "5.7.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz",
|
||||
"integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -4695,6 +4715,14 @@
|
|||
"requires": {
|
||||
"pify": "^4.0.1",
|
||||
"semver": "^5.6.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"semver": {
|
||||
"version": "5.7.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz",
|
||||
"integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"mamacro": {
|
||||
|
@ -5280,6 +5308,14 @@
|
|||
"resolve": "^1.10.0",
|
||||
"semver": "2 || 3 || 4 || 5",
|
||||
"validate-npm-package-license": "^3.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"semver": {
|
||||
"version": "5.7.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz",
|
||||
"integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"normalize-path": {
|
||||
|
@ -6610,6 +6646,12 @@
|
|||
"resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz",
|
||||
"integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=",
|
||||
"dev": true
|
||||
},
|
||||
"semver": {
|
||||
"version": "5.7.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz",
|
||||
"integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -6670,9 +6712,9 @@
|
|||
}
|
||||
},
|
||||
"semver": {
|
||||
"version": "5.7.0",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz",
|
||||
"integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==",
|
||||
"version": "6.1.1",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-6.1.1.tgz",
|
||||
"integrity": "sha512-rWYq2e5iYW+fFe/oPPtYJxYgjBm8sC4rmoGdUOgBB7VnwKt6HrL793l2voH1UlsyYZpJ4g0wfjnTEO1s1NP2eQ==",
|
||||
"dev": true
|
||||
},
|
||||
"send": {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "frankerfacez",
|
||||
"author": "Dan Salvato LLC",
|
||||
"version": "4.0.0",
|
||||
"version": "4.5.5",
|
||||
"description": "FrankerFaceZ is a Twitch enhancement suite.",
|
||||
"license": "Apache-2.0",
|
||||
"scripts": {
|
||||
|
@ -41,6 +41,7 @@
|
|||
"raw-loader": "^3.0.0",
|
||||
"rimraf": "^2.6.3",
|
||||
"sass-loader": "^7.1.0",
|
||||
"semver": "^6.1.1",
|
||||
"terser-webpack-plugin": "^1.3.0",
|
||||
"vue-loader": "^15.7.0",
|
||||
"vue-template-compiler": "^2.6.10",
|
||||
|
|
118
src/bridge.js
Normal file
118
src/bridge.js
Normal file
|
@ -0,0 +1,118 @@
|
|||
'use strict';
|
||||
|
||||
import RavenLogger from './raven';
|
||||
|
||||
import Logger from 'utilities/logging';
|
||||
import Module from 'utilities/module';
|
||||
|
||||
import {DEBUG} from 'utilities/constants';
|
||||
|
||||
import SettingsManager from './settings/index';
|
||||
|
||||
class FFZBridge extends Module {
|
||||
constructor() {
|
||||
super();
|
||||
const start_time = performance.now(),
|
||||
VER = FFZBridge.version_info;
|
||||
|
||||
FFZBridge.instance = this;
|
||||
|
||||
this.name = 'ffz_bridge';
|
||||
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.init = true;
|
||||
|
||||
this.core_log = this.log.get('core');
|
||||
|
||||
this.log.info(`FrankerFaceZ Settings Bridge v${VER} (build ${VER.build}${VER.commit ? ` - commit ${VER.commit}` : ''})`);
|
||||
|
||||
|
||||
// ========================================================================
|
||||
// Core Systems
|
||||
// ========================================================================
|
||||
|
||||
this.inject('settings', SettingsManager);
|
||||
|
||||
|
||||
// ========================================================================
|
||||
// Startup
|
||||
// ========================================================================
|
||||
|
||||
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 FFZBridge.instance;
|
||||
}
|
||||
|
||||
onEnable() {
|
||||
window.addEventListener('message', this.onMessage.bind(this));
|
||||
this.settings.provider.on('changed', this.onProviderChange, this);
|
||||
this.send({
|
||||
ffz_type: 'ready'
|
||||
});
|
||||
}
|
||||
|
||||
onMessage(event) {
|
||||
const msg = event.data;
|
||||
if ( ! msg || ! msg.ffz_type )
|
||||
return;
|
||||
|
||||
if ( msg.ffz_type === 'load' ) {
|
||||
const out = {};
|
||||
for(const [key, value] of this.settings.provider.entries())
|
||||
out[key] = value;
|
||||
|
||||
this.send({
|
||||
ffz_type: 'loaded',
|
||||
data: out
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
send(msg) { // eslint-disable-line class-methods-use-this
|
||||
try {
|
||||
window.parent.postMessage(msg, '*')
|
||||
} catch(err) { this.log.error('send error', err); /* no-op */ }
|
||||
}
|
||||
|
||||
onProviderChange(key, value, deleted) {
|
||||
this.send({
|
||||
ffz_type: 'change',
|
||||
key,
|
||||
value,
|
||||
deleted
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
FFZBridge.Logger = Logger;
|
||||
|
||||
const VER = FFZBridge.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' : ''}`
|
||||
}
|
||||
|
||||
window.FFZBridge = FFZBridge;
|
||||
window.ffz_bridge = new FFZBridge();
|
|
@ -6,6 +6,7 @@
|
|||
return;
|
||||
|
||||
const DEBUG = localStorage.ffzDebugMode == 'true' && document.body.classList.contains('ffz-dev') && ! window.Ember,
|
||||
FLAVOR = location.pathname === '/p/ffz_bridge/' ? 'bridge' : 'avalon',
|
||||
SERVER = DEBUG ? '//localhost:8000' : '//cdn.frankerfacez.com',
|
||||
CLIPS = /clips\.twitch\.tv/.test(location.hostname) ? 'clips/' : '',
|
||||
|
||||
|
@ -14,6 +15,6 @@
|
|||
script.id = 'ffz-script';
|
||||
script.async = true;
|
||||
script.crossOrigin = 'anonymous';
|
||||
script.src = `${SERVER}/script/${CLIPS}avalon.js?_=${Date.now()}`;
|
||||
script.src = `${SERVER}/script/${CLIPS}${FLAVOR}.js?_=${Date.now()}`;
|
||||
document.head.appendChild(script);
|
||||
})();
|
|
@ -149,7 +149,10 @@ ${typeof x[1] === 'string' ? x[1] : JSON.stringify(x[1], null, 4)}`).join('\n\n'
|
|||
FrankerFaceZ.Logger = Logger;
|
||||
|
||||
const VER = FrankerFaceZ.version_info = {
|
||||
major: 4, minor: 5, revision: 4,
|
||||
major: __version_major__,
|
||||
minor: __version_minor__,
|
||||
revision: __version_patch__,
|
||||
extra: __version_prerelease__?.length && __version_prerelease__[0],
|
||||
commit: __git_commit__,
|
||||
build: __webpack_hash__,
|
||||
toString: () =>
|
||||
|
|
23
src/raven.js
23
src/raven.js
|
@ -58,8 +58,6 @@ export default class RavenLogger extends Module {
|
|||
super(...args);
|
||||
|
||||
this.inject('settings');
|
||||
this.inject('site');
|
||||
this.inject('experiments');
|
||||
|
||||
// Do these in an event handler because we're initialized before
|
||||
// settings are even ready.
|
||||
|
@ -131,7 +129,7 @@ export default class RavenLogger extends Module {
|
|||
autoBreadcrumbs: {
|
||||
console: false
|
||||
},
|
||||
release: FrankerFaceZ.version_info.toString(),
|
||||
release: (window.FrankerFaceZ || window.FFZBridge).version_info.toString(),
|
||||
environment: DEBUG ? 'development' : 'production',
|
||||
captureUnhandledRejections: false,
|
||||
ignoreErrors: [
|
||||
|
@ -189,7 +187,7 @@ export default class RavenLogger extends Module {
|
|||
return false;
|
||||
|
||||
if ( this.settings && this.settings.get('reports.error.include-user') ) {
|
||||
const user = this.site && this.site.getUser();
|
||||
const user = this.resolve('site')?.getUser();
|
||||
if ( user )
|
||||
data.user = {id: user.id, username: user.login}
|
||||
}
|
||||
|
@ -305,22 +303,25 @@ export default class RavenLogger extends Module {
|
|||
chat_settings[key] = value;
|
||||
}
|
||||
|
||||
for(const [key, value] of Object.entries(this.experiments.getTwitchExperiments()))
|
||||
if ( this.experiments.usingTwitchExperiment(key) )
|
||||
twitch_experiments[value.name] = this.experiments.getTwitchAssignment(key);
|
||||
const exp = this.resolve('experiments');
|
||||
if ( exp ) {
|
||||
for(const [key, value] of Object.entries(exp.getTwitchExperiments()))
|
||||
if ( exp.usingTwitchExperiment(key) )
|
||||
twitch_experiments[value.name] = exp.getTwitchAssignment(key);
|
||||
|
||||
for(const key of Object.keys(this.experiments.experiments))
|
||||
experiments[key] = this.experiments.getAssignment(key);
|
||||
for(const key of Object.keys(exp.experiments))
|
||||
experiments[key] = exp.getAssignment(key);
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
buildTags() {
|
||||
const core = this.site.getCore(),
|
||||
const core = this.resolve('site')?.getCore(),
|
||||
out = {};
|
||||
|
||||
out.flavor = this.site.constructor.name;
|
||||
out.flavor = this.site?.constructor.name;
|
||||
out.build = __webpack_hash__;
|
||||
out.git_commit = __git_commit__;
|
||||
|
||||
|
|
|
@ -98,7 +98,7 @@ export const Page = {
|
|||
parts = [];
|
||||
|
||||
if ( Object.keys(config.values).length ) {
|
||||
const ffz = FrankerFaceZ.get(),
|
||||
const ffz = window.FrankerFaceZ?.get(),
|
||||
router = ffz && ffz.resolve('site.router');
|
||||
|
||||
if ( router ) {
|
||||
|
|
|
@ -116,7 +116,7 @@ export default class Line extends Module {
|
|||
return msg._ffz_message;
|
||||
|
||||
const room = this.chat.getRoom(video.owner.id, null, true, true),
|
||||
author = msg.commenter,
|
||||
author = msg.commenter || {},
|
||||
badges = {};
|
||||
|
||||
if ( msg.message.userBadges )
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
'use strict';
|
||||
|
||||
// ============================================================================
|
||||
// CSS Tweaks for Twitch Twilight
|
||||
// CSS Tweaks for Twitch Clips
|
||||
// ============================================================================
|
||||
|
||||
import Module from 'utilities/module';
|
||||
|
@ -21,7 +21,6 @@ export default class CSSTweaks extends Module {
|
|||
this.should_enable = true;
|
||||
|
||||
this.inject('settings');
|
||||
this.inject('site.chat');
|
||||
this.inject('site.theme');
|
||||
|
||||
this.style = new ManagedStyle;
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
.clips-chat-replay {
|
||||
font-size: var(--ffz-chat-font-size);
|
||||
a.clip-chat__message-author,
|
||||
.message {
|
||||
font-size: var(--ffz-chat-font-size) !important;
|
||||
}
|
||||
|
||||
line-height: var(--ffz-chat-line-height);
|
||||
font-family: var(--ffz-chat-font-family);
|
||||
}
|
104
src/sites/twitch-clips/modules/settings_sync.js
Normal file
104
src/sites/twitch-clips/modules/settings_sync.js
Normal file
|
@ -0,0 +1,104 @@
|
|||
'use strict';
|
||||
|
||||
// ============================================================================
|
||||
// Settings Sync
|
||||
// ============================================================================
|
||||
|
||||
import Module from 'utilities/module';
|
||||
import {createElement} from 'utilities/dom';
|
||||
|
||||
const VALID_KEYS = [
|
||||
'client-id',
|
||||
'profiles'
|
||||
];
|
||||
|
||||
export default class SettingsSync extends Module {
|
||||
constructor(...args) {
|
||||
super(...args);
|
||||
|
||||
this.should_enable = true;
|
||||
|
||||
this.inject('settings');
|
||||
}
|
||||
|
||||
onEnable() {
|
||||
const frame = this.frame = createElement('iframe');
|
||||
frame.src = '//www.twitch.tv/p/ffz_bridge/';
|
||||
frame.id = 'ffz-settings-bridge';
|
||||
frame.style.width = 0;
|
||||
frame.style.height = 0;
|
||||
|
||||
window.addEventListener('message', this.onMessage.bind(this));
|
||||
document.body.appendChild(frame);
|
||||
}
|
||||
|
||||
send(msg) {
|
||||
try {
|
||||
this.frame.contentWindow.postMessage(msg, '*');
|
||||
} catch(err) { this.log.error('send error', err); /* no-op */ }
|
||||
}
|
||||
|
||||
onMessage(event) {
|
||||
const msg = event.data;
|
||||
if ( ! msg || ! msg.ffz_type )
|
||||
return;
|
||||
|
||||
if ( msg.ffz_type === 'ready' )
|
||||
this.send({ffz_type: 'load'});
|
||||
else if ( msg.ffz_type === 'loaded' )
|
||||
this.onLoad(msg.data);
|
||||
else if ( msg.ffz_type === 'change' )
|
||||
this.onChange(msg);
|
||||
else
|
||||
this.log.info('Unknown Message', msg.ffz_type, msg);
|
||||
}
|
||||
|
||||
onLoad(data) {
|
||||
if ( ! data )
|
||||
return;
|
||||
|
||||
const provider = this.settings.provider,
|
||||
old_keys = new Set(provider.keys());
|
||||
|
||||
for(const [key, value] of Object.entries(data)) {
|
||||
old_keys.delete(key);
|
||||
if ( ! this.isValidSetting(key) || provider.get(key) === value )
|
||||
continue;
|
||||
|
||||
provider.set(key, value);
|
||||
provider.emit('changed', key, value, false);
|
||||
}
|
||||
|
||||
for(const key of old_keys) {
|
||||
provider.delete(key);
|
||||
provider.emit('changed', key, undefined, true);
|
||||
}
|
||||
}
|
||||
|
||||
onChange(msg) {
|
||||
const key = msg.key,
|
||||
value = msg.value,
|
||||
deleted = msg.deleted;
|
||||
|
||||
if ( ! this.isValidSetting(key) )
|
||||
return;
|
||||
|
||||
if ( deleted )
|
||||
this.settings.provider.delete(key);
|
||||
else
|
||||
this.settings.provider.set(key, value);
|
||||
|
||||
this.settings.provider.emit('changed', key, value, deleted);
|
||||
}
|
||||
|
||||
isValidSetting(key) {
|
||||
if ( ! key.startsWith('p:') )
|
||||
return VALID_KEYS.includes(key);
|
||||
|
||||
const idx = key.indexOf(':', 2);
|
||||
if ( idx === -1 )
|
||||
return false;
|
||||
|
||||
return this.settings.definitions.has(key.slice(idx + 1));
|
||||
}
|
||||
}
|
|
@ -57,6 +57,11 @@ module.exports = merge(common, {
|
|||
next();
|
||||
});
|
||||
|
||||
app.get('/script/bridge.js', (req, res, next) => {
|
||||
req.url = req.url.replace(/^\/script/, '/script/clips');
|
||||
next();
|
||||
});
|
||||
|
||||
app.get('/dev_server', (req, res) => {
|
||||
res.json({
|
||||
path: process.cwd(),
|
||||
|
|
|
@ -1,14 +1,17 @@
|
|||
const webpack = require('webpack');
|
||||
const path = require('path');
|
||||
const semver = require('semver');
|
||||
|
||||
const VueLoaderPlugin = require('vue-loader/lib/plugin');
|
||||
|
||||
/* global process module __dirname */
|
||||
|
||||
const VERSION = semver.parse(require('./package.json').version);
|
||||
const PRODUCTION = process.env.NODE_ENV === 'production';
|
||||
|
||||
module.exports = {
|
||||
entry: {
|
||||
bridge: './src/bridge.js',
|
||||
avalon: './src/main.js'
|
||||
},
|
||||
resolve: {
|
||||
|
@ -43,7 +46,13 @@ module.exports = {
|
|||
},
|
||||
plugins: [
|
||||
new VueLoaderPlugin(),
|
||||
new webpack.ExtendedAPIPlugin()
|
||||
new webpack.ExtendedAPIPlugin(),
|
||||
new webpack.DefinePlugin({
|
||||
__version_major__: VERSION.major,
|
||||
__version_minor__: VERSION.minor,
|
||||
__version_patch__: VERSION.patch,
|
||||
__version_prerelease__: VERSION.prerelease
|
||||
}),
|
||||
],
|
||||
module: {
|
||||
rules: [{
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue