1
0
Fork 0
mirror of https://github.com/FrankerFaceZ/FrankerFaceZ.git synced 2025-07-28 05:28:30 +00:00
* Added: Support for Twitch's redesigned badges.
* Added: Version selector to choose between the new vs old badge designs.
* Added: Option to adjust badge colors for visibility depending on the current background color.
* Changed: Use the channel accent color for the border on re-subscription messages and other notices.
* Fixed: Update `dayjs` dependency for upstream i18n fixes.
* Fixed: Hiding Side Navigation not functioning with a certain Twitch experiment.
* Fixed: Certain player settings, such as hiding extensions, not functioning.
* Maintenance: Update a few dependencies.
This commit is contained in:
SirStendec 2019-12-05 23:13:27 -05:00
parent ff0f0ea074
commit 1fe7c417f3
14 changed files with 229 additions and 64 deletions

93
package-lock.json generated
View file

@ -1,6 +1,6 @@
{
"name": "frankerfacez",
"version": "4.14.12",
"version": "4.17.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@ -470,9 +470,9 @@
}
},
"@ffz/icu-msgparser": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@ffz/icu-msgparser/-/icu-msgparser-1.0.1.tgz",
"integrity": "sha512-0+i29DZUJIqrK02rHcxDXmuLSOyp4EJERu4uQDOh7w39d5TqXHbFP2CRtSXjYYCQZWHoKwn37ZZScn+8+zH56g=="
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/@ffz/icu-msgparser/-/icu-msgparser-1.0.2.tgz",
"integrity": "sha512-LTtWOQ4fftxcC7Z86u9LTi1eZ4X07hQH5yvcURlYSpVTaY9dXXE/h5BdtJB0TIk7FkSiAuN/3sRkfHD0u3+S7Q=="
},
"@types/anymatch": {
"version": "1.3.1",
@ -1501,6 +1501,17 @@
"ssri": "^6.0.1",
"unique-filename": "^1.1.1",
"y18n": "^4.0.0"
},
"dependencies": {
"rimraf": {
"version": "2.7.1",
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
"integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
"dev": true,
"requires": {
"glob": "^7.1.3"
}
}
}
},
"cache-base": {
@ -1893,6 +1904,17 @@
"mkdirp": "^0.5.1",
"rimraf": "^2.5.4",
"run-queue": "^1.0.0"
},
"dependencies": {
"rimraf": {
"version": "2.7.1",
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
"integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
"dev": true,
"requires": {
"glob": "^7.1.3"
}
}
}
},
"copy-descriptor": {
@ -2088,9 +2110,9 @@
"dev": true
},
"dayjs": {
"version": "1.8.15",
"resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.8.15.tgz",
"integrity": "sha512-HYHCI1nohG52B45vCQg8Re3hNDZbMroWPkhz50yaX7Lu0ATyjGsTdoYZBpjED9ar6chqTx2dmSmM8A51mojnAg=="
"version": "1.8.17",
"resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.8.17.tgz",
"integrity": "sha512-47VY/htqYqr9GHd7HW/h56PpQzRBSJcxIQFwqL3P20bMF/3az5c3PWdVY3LmPXFl6cQCYHL7c79b9ov+2bOBbw=="
},
"de-indent": {
"version": "1.0.2",
@ -2226,6 +2248,15 @@
"dev": true
}
}
},
"rimraf": {
"version": "2.7.1",
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
"integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
"dev": true,
"requires": {
"glob": "^7.1.3"
}
}
}
},
@ -3128,6 +3159,17 @@
"flatted": "^2.0.0",
"rimraf": "2.6.3",
"write": "1.0.3"
},
"dependencies": {
"rimraf": {
"version": "2.6.3",
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz",
"integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==",
"dev": true,
"requires": {
"glob": "^7.1.3"
}
}
}
},
"flatted": {
@ -3822,6 +3864,17 @@
"inherits": "~2.0.0",
"mkdirp": ">=0.5 0",
"rimraf": "2"
},
"dependencies": {
"rimraf": {
"version": "2.7.1",
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
"integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
"dev": true,
"requires": {
"glob": "^7.1.3"
}
}
}
},
"function-bind": {
@ -5362,6 +5415,17 @@
"mkdirp": "^0.5.1",
"rimraf": "^2.5.4",
"run-queue": "^1.0.3"
},
"dependencies": {
"rimraf": {
"version": "2.7.1",
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
"integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
"dev": true,
"requires": {
"glob": "^7.1.3"
}
}
}
},
"ms": {
@ -5473,6 +5537,15 @@
"which": "1"
},
"dependencies": {
"rimraf": {
"version": "2.7.1",
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
"integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
"dev": true,
"requires": {
"glob": "^7.1.3"
}
},
"semver": {
"version": "5.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz",
@ -6786,9 +6859,9 @@
"dev": true
},
"rimraf": {
"version": "2.6.3",
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz",
"integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==",
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.0.tgz",
"integrity": "sha512-NDGVxTsjqfunkds7CqsOiEnxln4Bo7Nddl3XhS4pXg5OzwkLqJ971ZVAAnB+DDLnF76N+VnDEiBHaVV8I06SUg==",
"dev": true,
"requires": {
"glob": "^7.1.3"

View file

@ -1,7 +1,7 @@
{
"name": "frankerfacez",
"author": "Dan Salvato LLC",
"version": "4.16.0",
"version": "4.17.0",
"description": "FrankerFaceZ is a Twitch enhancement suite.",
"license": "Apache-2.0",
"scripts": {
@ -45,7 +45,7 @@
"json-loader": "^0.5.7",
"node-sass": "^4.12.0",
"raw-loader": "^3.1.0",
"rimraf": "^2.6.3",
"rimraf": "^3.0.0",
"sass-loader": "^7.1.0",
"semver": "^6.3.0",
"terser-webpack-plugin": "^1.3.0",
@ -62,9 +62,9 @@
"url": "https://github.com/FrankerFaceZ/FrankerFaceZ.git"
},
"dependencies": {
"@ffz/icu-msgparser": "^1.0.1",
"@ffz/icu-msgparser": "^1.0.2",
"crypto-js": "^3.1.9-1",
"dayjs": "^1.8.15",
"dayjs": "^1.8.17",
"displacejs": "github:sirstendec/displace",
"emoji-regex": "^8.0.0",
"file-saver": "^2.0.1",

View file

@ -6,7 +6,7 @@
import Parser from '@ffz/icu-msgparser';
import {SERVER, DEBUG} from 'utilities/constants';
import {DEBUG} from 'utilities/constants';
import {get, pick_random, shallow_copy, deep_copy} from 'utilities/object';
import Module from 'utilities/module';

View file

@ -4,13 +4,15 @@
// Badge Handling
// ============================================================================
import {NEW_API, API_SERVER, IS_WEBKIT, WEBKIT_CSS as WEBKIT} from 'utilities/constants';
import {NEW_API, SERVER, API_SERVER, IS_WEBKIT, WEBKIT_CSS as WEBKIT} from 'utilities/constants';
import {createElement, ManagedStyle} from 'utilities/dom';
import {has} from 'utilities/object';
import Module from 'utilities/module';
import { ColorAdjuster } from 'src/utilities/color';
export const CSS_BADGES = {
const CSS_BADGES = {
1: {
staff: { 1: { color: '#200f33', svg: true, trans: { color: '#6441a5' } } },
admin: { 1: { color: '#faaf19', svg: true } },
global_mod: { 1: { color: '#0c6f20', svg: true } },
@ -25,6 +27,25 @@ export const CSS_BADGES = {
premium: { 1: { color: '#009cdc' } },
subscriber: { 0: { color: '#6441a5' }, 1: { color: '#6441a5' }},
},
2: {
staff: { 1: { color: '#000' } },
admin: { 1: { color: '#FFCA5F' } },
broadcaster: { 1: { color: '#E91916' } },
moderator: { 1: { color: '#00FA05' } },
global_mod: { 1: { color: '#006441' } },
twitchbot: { 1: { color: '#00FA05' } },
partner: { 1: { color: '#9146FF' } },
subscriber: { 0: { color: '#8205B4'}, 1: { color: '#8205B4' } },
vip: { 1: { color: '#FA1ED2' } },
turbo: { 1: { color: '#59399A' } },
premium: { 1: { color: '#00A8E1' } },
'anonymous-cheerer': { 1: { color: '#4B367C' } },
'clip-champ': { 1: { color: '#9146FF' } }
}
}
export const BADGE_POSITIONS = {
@ -41,7 +62,7 @@ export const BADGE_POSITIONS = {
const NO_REPEAT = 'background-repeat:no-repeat;background-position:center;',
BASE_IMAGE = 'https://cdn.frankerfacez.com/badges/twitch/',
BASE_IMAGE = `${SERVER}/static/badges/twitch/`,
CSS_MASK_IMAGE = IS_WEBKIT ? 'webkitMaskImage' : 'maskImage',
CSS_TEMPLATES = {
@ -70,9 +91,9 @@ export function generateOverrideCSS(data, style) {
}
export function generateBadgeCSS(badge, version, data, style, is_dark, scale = 1) {
export function generateBadgeCSS(badge, version, data, style, is_dark, badge_version = 2, color_fixer, scale = 1) {
let color = data.color || 'transparent',
base_image = data.image || `${BASE_IMAGE}${badge}${data.svg ? '.svg' : `/${version}/`}`,
base_image = data.image || `${BASE_IMAGE}${badge_version}/${badge}${data.svg ? '.svg' : `/${version}/`}`,
trans = false,
invert = false,
svg, image, image_set;
@ -123,6 +144,9 @@ export function generateBadgeCSS(badge, version, data, style, is_dark, scale = 1
image_set = svg;
}
if ( color_fixer && color && color !== 'transparent' )
color = color_fixer.process(color) || color;
// TODO: Fix the click_url name once we actually support badge clicking.
return `${data.__click_url ? 'cursor:pointer;' : ''}${invert ? 'filter:invert(100%);' : ''}${CSS_TEMPLATES[style]({
scale,
@ -148,6 +172,29 @@ export default class Badges extends Module {
this.badges = {};
this.twitch_badges = {};
this.settings.add('chat.badges.version', {
default: 2,
ui: {
path: 'Chat > Badges >> tabs ~> Appearance',
title: 'Version',
component: 'setting-select-box',
data: [
{value: 1, title: '1 (Pre December 2019)'},
{value: 2, title: '2 (Current)'}
]
}
});
this.settings.add('chat.badges.fix-colors', {
default: true,
ui: {
path: 'Chat > Badges >> tabs ~> Appearance',
title: 'Adjust badge colors for visibility.',
description: 'Ensures that badges are visible against the current background.\n\n**Note:** Only affects badges with custom rendering. Subscriber badges, bit badges, etc. are not affected.',
component: 'setting-check-box'
}
});
this.settings.add('chat.badges.hidden', {
default: {},
type: 'object_merge',
@ -169,13 +216,13 @@ export default class Badges extends Module {
})
this.settings.add('chat.badges.style', {
default: 0,
default: 1,
ui: {
path: 'Chat > Badges >> tabs ~> Appearance',
title: 'Style',
component: 'setting-select-box',
data: [
{value: 0, title: 'Default'},
{value: 0, title: 'Square'},
{value: 1, title: 'Rounded'},
{value: 2, title: 'Circular'},
{value: 3, title: 'Circular (Color Only)'},
@ -256,6 +303,8 @@ export default class Badges extends Module {
this.parent.context.on('changed:chat.badges.style', this.rebuildAllCSS, this);
this.parent.context.on('changed:theme.is-dark', this.rebuildAllCSS, this);
this.parent.context.on('changed:theme.tooltips-dark', this.rebuildAllCSS, this);
this.parent.context.on('changed:chat.badges.version', this.rebuildAllCSS, this);
this.parent.context.on('changed:chat.badges.fix-colors', this.rebuildColoredBadges, this);
this.rebuildAllCSS();
this.loadGlobalBadges();
@ -509,7 +558,29 @@ export default class Badges extends Module {
}
rebuildColor() {
if ( this.parent.context.get('chat.badges.fix-colors') ) {
this.color_fixer = new ColorAdjuster(
this.parent.context.get('theme.is-dark') ? '#181818' : '#FFFFFF',
1,
2.5
);
} else
this.color_fixer = null;
}
rebuildColoredBadges() {
this.rebuildColor();
this.buildBadgeCSS();
this.buildTwitchCSSBadgeCSS();
}
rebuildAllCSS() {
this.rebuildColor();
for(const room of this.parent.iterateRooms()) {
room.buildBadgeCSS();
room.buildModBadgeCSS();
@ -621,7 +692,7 @@ export default class Badges extends Module {
const data = this.badges[key],
selector = `.ffz-badge[data-badge="${key}"]`;
out.push(`${selector}{${generateBadgeCSS(key, 0, data, style, is_dark)}}`);
out.push(`${selector}{${generateBadgeCSS(key, 0, data, style, is_dark, 0, this.color_fixer)}}`);
out.push(`.ffz-badge[data-replaced="${key}"]{${generateOverrideCSS(data, style, is_dark)}}`);
}
@ -686,18 +757,21 @@ export default class Badges extends Module {
buildTwitchCSSBadgeCSS() {
const style = this.parent.context.get('chat.badges.style'),
is_dark = this.parent.context.get('theme.is-dark');
is_dark = this.parent.context.get('theme.is-dark'),
badge_version = this.parent.context.get('chat.badges.version'),
versioned = CSS_BADGES[badge_version] || {};
const out = [];
for(const key in CSS_BADGES)
if ( has(CSS_BADGES, key) ) {
const data = CSS_BADGES[key];
for(const key in versioned)
if ( has(versioned, key) ) {
const data = versioned[key];
for(const version in data)
if ( has(data, version) ) {
const d = data[version],
selector = `.ffz-badge[data-badge="${key}"][data-version="${version}"]`;
out.push(`${selector}{${generateBadgeCSS(key, version, d, style, is_dark)}}`);
out.push(`${selector}{${generateBadgeCSS(key, version, d, style, is_dark, badge_version, this.color_fixer)}}`);
}
}
@ -709,10 +783,13 @@ export default class Badges extends Module {
if ( ! this.twitch_badges )
this.style.delete('twitch-badges');
const badge_version = this.parent.context.get('chat.badges.version'),
versioned = CSS_BADGES[badge_version] || {};
const out = [];
for(const key in this.twitch_badges)
if ( has(this.twitch_badges, key) ) {
if ( has(CSS_BADGES, key) )
if ( has(versioned, key) )
continue;
const versions = this.twitch_badges[key];

View file

@ -20,7 +20,6 @@ import SettingsMenu from './settings_menu';
import EmoteMenu from './emote_menu';
import Input from './input';
import ViewerCards from './viewer_card';
import { isHighlightedReward } from './points';
const REGEX_EMOTES = {

View file

@ -527,7 +527,7 @@ other {# messages were deleted by a moderator.}
}, the_list);
}
cls = `user-notice-line tw-pd-y-05 ffz--subscribe-line${show_class ? ' ffz--deleted-message' : ''}`;
cls = `ffz-notice-line user-notice-line tw-pd-y-05 ffz--subscribe-line${show_class ? ' ffz--deleted-message' : ''}`;
out = [
e('div', {
className: 'tw-flex tw-c-text-alt-2',
@ -590,7 +590,7 @@ other {# messages were deleted by a moderator.}
count: msg.sub_total
}));
cls = `user-notice-line tw-pd-y-05 tw-pd-r-2 ffz--subscribe-line${show_class ? ' ffz--deleted-message' : ''}`;
cls = `ffz-notice-line user-notice-line tw-pd-y-05 tw-pd-r-2 ffz--subscribe-line${show_class ? ' ffz--deleted-message' : ''}`;
out = [
e('div', {className: 'tw-flex tw-c-text-alt-2'}, [
t.chat.context.get('chat.subs.compact') ? null :
@ -652,7 +652,7 @@ other {# messages were deleted by a moderator.}
));
}
cls = `user-notice-line tw-pd-y-05 tw-pd-r-2 ffz--subscribe-line${show_class ? ' ffz--deleted-message' : ''}`;
cls = `ffz-notice-line user-notice-line tw-pd-y-05 tw-pd-r-2 ffz--subscribe-line${show_class ? ' ffz--deleted-message' : ''}`;
out = [
e('div', {className: 'tw-flex tw-c-text-alt-2'}, [
t.chat.context.get('chat.subs.compact') ? null :
@ -690,7 +690,7 @@ other {# messages were deleted by a moderator.}
]);
if ( system_msg ) {
cls = `user-notice-line tw-pd-y-05 tw-pd-r-2 ffz--ritual-line${show_class ? ' ffz--deleted-message' : ''}`;
cls = `ffz-notice-line user-notice-line tw-pd-y-05 tw-pd-r-2 ffz--ritual-line${show_class ? ' ffz--deleted-message' : ''}`;
out = [
system_msg,
out && e('div', {
@ -710,7 +710,7 @@ other {# messages were deleted by a moderator.}
t.i18n.formatNumber(getRewardCost(msg.ffz_reward))
]);
cls = `ffz--points-line tw-pd-l-1 tw-pd-y-05 tw-pd-r-2${isHighlightedReward(msg.ffz_reward) ? ' ffz--points-highlight' : ''}${show_class ? ' ffz--deleted-message' : ''}`;
cls = `ffz-notice-line ffz--points-line tw-pd-l-1 tw-pd-y-05 tw-pd-r-2${isHighlightedReward(msg.ffz_reward) ? ' ffz--points-highlight' : ''}${show_class ? ' ffz--deleted-message' : ''}`;
out = [
e('div', {className: 'tw-c-text-alt-2'}, [
out ? null : t.actions.renderInline(msg, this.props.showModerationIcons, u, r, e),

View file

@ -23,8 +23,8 @@ const CLASSES = {
'prime-offers': '.top-nav__prime',
'player-ext': '.highwind-video-player .extension-taskbar,.highwind-video-player .extension-container,.highwind-video-player .extensions-dock__layout,.highwind-video-player .extensions-notifications,.highwind-video-player .extensions-video-overlay-size-container',
'player-ext-hover': '.highwind-video-player__overlay[data-controls="false"] .extension-taskbar,.highwind-video-player__overlay[data-controls="false"] .extension-container,.highwind-video-player__overlay[data-controls="false"] .extensions-dock__layout,.highwind-video-player__overlay[data-controls="false"] .extensions-notifications,.highwind-video-player__overlay[data-controls="false"] .extensions-video-overlay-size-container',
'player-ext': '.video-player .extension-taskbar,.video-player .extension-container,.video-player .extensions-dock__layout,.video-player .extensions-notifications,.video-player .extensions-video-overlay-size-container,.video-player .extensions-dock__layout',
'player-ext-hover': '.video-player__overlay[data-controls="false"] .extension-taskbar,.video-player__overlay[data-controls="false"] .extension-container,.video-player__overlay[data-controls="false"] .extensions-dock__layout,.video-player__overlay[data-controls="false"] .extensions-notifications,.video-player__overlay[data-controls="false"] .extensions-video-overlay-size-container',
'player-event-bar': '.channel-root .live-event-banner-ui__header',
'player-rerun-bar': '.channel-root__player-container div.tw-c-text-overlay:not([data-a-target="hosting-ui-header"])',
@ -65,7 +65,7 @@ export default class CSSTweaks extends Module {
component: 'setting-check-box'
},
changed: val => this.toggleHide('side-nav', !val)
changed: val => this.toggle('hide-side-nav', !val)
});
this.settings.add('layout.side-nav.show-avatars', {
@ -298,7 +298,7 @@ export default class CSSTweaks extends Module {
this.toggle('theatre-nav', this.settings.get('layout.theatre-navigation'));
this.toggle('hide-side-nav-avatars', ! this.settings.get('layout.side-nav.show-avatars'));
this.toggleHide('side-nav', !this.settings.get('layout.side-nav.show'));
this.toggle('hide-side-nav', !this.settings.get('layout.side-nav.show'));
this.toggleHide('side-rec-friends', !this.settings.get('layout.side-nav.show-rec-friends'));
this.toggleHide('side-offline-channels', this.settings.get('layout.side-nav.hide-offline'));
this.toggleHide('prime-offers', !this.settings.get('layout.prime-offers'));

View file

@ -1,7 +1,5 @@
.player .extension-overlay__iframe,
.player .extension-overlay,
.highwind-video-player .extension-overlay__iframe,
.highwind-video-player .extension-overlay,
.highwind-video-player .extension-view__iframe {
.video-player .extension-overlay__iframe,
.video-player .extension-overlay,
.video-player .extension-view__iframe {
pointer-events: none !important;
}

View file

@ -1,4 +1,3 @@
.highwind-video-player__overlay[data-controls="false"][data-paused="false"][data-ended="false"],
.player:hover:not([data-controls="true"]):not([data-paused="true"]):not([data-ended="true"]) {
.video-player__overlay[data-controls="false"][data-paused="false"][data-ended="false"] {
cursor: none;
}

View file

@ -1,4 +1,3 @@
.highwind-video-player .volume-slider__slider-container,
.player .player-volume__slider-container {
.video-player .volume-slider__slider-container {
opacity: 1 !important;
}

View file

@ -1,5 +1,5 @@
.highwind-video-player__container--theatre-whispers,
.video-player--theatre.video-player--logged-in .player.video-player__container {
.video-player__container--theatre-whispers,
.video-player--theatre.video-player--logged-in .video-player.video-player__container {
bottom: 0 !important;
}

View file

@ -164,9 +164,11 @@
background-color: var(--ffz-channel-color-20);
}
.ffz--points-line {
border-left: 4px solid var(--ffz-channel-color);
.ffz-notice-line {
border-left: 4px solid var(--ffz-channel-color) !important;
}
.ffz--points-line {
.ffz--points-reward,
.ffz--points-cost {
font-weight: 600;

View file

@ -0,0 +1,10 @@
query FFZ_LastBroadcast($id: ID, $login: String) {
user(id: $id, login: $login) {
id
lastBroadcast {
id
startedAt
title
}
}
}

View file

@ -177,6 +177,14 @@ export default class TwitchData extends Module {
return get('data.user', data);
}
async getLastBroadcast(id, login) {
const data = await this.queryApollo(
require('./data/last-broadcast.gql'),
{ id, login }
);
return get('data.user.lastBroadcast', data);
}
// ========================================================================
// Broadcast ID