1
0
Fork 0
mirror of https://github.com/FrankerFaceZ/FrankerFaceZ.git synced 2025-06-27 21:05:53 +00:00
* 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:
SirStendec 2019-06-20 17:14:03 -04:00
parent 04aa1789a2
commit f1c527b721
14 changed files with 314 additions and 23 deletions

View file

@ -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
View file

@ -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": {

View file

@ -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
View 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();

View file

@ -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);
})();

View file

@ -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: () =>

View file

@ -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__;

View file

@ -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 ) {

View file

@ -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 )

View file

@ -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;

View file

@ -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);
}

View 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));
}
}

View file

@ -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(),

View file

@ -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: [{