diff --git a/package.json b/package.json index 395b4142..14efeee1 100755 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "frankerfacez", "author": "Dan Salvato LLC", - "version": "4.20.53", + "version": "4.20.54", "description": "FrankerFaceZ is a Twitch enhancement suite.", "license": "Apache-2.0", "scripts": { diff --git a/src/modules/chat/badges.jsx b/src/modules/chat/badges.jsx index 9fe1102e..8c6b0702 100644 --- a/src/modules/chat/badges.jsx +++ b/src/modules/chat/badges.jsx @@ -493,8 +493,6 @@ export default class Badges extends Module { } } - this.log.info('badge-click', event.target); - if ( url ) { const link = createElement('a', { target: '_blank', @@ -586,8 +584,15 @@ export default class Badges extends Module { }; } + const handled_ids = new Set; + for(const badge of badges) if ( badge && badge.id != null ) { + if ( handled_ids.has(badge.id) ) + continue; + + handled_ids.add(badge.id); + const full_badge = this.badges[badge.id] || {}, is_hidden = hidden_badges[badge.id]; @@ -609,6 +614,12 @@ export default class Badges extends Module { title: badge.title || full_badge.title }; + // Hacky nonsense. + if ( ! full_badge.addon ) { + bd.image = `//cdn.frankerfacez.com/badge/${badge.id}/4/rounded`; + bd.color = null; + } + let style; if ( old_badge ) { @@ -821,7 +832,7 @@ export default class Badges extends Module { data.replaces = true; } - if ( data.name === 'developer' || data.name === 'supporter' ) + if ( ! data.addon && (data.name === 'developer' || data.name === 'supporter') ) data.click_url = 'https://www.frankerfacez.com/donate'; if ( generate_css ) diff --git a/src/modules/chat/room.js b/src/modules/chat/room.js index 98455d41..97e0cacc 100644 --- a/src/modules/chat/room.js +++ b/src/modules/chat/room.js @@ -276,6 +276,13 @@ export default class Room { return false; } + const old_badges = this.data?.user_badge_ids; + if ( old_badges ) + for(const badge_id in old_badges ) + if ( has(old_badges, badge_id) ) + for(const user of old_badges[badge_id]) + this.getUser(user, undefined).removeBadge('ffz', badge_id); + const d = data.room, id = `${d.twitch_id}`; @@ -306,14 +313,12 @@ export default class Room { if ( has(data.sets, set_id) ) this.manager.emotes.loadSetData(set_id, data.sets[set_id]); - - const badges = d.user_badges; + const badges = d.user_badge_ids; if ( badges ) for(const badge_id in badges) if ( has(badges, badge_id) ) for(const user of badges[badge_id]) - this.getUser(undefined, user).addBadge('ffz', badge_id); - + this.getUser(user, undefined).addBadge('ffz', badge_id); if ( d.css ) this.style.set('css', d.css); diff --git a/src/modules/main_menu/components/clear-settings.vue b/src/modules/main_menu/components/clear-settings.vue new file mode 100644 index 00000000..953389cc --- /dev/null +++ b/src/modules/main_menu/components/clear-settings.vue @@ -0,0 +1,216 @@ + + + \ No newline at end of file diff --git a/src/modules/main_menu/index.js b/src/modules/main_menu/index.js index 6988a9cf..38e87c64 100644 --- a/src/modules/main_menu/index.js +++ b/src/modules/main_menu/index.js @@ -60,6 +60,12 @@ export default class MainMenu extends Module { getFFZ: () => this.resolve('core') }); + this.settings.addUI('clear', { + path: 'Data Management > Storage @{"profile_warning": false} >> tabs ~> Clear', + component: 'clear-settings', + force_seen: true + }); + this.settings.addUI('home', { path: 'Home @{"sort": -1000, "profile_warning": false}', component: 'home-page' diff --git a/src/raven.js b/src/raven.js index efc60d3f..040c5d24 100644 --- a/src/raven.js +++ b/src/raven.js @@ -191,7 +191,6 @@ export default class RavenLogger extends Module { return true; }, shouldSendCallback: data => { - debugger; if ( this.settings && ! this.settings.get('reports.error.enable') ) { if ( data.tags && data.tags.example && this.__example_waiter ) { this.__example_waiter(null); diff --git a/src/settings/clearables.js b/src/settings/clearables.js new file mode 100644 index 00000000..fc42cdfd --- /dev/null +++ b/src/settings/clearables.js @@ -0,0 +1,68 @@ +'use strict'; + +// ============================================================================ +// Clearable Settings +// ============================================================================ + +export const Experiments = { + label: 'Experiment Overrides', + keys: [ + 'exp-lock', + 'experiment-overrides' + ] +}; + +export const HiddenEmotes = { + label: 'Hidden Emotes', + keys(provider) { + const keys = ['emote-menu.hidden-sets']; + for(const key of provider.keys()) + if ( key.startsWith('hidden-emotes.') ) + keys.push(key); + + return keys; + } +}; + +export const FavoriteEmotes = { + label: 'Favorited Emotes', + keys(provider) { + const keys = []; + for(const key of provider.keys()) + if ( key.startsWith('favorite-emotes.') ) + keys.push(key); + + return keys; + } +}; + +export const Overrides = { + label: 'Name and Color Overrides', + keys: [ + 'overrides.colors', + 'overrides.names' + ] +}; + +export const Profiles = { + label: 'Profiles', + clear(provider, settings) { + const keys = ['profiles']; + for(const key of provider.keys()) + if ( /^p:\d+:/.test(key) ) + keys.push(key); + + for(const key of keys) + provider.delete(key); + + settings.loadProfiles(); + } +}; + +export const Everything = { + label: 'Absolutely Everything', + clear(provider, settings) { + provider.clear(); + settings.loadProfiles(); + } +}; diff --git a/src/settings/index.js b/src/settings/index.js index 3302afa6..a6102ad2 100644 --- a/src/settings/index.js +++ b/src/settings/index.js @@ -5,7 +5,7 @@ // ============================================================================ import Module from 'utilities/module'; -import {deep_equals, has, debounce} from 'utilities/object'; +import {deep_equals, has, debounce, deep_copy} from 'utilities/object'; import {IndexedDBProvider, LocalStorageProvider} from './providers'; import SettingsProfile from './profile'; @@ -13,6 +13,7 @@ import SettingsContext from './context'; import MigrationManager from './migration'; import * as FILTERS from './filters'; +import * as CLEARABLES from './clearables'; // ============================================================================ @@ -51,6 +52,13 @@ export default class SettingsManager extends Module { this.ui_structures = new Map; this.definitions = new Map; + // Clearable Data Rules + this.clearables = {}; + + for(const key in CLEARABLES) + if ( has(CLEARABLES, key) ) + this.clearables[key] = CLEARABLES[key]; + // Filters this.filters = {}; @@ -607,6 +615,22 @@ export default class SettingsManager extends Module { this.ui_structures.set(key, definition); this.emit(':added-definition', key, definition); } + + + addClearable(key, definition) { + if ( typeof key === 'object' ) { + for(const k in key) + if ( has(key, k) ) + this.addClearable(k, key[k]); + return; + } + + this.clearables[key] = definition; + } + + getClearables() { + return deep_copy(this.clearables); + } } diff --git a/src/settings/providers.js b/src/settings/providers.js index 610351c7..7c2adc8b 100644 --- a/src/settings/providers.js +++ b/src/settings/providers.js @@ -300,9 +300,10 @@ export class IndexedDBProvider extends SettingsProvider { const {type, key} = event.data; if ( type === 'set' ) { - const val = JSON.parse(localStorage.getItem(this.prefix + key)); - this._cached.set(key, val); - this.emit('changed', key, val, false); + this._get(key).then(val => { + this._cached.set(key, val); + this.emit('changed', key, val, false); + }).catch(err => this.manager.log.error(`Error getting setting "${key}" from database`, err)); } else if ( type === 'delete' ) { this._cached.delete(key); @@ -343,8 +344,8 @@ export class IndexedDBProvider extends SettingsProvider { this._cached.set(key, value); this._set(key, value) - .catch(err => this.manager.log.error(`Error saving setting "${key}" to database`, err)) - .then(() => this.broadcast({type: 'set', key})); + .then(() => this.broadcast({type: 'set', key})) + .catch(err => this.manager.log.error(`Error saving setting "${key}" to database`, err)); this.emit('set', key, value, false); } @@ -473,6 +474,23 @@ export class IndexedDBProvider extends SettingsProvider { } + async _get(key) { + const db = await this.getDB(), + trx = db.transaction(['settings'], 'readonly'), + store = trx.objectStore('settings'); + + return new Promise((s,f) => { + store.onerror = f; + + const req = store.get(key); + req.onerror = f; + req.onsuccess = () => { + s(req.result.v); + } + }); + } + + async _set(key, value) { const db = await this.getDB(), trx = db.transaction(['settings'], 'readwrite'), @@ -480,9 +498,10 @@ export class IndexedDBProvider extends SettingsProvider { return new Promise((s,f) => { store.onerror = f; - store.onsuccess = s; - store.put({k: key, v: value}); + const req = store.put({k: key, v: value}); + req.onerror = f; + req.onsuccess = s; }); } @@ -494,9 +513,10 @@ export class IndexedDBProvider extends SettingsProvider { return new Promise((s,f) => { store.onerror = f; - store.onsuccess = s; - store.delete(key); + const req = store.delete(key); + req.onerror = f; + req.onsuccess = s; }); } @@ -508,9 +528,10 @@ export class IndexedDBProvider extends SettingsProvider { return new Promise((s,f) => { store.onerror = f; - store.onsuccess = s; - store.clear(); + const req = store.clear(); + req.onerror = f; + req.onsuccess = s; }); } diff --git a/src/sites/twitch-twilight/modules/chat/emote_menu.jsx b/src/sites/twitch-twilight/modules/chat/emote_menu.jsx index 55d409ac..8a425cf1 100644 --- a/src/sites/twitch-twilight/modules/chat/emote_menu.jsx +++ b/src/sites/twitch-twilight/modules/chat/emote_menu.jsx @@ -762,7 +762,7 @@ export default class EmoteMenu extends Module { return (