CR v0.1.4

This commit is contained in:
_Lighty_ 2020-03-05 16:16:55 +01:00
parent 164a8b9e4c
commit a2fe1bc7dd
3 changed files with 203 additions and 163 deletions

View File

@ -1,4 +1,10 @@
# [CrashRecovery](https://1lighty.github.io/BetterDiscordStuff/?plugin=CrashRecovery "CrashRecovery") Changelog # [CrashRecovery](https://1lighty.github.io/BetterDiscordStuff/?plugin=CrashRecovery "CrashRecovery") Changelog
### 0.1.4
- Improved detection accuracy
- Added failsafe in case something goes wrong when: initializing, starting or when trying to display the recover button
- Added third step when trying to recover, as to not switch channels unless required, can be disabled in settings.
- Plugin is no longer experimental
### 0.1.3 ### 0.1.3
- Fixed crash if XenoLib or ZeresPluginLib were missing - Fixed crash if XenoLib or ZeresPluginLib were missing

View File

@ -41,51 +41,62 @@ var CrashRecovery = (() => {
twitter_username: '' twitter_username: ''
} }
], ],
version: '0.1.3', version: '0.1.4',
description: 'THIS IS AN EXPERIMENTAL PLUGIN! In the event that your Discord crashes, the plugin enables you to get Discord back to a working state, without needing to reload at all.', description: 'In the event that your Discord crashes, the plugin enables you to get Discord back to a working state, without needing to reload at all.',
github: 'https://github.com/1Lighty', github: 'https://github.com/1Lighty',
github_raw: 'https://raw.githubusercontent.com/1Lighty/BetterDiscordPlugins/master/Plugins/CrashRecovery/CrashRecovery.plugin.js' github_raw: 'https://raw.githubusercontent.com/1Lighty/BetterDiscordPlugins/master/Plugins/CrashRecovery/CrashRecovery.plugin.js'
}, },
changelog: [ changelog: [
{ {
title: 'sad', title: 'misc changes',
type: 'fixed', type: 'fixed',
items: ['Fixed crash if XenoLib or ZeresPluginLib were missing'] items: ['Improved detection accuracy', 'Added failsafe in case something goes wrong when: initializing, starting or when trying to display the recover button', 'Added third step when trying to recover, as to not switch channels unless required, can be disabled in settings.', 'Plugin is no longer experimental']
}
],
defaultConfig: [
{
name: 'Enable step 3',
note: 'Moves channel switch to a third and last step, otherwise it switches on step 2',
id: 'useThirdStep',
type: 'switch',
value: true
} }
] ]
}; };
/* Build */ /* Build */
const buildPlugin = ([Plugin, Api]) => { const buildPlugin = ([Plugin, Api]) => {
const { Logger, DiscordAPI, Settings, Utilities, WebpackModules, DiscordModules, ColorConverter, ReactComponents, Patcher, PluginUtilities } = Api; const { Logger, Utilities, WebpackModules, DiscordModules, Patcher, PluginUtilities, ReactTools, PluginUpdater } = Api;
const { React, ChannelStore, Dispatcher, MessageActions, APIModule, FlexChild: Flex } = DiscordModules; const { React, Dispatcher, FlexChild: Flex, GuildStore } = DiscordModules;
const DelayedCall = WebpackModules.getByProps('DelayedCall').DelayedCall;
const DelayedCall = (WebpackModules.getByProps('DelayedCall') || {}).DelayedCall;
const ElectronDiscordModule = WebpackModules.getByProps('cleanupDisplaySleep'); const ElectronDiscordModule = WebpackModules.getByProps('cleanupDisplaySleep');
class ErrorCatcher extends React.PureComponent {
constructor(props) {
super(props);
this.state = { hasError: false };
}
componentDidCatch(err, inf) {
Logger.err(`Error in ${this.props.label}, screenshot or copy paste the error above to Lighty for help.`);
this.setState({ hasError: true });
if (typeof this.props.onError === 'function') this.props.onError(err);
}
render() {
if (this.state.hasError) return null;
return this.props.children;
}
}
return class CrashRecovery extends Plugin { return class CrashRecovery extends Plugin {
constructor() { constructor() {
super(); super();
XenoLib.changeName(__filename, 'CrashRecovery'); XenoLib.changeName(__filename, 'CrashRecovery');
this._startFailure = message => {
PluginUpdater.checkForUpdate(this.name, this.version, this._config.info.github_raw);
XenoLib.Notifications.error(`[**${this.name}**] ${message} Please update it, press CTRL + R, or ${GuildStore.getGuild(XenoLib.supportServerId) ? 'go to <#639665366380838924>' : '[join my support server](https://discord.gg/NYvWdN5)'} for further assistance.`, { timeout: 0 });
};
const oOnStart = this.onStart.bind(this);
this.onStart = () => {
try {
oOnStart();
} catch (e) {
Logger.stacktrace('Failed to start!', e);
this._startFailure('Failed to start!');
try {
this.onStop();
} catch (e) {}
}
};
} }
onStart() { onStart() {
this.attempts = 0;
this.promises = { state: { cancelled: false } };
if (!DelayedCall) return this._startFailure('DelayedCall missing, plugin cannot function.');
delete this.onCrashRecoveredDelayedCall; delete this.onCrashRecoveredDelayedCall;
this.onCrashRecoveredDelayedCall = new DelayedCall(1000, () => { this.onCrashRecoveredDelayedCall = new DelayedCall(1000, () => {
XenoLib.Notifications.remove(this.notificationId); XenoLib.Notifications.remove(this.notificationId);
@ -108,10 +119,20 @@ var CrashRecovery = (() => {
this.suspectedPlugin = null; this.suspectedPlugin = null;
this.suspectedPlugin2 = null; this.suspectedPlugin2 = null;
this.attempts = 0; this.attempts = 0;
const appMount = document.querySelector('#app-mount');
appMount.append(document.querySelector('.xenoLib-notifications'));
const BIVOverlay = document.querySelector('.biv-overlay');
if (BIVOverlay) appMount.append(BIVOverlay);
Logger.info('Corrected incorrectly placed containers');
}); });
this.attempts = 0;
this.promises = { state: { cancelled: false } };
this.patchAll(); this.patchAll();
if (!document.querySelector(`.${XenoLib.getSingleClass('errorPage')}`))
this.__safeClearTimeout = setTimeout(() => {
if (global.bdpluginErrors && global.bdpluginErrors.length) {
global.bdpluginErrors = [];
Logger.info('Cleared global.bdpluginErrors');
}
}, 7500);
} }
onStop() { onStop() {
this.promises.state.cancelled = true; this.promises.state.cancelled = true;
@ -125,11 +146,17 @@ var CrashRecovery = (() => {
queryResponsiblePlugins(stack) { queryResponsiblePlugins(stack) {
try { try {
const match = stack.match(/(?:\\|\/)([^\/\\]+)\.plugin.js/g); const match = stack.match(/^.*(?:\\|\/|VM\d+ )([^\/\\\n]+)\.plugin\.js/gm);
const plugins = []; const plugins = [];
if (!match || !match.length) return null; if (!match || !match.length) return null;
let onDispatchEventFound = false;
for (let i = 0; i < match.length; i++) { for (let i = 0; i < match.length; i++) {
const pluginName = match[i].match(/(?:\\|\/)([^\/\\]+)\.plugin.js/)[1]; const pluginName = match[i].match(/(?:\\|\/)([^\/\\]+)\.plugin\.js/)[1];
if (match[i].indexOf('MessageLoggerV2.onDispatchEvent') !== -1) {
onDispatchEventFound = true;
continue;
}
if (onDispatchEventFound && /Object\.callback.*(?:\\|\/|VM\d+ )MessageLoggerV2\.plugin\.js/.test(match[i])) continue;
if (pluginName === '0PluginLibrary' || pluginName === this.name) continue; if (pluginName === '0PluginLibrary' || pluginName === this.name) continue;
const bbdplugin = Object.values(bdplugins).find(m => m.filename.startsWith(pluginName)); const bbdplugin = Object.values(bdplugins).find(m => m.filename.startsWith(pluginName));
const name = (bbdplugin && bbdplugin.name) || pluginName; const name = (bbdplugin && bbdplugin.name) || pluginName;
@ -150,13 +177,14 @@ var CrashRecovery = (() => {
DiscordModules.ModalStack.popAll(); DiscordModules.ModalStack.popAll();
DiscordModules.LayerManager.popAllLayers(); DiscordModules.LayerManager.popAllLayers();
DiscordModules.PopoutStack.closeAll(); DiscordModules.PopoutStack.closeAll();
DiscordModules.NavigationUtils.transitionTo('/channels/@me');
WebpackModules.getByProps('openModal').modalsApi.setState(() => ({ default: [] })); /* slow? unsafe? async? */ WebpackModules.getByProps('openModal').modalsApi.setState(() => ({ default: [] })); /* slow? unsafe? async? */
if (!this.settings.useThirdStep) DiscordModules.NavigationUtils.transitionTo('/channels/@me');
}); });
} }
handleCrash(_this, stack, isRender) { handleCrash(_this, stack, isRender) {
this.onCrashRecoveredDelayedCall.cancel(); this.onCrashRecoveredDelayedCall.cancel();
if (this.__safeClearTimeout) clearTimeout(this.__safeClearTimeout), (this.__safeClearTimeout = 0);
if (!isRender) { if (!isRender) {
_this.setState({ _this.setState({
error: { stack } error: { stack }
@ -185,12 +213,15 @@ var CrashRecovery = (() => {
}, 750); }, 750);
} }
if (this.setStateTimeout) return; if (this.setStateTimeout) return;
if (this.attempts >= 10 || (this.attempts >= 2 && (!responsiblePlugins || !responsiblePlugins[0]))) { if (this.attempts >= 10 || ((this.settings.useThirdStep ? this.attempts >= 3 : this.attempts >= 2) && (!responsiblePlugins || !responsiblePlugins[0]))) {
XenoLib.Notifications.update(this.notificationId, { content: 'Failed to recover from crash', loading: false }); XenoLib.Notifications.update(this.notificationId, { content: 'Failed to recover from crash', loading: false });
return; return;
} }
if (this.attempts === 1) XenoLib.Notifications.update(this.notificationId, { content: 'Failed, trying again' }); if (this.attempts === 1) XenoLib.Notifications.update(this.notificationId, { content: 'Failed, trying again' });
else if (this.attempts >= 2) { else if (this.settings.useThirdStep && this.attempts === 2) {
Dispatcher.wait(() => DiscordModules.NavigationUtils.transitionTo('/channels/@me'));
XenoLib.Notifications.update(this.notificationId, { content: `Failed, switching channels` });
} else if (this.attempts >= 2) {
try { try {
pluginModule.disablePlugin(responsiblePlugins[0]); pluginModule.disablePlugin(responsiblePlugins[0]);
} catch (e) {} } catch (e) {}
@ -225,43 +256,50 @@ var CrashRecovery = (() => {
if (!this.notificationId) { if (!this.notificationId) {
this.handleCrash(_this, _this.state.error.stack, true); this.handleCrash(_this, _this.state.error.stack, true);
} }
ret.props.action = React.createElement( /* better be safe than sorry! */
Flex, if (!_this.state.customPageError) {
{ ret.props.action = React.createElement(
grow: 0, XenoLib.ReactComponents.ErrorBoundary,
direction: Flex.Direction.HORIZONTAL { label: 'ErrorBoundary patch', onError: () => _this.setState({ customPageError: true /* sad day.. */ }) },
}, React.createElement(
React.createElement( Flex,
XenoLib.ReactComponents.Button, {
{ grow: 0,
size: XenoLib.ReactComponents.ButtonOptions.ButtonSizes.LARGE, direction: Flex.Direction.HORIZONTAL
style: {
marginRight: 20
}, },
onClick: () => { React.createElement(
this.attempts = 0; XenoLib.ReactComponents.Button,
this.disabledPlugins = null; {
XenoLib.Notifications.update(this.notificationId, { content: 'If you say so.. trying again', loading: true }); size: XenoLib.ReactComponents.ButtonOptions.ButtonSizes.LARGE,
_this.setState({ style: {
error: null, marginRight: 20
info: null },
}); onClick: () => {
} this.attempts = 0;
}, this.disabledPlugins = null;
'Recover' XenoLib.Notifications.update(this.notificationId, { content: 'If you say so.. trying again', loading: true });
), _this.setState({
React.createElement( error: null,
XenoLib.ReactComponents.Button, info: null
{ });
size: XenoLib.ReactComponents.ButtonOptions.ButtonSizes.LARGE, }
style: { },
marginRight: 20 'Recover'
}, ),
onClick: () => window.location.reload(true) React.createElement(
}, XenoLib.ReactComponents.Button,
'Reload' {
) size: XenoLib.ReactComponents.ButtonOptions.ButtonSizes.LARGE,
); style: {
marginRight: 20
},
onClick: () => window.location.reload(true)
},
'Reload'
)
)
);
}
ret.props.note = [ ret.props.note = [
React.createElement('div', {}, 'Discord has crashed!'), React.createElement('div', {}, 'Discord has crashed!'),
this.suspectedPlugin ? React.createElement('div', {}, this.suspectedPlugin, this.suspectedPlugin2 && this.suspectedPlugin2 !== this.suspectedPlugin ? [' or ', this.suspectedPlugin2] : false, ' is likely responsible for the crash') : this.suspectedPlugin2 ? React.createElement('div', {}, this.suspectedPlugin2, ' is likely responsible for the crash') : React.createElement('div', {}, 'Plugin responsible for crash is unknown'), this.suspectedPlugin ? React.createElement('div', {}, this.suspectedPlugin, this.suspectedPlugin2 && this.suspectedPlugin2 !== this.suspectedPlugin ? [' or ', this.suspectedPlugin2] : false, ' is likely responsible for the crash') : this.suspectedPlugin2 ? React.createElement('div', {}, this.suspectedPlugin2, ' is likely responsible for the crash') : React.createElement('div', {}, 'Plugin responsible for crash is unknown'),
@ -277,11 +315,17 @@ var CrashRecovery = (() => {
global.bdpluginErrors && global.bdpluginErrors.length ? React.createElement('div', {}, global.bdpluginErrors.length, ' plugins have been disabled by BBD due to the crash') : null global.bdpluginErrors && global.bdpluginErrors.length ? React.createElement('div', {}, global.bdpluginErrors.length, ' plugins have been disabled by BBD due to the crash') : null
]; ];
}); });
ZLibrary.ReactTools.getOwnerInstance(document.querySelector('.errorPage-u8SYh4') || document.querySelector('#app-mount > svg:first-of-type'), { include: ['ErrorBoundary'] }).forceUpdate(); const ErrorBoundaryInstance = ReactTools.getOwnerInstance(document.querySelector(`.${XenoLib.getSingleClass('errorPage')}`) || document.querySelector('#app-mount > svg:first-of-type'), { include: ['ErrorBoundary'] });
ErrorBoundaryInstance.state.customPageError = false;
ErrorBoundaryInstance.forceUpdate();
} }
/* PATCHES */ /* PATCHES */
showChangelog(footer) {
XenoLib.showChangelog(`${this.name} has been updated!`, this.version, this._config.changelog);
}
getSettingsPanel() { getSettingsPanel() {
return this.buildSettingsPanel().getElement(); return this.buildSettingsPanel().getElement();
} }
@ -319,7 +363,21 @@ var CrashRecovery = (() => {
/* Finalize */ /* Finalize */
return !global.ZeresPluginLibrary || !global.XenoLib let ZeresPluginLibraryOutdated = false;
let XenoLibOutdated = false;
try {
if (global.BdApi && 'function' == typeof BdApi.getPlugin) {
const i = (i, n) => ((i = i.split('.').map(i => parseInt(i))), (n = n.split('.').map(i => parseInt(i))), !!(n[0] > i[0]) || !!(n[0] == i[0] && n[1] > i[1]) || !!(n[0] == i[0] && n[1] == i[1] && n[2] > i[2])),
n = (n, e) => n && n._config && n._config.info && n._config.info.version && i(n._config.info.version, e),
e = BdApi.getPlugin('ZeresPluginLibrary'),
o = BdApi.getPlugin('XenoLib');
n(e, '1.2.10') && (ZeresPluginLibraryOutdated = !0), n(o, '1.3.11') && (XenoLibOutdated = !0);
}
} catch (i) {
console.error('Error checking if libraries are out of date', i);
}
return !global.ZeresPluginLibrary || !global.XenoLib || ZeresPluginLibraryOutdated || XenoLibOutdated
? class { ? class {
getName() { getName() {
return this.name.replace(/\s+/g, ''); return this.name.replace(/\s+/g, '');
@ -335,119 +393,94 @@ var CrashRecovery = (() => {
} }
stop() {} stop() {}
load() { load() {
const XenoLibMissing = !global.XenoLib; const a = !global.XenoLib,
const zlibMissing = !global.ZeresPluginLibrary; b = !global.ZeresPluginLibrary,
const bothLibsMissing = XenoLibMissing && zlibMissing; c = (a && b) || ((a || b) && (XenoLibOutdated || ZeresPluginLibraryOutdated)) || XenoLibOutdated || ZeresPluginLibraryOutdated,
const header = `Missing ${(bothLibsMissing && 'Libraries') || 'Library'}`; d = (() => {
const content = `The ${(bothLibsMissing && 'Libraries') || 'Library'} ${(zlibMissing && 'ZeresPluginLibrary') || ''} ${(XenoLibMissing && (zlibMissing ? 'and XenoLib' : 'XenoLib')) || ''} required for ${this.name} ${(bothLibsMissing && 'are') || 'is'} missing.`; let d = '';
const ModalStack = BdApi.findModuleByProps('push', 'update', 'pop', 'popWithKey'); return a || b ? (d += `Missing${XenoLibOutdated || ZeresPluginLibraryOutdated ? ' and outdated' : ''} `) : (XenoLibOutdated || ZeresPluginLibraryOutdated) && (d += `Outdated `), (d += `${c ? 'Libraries' : 'Library'} `), d;
const TextElement = BdApi.findModuleByProps('Sizes', 'Weights'); })(),
const ConfirmationModal = BdApi.findModule(m => m.defaultProps && m.key && m.key() === 'confirm-modal'); e = (() => {
const onFail = () => BdApi.getCore().alert(header, `${content}<br/>Due to a slight mishap however, you'll have to download the libraries yourself. After opening the links, do CTRL + S to download the library.<br/>${(zlibMissing && '<br/><a href="https://rauenzi.github.io/BDPluginLibrary/release/0PluginLibrary.plugin.js"target="_blank">Click here to download ZeresPluginLibrary</a>') || ''}${(zlibMissing && '<br/><a href="http://localhost:7474/XenoLib.js"target="_blank">Click here to download XenoLib</a>') || ''}`); let d = `The ${c ? 'libraries' : 'library'} `;
if (!ModalStack || !ConfirmationModal || !TextElement) return onFail(); return a || XenoLibOutdated ? ((d += 'XenoLib '), (b || ZeresPluginLibraryOutdated) && (d += 'and ZeresPluginLibrary ')) : (b || ZeresPluginLibraryOutdated) && (d += 'ZeresPluginLibrary '), (d += `required for ${this.name} ${c ? 'are' : 'is'} ${a || b ? 'missing' : ''}${XenoLibOutdated || ZeresPluginLibraryOutdated ? (a || b ? ' and/or outdated' : 'outdated') : ''}.`), d;
class TempErrorBoundary extends BdApi.React.PureComponent { })(),
constructor(props) { f = BdApi.findModuleByProps('push', 'update', 'pop', 'popWithKey'),
super(props); g = BdApi.findModuleByProps('Sizes', 'Weights'),
this.state = { hasError: false }; h = BdApi.findModule(a => a.defaultProps && a.key && 'confirm-modal' === a.key()),
i = () => BdApi.getCore().alert(d, `${e}<br/>Due to a slight mishap however, you'll have to download the libraries yourself. After opening the links, do CTRL + S to download the library.<br/>${b || ZeresPluginLibraryOutdated ? '<br/><a href="http://betterdiscord.net/ghdl/?url=https://github.com/rauenzi/BDPluginLibrary/blob/master/release/0PluginLibrary.plugin.js"target="_blank">Click here to download ZeresPluginLibrary</a>' : ''}${a || XenoLibOutdated ? '<br/><a href="http://betterdiscord.net/ghdl/?url=https://github.com/1Lighty/BetterDiscordPlugins/blob/master/Plugins/1XenoLib.plugin.js"target="_blank">Click here to download XenoLib</a>' : ''}`);
if (!f || !h || !g) return i();
let j;
const k = (() => {
if (!global.pluginModule || !global.BDEvents) return;
if (a || XenoLibOutdated) {
const a = () => {
BDEvents.off('xenolib-loaded', a), f.popWithKey(j), pluginModule.reloadPlugin(this.name);
};
return BDEvents.on('xenolib-loaded', a), () => BDEvents.off('xenolib-loaded', a);
} }
componentDidCatch(err, inf) { const b = a => {
console.error(`Error in ${this.props.label}, screenshot or copy paste the error above to Lighty for help.`); 'ZeresPluginLibrary' !== a || (BDEvents.off('plugin-loaded', b), BDEvents.off('plugin-reloaded', b), f.popWithKey(j), pluginModule.reloadPlugin(this.name));
this.setState({ hasError: true }); };
if (typeof this.props.onError === 'function') this.props.onError(err); return BDEvents.on('plugin-loaded', b), BDEvents.on('plugin-reloaded', b), () => (BDEvents.off('plugin-loaded', b), BDEvents.off('plugin-reloaded', b));
})();
class l extends BdApi.React.PureComponent {
constructor(a) {
super(a), (this.state = { hasError: !1 });
}
componentDidCatch(a, b) {
console.error(`Error in ${this.props.label}, screenshot or copy paste the error above to Lighty for help.`), this.setState({ hasError: !0 }), 'function' == typeof this.props.onError && this.props.onError(a);
} }
render() { render() {
if (this.state.hasError) return null; return this.state.hasError ? null : this.props.children;
return this.props.children;
} }
} }
let modalId; j = f.push(a =>
const onHeckWouldYouLookAtThat = (() => { BdApi.React.createElement(
if (!global.pluginModule || !global.BDEvents) return; l,
if (XenoLibMissing) {
const listener = () => {
BDEvents.off('xenolib-loaded', listener);
ModalStack.popWithKey(modalId); /* make it easier on the user */
pluginModule.reloadPlugin(this.name);
};
BDEvents.on('xenolib-loaded', listener);
return () => BDEvents.off('xenolib-loaded', listener);
} else {
const onLoaded = e => {
if (e !== 'ZeresPluginLibrary') return;
BDEvents.off('plugin-loaded', onLoaded);
ModalStack.popWithKey(modalId); /* make it easier on the user */
pluginModule.reloadPlugin(this.name);
};
BDEvents.on('plugin-loaded', onLoaded);
return () => BDEvents.off('plugin-loaded', onLoaded);
}
})();
modalId = ModalStack.push(props => {
return BdApi.React.createElement(
TempErrorBoundary,
{ {
label: 'missing dependency modal', label: 'missing dependency modal',
onError: () => { onError: () => {
ModalStack.popWithKey(modalId); /* smh... */ f.popWithKey(j), i();
onFail();
} }
}, },
BdApi.React.createElement( BdApi.React.createElement(
ConfirmationModal, h,
Object.assign( Object.assign(
{ {
header, header: d,
children: [BdApi.React.createElement(TextElement, { color: TextElement.Colors.PRIMARY, children: [`${content} Please click Download Now to install ${(bothLibsMissing && 'them') || 'it'}.`] })], children: [BdApi.React.createElement(g, { color: g.Colors.PRIMARY, children: [`${e} Please click Download Now to download ${c ? 'them' : 'it'}.`] })],
red: false, red: !1,
confirmText: 'Download Now', confirmText: 'Download Now',
cancelText: 'Cancel', cancelText: 'Cancel',
onConfirm: () => { onConfirm: () => {
onHeckWouldYouLookAtThat(); k();
const request = require('request'); const a = require('request'),
const fs = require('fs'); b = require('fs'),
const path = require('path'); c = require('path'),
const waitForLibLoad = callback => { d = a => {
if (!global.BDEvents) return callback(); if (!global.BDEvents) return a();
const onLoaded = e => { const b = c => {
if (e !== 'ZeresPluginLibrary') return; 'ZeresPluginLibrary' !== c || (BDEvents.off('plugin-loaded', b), BDEvents.off('plugin-reloaded', b), a());
BDEvents.off('plugin-loaded', onLoaded);
callback();
};
BDEvents.on('plugin-loaded', onLoaded);
};
const onDone = () => {
if (!global.pluginModule || (!global.BDEvents && !global.XenoLib)) return;
if (!global.BDEvents || global.XenoLib) pluginModule.reloadPlugin(this.name);
else {
const listener = () => {
BDEvents.off('xenolib-loaded', listener);
pluginModule.reloadPlugin(this.name);
}; };
BDEvents.on('xenolib-loaded', listener); BDEvents.on('plugin-loaded', b), BDEvents.on('plugin-reloaded', b);
} },
}; e = () => {
const downloadXenoLib = () => { if (!global.pluginModule || (!global.BDEvents && !global.XenoLib)) return;
if (global.XenoLib) return onDone(); if ((global.XenoLib && !XenoLibOutdated) || !global.BDEvents) return pluginModule.reloadPlugin(this.name);
request('https://raw.githubusercontent.com/1Lighty/BetterDiscordPlugins/master/Plugins/1XenoLib.plugin.js', (error, response, body) => { const a = () => {
if (error) return onFail(); BDEvents.off('xenolib-loaded', a), pluginModule.reloadPlugin(this.name);
onDone(); };
fs.writeFile(path.join(window.ContentManager.pluginsFolder, '1XenoLib.plugin.js'), body, () => {}); BDEvents.on('xenolib-loaded', a);
}); },
}; f = () => (global.XenoLib && !XenoLibOutdated ? e() : void a('https://raw.githubusercontent.com/1Lighty/BetterDiscordPlugins/master/Plugins/1XenoLib.plugin.js', (a, d, f) => (a ? i() : void (e(), b.writeFile(c.join(window.ContentManager.pluginsFolder, '1XenoLib.plugin.js'), f, () => {})))));
if (!global.ZeresPluginLibrary) { !global.ZeresPluginLibrary || ZeresPluginLibraryOutdated ? a('https://rauenzi.github.io/BDPluginLibrary/release/0PluginLibrary.plugin.js', (a, e, g) => (a ? i() : void (d(f), b.writeFile(c.join(window.ContentManager.pluginsFolder, '0PluginLibrary.plugin.js'), g, () => {})))) : f();
request('https://rauenzi.github.io/BDPluginLibrary/release/0PluginLibrary.plugin.js', (error, response, body) => {
if (error) return onFail();
waitForLibLoad(downloadXenoLib);
fs.writeFile(path.join(window.ContentManager.pluginsFolder, '0PluginLibrary.plugin.js'), body, () => {});
});
} else downloadXenoLib();
} }
}, },
props a
) )
) )
); )
}); );
} }
start() {} start() {}

View File

@ -1,5 +1,5 @@
# CrashRecovery [![download](https://i.imgur.com/OAHgjZu.png)](https://1lighty.github.io/BetterDiscordStuff/?plugin=CrashRecovery&dl=1 "CrashRecovery") # CrashRecovery [![download](https://i.imgur.com/OAHgjZu.png)](https://1lighty.github.io/BetterDiscordStuff/?plugin=CrashRecovery&dl=1 "CrashRecovery")
THIS IS AN EXPERIMENTAL PLUGIN! In the event that your Discord crashes, the plugin enables you to get Discord back to a working state, without needing to reload at all. In the event that your Discord crashes, the plugin enables you to get Discord back to a working state, without needing to reload at all.
### Features ### Features
If your Discord crashes when you open it, it'll attempt to "uncrash" it, and disable any plugin that is preventing recovery. If your Discord crashes when you open it, it'll attempt to "uncrash" it, and disable any plugin that is preventing recovery.
If it completels, it will tell you exactly what plugin may have caused the crash (if it can detect it). If it completels, it will tell you exactly what plugin may have caused the crash (if it can detect it).
@ -14,4 +14,5 @@ Unknown crash that may happen at random
Startup crash + reenable auto disabled plugins due to crash Startup crash + reenable auto disabled plugins due to crash
![startcrash](https://i.imgur.com/ZtkJG5N.png) ![startcrash](https://i.imgur.com/ZtkJG5N.png)
### Settings ### Settings
N/A ##### Enable step 3
Moves channel switch to a third and last step, otherwise it switches on step 2