diff --git a/client/src/builtin/EmoteModule.js b/client/src/builtin/EmoteModule.js index ab208737..f509191b 100644 --- a/client/src/builtin/EmoteModule.js +++ b/client/src/builtin/EmoteModule.js @@ -25,7 +25,7 @@ const EMOTE_SOURCES = [ 'https://static-cdn.jtvnw.net/emoticons/v1/:id/1.0', 'https://cdn.frankerfacez.com/emoticon/:id/1', 'https://cdn.betterttv.net/emote/:id/1x' -] +]; export default new class EmoteModule extends BuiltinModule { @@ -57,32 +57,25 @@ export default new class EmoteModule extends BuiltinModule { { text: 'Favourite', type: 'toggle', - checked: target && target.alt ? this.favourites.find(e => e.name === target.alt.replace(/;/g, '')) : false, + checked: target && target.alt && this.isFavourite(target.alt.replace(/;/g, '')), onChange: (checked, target) => { const { alt } = target; if (!alt) return false; - const name = alt.replace(/;/g, ''); + const emote = alt.replace(/;/g, ''); - if (!checked) return this.removeFavourite(name); - - const emote = this.findByName(name, true); - if (!emote) return false; - return this.addFavourite(emote); + if (!checked) return this.removeFavourite(emote), false; + return this.addFavourite(emote), true; } } - ], filter => filter.closest('.bd-emote')); + ], target => target.closest('.bd-emote')); if (!this.database.size) { await this.loadLocalDb(); } // Read favourites and most used from database - const userData = await Database.findOne({ 'id': 'EmoteModule' }); - if (userData) { - if (userData.hasOwnProperty('favourites')) this._favourites = userData.favourites; - if (userData.hasOwnProperty('mostused')) this._mostUsed = userData.mostused; - } + await this.loadUserData(); this.patchMessageContent(); this.patchSendAndEdit(); @@ -90,18 +83,36 @@ export default new class EmoteModule extends BuiltinModule { MonkeyPatch('BD:EMOTEMODULE', ImageWrapper.component.prototype).after('render', this.beforeRenderImageWrapper.bind(this)); } + /** + * Adds an emote to favourites. + * @param {Object|String} emote + * @return {Promise} + */ addFavourite(emote) { - if (this.favourites.find(e => e.name === emote.name)) return true; + if (this.isFavourite(emote)) return; + if (typeof emote === 'string') emote = this.findByName(emote, true); this.favourites.push(emote); - Database.insertOrUpdate({ 'id': 'EmoteModule' }, { 'id': 'EmoteModule', favourites: this.favourites, mostused: this.mostUsed }) - return true; + return this.saveUserData(); } - removeFavourite(name) { - if (!this.favourites.find(e => e.name === name)) return false; - this._favourites = this._favourites.filter(e => e.name !== name); - Database.insertOrUpdate({ 'id': 'EmoteModule' }, { 'id': 'EmoteModule', favourites: this.favourites, mostused: this.mostUsed }) - return false; + /** + * Removes an emote from favourites. + * @param {Object|String} emote + * @return {Promise} + */ + removeFavourite(emote) { + if (!this.isFavourite(emote)) return; + Utils.removeFromArray(this.favourites, e => e.name === emote || e.name === emote.name, true); + return this.saveUserData(); + } + + /** + * Checks if an emote is in favourites. + * @param {Object|String} emote + * @return {Boolean} + */ + isFavourite(emote) { + return !!this.favourites.find(e => e.name === emote || e.name === emote.name); } async disabled() { @@ -123,6 +134,23 @@ export default new class EmoteModule extends BuiltinModule { } } + async loadUserData() { + const userData = await Database.findOne({ type: 'builtin', id: 'EmoteModule' }); + if (!userData) return; + + if (userData.hasOwnProperty('favourites')) this._favourites = userData.favourites; + if (userData.hasOwnProperty('mostused')) this._mostUsed = userData.mostused; + } + + async saveUserData() { + await Database.insertOrUpdate({ type: 'builtin', id: 'EmoteModule' }, { + type: 'builtin', + id: 'EmoteModule', + favourites: this.favourites, + mostused: this.mostUsed + }); + } + /** * Patches MessageContent render method */ @@ -227,6 +255,7 @@ export default new class EmoteModule extends BuiltinModule { /** * Add/update emote to most used * @param {Object} emote emote to add/update + * @return {Promise} */ addToMostUsed(emote) { const isMostUsed = this.mostUsed.find(mu => mu.key === emote.name); @@ -242,7 +271,7 @@ export default new class EmoteModule extends BuiltinModule { } // Save most used to database // TODO only save first n - Database.insertOrUpdate({ 'id': 'EmoteModule' }, { 'id': 'EmoteModule', favourites: this.favourites, mostused: this.mostUsed }) + return this.saveUserData(); } /** diff --git a/client/src/modules/pluginapi.js b/client/src/modules/pluginapi.js index f0e7f4be..095d3d0c 100644 --- a/client/src/modules/pluginapi.js +++ b/client/src/modules/pluginapi.js @@ -420,28 +420,38 @@ export default class PluginApi { */ get emotes() { - return EmoteModule.emotes; + return EmoteModule.database; } - get favourite_emotes() { - return EmoteModule.favourite_emotes; + get favouriteEmotes() { + return EmoteModule.favourites; + } + get mostUsedEmotes() { + return EmoteModule.mostUsed; } setFavouriteEmote(emote, favourite) { - return EmoteModule.setFavourite(emote, favourite); + return EmoteModule[favourite ? 'removeFavourite' : 'addFavourite'](emote); } addFavouriteEmote(emote) { return EmoteModule.addFavourite(emote); } removeFavouriteEmote(emote) { - return EmoteModule.addFavourite(emote); + return EmoteModule.removeFavourite(emote); } isFavouriteEmote(emote) { return EmoteModule.isFavourite(emote); } getEmote(emote) { - return EmoteModule.getEmote(emote); + return EmoteModule.findByName(emote, true); } - filterEmotes(regex, limit, start = 0) { - return EmoteModule.filterEmotes(regex, limit, start); + getEmoteUseCount(emote) { + const mostUsed = EmoteModule.mostUsed.find(mu => mu.key === emote.name); + return mostUsed ? mostUsed.useCount : 0; + } + incrementEmoteUseCount(emote) { + return EmoteModule.addToMostUsed(emote); + } + searchEmotes(regex, limit) { + return EmoteModule.search(regex, limit); } get Emotes() { return Object.defineProperties({ @@ -450,13 +460,18 @@ export default class PluginApi { removeFavourite: this.removeFavouriteEmote.bind(this), isFavourite: this.isFavouriteEmote.bind(this), getEmote: this.getEmote.bind(this), - filter: this.filterEmotes.bind(this) + getUseCount: this.getEmoteUseCount.bind(this), + incrementUseCount: this.incrementEmoteUseCount.bind(this), + search: this.searchEmotes.bind(this) }, { emotes: { get: () => this.emotes }, - favourite_emotes: { - get: () => this.favourite_emotes + favourites: { + get: () => this.favouriteEmotes + }, + mostused: { + get: () => this.mostUsedEmotes } }); } diff --git a/client/src/ui/contextmenus.js b/client/src/ui/contextmenus.js index dc04bc06..67b57de9 100644 --- a/client/src/ui/contextmenus.js +++ b/client/src/ui/contextmenus.js @@ -51,7 +51,7 @@ export class DiscordContextMenu { * @param {any} items items to add * @param {Function} [filter] filter function for target filtering */ - static add(id, items, filter) { + static add(items, filter) { if (!this.patched) this.patch(); const menu = { items, filter }; this.menus.push(menu); @@ -71,8 +71,8 @@ export class DiscordContextMenu { this.patched = true; const self = this; MonkeyPatch('BD:DiscordCMOCM', WebpackModules.getModuleByProps(['openContextMenu'])).instead('openContextMenu', (_, [e, fn], originalFn) => { - const overrideFn = function (...args) { - const res = fn(...args); + const overrideFn = function () { + const res = fn.apply(this, arguments); if (!res.hasOwnProperty('type')) return res; if (!res.type.prototype || !res.type.prototype.render || res.type.prototype.render.__patched) return res; MonkeyPatch('BD:DiscordCMRender', res.type.prototype).after('render', (c, a, r) => self.renderCm(c, a, r, res)); @@ -91,7 +91,7 @@ export class DiscordContextMenu { if (!retVal.props.children) return; if (!(retVal.props.children instanceof Array)) retVal.props.children = [retVal.props.children]; - for (const menu of this.menus.filter(menu => { if (!menu.filter) return true; return menu.filter(target)})) { + for (const menu of this.menus.filter(menu => !menu.filter || menu.filter(target))) { retVal.props.children.push(VueInjector.createReactElement(CMGroup, { target, top, diff --git a/common/modules/utils.js b/common/modules/utils.js index 03f76d1e..2635ff43 100644 --- a/common/modules/utils.js +++ b/common/modules/utils.js @@ -177,9 +177,9 @@ export class Utils { * @param {Any} item The item to remove from the array * @return {Array} */ - static removeFromArray(array, item) { + static removeFromArray(array, item, filter) { let index; - while ((index = array.indexOf(item)) > -1) + while ((index = filter ? array.findIndex(item) : array.indexOf(item)) > -1) array.splice(index, 1); return array; }