diff --git a/client/src/builtin/24Hour.js b/client/src/builtin/24Hour.js new file mode 100644 index 00000000..2feb5e3c --- /dev/null +++ b/client/src/builtin/24Hour.js @@ -0,0 +1,37 @@ +/** + * BetterDiscord 24 Hour Timestamps Module + * Copyright (c) 2015-present Jiiks/JsSucks - https://github.com/Jiiks / https://github.com/JsSucks + * All rights reserved. + * https://betterdiscord.net + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. +*/ + +import BuiltinModule from './BuiltinModule'; +import { Patcher, MonkeyPatch, WebpackModules, ReactComponents } from 'modules'; + +const twelveHour = new RegExp(`([0-9]{1,2}):([0-9]{1,2})\\s(AM|PM)`); + +export default new class TwentyFourHour extends BuiltinModule { + + get settingPath() { + return ['ui', 'default', '24-hour']; + } + + async enabled(e) { + if (Patcher.getPatchesByCaller('BD:TwentyFourHour').length) return; + const TimeFormatter = WebpackModules.getModuleByName('TimeFormatter'); + MonkeyPatch('BD:TwentyFourHour', TimeFormatter).after('calendarFormat', (thisObject, args, returnValue) => { + const matched = returnValue.match(twelveHour); + if (!matched || matched.length != 4) return; + if (matched[3] == 'AM') return returnValue.replace(matched[0], `${matched[1].padStart(2, '0')}:${matched[2]}`) + return returnValue.replace(matched[0], `${parseInt(matched[1]) + 12}:${matched[2]}`) + }); + } + + disabled(e) { + Patcher.unpatchAll('BD:TwentyFourHour'); + } + +} diff --git a/client/src/builtin/BlockedMessages.js b/client/src/builtin/BlockedMessages.js new file mode 100644 index 00000000..961790fb --- /dev/null +++ b/client/src/builtin/BlockedMessages.js @@ -0,0 +1,49 @@ +/** + * BetterDiscord Blocked Messages Module + * Copyright (c) 2015-present Jiiks/JsSucks - https://github.com/Jiiks / https://github.com/JsSucks + * All rights reserved. + * https://betterdiscord.net + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. +*/ + +import BuiltinModule from './BuiltinModule'; +import { Patcher, MonkeyPatch, WebpackModules, ReactComponents } from 'modules'; + +export default new class BlockedMessages extends BuiltinModule { + + get settingPath() { + return ['ui', 'default', 'blocked-messages']; + } + + static isBlocked(id) { + const RelationshipStore = WebpackModules.getModuleByName('RelationshipStore'); + return RelationshipStore.isBlocked(id); + } + + async enabled(e) { + if (Patcher.getPatchesByCaller('BD:BlockedMessages').length) return; + const MessageActions = WebpackModules.getModuleByName('MessageActions'); + MonkeyPatch('BD:BlockedMessages', MessageActions).instead('receiveMessage', this.processMessage); + + const MessageListComponents = WebpackModules.getModuleByProps(['BlockedMessageGroup']); + MessageListComponents.OriginalBlockedMessageGroup = MessageListComponents.BlockedMessageGroup; + MessageListComponents.BlockedMessageGroup = () => {return null;}; + this.cancelBlockedMessages = () => { + MessageListComponents.BlockedMessageGroup = MessageListComponents.OriginalBlockedMessageGroup; + delete MessageListComponents.OriginalBlockedMessageGroup; + } + } + + processMessage(thisObject, args, originalFunction) { + if (args[1] && args[1].author && args[1].author.id && BlockedMessages.isBlocked(args[1].author.id)) return; + return originalFunction(...args); + } + + disabled(e) { + Patcher.unpatchAll('BD:BlockedMessages'); + if (this.cancelBlockedMessages) this.cancelBlockedMessages(); + } + +} diff --git a/client/src/builtin/ColoredText.js b/client/src/builtin/ColoredText.js new file mode 100644 index 00000000..9a51ea8a --- /dev/null +++ b/client/src/builtin/ColoredText.js @@ -0,0 +1,39 @@ +/** + * BetterDiscord Colored Text Module + * Copyright (c) 2015-present Jiiks/JsSucks - https://github.com/Jiiks / https://github.com/JsSucks + * All rights reserved. + * https://betterdiscord.net + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. +*/ + +import BuiltinModule from './BuiltinModule'; + +import { Utils } from 'common'; +import { Patcher, MonkeyPatch, WebpackModules, ReactComponents } from 'modules'; + +export default new class ColoredText extends BuiltinModule { + + get settingPath() { + return ['ui', 'default', 'colored-text']; + } + + async enabled(e) { + if (Patcher.getPatchesByCaller('BD:ColoredText').length) return; + const MessageContent = await ReactComponents.getComponent('MessageContent', { selector: WebpackModules.getSelector('container', 'containerCozy', 'containerCompact', 'edited') }); + MonkeyPatch('BD:ColoredText', MessageContent.component.prototype).after('render', this.injectColoredText); + MessageContent.forceUpdateAll(); + } + + injectColoredText(thisObject, args, returnValue) { + const markup = Utils.findInReactTree(returnValue, m => m && m.props && m.props.className && m.props.className.includes('da-markup')); + const roleColor = thisObject.props.message.colorString; + if (markup && roleColor) markup.props.style = {color: roleColor}; + } + + disabled(e) { + Patcher.unpatchAll('BD:ColoredText'); + } + +} diff --git a/client/src/builtin/KillClyde.js b/client/src/builtin/KillClyde.js new file mode 100644 index 00000000..b35f54b8 --- /dev/null +++ b/client/src/builtin/KillClyde.js @@ -0,0 +1,30 @@ +/** + * BetterDiscord Kill Clyde Module + * Copyright (c) 2015-present Jiiks/JsSucks - https://github.com/Jiiks / https://github.com/JsSucks + * All rights reserved. + * https://betterdiscord.net + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. +*/ + +import BuiltinModule from './BuiltinModule'; +import { Patcher, MonkeyPatch, WebpackModules } from 'modules'; + +export default new class KillClyde extends BuiltinModule { + + get settingPath() { + return ['ui', 'default', 'kill-clyde']; + } + + async enabled(e) { + if (Patcher.getPatchesByCaller('BD:KillClyde').length) return; + const MessageActions = WebpackModules.getModuleByName('MessageActions'); + MonkeyPatch('BD:KillClyde', MessageActions).instead('sendBotMessage', void 0); + } + + disabled(e) { + Patcher.unpatchAll('BD:KillClyde'); + } + +} diff --git a/client/src/builtin/Manager.js b/client/src/builtin/Manager.js index 4d769966..ccdbe44e 100644 --- a/client/src/builtin/Manager.js +++ b/client/src/builtin/Manager.js @@ -3,6 +3,11 @@ import { default as ReactDevtoolsModule } from './ReactDevtoolsModule'; import { default as VueDevtoolsModule } from './VueDevToolsModule'; import { default as TrackingProtection } from './TrackingProtection'; import { default as E2EE } from './E2EE'; +import { default as ColoredText } from './ColoredText'; +import { default as TwentyFourHour } from './24Hour'; +import { default as KillClyde } from './KillClyde'; +import { default as BlockedMessages } from './BlockedMessages'; +import { default as VoiceDisconnect } from './VoiceDisconnect'; export default class { static initAll() { @@ -11,5 +16,10 @@ export default class { VueDevtoolsModule.init(); TrackingProtection.init(); E2EE.init(); + ColoredText.init(); + TwentyFourHour.init(); + KillClyde.init(); + BlockedMessages.init(); + VoiceDisconnect.init(); } } diff --git a/client/src/builtin/VoiceDisconnect.js b/client/src/builtin/VoiceDisconnect.js new file mode 100644 index 00000000..4316ec7c --- /dev/null +++ b/client/src/builtin/VoiceDisconnect.js @@ -0,0 +1,33 @@ +/** + * BetterDiscord Voice Disconnect Timestamps Module + * Copyright (c) 2015-present Jiiks/JsSucks - https://github.com/Jiiks / https://github.com/JsSucks + * All rights reserved. + * https://betterdiscord.net + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. +*/ + +import BuiltinModule from './BuiltinModule'; +import { WebpackModules } from 'modules'; + +export default new class VoiceDisconnect extends BuiltinModule { + + get settingPath() { + return ['core', 'default', 'voice-disconnect']; + } + + async enabled(e) { + window.addEventListener('beforeunload', this.listener); + } + + listener() { + const VoiceChannelActions = WebpackModules.getModuleByName('VoiceChannelActions'); + VoiceChannelActions.selectVoiceChannel(null, null); + } + + disabled(e) { + window.removeEventListener('beforeunload', this.listener); + } + +} diff --git a/client/src/builtin/builtin.js b/client/src/builtin/builtin.js index 53c81628..e6b33526 100644 --- a/client/src/builtin/builtin.js +++ b/client/src/builtin/builtin.js @@ -4,3 +4,8 @@ export { default as VueDevtoolsModule } from './VueDevToolsModule'; export { default as TrackingProtection } from './TrackingProtection'; export { default as BuiltinManager } from './Manager'; export { default as E2EE } from './E2EE'; +export { default as ColoredText } from './ColoredText'; +export { default as TwentyFourHour } from './24Hour'; +export { default as KillClyde } from './KillClyde'; +export { default as BlockedMessages } from './BlockedMessages'; +export { default as VoiceDisconnect } from './VoiceDisconnect'; diff --git a/client/src/data/user.settings.default.json b/client/src/data/user.settings.default.json index 902a134b..d20c754e 100644 --- a/client/src/data/user.settings.default.json +++ b/client/src/data/user.settings.default.json @@ -12,8 +12,7 @@ "type": "bool", "text": "Voice Disconnect", "hint": "Disconnect from voice server when Discord closes", - "value": false, - "disabled": true + "value": false }, { "id": "menu-keybind", @@ -100,6 +99,34 @@ "text": "Enable Toasts", "hint": "Allows plugins to show toasts.", "value": true + }, + { + "id": "colored-text", + "type": "bool", + "text": "Colored Text", + "hint": "Colors messages to match the user's role color.", + "value": false + }, + { + "id": "24-hour", + "type": "bool", + "text": "24 Hour Timestamps", + "hint": "Replaces 12 hour timestamps with proper ones.", + "value": false + }, + { + "id": "kill-clyde", + "type": "bool", + "text": "Kill Clyde", + "hint": "Prevents Clyde from sending you error messages.", + "value": false + }, + { + "id": "blocked-messages", + "type": "bool", + "text": "Prevent Blocked Messages", + "hint": "Hides blocked messages in chat and even hides the new message notification.", + "value": false } ] } diff --git a/client/src/modules/webpackmodules.js b/client/src/modules/webpackmodules.js index 5ae5a00e..1867805e 100644 --- a/client/src/modules/webpackmodules.js +++ b/client/src/modules/webpackmodules.js @@ -36,6 +36,7 @@ const KnownModules = { ChannelActions: Filters.byProperties(['selectChannel']), PrivateChannelActions: Filters.byProperties(['openPrivateChannel']), ChannelSelector: Filters.byProperties(['selectGuild', 'selectChannel']), + VoiceChannelActions: Filters.byProperties(['selectVoiceChannel']), /* Current User Info, State and Settings */ UserInfoStore: Filters.byProperties(['getToken']), @@ -44,7 +45,7 @@ const KnownModules = { UserSettingsUpdater: Filters.byProperties(['updateRemoteSettings']), OnlineWatcher: Filters.byProperties(['isOnline']), CurrentUserIdle: Filters.byProperties(['getIdleTime']), - RelationshipStore: Filters.byProperties(['isBlocked']), + RelationshipStore: Filters.byProperties(['isBlocked', 'isFriend']), RelationshipManager: Filters.byProperties(['addRelationship']), MentionStore: Filters.byProperties(['getMentions']), @@ -135,6 +136,7 @@ const KnownModules = { Moment: Filters.byProperties(['parseZone']), LocationManager: Filters.byProperties(['createLocation']), Timestamps: Filters.byProperties(['fromTimestamp']), + TimeFormatter: Filters.byProperties(['dateFormat']), /* Strings and Utils */ Strings: Filters.byProperties(['TEXT', 'TEXTAREA_PLACEHOLDER']),