2019-05-28 23:27:25 +02:00
import BDV2 from "./bdv2" ;
2019-05-29 05:48:41 +02:00
import Utilties from "./utilities" ;
import { Config , SettingsCookie } from "data" ;
2019-05-28 23:27:25 +02:00
import EmoteModule from "./emotes" ;
import QuickEmoteMenu from "./emotemenu" ;
2019-05-29 05:48:41 +02:00
// import VoiceMode from "./voicemode";
// import DevMode from "./devmode";
import PluginManager from "./pluginmanager" ;
import ThemeManager from "./thememanager" ;
2019-05-28 23:27:25 +02:00
import DataStore from "./datastore" ;
2019-05-29 05:48:41 +02:00
import PublicServers from "./publicservers" ;
import SettingsPanel from "./settingspanel" ;
2019-05-28 23:27:25 +02:00
2019-05-29 05:48:41 +02:00
function Core ( ) {
2019-05-28 20:19:48 +02:00
}
2019-05-29 05:48:41 +02:00
Core . prototype . setConfig = function ( config ) {
Object . assign ( Config , config ) ;
} ;
2019-05-28 20:19:48 +02:00
Core . prototype . init = async function ( ) {
2019-05-28 23:27:25 +02:00
if ( Config . version < Config . minSupportedVersion ) {
this . alert ( "Not Supported" , "BetterDiscord v" + Config . version + " (your version)" + " is not supported by the latest js (" + Config . bbdVersion + ").<br><br> Please download the latest version from <a href='https://github.com/rauenzi/BetterDiscordApp/releases/latest' target='_blank'>GitHub</a>" ) ;
2019-05-28 20:19:48 +02:00
return ;
}
2019-05-29 05:48:41 +02:00
const latestLocalVersion = Config . updater ? Config . updater . LatestVersion : Config . latestVersion ;
if ( latestLocalVersion > Config . version ) {
2019-05-28 20:19:48 +02:00
this . alert ( "Update Available" , `
2019-05-29 05:48:41 +02:00
An update for BandagedBD is available ( $ { latestLocalVersion } ) ! Please Reinstall ! < br / > < br / >
2019-05-28 20:19:48 +02:00
< a href = 'https://github.com/rauenzi/BetterDiscordApp/releases/latest' target = '_blank' > Download Installer < / a >
` );
}
2019-05-28 23:27:25 +02:00
Utilties . log ( "Startup" , "Initializing Settings" ) ;
2019-05-28 20:19:48 +02:00
this . initSettings ( ) ;
2019-05-28 23:27:25 +02:00
Utilties . log ( "Startup" , "Initializing EmoteModule" ) ;
2019-05-29 05:48:41 +02:00
window . emotePromise = EmoteModule . init ( ) . then ( ( ) => {
EmoteModule . initialized = true ;
2019-05-28 23:27:25 +02:00
Utilties . log ( "Startup" , "Initializing QuickEmoteMenu" ) ;
2019-05-29 05:48:41 +02:00
QuickEmoteMenu . init ( ) ;
2019-05-28 20:19:48 +02:00
} ) ;
this . injectExternals ( ) ;
await this . checkForGuilds ( ) ;
BDV2 . initialize ( ) ;
2019-05-28 23:27:25 +02:00
Utilties . log ( "Startup" , "Updating Settings" ) ;
2019-05-29 05:48:41 +02:00
SettingsPanel . initializeSettings ( ) ;
2019-05-28 20:19:48 +02:00
2019-05-28 23:27:25 +02:00
Utilties . log ( "Startup" , "Loading Plugins" ) ;
2019-05-29 05:48:41 +02:00
const pluginErrors = PluginManager . loadPlugins ( ) ;
2019-05-28 20:19:48 +02:00
2019-05-28 23:27:25 +02:00
Utilties . log ( "Startup" , "Loading Themes" ) ;
2019-05-29 05:48:41 +02:00
const themeErrors = ThemeManager . loadThemes ( ) ;
2019-05-28 20:19:48 +02:00
$ ( "#customcss" ) . detach ( ) . appendTo ( document . head ) ;
window . addEventListener ( "beforeunload" , function ( ) {
2019-05-29 05:48:41 +02:00
if ( SettingsCookie [ "bda-dc-0" ] ) document . querySelector ( ".btn.btn-disconnect" ) . click ( ) ;
2019-05-28 20:19:48 +02:00
} ) ;
2019-05-29 05:48:41 +02:00
PublicServers . initialize ( ) ;
EmoteModule . autoCapitalize ( ) ;
2019-05-28 20:19:48 +02:00
2019-05-28 23:27:25 +02:00
Utilties . log ( "Startup" , "Removing Loading Icon" ) ;
2019-05-28 20:19:48 +02:00
document . getElementsByClassName ( "bd-loaderv2" ) [ 0 ] . remove ( ) ;
2019-05-28 23:27:25 +02:00
Utilties . log ( "Startup" , "Initializing Main Observer" ) ;
2019-05-28 20:19:48 +02:00
this . initObserver ( ) ;
// Show loading errors
2019-05-29 05:48:41 +02:00
if ( SettingsCookie [ "fork-ps-1" ] ) {
2019-05-28 23:27:25 +02:00
Utilties . log ( "Startup" , "Collecting Startup Errors" ) ;
this . showContentErrors ( { plugins : pluginErrors , themes : themeErrors } ) ;
2019-05-28 20:19:48 +02:00
}
// if (!DataStore.getBDData(bbdVersion)) {
// BdApi.alert("BBD Updated!", ["Lots of things were fixed in this update like Public Servers, Minimal Mode, Dark Mode and 24 Hour Timestamps.", BdApi.React.createElement("br"), BdApi.React.createElement("br"), "Feel free to test them all out!"]);
// DataStore.setBDData(bbdVersion, true);
// }
} ;
Core . prototype . checkForGuilds = function ( ) {
return new Promise ( resolve => {
const checkForGuilds = function ( ) {
const wrapper = BDV2 . guildClasses . wrapper . split ( " " ) [ 0 ] ;
const guild = BDV2 . guildClasses . listItem . split ( " " ) [ 0 ] ;
const blob = BDV2 . guildClasses . blobContainer . split ( " " ) [ 0 ] ;
2019-05-28 23:27:25 +02:00
if ( document . querySelectorAll ( ` . ${ wrapper } . ${ guild } . ${ blob } ` ) . length > 0 ) return resolve ( Config . deferLoaded = true ) ;
2019-05-28 20:19:48 +02:00
setTimeout ( checkForGuilds , 100 ) ;
} ;
$ ( document ) . ready ( function ( ) {
setTimeout ( checkForGuilds , 100 ) ;
} ) ;
} ) ;
} ;
Core . prototype . injectExternals = async function ( ) {
2019-05-28 23:27:25 +02:00
await Utilties . injectJs ( "https://cdnjs.cloudflare.com/ajax/libs/ace/1.2.9/ace.js" ) ;
2019-05-29 06:29:15 +02:00
if ( window . _ _non _webpack _require _ _ . original ) window . require = window . require . original ;
2019-05-28 20:19:48 +02:00
} ;
Core . prototype . initSettings = function ( ) {
DataStore . initialize ( ) ;
2019-05-28 23:27:25 +02:00
if ( ! DataStore . getSettingGroup ( "settings" ) ) return this . saveSettings ( ) ;
const savedSettings = this . loadSettings ( ) ;
$ ( "<style id=\"customcss\">" ) . text ( atob ( DataStore . getBDData ( "bdcustomcss" ) ) ) . appendTo ( document . head ) ;
for ( const setting in savedSettings ) {
2019-05-29 05:48:41 +02:00
if ( savedSettings [ setting ] !== undefined ) SettingsCookie [ setting ] = savedSettings [ setting ] ;
2019-05-28 20:19:48 +02:00
}
2019-05-28 23:27:25 +02:00
this . saveSettings ( ) ;
2019-05-28 20:19:48 +02:00
} ;
Core . prototype . saveSettings = function ( ) {
2019-05-29 05:48:41 +02:00
DataStore . setSettingGroup ( "settings" , SettingsCookie ) ;
2019-05-28 20:19:48 +02:00
} ;
Core . prototype . loadSettings = function ( ) {
2019-05-29 05:48:41 +02:00
return DataStore . getSettingGroup ( "settings" ) ;
2019-05-28 20:19:48 +02:00
} ;
Core . prototype . initObserver = function ( ) {
const mainObserver = new MutationObserver ( ( mutations ) => {
for ( let i = 0 , mlen = mutations . length ; i < mlen ; i ++ ) {
2019-05-29 06:29:15 +02:00
const mutation = mutations [ i ] ;
2019-05-29 05:48:41 +02:00
if ( typeof PluginManager !== "undefined" ) PluginManager . rawObserver ( mutation ) ;
2019-05-28 20:19:48 +02:00
// if there was nothing added, skip
if ( ! mutation . addedNodes . length || ! ( mutation . addedNodes [ 0 ] instanceof Element ) ) continue ;
2019-05-29 06:29:15 +02:00
const node = mutation . addedNodes [ 0 ] ;
2019-05-28 20:19:48 +02:00
if ( node . classList . contains ( "layer-3QrUeG" ) ) {
if ( node . getElementsByClassName ( "guild-settings-base-section" ) . length ) node . setAttribute ( "layer-id" , "server-settings" ) ;
if ( node . getElementsByClassName ( "socialLinks-3jqNFy" ) . length ) {
node . setAttribute ( "layer-id" , "user-settings" ) ;
node . setAttribute ( "id" , "user-settings" ) ;
2019-05-29 05:48:41 +02:00
if ( ! document . getElementById ( "bd-settings-sidebar" ) ) SettingsPanel . renderSidebar ( ) ;
2019-05-28 20:19:48 +02:00
}
}
// Emoji Picker
2019-05-29 05:48:41 +02:00
if ( node . classList . contains ( "popout-3sVMXz" ) && ! node . classList . contains ( "popoutLeft-30WmrD" ) && node . getElementsByClassName ( "emojiPicker-3m1S-j" ) . length ) QuickEmoteMenu . obsCallback ( node ) ;
2019-05-28 20:19:48 +02:00
}
} ) ;
mainObserver . observe ( document , {
childList : true ,
subtree : true
} ) ;
} ;
Core . prototype . inject24Hour = function ( ) {
if ( this . cancel24Hour ) return ;
const twelveHour = new RegExp ( ` ([0-9]{1,2}):([0-9]{1,2}) \\ s(AM|PM) ` ) ;
const convert = ( data ) => {
2019-05-29 05:48:41 +02:00
if ( ! SettingsCookie [ "bda-gs-6" ] ) return ;
2019-05-28 20:19:48 +02:00
const matched = data . returnValue . match ( twelveHour ) ;
if ( ! matched || matched . length !== 4 ) return ;
if ( matched [ 3 ] === "AM" ) return data . returnValue = data . returnValue . replace ( matched [ 0 ] , ` ${ matched [ 1 ] === "12" ? "00" : matched [ 1 ] . padStart ( 2 , "0" ) } : ${ matched [ 2 ] } ` ) ;
return data . returnValue = data . returnValue . replace ( matched [ 0 ] , ` ${ matched [ 1 ] === "12" ? "12" : parseInt ( matched [ 1 ] ) + 12 } : ${ matched [ 2 ] } ` ) ;
} ;
2019-05-28 23:27:25 +02:00
const cancelCozy = Utilties . monkeyPatch ( BDV2 . TimeFormatter , "calendarFormat" , { after : convert } ) ; // Called in Cozy mode
const cancelCompact = Utilties . monkeyPatch ( BDV2 . TimeFormatter , "dateFormat" , { after : convert } ) ; // Called in Compact mode
2019-05-28 20:19:48 +02:00
this . cancel24Hour = ( ) => { cancelCozy ( ) ; cancelCompact ( ) ; } ; // Cancel both
} ;
Core . prototype . injectColoredText = function ( ) {
if ( this . cancelColoredText ) return ;
2019-05-28 23:27:25 +02:00
this . cancelColoredText = Utilties . monkeyPatch ( BDV2 . MessageContentComponent . prototype , "render" , { after : ( data ) => {
2019-05-29 05:48:41 +02:00
if ( ! SettingsCookie [ "bda-gs-7" ] ) return ;
2019-05-28 23:27:25 +02:00
Utilties . monkeyPatch ( data . returnValue . props , "children" , { silent : true , after : ( { returnValue } ) => {
2019-05-28 20:19:48 +02:00
const markup = returnValue . props . children [ 1 ] ;
const roleColor = data . thisObject . props . message . colorString ;
if ( markup && roleColor ) markup . props . style = { color : roleColor } ;
return returnValue ;
} } ) ;
} } ) ;
} ;
Core . prototype . removeColoredText = function ( ) {
document . querySelectorAll ( ".markup-2BOw-j" ) . forEach ( elem => {
elem . style . setProperty ( "color" , "" ) ;
} ) ;
} ;
Core . prototype . alert = function ( title , content ) {
2019-05-29 06:29:15 +02:00
const modal = $ ( ` <div class="bd-modal-wrapper theme-dark">
2019-05-28 20:19:48 +02:00
< div class = "bd-backdrop backdrop-1wrmKB" > < / d i v >
< div class = "bd-modal modal-1UGdnR" >
< div class = "bd-modal-inner inner-1JeGVc" >
< div class = "header header-1R_AjF" >
< div class = "title" > $ { title } < / d i v >
< / d i v >
< div class = "bd-modal-body" >
< div class = "scroller-wrap fade" >
< div class = "scroller" >
$ { content }
< / d i v >
< / d i v >
< / d i v >
< div class = "footer footer-2yfCgX" >
< button type = "button" > Okay < / b u t t o n >
< / d i v >
< / d i v >
< / d i v >
< / d i v > ` ) ;
modal . find ( ".footer button" ) . on ( "click" , ( ) => {
modal . addClass ( "closing" ) ;
setTimeout ( ( ) => { modal . remove ( ) ; } , 300 ) ;
} ) ;
modal . find ( ".bd-backdrop" ) . on ( "click" , ( ) => {
modal . addClass ( "closing" ) ;
setTimeout ( ( ) => { modal . remove ( ) ; } , 300 ) ;
} ) ;
modal . appendTo ( "#app-mount" ) ;
} ;
Core . prototype . showContentErrors = function ( { plugins : pluginErrors = [ ] , themes : themeErrors = [ ] } ) {
if ( ! pluginErrors || ! themeErrors ) return ;
if ( ! pluginErrors . length && ! themeErrors . length ) return ;
2019-05-29 06:29:15 +02:00
const modal = $ ( ` <div class="bd-modal-wrapper theme-dark">
2019-05-28 20:19:48 +02:00
< div class = "bd-backdrop backdrop-1wrmKB" > < / d i v >
< div class = "bd-modal bd-content-modal modal-1UGdnR" >
< div class = "bd-modal-inner inner-1JeGVc" >
< div class = "header header-1R_AjF" > < div class = "title" > Content Errors < / d i v > < / d i v >
< div class = "bd-modal-body" >
< div class = "tab-bar-container" >
< div class = "tab-bar TOP" >
< div class = "tab-bar-item" > Plugins < / d i v >
< div class = "tab-bar-item" > Themes < / d i v >
< / d i v >
< / d i v >
< div class = "table-header" >
< div class = "table-column column-name" > Name < / d i v >
< div class = "table-column column-message" > Message < / d i v >
< div class = "table-column column-error" > Error < / d i v >
< / d i v >
< div class = "scroller-wrap fade" >
< div class = "scroller" >
< / d i v >
< / d i v >
< / d i v >
< div class = "footer footer-2yfCgX" >
< button type = "button" > Okay < / b u t t o n >
< / d i v >
< / d i v >
< / d i v >
< / d i v > ` ) ;
function generateTab ( errors ) {
2019-05-29 06:29:15 +02:00
const container = $ ( ` <div class="errors"> ` ) ;
for ( const err of errors ) {
const error = $ ( ` <div class="error">
2019-05-28 20:19:48 +02:00
< div class = "table-column column-name" > $ { err . name ? err . name : err . file } < / d i v >
< div class = "table-column column-message" > $ { err . message } < / d i v >
< div class = "table-column column-error" > < a class = "error-link" href = "" > $ { err . error ? err . error . message : "" } < / a > < / d i v >
< / d i v > ` ) ;
container . append ( error ) ;
if ( err . error ) {
error . find ( "a" ) . on ( "click" , ( e ) => {
e . preventDefault ( ) ;
2019-05-28 23:27:25 +02:00
Utilties . err ( "ContentManager" , ` Error details for ${ err . name ? err . name : err . file } . ` , err . error ) ;
2019-05-28 20:19:48 +02:00
} ) ;
}
}
return container ;
}
2019-05-29 06:29:15 +02:00
const tabs = [ generateTab ( pluginErrors ) , generateTab ( themeErrors ) ] ;
2019-05-28 20:19:48 +02:00
modal . find ( ".tab-bar-item" ) . on ( "click" , ( e ) => {
e . preventDefault ( ) ;
modal . find ( ".tab-bar-item" ) . removeClass ( "selected" ) ;
$ ( e . target ) . addClass ( "selected" ) ;
modal . find ( ".scroller" ) . empty ( ) . append ( tabs [ $ ( e . target ) . index ( ) ] ) ;
} ) ;
modal . find ( ".footer button" ) . on ( "click" , ( ) => {
modal . addClass ( "closing" ) ;
setTimeout ( ( ) => { modal . remove ( ) ; } , 300 ) ;
} ) ;
modal . find ( ".bd-backdrop" ) . on ( "click" , ( ) => {
modal . addClass ( "closing" ) ;
setTimeout ( ( ) => { modal . remove ( ) ; } , 300 ) ;
} ) ;
modal . appendTo ( "#app-mount" ) ;
if ( pluginErrors . length ) modal . find ( ".tab-bar-item" ) [ 0 ] . click ( ) ;
else modal . find ( ".tab-bar-item" ) [ 1 ] . click ( ) ;
} ;
/ * *
* This shows a toast similar to android towards the bottom of the screen .
*
* @ param { string } content The string to show in the toast .
* @ param { object } options Options object . Optional parameter .
* @ param { string } options . type Changes the type of the toast stylistically and semantically . Choices : "" , "info" , "success" , "danger" / "error" , "warning" / "warn" . Default : ""
* @ param { boolean } options . icon Determines whether the icon should show corresponding to the type . A toast without type will always have no icon . Default : true
* @ param { number } options . timeout Adjusts the time ( in ms ) the toast should be shown for before disappearing automatically . Default : 3000
* /
Core . prototype . showToast = function ( content , options = { } ) {
2019-05-28 23:27:25 +02:00
if ( ! Config . deferLoaded ) return ;
2019-05-28 20:19:48 +02:00
if ( ! document . querySelector ( ".bd-toasts" ) ) {
2019-05-29 06:29:15 +02:00
const toastWrapper = document . createElement ( "div" ) ;
2019-05-28 20:19:48 +02:00
toastWrapper . classList . add ( "bd-toasts" ) ;
2019-05-29 06:29:15 +02:00
const boundingElement = document . querySelector ( ".chat-3bRxxu form, #friends, .noChannel-Z1DQK7, .activityFeed-28jde9" ) ;
2019-05-28 20:19:48 +02:00
toastWrapper . style . setProperty ( "left" , boundingElement ? boundingElement . getBoundingClientRect ( ) . left + "px" : "0px" ) ;
toastWrapper . style . setProperty ( "width" , boundingElement ? boundingElement . offsetWidth + "px" : "100%" ) ;
toastWrapper . style . setProperty ( "bottom" , ( document . querySelector ( ".chat-3bRxxu form" ) ? document . querySelector ( ".chat-3bRxxu form" ) . offsetHeight : 80 ) + "px" ) ;
document . querySelector ( ".app, .app-2rEoOp" ) . appendChild ( toastWrapper ) ;
}
const { type = "" , icon = true , timeout = 3000 } = options ;
2019-05-29 06:29:15 +02:00
const toastElem = document . createElement ( "div" ) ;
2019-05-28 20:19:48 +02:00
toastElem . classList . add ( "bd-toast" ) ;
if ( type ) toastElem . classList . add ( "toast-" + type ) ;
if ( type && icon ) toastElem . classList . add ( "icon" ) ;
toastElem . innerText = content ;
document . querySelector ( ".bd-toasts" ) . appendChild ( toastElem ) ;
setTimeout ( ( ) => {
toastElem . classList . add ( "closing" ) ;
setTimeout ( ( ) => {
toastElem . remove ( ) ;
if ( ! document . querySelectorAll ( ".bd-toasts .bd-toast" ) . length ) document . querySelector ( ".bd-toasts" ) . remove ( ) ;
} , 300 ) ;
} , timeout ) ;
2019-05-28 23:27:25 +02:00
} ;
2019-05-29 05:48:41 +02:00
export default new Core ( ) ;