diff --git a/fontello.config.json b/fontello.config.json
index 6341b8a3..cfc7aaa9 100644
--- a/fontello.config.json
+++ b/fontello.config.json
@@ -573,6 +573,12 @@
"css": "left-open",
"code": 59446,
"src": "fontawesome"
+ },
+ {
+ "uid": "c8585e1e5b0467f28b70bce765d5840c",
+ "css": "docs",
+ "code": 61637,
+ "src": "fontawesome"
}
]
}
\ No newline at end of file
diff --git a/package.json b/package.json
index 4c66a905..f5a8e834 100755
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
{
"name": "frankerfacez",
"author": "Dan Salvato LLC",
- "version": "4.14.6",
+ "version": "4.14.7",
"description": "FrankerFaceZ is a Twitch enhancement suite.",
"license": "Apache-2.0",
"scripts": {
diff --git a/res/font/ffz-fontello.eot b/res/font/ffz-fontello.eot
index 6701eb45..64d32e1b 100644
Binary files a/res/font/ffz-fontello.eot and b/res/font/ffz-fontello.eot differ
diff --git a/res/font/ffz-fontello.svg b/res/font/ffz-fontello.svg
index 8452e46e..bf9b1ac9 100644
--- a/res/font/ffz-fontello.svg
+++ b/res/font/ffz-fontello.svg
@@ -122,6 +122,8 @@
+
+
diff --git a/res/font/ffz-fontello.ttf b/res/font/ffz-fontello.ttf
index 29f79c4a..72aba6f0 100644
Binary files a/res/font/ffz-fontello.ttf and b/res/font/ffz-fontello.ttf differ
diff --git a/res/font/ffz-fontello.woff b/res/font/ffz-fontello.woff
index be309ffd..ed9edb85 100644
Binary files a/res/font/ffz-fontello.woff and b/res/font/ffz-fontello.woff differ
diff --git a/res/font/ffz-fontello.woff2 b/res/font/ffz-fontello.woff2
index 398054b0..ce4a84c6 100644
Binary files a/res/font/ffz-fontello.woff2 and b/res/font/ffz-fontello.woff2 differ
diff --git a/src/modules/main_menu/components/profile-manager.vue b/src/modules/main_menu/components/profile-manager.vue
index a80becc7..fd8bd7d9 100644
--- a/src/modules/main_menu/components/profile-manager.vue
+++ b/src/modules/main_menu/components/profile-manager.vue
@@ -324,11 +324,10 @@ export default {
importProfile(profile_data, data) {
this.import_profile = profile_data;
+ this.import_profile_data = data;
- if ( profile_data.url ) {
- this.import_profile_data = data;
+ if ( profile_data.url )
return;
- }
this.confirmImport(false);
},
@@ -342,6 +341,8 @@ export default {
if ( ! allow_update )
delete profile_data.url;
+ console.log('Importing', profile_data, data, this.import_data);
+
const prof = this.context.createProfile(profile_data);
prof.update({
diff --git a/src/modules/metadata.jsx b/src/modules/metadata.jsx
index d3840169..547ced89 100644
--- a/src/modules/metadata.jsx
+++ b/src/modules/metadata.jsx
@@ -7,7 +7,7 @@
import {createElement, ClickOutside, setChildren} from 'utilities/dom';
import {maybe_call} from 'utilities/object';
-import {duration_to_string} from 'utilities/time';
+import {duration_to_string, durationForURL} from 'utilities/time';
import Tooltip from 'utilities/tooltip';
import Module from 'utilities/module';
@@ -75,6 +75,9 @@ export default class Metadata extends Module {
this.definitions.uptime = {
+ inherit: true,
+ no_arrow: true,
+
refresh() { return this.settings.get('metadata.uptime') > 0 },
setup(data) {
@@ -89,7 +92,8 @@ export default class Metadata extends Module {
return {
created,
- uptime: created ? Math.floor((now - created.getTime()) / 1000) : -1
+ uptime: created ? Math.floor((now - created.getTime()) / 1000) : -1,
+ getBroadcastID: data.getBroadcastID
}
},
@@ -118,11 +122,66 @@ export default class Metadata extends Module {
'(since {since,datetime})',
{since: data.created}
)}`;
+ },
+
+ async popup(data, tip) {
+ const [permission, broadcast_id] = await Promise.all([
+ navigator.permissions.query({name: 'clipboard-write'}),
+ data.getBroadcastID()
+ ]);
+ if ( ! broadcast_id )
+ return (
+ { this.i18n.t('metadata.uptime-no-id', 'Sorry, we couldn\'t find an archived video for the current broadcast.') }
+
);
+
+ const url = `https://www.twitch.tv/videos/${broadcast_id}${data.uptime > 0 ? `?t=${durationForURL(data.uptime)}` : ''}`,
+ can_copy = permission?.state === 'granted' || permission?.state === 'prompt';
+
+ const copy = can_copy ? e => {
+ navigator.clipboard.writeText(url);
+ e.preventDefault();
+ return false;
+ } : null;
+
+ tip.element.classList.add('tw-balloon--lg');
+
+ return (
+
+ { this.i18n.t('metadata.uptime.link-to', 'Link to {time}', {
+ time: duration_to_string(data.uptime, false, false, false, false)
+ }) }
+
+
+
e.target.select()}
+ />
+ {can_copy &&
}
+
+
);
}
}
this.definitions['player-stats'] = {
- button: false,
+ button: true,
+ inherit: true,
refresh() {
return this.settings.get('metadata.player-stats')
@@ -170,10 +229,10 @@ export default class Metadata extends Module {
videoWidth,
displayHeight,
displayWidth,
- fps: (maybe_call(player.getVideoFrameRate, player) || 0).toFixed(2),
+ fps: Math.floor(maybe_call(player.getVideoFrameRate, player) || 0),
hlsLatencyBroadcaster: player.stats?.broadcasterLatency,
hlsLatencyEncoder: player.stats?.transcoderLatency,
- playbackRate: (maybe_call(player.getVideoBitRate, player) || 0) / 1000,
+ playbackRate: Math.floor((maybe_call(player.getVideoBitRate, player) || 0) / 1000),
skippedFrames: maybe_call(player.getDroppedFrames, player),
}
}
@@ -691,17 +750,8 @@ export default class Metadata extends Module {
button = true;
let btn, popup;
- const border = maybe_call(def.border, this, data);
-
- /* let cls = maybe_call(def.button, this, data);
-
- if ( typeof cls !== 'string' )
- cls = cls ? 'tw-border-t tw-border-l tw-border-b '
-
- if ( typeof cls !== 'string' )
- cls = cls ? 'ffz-button--hollow' : 'tw-button--text';
-
- const fix = cls === 'tw-button--text';*/
+ const border = maybe_call(def.border, this, data),
+ inherit = maybe_call(def.inherit, this, data);
if ( typeof icon === 'string' )
icon = (
@@ -709,29 +759,13 @@ export default class Metadata extends Module {
);
if ( def.popup && def.click ) {
- /*el = (
- {btn = ()}
- {popup = ()}
- );*/
-
el = (