emote updates
This commit is contained in:
parent
2d1d48e0fd
commit
720744a297
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
46
js/main.js
46
js/main.js
File diff suppressed because one or more lines are too long
|
@ -1,11 +1,28 @@
|
|||
import Builtin from "../structs/builtin";
|
||||
|
||||
import {Config, EmoteInfo, EmoteConfig} from "data";
|
||||
import {Config, EmoteConfig} from "data";
|
||||
import {Utilities, WebpackModules, DataStore, DiscordModules, Events, Settings, Strings} from "modules";
|
||||
import BDEmote from "../ui/emote";
|
||||
import Toasts from "../ui/toasts";
|
||||
// import EmoteMenu from "./emotemenu";
|
||||
import FormattableString from "../structs/string";
|
||||
const request = require("request");
|
||||
// const fs = require("fs");
|
||||
|
||||
const EmoteURLs = {
|
||||
TwitchGlobal: new FormattableString(`https://static-cdn.jtvnw.net/emoticons/v1/{{id}}/1.0`),
|
||||
TwitchSubscriber: new FormattableString(`https://static-cdn.jtvnw.net/emoticons/v1/{{id}}/1.0`),
|
||||
FrankerFaceZ: new FormattableString(`https://cdn.frankerfacez.com/emoticon/{{id}}/1`),
|
||||
BTTV: new FormattableString(`https://cdn.betterttv.net/emote/{{id}}/1x`),
|
||||
BTTV2: new FormattableString(`https://cdn.betterttv.net/emote/{{id}}/1x`)
|
||||
};
|
||||
|
||||
const EmoteMetaInfo = {
|
||||
TwitchGlobal: {},
|
||||
TwitchSubscriber: {},
|
||||
BTTV: {},
|
||||
FrankerFaceZ: {},
|
||||
BTTV2: {}
|
||||
};
|
||||
|
||||
const Emotes = {
|
||||
TwitchGlobal: {},
|
||||
|
@ -32,7 +49,8 @@ export default new class EmoteModule extends Builtin {
|
|||
get collection() {return "settings";}
|
||||
get category() {return "general";}
|
||||
get id() {return "emotes";}
|
||||
get categories() { return Object.keys(bdEmoteSettingIDs).filter(k => this.isCategoryEnabled(bdEmoteSettingIDs[k])); }
|
||||
get categories() {return Object.keys(bdEmoteSettingIDs).filter(k => this.isCategoryEnabled(bdEmoteSettingIDs[k]));}
|
||||
get shouldDownload() {return Settings.get("emotes", this.category, "download");}
|
||||
|
||||
isCategoryEnabled(id) {return super.get("emotes", "categories", id);}
|
||||
|
||||
|
@ -49,9 +67,8 @@ export default new class EmoteModule extends Builtin {
|
|||
get blacklist() {return blacklist;}
|
||||
get favorites() {return this.favoriteEmotes;}
|
||||
|
||||
getCategory(category) {
|
||||
return Emotes[category];
|
||||
}
|
||||
getCategory(category) {return Emotes[category];}
|
||||
getRemoteFile(category) {return new FormattableString(Utilities.repoUrl(`data/emotes/${category.toLowerCase()}.json`));}
|
||||
|
||||
initialize() {
|
||||
super.initialize();
|
||||
|
@ -66,10 +83,10 @@ export default new class EmoteModule extends Builtin {
|
|||
}
|
||||
|
||||
async enabled() {
|
||||
Settings.registerCollection("emotes", "Emotes", EmoteConfig, {title: Strings.Emotes.clearEmotes, onClick: () => { this.clearEmoteData(); this.loadEmoteData(EmoteInfo); }});
|
||||
Settings.registerCollection("emotes", "Emotes", EmoteConfig, {title: Strings.Emotes.clearEmotes, onClick: () => {this.clearEmoteData(); this.loadEmoteData();}});
|
||||
// Disable emote module for now because it's annoying and slow
|
||||
await this.getBlacklist();
|
||||
await this.loadEmoteData(EmoteInfo);
|
||||
await this.loadEmoteData();
|
||||
|
||||
while (!this.MessageContentComponent) await new Promise(resolve => setTimeout(resolve, 100));
|
||||
this.patchMessageContent();
|
||||
|
@ -178,103 +195,6 @@ export default new class EmoteModule extends Builtin {
|
|||
});
|
||||
}
|
||||
|
||||
async loadEmoteData(emoteInfo) {
|
||||
this.emotesLoaded = false;
|
||||
const _fs = require("fs");
|
||||
const emoteFile = "emote_data.json";
|
||||
const file = Config.dataPath + emoteFile;
|
||||
const exists = _fs.existsSync(file);
|
||||
|
||||
if (exists && this.isCacheValid()) {
|
||||
Toasts.show("Loading emotes from cache.", {type: "info"});
|
||||
this.log("Loading emotes from local cache.");
|
||||
|
||||
const data = await new Promise(resolve => {
|
||||
_fs.readFile(file, "utf8", (err, content) => {
|
||||
this.log("Emotes loaded from cache.");
|
||||
if (err) content = {};
|
||||
resolve(content);
|
||||
});
|
||||
});
|
||||
|
||||
const parsed = Utilities.testJSON(data);
|
||||
let isValid = !!parsed;
|
||||
if (isValid) Object.assign(Emotes, parsed);
|
||||
|
||||
for (const e in emoteInfo) {
|
||||
isValid = Object.keys(Emotes[emoteInfo[e].variable]).length > 0;
|
||||
}
|
||||
|
||||
if (isValid) {
|
||||
Toasts.show("Emotes successfully loaded.", {type: "success"});
|
||||
this.emotesLoaded = true;
|
||||
Events.dispatch("emotes-loaded");
|
||||
return;
|
||||
}
|
||||
|
||||
this.log("Cache was corrupt, downloading...");
|
||||
_fs.unlinkSync(file);
|
||||
}
|
||||
|
||||
if (!Settings.get(this.category, "general", "download")) return;
|
||||
Toasts.show(Strings.Emotes.downloading, {type: "info"});
|
||||
|
||||
for (const e in emoteInfo) {
|
||||
await new Promise(r => setTimeout(r, 1000));
|
||||
const data = await this.downloadEmotes(emoteInfo[e]);
|
||||
Emotes[emoteInfo[e].variable] = data;
|
||||
}
|
||||
|
||||
Toasts.show(Strings.Emotes.downloaded, {type: "success"});
|
||||
|
||||
try { _fs.writeFileSync(file, JSON.stringify(Emotes), "utf8"); }
|
||||
catch (err) { this.stacktrace("Could not save emote data.", err); }
|
||||
|
||||
this.emotesLoaded = true;
|
||||
Events.dispatch("emotes-loaded");
|
||||
}
|
||||
|
||||
downloadEmotes(emoteMeta) {
|
||||
const repoFile = Utilities.repoUrl(`data/emotes/${emoteMeta.variable.toLowerCase()}.json`);
|
||||
if (emoteMeta.url && !emoteMeta.backup) emoteMeta.backup = repoFile;
|
||||
if (!emoteMeta.url) emoteMeta.url = repoFile;
|
||||
|
||||
const options = {
|
||||
url: emoteMeta.url,
|
||||
timeout: emoteMeta.timeout ? emoteMeta.timeout : 5000,
|
||||
json: true
|
||||
};
|
||||
|
||||
this.log(`Downloading: ${emoteMeta.variable} (${emoteMeta.url})`);
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
request.get(options, (error, response, parsedData) => {
|
||||
if (error) {
|
||||
this.stacktrace("Could not download " + emoteMeta.variable, error);
|
||||
if (emoteMeta.backup || emoteMeta.url) {
|
||||
emoteMeta.url = emoteMeta.backup;
|
||||
emoteMeta.backup = null;
|
||||
if (emoteMeta.backupParser) emoteMeta.parser = emoteMeta.backupParser;
|
||||
return resolve(this.downloadEmotes(emoteMeta));
|
||||
}
|
||||
return reject({});
|
||||
}
|
||||
|
||||
if (typeof(emoteMeta.parser) === "function") parsedData = emoteMeta.parser(parsedData);
|
||||
|
||||
for (const emote in parsedData) {
|
||||
if (emote.length < 4 || blacklist.includes(emote)) {
|
||||
delete parsedData[emote];
|
||||
continue;
|
||||
}
|
||||
parsedData[emote] = emoteMeta.getEmoteURL(parsedData[emote]);
|
||||
}
|
||||
resolve(parsedData);
|
||||
this.log("Downloaded: " + emoteMeta.variable);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
getBlacklist() {
|
||||
return new Promise(resolve => {
|
||||
request.get({url: Utilities.repoUrl(`data/emotes/blacklist.json`), json: true}, (err, resp, data) => {
|
||||
|
@ -284,16 +204,64 @@ export default new class EmoteModule extends Builtin {
|
|||
});
|
||||
}
|
||||
|
||||
isCacheValid() {
|
||||
const cacheLength = DataStore.getBDData("emoteCacheDays") || DataStore.setBDData("emoteCacheDays", 7) || 7;
|
||||
const cacheDate = new Date(DataStore.getBDData("emoteCacheDate") || null);
|
||||
const currentDate = new Date();
|
||||
const daysBetween = Math.round(Math.abs((currentDate.getTime() - cacheDate.getTime()) / (24 * 60 * 60 * 1000)));
|
||||
if (daysBetween > cacheLength) {
|
||||
DataStore.setBDData("emoteCacheDate", currentDate.toJSON());
|
||||
return false;
|
||||
isCacheValid(category) {
|
||||
return new Promise(resolve => {
|
||||
const etag = DataStore.getCacheHash("emotes", category);
|
||||
if (!etag) return resolve(false);
|
||||
request.head({url: this.getRemoteFile(category), headers: {"If-None-Match": etag}}, (err, resp) => {
|
||||
resolve(resp.statusCode == 304);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
async loadEmoteData() {
|
||||
this.emotesLoaded = false;
|
||||
|
||||
for (const category in Emotes) {
|
||||
const exists = DataStore.emotesExist(category);
|
||||
const valid = await this.isCacheValid(category);
|
||||
const useCache = (valid) || (!valid && exists && !this.shouldDownload);
|
||||
let data = null;
|
||||
if (useCache) {
|
||||
this.log(`Loading ${category} emotes from local cache.`);
|
||||
const cachedData = DataStore.getEmoteData(category);
|
||||
const hasData = Object.keys(data).length > 0;
|
||||
if (hasData) data = cachedData;
|
||||
}
|
||||
if (!data) data = await this.downloadEmotes(category);
|
||||
Object.assign(Emotes[category], data);
|
||||
}
|
||||
return true;
|
||||
|
||||
// Toasts.show(Strings.Emotes.downloading, {type: "info"});
|
||||
// Toasts.show(Strings.Emotes.downloaded, {type: "success"});
|
||||
|
||||
this.emotesLoaded = true;
|
||||
Events.dispatch("emotes-loaded");
|
||||
}
|
||||
|
||||
downloadEmotes(category) {
|
||||
const url = this.getRemoteFile(category);
|
||||
this.log(`Downloading ${category} from ${url}`);
|
||||
const options = {url: url, timeout: 5000, json: true};
|
||||
return new Promise(resolve => {
|
||||
request.get(options, (error, response, parsedData) => {
|
||||
if (error || response.statusCode != 200) {
|
||||
this.stacktrace(`Could not download ${category} emotes.`, error);
|
||||
return resolve({});
|
||||
}
|
||||
|
||||
for (const emote in parsedData) {
|
||||
if (emote.length < 4 || blacklist.includes(emote) || !parsedData[emote]) {
|
||||
delete parsedData[emote];
|
||||
continue;
|
||||
}
|
||||
parsedData[emote] = EmoteURLs[category].format({id: parsedData[emote]});
|
||||
}
|
||||
DataStore.saveEmoteData(category, parsedData);
|
||||
resolve(parsedData);
|
||||
this.log(`Downloaded ${category}`);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
clearEmoteData() {
|
||||
|
@ -305,4 +273,24 @@ export default new class EmoteModule extends Builtin {
|
|||
DataStore.setBDData("emoteCacheDate", (new Date()).toJSON());
|
||||
for (const category in Emotes) Object.assign(Emotes, {[category]: {}});
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
// (async () => {
|
||||
// const emoteData = await new Promise(resolve => {
|
||||
// const req = require("request");
|
||||
// req.get({url: "https://twitchemotes.com/api_cache/v3/global.json", json: true}, (err, resp, parsedData) => {
|
||||
// for (const emote in parsedData) {
|
||||
// if (emote.length < 4 || window.bemotes.includes(emote)) {
|
||||
// delete parsedData[emote];
|
||||
// continue;
|
||||
// }
|
||||
// parsedData[emote] = parsedData[emote].id;
|
||||
// }
|
||||
// resolve(parsedData);
|
||||
// });
|
||||
// });
|
||||
// const fs = require("fs");
|
||||
// fs.writeFileSync("Z:\\Programming\\BetterDiscordStuff\\BetterDiscordApp\\data\\emotes\\global.json", JSON.stringify(emoteData));
|
||||
// return emoteData;
|
||||
// })();
|
|
@ -1,6 +1,4 @@
|
|||
import Config from "./config";
|
||||
import EmoteInfo from "./emotes/info";
|
||||
import EmoteConfig from "./emotes/config";
|
||||
import SettingsConfig from "./settings/config";
|
||||
|
||||
export {Config, EmoteInfo, EmoteConfig, SettingsConfig};
|
||||
export {default as Config} from "./config";
|
||||
export {default as EmoteConfig} from "./settings/emoteconfig";
|
||||
export {default as SettingsConfig} from "./settings/config";
|
||||
export {default as Strings} from "./strings";
|
|
@ -1,38 +0,0 @@
|
|||
export default {
|
||||
TwitchGlobal: {
|
||||
url: "https://twitchemotes.com/api_cache/v3/global.json",
|
||||
variable: "TwitchGlobal",
|
||||
getEmoteURL: (e) => `https://static-cdn.jtvnw.net/emoticons/v1/${e.id}/1.0`,
|
||||
getOldData: (url, name) => {return {id: url.match(/\/([0-9]+)\//)[1], code: name, emoticon_set: 0, description: null};}
|
||||
},
|
||||
TwitchSubscriber: {
|
||||
variable: "TwitchSubscriber",
|
||||
getEmoteURL: (e) => `https://static-cdn.jtvnw.net/emoticons/v1/${e}/1.0`,
|
||||
getOldData: (url) => url.match(/\/([0-9]+)\//)[1]
|
||||
},
|
||||
FrankerFaceZ: {
|
||||
variable: "FrankerFaceZ",
|
||||
getEmoteURL: (e) => `https://cdn.frankerfacez.com/emoticon/${e}/1`,
|
||||
getOldData: (url) => url.match(/\/([0-9]+)\//)[1]
|
||||
},
|
||||
BTTV: {
|
||||
url: "https://api.betterttv.net/emotes",
|
||||
variable: "BTTV",
|
||||
parser: (data) => {
|
||||
const emotes = {};
|
||||
for (let e = 0, len = data.emotes.length; e < len; e++) {
|
||||
const emote = data.emotes[e];
|
||||
emotes[emote.regex] = emote.url;
|
||||
}
|
||||
return emotes;
|
||||
},
|
||||
getEmoteURL: (e) => `${e}`,
|
||||
getOldData: (url) => url
|
||||
},
|
||||
BTTV2: {
|
||||
variable: "BTTV2",
|
||||
oldVariable: "emotesBTTV2",
|
||||
getEmoteURL: (e) => `https://cdn.betterttv.net/emote/${e}/1x`,
|
||||
getOldData: (url) => url.match(/emote\/(.+)\//)[1]
|
||||
}
|
||||
};
|
|
@ -17,28 +17,30 @@ export default new class DataStore {
|
|||
constructor() {
|
||||
this.data = {misc: {}};
|
||||
this.pluginData = {};
|
||||
this.localeHashes = {};
|
||||
this.cacheData = {};
|
||||
}
|
||||
|
||||
initialize() {
|
||||
if (!fs.existsSync(this.baseFolder)) fs.mkdirSync(this.baseFolder);
|
||||
if (!fs.existsSync(this.dataFolder)) fs.mkdirSync(this.dataFolder);
|
||||
if (!fs.existsSync(this.localeFolder)) fs.mkdirSync(this.localeFolder);
|
||||
if (!fs.existsSync(this.localeCache)) fs.writeFileSync(this.localeCache, JSON.stringify({}));
|
||||
if (!fs.existsSync(this.emoteFolder)) fs.mkdirSync(this.emoteFolder);
|
||||
if (!fs.existsSync(this.cacheFile)) fs.writeFileSync(this.cacheFile, JSON.stringify({}));
|
||||
if (!fs.existsSync(this.BDFile)) fs.writeFileSync(this.BDFile, JSON.stringify(this.data.misc, null, 4));
|
||||
if (!fs.existsSync(this.customCSS)) fs.writeFileSync(this.customCSS, "");
|
||||
const dataFiles = fs.readdirSync(this.dataFolder).filter(f => !fs.statSync(path.resolve(this.dataFolder, f)).isDirectory() && f.endsWith(".json"));
|
||||
for (const file of dataFiles) {
|
||||
this.data[file.split(".")[0]] = __non_webpack_require__(path.resolve(this.dataFolder, file));
|
||||
}
|
||||
this.localeHashes = JSON.parse(fs.readFileSync(this.localeCache).toString());
|
||||
this.cacheData = Utilities.testJSON(fs.readFileSync(this.cacheFile).toString()) || {};
|
||||
}
|
||||
|
||||
get customCSS() {return this._customCSS || (this._customCSS = path.resolve(this.dataFolder, "custom.css"));}
|
||||
get baseFolder() {return this._baseFolder || (this._baseFolder = path.resolve(Config.dataPath, "data"));}
|
||||
get dataFolder() {return this._dataFolder || (this._dataFolder = path.resolve(this.baseFolder, `${releaseChannel}`));}
|
||||
get localeFolder() {return this._localeFolder || (this._localeFolder = path.resolve(this.baseFolder, `locales`));}
|
||||
get localeCache() {return this._localeCache || (this._localeCache = path.resolve(this.localeFolder, `.cache`));}
|
||||
get emoteFolder() {return this._emoteFolder || (this._emoteFolder = path.resolve(this.baseFolder, `emotes`));}
|
||||
get cacheFile() {return this._cacheFile || (this._cacheFile = path.resolve(this.baseFolder, `.cache`));}
|
||||
get BDFile() {return this._BDFile || (this._BDFile = path.resolve(Config.dataPath, "data", `${releaseChannel}.json`));}
|
||||
getPluginFile(pluginName) {return path.resolve(Config.dataPath, "plugins", pluginName + ".config.json");}
|
||||
|
||||
|
@ -67,13 +69,30 @@ export default new class DataStore {
|
|||
fs.writeFileSync(path.resolve(this.localeFolder, `${locale}.json`), JSON.stringify(strings, null, 4));
|
||||
}
|
||||
|
||||
getLocaleHash(locale) {
|
||||
return this.localeHashes[locale] || "";
|
||||
getCacheHash(category, key) {
|
||||
if (!this.cacheData[category]) return "";
|
||||
if (!fs.existsSync(path.resolve(this.baseFolder, category, `${key}.json`))) return "";
|
||||
return this.cacheData[category][key] || "";
|
||||
}
|
||||
|
||||
saveLocaleHash(locale, hash) {
|
||||
this.localeHashes[locale] = hash;
|
||||
fs.writeFileSync(this.localeCache, JSON.stringify(this.localeHashes, null, 4));
|
||||
setCacheHash(category, key, hash) {
|
||||
if (!this.cacheData[category]) this.cacheData[category] = {};
|
||||
this.cacheData[category][key] = hash;
|
||||
fs.writeFileSync(this.cacheFile, JSON.stringify(this.cacheData, null, 4));
|
||||
}
|
||||
|
||||
emotesExist(category) {
|
||||
return fs.existsSync(path.resolve(this.emoteFolder, `${category}.json`));
|
||||
}
|
||||
|
||||
getEmoteData(category) {
|
||||
const file = path.resolve(this.emoteFolder, `${category}.json`);
|
||||
if (!fs.existsSync(file)) return null;
|
||||
return Utilities.testJSON(fs.readFileSync(file).toString());
|
||||
}
|
||||
|
||||
saveEmoteData(category, data) {
|
||||
fs.writeFileSync(path.resolve(this.emoteFolder, `${category}.json`), JSON.stringify(data));
|
||||
}
|
||||
|
||||
getData(key) {
|
||||
|
|
|
@ -39,7 +39,7 @@ export default new class LocaleManager {
|
|||
}
|
||||
|
||||
async getLocaleStrings(locale) {
|
||||
const hash = DataStore.getLocaleHash(locale);
|
||||
const hash = DataStore.getCacheHash("locales", locale);
|
||||
if (!hash) return await this.downloadLocale(locale);
|
||||
const invalid = await this.downloadLocale(locale, hash);
|
||||
if (!invalid) return DataStore.getLocale(locale);
|
||||
|
@ -54,12 +54,10 @@ export default new class LocaleManager {
|
|||
json: true
|
||||
};
|
||||
if (hash) options.headers = {"If-None-Match": hash};
|
||||
console.log(options.headers);
|
||||
request.get(options, (err, resp, newStrings) => {
|
||||
if (err || resp.statusCode !== 200) return resolve(null);
|
||||
console.log(resp);
|
||||
DataStore.saveLocale(locale, newStrings);
|
||||
DataStore.saveLocaleHash(locale, resp.headers.etag);
|
||||
DataStore.setCacheHash("locales", locale, resp.headers.etag);
|
||||
resolve(newStrings);
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue