diff --git a/src/modules/addonmanager.js b/src/modules/addonmanager.js index 28482a29..b587a2e8 100644 --- a/src/modules/addonmanager.js +++ b/src/modules/addonmanager.js @@ -33,6 +33,7 @@ export default class AddonManager { get name() {return "";} get moduleExtension() {return "";} get extension() {return "";} + get duplicatePattern() {return /./;} get addonFolder() {return "";} get language() {return "";} get prefix() {return "addon";} @@ -80,10 +81,30 @@ export default class AddonManager { if (this.watcher) return Logger.error(this.name, `Already watching ${this.prefix} addons.`); Logger.log(this.name, `Starting to watch ${this.prefix} addons.`); this.watcher = fs.watch(this.addonFolder, {persistent: false}, async (eventType, filename) => { - if (!eventType || !filename || !filename.endsWith(this.extension)) return; + if (!eventType || !filename) return; + + const absolutePath = path.resolve(this.addonFolder, filename); + if (!filename.endsWith(this.extension)) { + // Lets check to see if this filename has the duplicated file pattern `something(1).ext` + const match = filename.match(this.duplicatePattern); + if (!match) continue; + const ext = match[0]; + const truncated = filename.replace(ext, ""); + const newFilename = truncated + this.extension; + + // If this file already exists, give a warning and move on. + if (fs.existsSync(newFile)) { + Logger.warn("AddonManager", `Duplicate files found: ${filename} and ${newFilename}`); + continue; + } + + // Rename the file and let it go on + fs.renameSync(absolutePath, path.resolve(this.addonFolder, newFilename)); + } + await new Promise(r => setTimeout(r, 100)); try { - const stats = fs.statSync(path.resolve(this.addonFolder, filename)); + const stats = fs.statSync(absolutePath); if (!stats.isFile()) return; if (!stats || !stats.mtime || !stats.mtime.getTime()) return; if (typeof(stats.mtime.getTime()) !== "number") return; @@ -266,13 +287,31 @@ export default class AddonManager { const files = fs.readdirSync(this.addonFolder); for (const filename of files) { - if (!fs.statSync(path.resolve(this.addonFolder, filename)).isFile() || !filename.endsWith(this.extension)) continue; + const absolutePath = path.resolve(this.addonFolder, filename); + if (!fs.statSync(absolutePath).isFile()) continue; + if (!filename.endsWith(this.extension)) { + // Lets check to see if this filename has the duplicated file pattern `something(1).ext` + const match = filename.match(this.duplicatePattern); + if (!match) continue; + const ext = match[0]; + const truncated = filename.replace(ext, ""); + const newFilename = truncated + this.extension; + + // If this file already exists, give a warning and move on. + if (fs.existsSync(newFile)) { + Logger.warn("AddonManager", `Duplicate files found: ${filename} and ${newFilename}`); + continue; + } + + // Rename the file and let it go on + fs.renameSync(absolutePath, path.resolve(this.addonFolder, newFilename)); + } const addon = this.loadAddon(filename, false); if (addon instanceof AddonError) errors.push(addon); } this.saveState(); - if (Settings.get(this.collection, this.category, this.id)) this.watchAddons(); + //if (Settings.get(this.collection, this.category, this.id)) this.watchAddons(); return errors; } diff --git a/src/modules/patcher.js b/src/modules/patcher.js index edf7bd41..59dea1c8 100644 --- a/src/modules/patcher.js +++ b/src/modules/patcher.js @@ -46,9 +46,9 @@ export default class Patcher { } static resolveModule(module) { - if (module instanceof Function || (module instanceof Object && !(module instanceof Array))) return module; + if (!module || typeof(module) === "function" || (typeof(module) === "object" && !Array.isArray(module))) return module; if (typeof module === "string") return DiscordModules[module]; - if (module instanceof Array) return WebpackModules.findByUniqueProperties(module); + if (Array.isArray(module)) return WebpackModules.findByUniqueProperties(module); return null; } @@ -112,6 +112,7 @@ export default class Patcher { children: [] }; patch.proxyFunction = module[functionName] = this.makeOverride(patch); + Object.assign(module[functionName], patch.originalFunction); module[functionName].__originalFunction = patch.originalFunction; module[functionName].toString = () => patch.originalFunction.toString(); this.patches.push(patch); @@ -217,6 +218,7 @@ export default class Patcher { patch.children.splice(patch.children.findIndex(cpatch => cpatch.id === child.id && cpatch.type === type), 1); if (patch.children.length <= 0) { const patchNum = this.patches.findIndex(p => p.module == module && p.functionName == functionName); + if (patchNum < 0) return; this.patches[patchNum].revert(); this.patches.splice(patchNum, 1); } diff --git a/src/modules/pluginmanager.js b/src/modules/pluginmanager.js index 0031cedc..8b4b78b0 100644 --- a/src/modules/pluginmanager.js +++ b/src/modules/pluginmanager.js @@ -16,6 +16,7 @@ export default new class PluginManager extends AddonManager { get name() {return "PluginManager";} get moduleExtension() {return ".js";} get extension() {return ".plugin.js";} + get duplicatePattern() {return /\.plugin\([0-9]+\)\.js/} get addonFolder() {return path.resolve(Config.dataPath, "plugins");} get prefix() {return "plugin";} get language() {return "javascript";} diff --git a/src/modules/thememanager.js b/src/modules/thememanager.js index d1df00fa..f3325098 100644 --- a/src/modules/thememanager.js +++ b/src/modules/thememanager.js @@ -14,6 +14,7 @@ export default new class ThemeManager extends AddonManager { get name() {return "ThemeManager";} get moduleExtension() {return ".css";} get extension() {return ".theme.css";} + get duplicatePattern() {return /\.theme\([0-9]+\)\.css/} get addonFolder() {return path.resolve(Config.dataPath, "themes");} get prefix() {return "theme";} get language() {return "css";} diff --git a/src/modules/webpackmodules.js b/src/modules/webpackmodules.js index 5069e3ee..3b53c2ea 100644 --- a/src/modules/webpackmodules.js +++ b/src/modules/webpackmodules.js @@ -25,7 +25,10 @@ export class Filters { return module => { const component = filter(module); if (!component) return false; - return props.every(property => component[property] !== undefined); + for (let p = 0; p < props.length; p++) { + if (component[props[p]] === undefined) return false; + } + return true; }; } @@ -40,7 +43,10 @@ export class Filters { const component = filter(module); if (!component) return false; if (!component.prototype) return false; - return fields.every(field => component.prototype[field] !== undefined); + for (let f = 0; f < fields.length; f++) { + if (component.prototype[fields[f]] === undefined) return false; + } + return true; }; } @@ -54,7 +60,10 @@ export class Filters { return module => { const method = filter(module); if (!method) return false; - return method.toString([]).search(search) !== -1; + let methodString = ""; + try {methodString = method.toString([]);} + catch (err) {methodString = method.toString();} + return methodString.search(search) !== -1; }; } @@ -65,7 +74,9 @@ export class Filters { */ static byString(...strings) { return module => { - const moduleString = module.toString([]); + let moduleString = ""; + try {moduleString = module.toString([]);} + catch (err) {moduleString = module.toString();} for (const s of strings) { if (!moduleString.includes(s)) return false; } @@ -130,6 +141,10 @@ export default class WebpackModules { * @return {Any} */ static getModule(filter, first = true) { + const wrappedFilter = (m) => { + try {return filter(m);} + catch (err) {return false;} + }; const modules = this.getAllModules(); const rm = []; for (const index in modules) { @@ -139,8 +154,8 @@ export default class WebpackModules { let foundModule = null; if (!exports) continue; - if (exports.__esModule && exports.default && filter(exports.default)) foundModule = exports.default; - if (filter(exports)) foundModule = exports; + if (exports.__esModule && exports.default && wrappedFilter(exports.default)) foundModule = exports.default; + if (wrappedFilter(exports)) foundModule = exports; if (!foundModule) continue; if (first) return protect(foundModule); rm.push(protect(foundModule));