config.go 43 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114
  1. package main
  2. import (
  3. "bufio"
  4. "encoding/json"
  5. "io/ioutil"
  6. "log"
  7. "os"
  8. "strings"
  9. "github.com/bwmarrin/discordgo"
  10. "github.com/fatih/color"
  11. "github.com/muhammadmuzzammil1998/jsonc"
  12. "gopkg.in/ini.v1"
  13. )
  14. var (
  15. config = defaultConfiguration()
  16. )
  17. //#region Credentials
  18. var (
  19. placeholderToken string = "REPLACE_WITH_YOUR_TOKEN_OR_DELETE_LINE"
  20. placeholderEmail string = "REPLACE_WITH_YOUR_EMAIL_OR_DELETE_LINE"
  21. placeholderPassword string = "REPLACE_WITH_YOUR_PASSWORD_OR_DELETE_LINE"
  22. )
  23. type configurationCredentials struct {
  24. // Login
  25. Token string `json:"token,omitempty"` // required for bot token (this or login)
  26. Email string `json:"email,omitempty"` // required for login (this or token)
  27. Password string `json:"password,omitempty"` // required for login (this or token)
  28. UserBot bool `json:"userBot,omitempty"` // required
  29. // APIs
  30. TwitterAccessToken string `json:"twitterAccessToken,omitempty"` // optional
  31. TwitterAccessTokenSecret string `json:"twitterAccessTokenSecret,omitempty"` // optional
  32. TwitterConsumerKey string `json:"twitterConsumerKey,omitempty"` // optional
  33. TwitterConsumerSecret string `json:"twitterConsumerSecret,omitempty"` // optional
  34. FlickrApiKey string `json:"flickrApiKey,omitempty"` // optional
  35. GoogleDriveCredentialsJSON string `json:"googleDriveCredentialsJSON,omitempty"` // optional
  36. }
  37. //#endregion
  38. //#region Configuration
  39. // cd = Config Default
  40. // Needed for settings used without redundant nil checks, and settings defaulting + creation
  41. var (
  42. // Setup
  43. cdDebugOutput bool = false
  44. cdMessageOutput bool = true
  45. cdCommandPrefix string = "ddg "
  46. cdAllowSkipping bool = true
  47. cdScanOwnMessages bool = false
  48. cdCheckPermissions bool = true
  49. cdAllowGlobalCommands bool = true
  50. cdGithubUpdateChecking bool = true
  51. // Appearance
  52. cdPresenceEnabled bool = true
  53. cdPresenceStatus string = string(discordgo.StatusIdle)
  54. cdPresenceType discordgo.GameType = discordgo.GameTypeGame
  55. cdReactWhenDownloaded bool = true
  56. cdReactWhenDownloadedHistory bool = false
  57. cdInflateCount int64 = 0
  58. )
  59. func defaultConfiguration() configuration {
  60. return configuration{
  61. // Required
  62. Credentials: configurationCredentials{
  63. Token: placeholderToken,
  64. Email: placeholderEmail,
  65. Password: placeholderPassword,
  66. },
  67. // Setup
  68. Admins: []string{},
  69. DebugOutput: cdDebugOutput,
  70. MessageOutput: cdMessageOutput,
  71. CommandPrefix: cdCommandPrefix,
  72. AllowSkipping: cdAllowSkipping,
  73. ScanOwnMessages: cdScanOwnMessages,
  74. CheckPermissions: cdCheckPermissions,
  75. AllowGlobalCommands: cdAllowGlobalCommands,
  76. AutorunHistory: false,
  77. AutorunHistoryBefore: "",
  78. AutorunHistorySince: "",
  79. AsynchronousHistory: false,
  80. ExitOnBadConnection: false,
  81. DownloadRetryMax: 3,
  82. DownloadTimeout: 60,
  83. DiscordTimeout: 180,
  84. GithubUpdateChecking: cdGithubUpdateChecking,
  85. DiscordLogLevel: discordgo.LogError,
  86. FilterDuplicateImages: false,
  87. FilterDuplicateImagesThreshold: 0,
  88. // Appearance
  89. PresenceEnabled: cdPresenceEnabled,
  90. PresenceStatus: cdPresenceStatus,
  91. PresenceType: cdPresenceType,
  92. ReactWhenDownloaded: cdReactWhenDownloaded,
  93. ReactWhenDownloadedHistory: cdReactWhenDownloadedHistory,
  94. FilenameDateFormat: "2006-01-02_15-04-05",
  95. FilenameFormat: "{{date}} {{shortID}} {{file}}",
  96. InflateCount: &cdInflateCount,
  97. NumberFormatEuropean: false,
  98. }
  99. }
  100. type configuration struct {
  101. Constants map[string]string `json:"_constants,omitempty"`
  102. // Required
  103. Credentials configurationCredentials `json:"credentials"` // required
  104. // Setup
  105. Admins []string `json:"admins"` // optional
  106. AdminChannels []configurationAdminChannel `json:"adminChannels"` // optional
  107. DebugOutput bool `json:"debugOutput"` // optional, defaults
  108. MessageOutput bool `json:"messageOutput"` // optional, defaults
  109. CommandPrefix string `json:"commandPrefix"` // optional, defaults
  110. AllowSkipping bool `json:"allowSkipping"` // optional, defaults
  111. ScanOwnMessages bool `json:"scanOwnMessages"` // optional, defaults
  112. CheckPermissions bool `json:"checkPermissions,omitempty"` // optional, defaults
  113. AllowGlobalCommands bool `json:"allowGlobalCommmands,omitempty"` // optional, defaults
  114. AutorunHistory bool `json:"autorunHistory,omitempty"` // optional, defaults
  115. AutorunHistoryBefore string `json:"autorunHistoryBefore,omitempty"` // optional
  116. AutorunHistorySince string `json:"autorunHistorySince,omitempty"` // optional
  117. AsynchronousHistory bool `json:"asyncHistory,omitempty"` // optional, defaults
  118. ExitOnBadConnection bool `json:"exitOnBadConnection,omitempty"` // optional, defaults
  119. DownloadRetryMax int `json:"downloadRetryMax,omitempty"` // optional, defaults
  120. DownloadTimeout int `json:"downloadTimeout,omitempty"` // optional, defaults
  121. DiscordTimeout int `json:"discordTimeout,omitempty"` // optional, defaults
  122. GithubUpdateChecking bool `json:"githubUpdateChecking"` // optional, defaults
  123. DiscordLogLevel int `json:"discordLogLevel,omitempty"` // optional, defaults
  124. FilterDuplicateImages bool `json:"filterDuplicateImages,omitempty"` // optional, defaults
  125. FilterDuplicateImagesThreshold float64 `json:"filterDuplicateImagesThreshold,omitempty"` // optional, defaults
  126. // Appearance
  127. PresenceEnabled bool `json:"presenceEnabled"` // optional, defaults
  128. PresenceStatus string `json:"presenceStatus"` // optional, defaults
  129. PresenceType discordgo.GameType `json:"presenceType,omitempty"` // optional, defaults
  130. PresenceOverwrite *string `json:"presenceOverwrite,omitempty"` // optional, unused if undefined
  131. PresenceOverwriteDetails *string `json:"presenceOverwriteDetails,omitempty"` // optional, unused if undefined
  132. PresenceOverwriteState *string `json:"presenceOverwriteState,omitempty"` // optional, unused if undefined
  133. ReactWhenDownloaded bool `json:"reactWhenDownloaded,omitempty"` // optional, defaults
  134. ReactWhenDownloadedHistory bool `json:"reactWhenDownloadedHistory,omitempty"` // optional, defaults
  135. FilenameDateFormat string `json:"filenameDateFormat,omitempty"` // optional, defaults
  136. FilenameFormat string `json:"filenameFormat,omitempty"` // optional, defaults
  137. EmbedColor *string `json:"embedColor,omitempty"` // optional, defaults to role if undefined, then defaults random if no role color
  138. InflateCount *int64 `json:"inflateCount,omitempty"` // optional, defaults to 0 if undefined
  139. NumberFormatEuropean bool `json:"numberFormatEuropean,omitempty"` // optional, defaults
  140. // Channels
  141. All *configurationChannel `json:"all,omitempty"` // optional, defaults
  142. AllBlacklistChannels *[]string `json:"allBlacklistChannels,omitempty"` // optional
  143. AllBlacklistServers *[]string `json:"allBlacklistServers,omitempty"` // optional
  144. Servers []configurationChannel `json:"servers"` // required
  145. Channels []configurationChannel `json:"channels"` // required
  146. /* IDEAS / TODO:
  147. *
  148. */
  149. }
  150. type constStruct struct {
  151. Constants map[string]string `json:"_constants,omitempty"`
  152. }
  153. //#endregion
  154. //#region Channels
  155. // ccd = Channel Config Default
  156. // Needed for settings used without redundant nil checks, and settings defaulting + creation
  157. var (
  158. // Setup
  159. ccdEnabled bool = true
  160. ccdSave bool = true
  161. ccdAllowCommands bool = true
  162. ccdScanEdits bool = true
  163. ccdIgnoreBots bool = false
  164. ccdSendErrorMessages bool = true
  165. ccdSendFileDirectly bool = true
  166. // Appearance
  167. ccdUpdatePresence bool = true
  168. ccdReactWhenDownloadedEmoji string = ""
  169. ccdReactWhenDownloaded bool = false
  170. ccdReactWhenDownloadedHistory bool = false
  171. ccdBlacklistReactEmojis []string = []string{}
  172. ccdTypeWhileProcessing bool = false
  173. // Rules for Saving
  174. ccdDivideFoldersByServer bool = false
  175. ccdDivideFoldersByChannel bool = false
  176. ccdDivideFoldersByUser bool = false
  177. ccdDivideFoldersByType bool = true
  178. ccdDivideFoldersUseID bool = false
  179. ccdSaveImages bool = true
  180. ccdSaveVideos bool = true
  181. ccdSaveAudioFiles bool = false
  182. ccdSaveTextFiles bool = false
  183. ccdSaveOtherFiles bool = false
  184. ccdSavePossibleDuplicates bool = false
  185. )
  186. type configurationChannel struct {
  187. // Main
  188. ChannelID string `json:"channel,omitempty"` // used for config.Channels
  189. ChannelIDs *[]string `json:"channels,omitempty"` // ---> alternative to ChannelID
  190. ServerID string `json:"server,omitempty"` // used for config.Servers
  191. ServerIDs *[]string `json:"servers,omitempty"` // ---> alternative to ServerID
  192. ServerBlacklist *[]string `json:"serverBlacklist,omitempty"` // for server.ServerID & server.ServerIDs
  193. Destination string `json:"destination"` // required
  194. // Setup
  195. Enabled *bool `json:"enabled,omitempty"` // optional, defaults
  196. Save *bool `json:"save,omitempty"` // optional, defaults
  197. AllowCommands *bool `json:"allowCommands,omitempty"` // optional, defaults
  198. ScanEdits *bool `json:"scanEdits,omitempty"` // optional, defaults
  199. IgnoreBots *bool `json:"ignoreBots,omitempty"` // optional, defaults
  200. OverwriteAutorunHistory *bool `json:"overwriteAutorunHistory,omitempty"` // optional
  201. OverwriteAutorunHistoryBefore *string `json:"overwriteAutorunHistoryBefore,omitempty"` // optional
  202. OverwriteAutorunHistorySince *string `json:"overwriteAutorunHistorySince,omitempty"` // optional
  203. SendErrorMessages *bool `json:"sendErrorMessages,omitempty"` // optional, defaults
  204. SendFileToChannel *string `json:"sendFileToChannel"` // optional, defaults
  205. SendFileToChannels *[]string `json:"sendFileToChannels"` // optional, defaults
  206. SendFileDirectly *bool `json:"sendFileDirectly"` // optional, defaults
  207. // Appearance
  208. UpdatePresence *bool `json:"updatePresence,omitempty"` // optional, defaults
  209. ReactWhenDownloaded *bool `json:"reactWhenDownloaded,omitempty"` // optional, defaults
  210. ReactWhenDownloadedEmoji *string `json:"reactWhenDownloadedEmoji,omitempty"` // optional, defaults
  211. ReactWhenDownloadedHistory *bool `json:"reactWhenDownloadedHistory,omitempty"` // optional, defaults
  212. BlacklistReactEmojis *[]string `json:"blacklistReactEmojis,omitempty"` // optional
  213. TypeWhileProcessing *bool `json:"typeWhileProcessing,omitempty"` // optional, defaults
  214. // Overwrite Global Settings
  215. OverwriteFilenameDateFormat *string `json:"overwriteFilenameDateFormat,omitempty"` // optional
  216. OverwriteFilenameFormat *string `json:"overwriteFilenameFormat,omitempty"` // optional
  217. OverwriteAllowSkipping *bool `json:"overwriteAllowSkipping,omitempty"` // optional
  218. OverwriteEmbedColor *string `json:"overwriteEmbedColor,omitempty"` // optional, defaults to role if undefined, then defaults random if no role color
  219. // Rules for Saving
  220. DivideFoldersByServer *bool `json:"divideFoldersByServer,omitempty"` // optional, defaults
  221. DivideFoldersByChannel *bool `json:"divideFoldersByChannel,omitempty"` // optional, defaults
  222. DivideFoldersByUser *bool `json:"divideFoldersByUser,omitempty"` // optional, defaults
  223. DivideFoldersByType *bool `json:"divideFoldersByType,omitempty"` // optional, defaults
  224. DivideFoldersUseID *bool `json:"divideFoldersUseID,omitempty"` // optional, defaults
  225. SaveImages *bool `json:"saveImages,omitempty"` // optional, defaults
  226. SaveVideos *bool `json:"saveVideos,omitempty"` // optional, defaults
  227. SaveAudioFiles *bool `json:"saveAudioFiles,omitempty"` // optional, defaults
  228. SaveTextFiles *bool `json:"saveTextFiles,omitempty"` // optional, defaults
  229. SaveOtherFiles *bool `json:"saveOtherFiles,omitempty"` // optional, defaults
  230. SavePossibleDuplicates *bool `json:"savePossibleDuplicates,omitempty"` // optional, defaults
  231. // Misc Rules
  232. Filters *configurationChannelFilters `json:"filters,omitempty"` // optional
  233. LogLinks *configurationChannelLog `json:"logLinks,omitempty"` // optional
  234. LogMessages *configurationChannelLog `json:"logMessages,omitempty"` // optional
  235. }
  236. var (
  237. ccfdBlockedExtensions = []string{
  238. ".htm",
  239. ".html",
  240. ".php",
  241. ".exe",
  242. ".dll",
  243. ".bin",
  244. ".cmd",
  245. ".sh",
  246. ".py",
  247. ".jar",
  248. }
  249. ccfdBlockedPhrases = []string{
  250. "skip",
  251. "ignore",
  252. "don't save",
  253. "no save",
  254. }
  255. )
  256. type configurationChannelFilters struct {
  257. BlockedPhrases *[]string `json:"blockedPhrases,omitempty"` // optional
  258. AllowedPhrases *[]string `json:"allowedPhrases,omitempty"` // optional
  259. BlockedUsers *[]string `json:"blockedUsers,omitempty"` // optional
  260. AllowedUsers *[]string `json:"allowedUsers,omitempty"` // optional
  261. BlockedRoles *[]string `json:"blockedRoles,omitempty"` // optional
  262. AllowedRoles *[]string `json:"allowedRoles,omitempty"` // optional
  263. BlockedExtensions *[]string `json:"blockedExtensions,omitempty"` // optional
  264. AllowedExtensions *[]string `json:"allowedExtensions,omitempty"` // optional
  265. BlockedDomains *[]string `json:"blockedDomains,omitempty"` // optional
  266. AllowedDomains *[]string `json:"allowedDomains,omitempty"` // optional
  267. }
  268. var (
  269. ccldDestinationIsFolder bool = false
  270. ccldDivideLogsByServer bool = true
  271. ccldDivideLogsByChannel bool = true
  272. ccldDivideLogsByUser bool = false
  273. ccldDivideLogsByStatus bool = false
  274. ccldLogDownloads bool = true
  275. ccldLogFailures bool = true
  276. )
  277. type configurationChannelLog struct {
  278. Destination string `json:"destination"` // required
  279. DestinationIsFolder *bool `json:"destinationIsFolder,omitempty"` // optional, defaults
  280. DivideLogsByServer *bool `json:"divideLogsByServer,omitempty"` // optional, defaults
  281. DivideLogsByChannel *bool `json:"divideLogsByChannel,omitempty"` // optional, defaults
  282. DivideLogsByUser *bool `json:"divideLogsByUser,omitempty"` // optional, defaults
  283. DivideLogsByStatus *bool `json:"divideLogsByStatus,omitempty"` // optional, defaults
  284. LogDownloads *bool `json:"logDownloads,omitempty"` // optional, defaults
  285. LogFailures *bool `json:"logFailures,omitempty"` // optional, defaults
  286. FilterDuplicates *bool `json:"filterDuplicates,omitempty"` // optional, defaults
  287. Prefix *string `json:"prefix,omitempty"` // optional
  288. Suffix *string `json:"suffix,omitempty"` // optional
  289. UserData *bool `json:"userData,omitempty"` // optional, defaults
  290. }
  291. //#endregion
  292. //#region Admin Channels
  293. var (
  294. acdLogStatus bool = true
  295. acdLogErrors bool = true
  296. acdUnlockCommands bool = false
  297. )
  298. type configurationAdminChannel struct {
  299. // Required
  300. ChannelID string `json:"channel"` // required
  301. ChannelIDs *[]string `json:"channels,omitempty"` // ---> alternative to ChannelID
  302. LogStatus *bool `json:"logStatus,omitempty"` // optional, defaults
  303. LogErrors *bool `json:"logErrors,omitempty"` // optional, defaults
  304. UnlockCommands *bool `json:"unlockCommands,omitempty"` // optional, defaults
  305. /* IDEAS / TODO:
  306. * SendHourlyDigest *bool `json:"sendHourlyDigest,omitempty"` // optional
  307. * SendDailyDigest *bool `json:"sendDailyDigest,omitempty"` // optional
  308. */
  309. }
  310. //#endregion
  311. func initConfig() {
  312. if _, err := os.Stat(configFileBase + ".jsonc"); err == nil {
  313. configFile = configFileBase + ".jsonc"
  314. configFileC = true
  315. } else {
  316. configFile = configFileBase + ".json"
  317. configFileC = false
  318. }
  319. }
  320. func loadConfig() {
  321. // Determine json type
  322. if _, err := os.Stat(configFileBase + ".jsonc"); err == nil {
  323. configFile = configFileBase + ".jsonc"
  324. configFileC = true
  325. } else {
  326. configFile = configFileBase + ".json"
  327. configFileC = false
  328. }
  329. // .
  330. log.Println(logPrefixSettings, color.YellowString("Loading from \"%s\"...", configFile))
  331. // Load settings
  332. configContent, err := ioutil.ReadFile(configFile)
  333. if err != nil {
  334. log.Println(logPrefixSettings, color.HiRedString("Failed to open file...\t%s", err))
  335. createConfig()
  336. properExit()
  337. } else {
  338. fixed := string(configContent)
  339. // Fix backslashes
  340. fixed = strings.ReplaceAll(fixed, "\\", "\\\\")
  341. for strings.Contains(fixed, "\\\\\\") {
  342. fixed = strings.ReplaceAll(fixed, "\\\\\\", "\\\\")
  343. }
  344. //TODO: Not even sure if this is realistic to do but would be nice to have line comma & trailing comma fixing
  345. // Parse
  346. newConfig := defaultConfiguration()
  347. if configFileC {
  348. err = jsonc.Unmarshal([]byte(fixed), &newConfig)
  349. } else {
  350. err = json.Unmarshal([]byte(fixed), &newConfig)
  351. }
  352. if err != nil {
  353. log.Println(logPrefixSettings, color.HiRedString("Failed to parse settings file...\t%s", err))
  354. log.Println(logPrefixSettings, color.MagentaString("Please ensure you're following proper JSON format syntax."))
  355. properExit()
  356. }
  357. // Constants
  358. if newConfig.Constants != nil {
  359. for key, value := range newConfig.Constants {
  360. if strings.Contains(fixed, key) {
  361. fixed = strings.ReplaceAll(fixed, key, value)
  362. }
  363. }
  364. // Re-parse
  365. newConfig = defaultConfiguration()
  366. if configFileC {
  367. err = jsonc.Unmarshal([]byte(fixed), &newConfig)
  368. } else {
  369. err = json.Unmarshal([]byte(fixed), &newConfig)
  370. }
  371. if err != nil {
  372. log.Println(logPrefixSettings, color.HiRedString("Failed to re-parse settings file after replacing constants...\t%s", err))
  373. log.Println(logPrefixSettings, color.MagentaString("Please ensure you're following proper JSON format syntax."))
  374. properExit()
  375. }
  376. newConfig.Constants = nil
  377. }
  378. config = newConfig
  379. // Channel Config Defaults
  380. // this is dumb but don't see a better way to initialize defaults
  381. for i := 0; i < len(config.Servers); i++ {
  382. channelDefault(&config.Servers[i])
  383. }
  384. for i := 0; i < len(config.Channels); i++ {
  385. channelDefault(&config.Channels[i])
  386. }
  387. if config.All != nil {
  388. channelDefault(config.All)
  389. }
  390. for i := 0; i < len(config.AdminChannels); i++ {
  391. adminChannelDefault(&config.AdminChannels[i])
  392. }
  393. // Debug Output
  394. if config.DebugOutput {
  395. dupeConfig := config
  396. if dupeConfig.Credentials.Token != "" && dupeConfig.Credentials.Token != placeholderToken {
  397. dupeConfig.Credentials.Token = "STRIPPED_FOR_OUTPUT"
  398. }
  399. if dupeConfig.Credentials.Email != "" && dupeConfig.Credentials.Email != placeholderEmail {
  400. dupeConfig.Credentials.Email = "STRIPPED_FOR_OUTPUT"
  401. }
  402. if dupeConfig.Credentials.Password != "" && dupeConfig.Credentials.Password != placeholderPassword {
  403. dupeConfig.Credentials.Password = "STRIPPED_FOR_OUTPUT"
  404. }
  405. if dupeConfig.Credentials.TwitterAccessToken != "" {
  406. dupeConfig.Credentials.TwitterAccessToken = "STRIPPED_FOR_OUTPUT"
  407. }
  408. if dupeConfig.Credentials.TwitterAccessTokenSecret != "" {
  409. dupeConfig.Credentials.TwitterAccessTokenSecret = "STRIPPED_FOR_OUTPUT"
  410. }
  411. if dupeConfig.Credentials.TwitterConsumerKey != "" {
  412. dupeConfig.Credentials.TwitterConsumerKey = "STRIPPED_FOR_OUTPUT"
  413. }
  414. if dupeConfig.Credentials.TwitterConsumerSecret != "" {
  415. dupeConfig.Credentials.TwitterConsumerSecret = "STRIPPED_FOR_OUTPUT"
  416. }
  417. if dupeConfig.Credentials.FlickrApiKey != "" {
  418. dupeConfig.Credentials.FlickrApiKey = "STRIPPED_FOR_OUTPUT"
  419. }
  420. s, err := json.MarshalIndent(dupeConfig, "", "\t")
  421. if err != nil {
  422. log.Println(logPrefixSettings, logPrefixDebug, color.HiRedString("Failed to output...\t%s", err))
  423. } else {
  424. log.Println(logPrefixSettings, logPrefixDebug, color.HiYellowString("Parsed into JSON:\n\n"),
  425. color.YellowString(string(s)),
  426. )
  427. }
  428. }
  429. // Credentials Check
  430. if (config.Credentials.Token == "" || config.Credentials.Token == placeholderToken) &&
  431. (config.Credentials.Email == "" || config.Credentials.Email == placeholderEmail) &&
  432. (config.Credentials.Password == "" || config.Credentials.Password == placeholderPassword) {
  433. log.Println(logPrefixSettings, color.HiRedString("No valid discord login found. Token, Email, and Password are all invalid..."))
  434. log.Println(logPrefixSettings, color.HiYellowString("Please save your credentials & info into \"%s\" then restart...", configFile))
  435. log.Println(logPrefixSettings, color.MagentaString("If your credentials are already properly saved, please ensure you're following proper JSON format syntax."))
  436. log.Println(logPrefixSettings, color.MagentaString("You DO NOT NEED `Token` *AND* `Email`+`Password`, just one OR the other."))
  437. properExit()
  438. }
  439. }
  440. }
  441. func createConfig() {
  442. log.Println(logPrefixSetup, color.YellowString("Creating new settings file..."))
  443. enteredBaseChannel := "REPLACE_WITH_DISCORD_CHANNEL_ID_TO_DOWNLOAD_FROM"
  444. enteredBaseDestination := "REPLACE_WITH_FOLDER_LOCATION_TO_DOWNLOAD_TO"
  445. // Separate from Defaultconfiguration because there's some elements we want to strip for settings creation
  446. defaultConfig := configuration{
  447. Credentials: configurationCredentials{
  448. Token: placeholderToken,
  449. Email: placeholderEmail,
  450. Password: placeholderPassword,
  451. },
  452. Admins: []string{"REPLACE_WITH_YOUR_DISCORD_USER_ID"},
  453. CommandPrefix: cdCommandPrefix,
  454. AllowSkipping: cdAllowSkipping,
  455. ScanOwnMessages: cdScanOwnMessages,
  456. PresenceEnabled: cdPresenceEnabled,
  457. PresenceStatus: cdPresenceStatus,
  458. PresenceType: cdPresenceType,
  459. ReactWhenDownloaded: cdReactWhenDownloaded,
  460. GithubUpdateChecking: cdGithubUpdateChecking,
  461. DebugOutput: cdDebugOutput,
  462. }
  463. // Import old config
  464. if _, err := os.Stat("config.ini"); err == nil {
  465. log.Println(logPrefixSetup, color.HiGreenString("Detected config.ini from Seklfreak's discord-image-downloader-go, importing..."))
  466. cfg, err := ini.Load("config.ini")
  467. if err != nil {
  468. log.Println(logPrefixSetup, color.HiRedString("Unable to read your old config file:\t%s", err))
  469. cfg = ini.Empty()
  470. } else {
  471. // Import old ini
  472. // Auth
  473. if cfg.Section("auth").HasKey("token") {
  474. defaultConfig.Credentials.Token = cfg.Section("auth").Key("token").String()
  475. log.Println(color.GreenString("IMPORTED token:\t\t\t%s", defaultConfig.Credentials.Token))
  476. } else {
  477. defaultConfig.Credentials.Token = ""
  478. }
  479. if cfg.Section("auth").HasKey("email") {
  480. defaultConfig.Credentials.Email = cfg.Section("auth").Key("email").String()
  481. log.Println(color.GreenString("IMPORTED email:\t\t\t%s", defaultConfig.Credentials.Email))
  482. } else {
  483. defaultConfig.Credentials.Email = ""
  484. }
  485. if cfg.Section("auth").HasKey("password") {
  486. defaultConfig.Credentials.Password = cfg.Section("auth").Key("password").String()
  487. log.Println(color.GreenString("IMPORTED password:\t\t\t%s", defaultConfig.Credentials.Password))
  488. } else {
  489. defaultConfig.Credentials.Password = ""
  490. }
  491. if cfg.Section("google").HasKey("client credentials json") {
  492. defaultConfig.Credentials.GoogleDriveCredentialsJSON = cfg.Section("google").Key("client credentials json").String()
  493. log.Println(color.GreenString("IMPORTED Google Drive Credentials:\t\t\t%s", defaultConfig.Credentials.GoogleDriveCredentialsJSON))
  494. }
  495. if cfg.Section("flickr").HasKey("api key") {
  496. defaultConfig.Credentials.FlickrApiKey = cfg.Section("flickr").Key("api key").String()
  497. log.Println(color.GreenString("IMPORTED Flickr API Key:\t\t\t%s", defaultConfig.Credentials.FlickrApiKey))
  498. }
  499. if cfg.Section("twitter").HasKey("consumer key") {
  500. defaultConfig.Credentials.TwitterConsumerKey = cfg.Section("twitter").Key("consumer key").String()
  501. log.Println(color.GreenString("IMPORTED Twitter Consumer Key:\t\t\t%s", defaultConfig.Credentials.TwitterConsumerKey))
  502. }
  503. if cfg.Section("twitter").HasKey("consumer secret") {
  504. defaultConfig.Credentials.TwitterConsumerSecret = cfg.Section("twitter").Key("consumer secret").String()
  505. log.Println(color.GreenString("IMPORTED Twitter Consumer Secret:\t\t\t%s", defaultConfig.Credentials.TwitterConsumerSecret))
  506. }
  507. if cfg.Section("twitter").HasKey("access token") {
  508. defaultConfig.Credentials.TwitterAccessToken = cfg.Section("twitter").Key("access token").String()
  509. log.Println(color.GreenString("IMPORTED Twitter Access Token:\t\t\t%s", defaultConfig.Credentials.TwitterAccessToken))
  510. }
  511. if cfg.Section("twitter").HasKey("access token secret") {
  512. defaultConfig.Credentials.TwitterAccessTokenSecret = cfg.Section("twitter").Key("access token secret").String()
  513. log.Println(color.GreenString("IMPORTED Twitter Access Token Secret:\t\t\t%s", defaultConfig.Credentials.TwitterAccessTokenSecret))
  514. }
  515. // General
  516. if cfg.Section("general").HasKey("max download retries") {
  517. defaultConfig.DownloadRetryMax = cfg.Section("general").Key("max download retries").MustInt()
  518. log.Println(color.GreenString("IMPORTED Max Download Retries:\t%d", defaultConfig.DownloadRetryMax))
  519. }
  520. if cfg.Section("general").HasKey("download timeout") {
  521. defaultConfig.DownloadTimeout = cfg.Section("general").Key("download timeout").MustInt()
  522. log.Println(color.GreenString("IMPORTED Download Timeout:\t\t%d", defaultConfig.DownloadRetryMax))
  523. }
  524. // Status
  525. if cfg.Section("status").HasKey("status enabled") {
  526. defaultConfig.PresenceEnabled = cfg.Section("status").Key("status enabled").MustBool()
  527. log.Println(color.GreenString("IMPORTED Presence Enabled:\t\t%s", boolS(defaultConfig.PresenceEnabled)))
  528. }
  529. if cfg.Section("status").HasKey("status type") {
  530. defaultConfig.PresenceStatus = cfg.Section("status").Key("status type").String()
  531. log.Println(color.GreenString("IMPORTED Presence Status:\t\t%s", defaultConfig.PresenceStatus))
  532. }
  533. if cfg.Section("status").HasKey("status label") {
  534. defaultConfig.PresenceType = discordgo.GameType(cfg.Section("status").Key("status label").MustInt())
  535. log.Println(color.GreenString("IMPORTED Presence Type:\t\t%d", defaultConfig.PresenceType))
  536. }
  537. // Channels
  538. InteractiveChannelWhitelist := cfg.Section("interactive channels").KeysHash()
  539. for key := range InteractiveChannelWhitelist {
  540. newChannel := configurationAdminChannel{
  541. ChannelID: key,
  542. }
  543. log.Println(color.GreenString("IMPORTED Admin Channel:\t\t%s", key))
  544. defaultConfig.AdminChannels = append(defaultConfig.AdminChannels, newChannel)
  545. }
  546. ChannelWhitelist := cfg.Section("channels").KeysHash()
  547. for key, value := range ChannelWhitelist {
  548. newChannel := configurationChannel{
  549. ChannelID: key,
  550. Destination: value,
  551. }
  552. log.Println(color.GreenString("IMPORTED Channel:\t\t\t%s to \"%s\"", key, value))
  553. defaultConfig.Channels = append(defaultConfig.Channels, newChannel)
  554. }
  555. }
  556. log.Println(logPrefixSetup, color.HiGreenString("Finished importing config.ini from Seklfreak's discord-image-downloader-go!"))
  557. } else {
  558. baseChannel := configurationChannel{
  559. ChannelID: enteredBaseChannel,
  560. Destination: enteredBaseDestination,
  561. Enabled: &ccdEnabled,
  562. Save: &ccdSave,
  563. AllowCommands: &ccdAllowCommands,
  564. SendErrorMessages: &ccdSendErrorMessages,
  565. ScanEdits: &ccdScanEdits,
  566. IgnoreBots: &ccdIgnoreBots,
  567. UpdatePresence: &ccdUpdatePresence,
  568. ReactWhenDownloadedEmoji: &ccdReactWhenDownloadedEmoji,
  569. ReactWhenDownloadedHistory: &ccdReactWhenDownloadedHistory,
  570. DivideFoldersByType: &ccdDivideFoldersByType,
  571. SaveImages: &ccdSaveImages,
  572. SaveVideos: &ccdSaveVideos,
  573. }
  574. defaultConfig.Channels = append(defaultConfig.Channels, baseChannel)
  575. baseAdminChannel := configurationAdminChannel{
  576. ChannelID: "REPLACE_WITH_DISCORD_CHANNEL_ID_FOR_ADMIN_COMMANDS",
  577. }
  578. defaultConfig.AdminChannels = append(defaultConfig.AdminChannels, baseAdminChannel)
  579. //TODO: Improve, this is very crude, I just wanted *something* for this.
  580. log.Print(color.HiCyanString("Would you like to enter settings info now? [Y/N]: "))
  581. reader := bufio.NewReader(os.Stdin)
  582. inputCredsYN, _ := reader.ReadString('\n')
  583. inputCredsYN = strings.ReplaceAll(inputCredsYN, "\n", "")
  584. inputCredsYN = strings.ReplaceAll(inputCredsYN, "\r", "")
  585. if strings.Contains(strings.ToLower(inputCredsYN), "y") {
  586. EnterCreds:
  587. log.Print(color.HiCyanString("Token or Login? [\"token\"/\"login\"]: "))
  588. inputCreds, _ := reader.ReadString('\n')
  589. inputCreds = strings.ReplaceAll(inputCreds, "\n", "")
  590. inputCreds = strings.ReplaceAll(inputCreds, "\r", "")
  591. if strings.Contains(strings.ToLower(inputCreds), "token") {
  592. EnterToken:
  593. log.Print(color.HiCyanString("Enter token: "))
  594. inputToken, _ := reader.ReadString('\n')
  595. inputToken = strings.ReplaceAll(inputToken, "\n", "")
  596. inputToken = strings.ReplaceAll(inputToken, "\r", "")
  597. if inputToken != "" {
  598. defaultConfig.Credentials.Token = inputToken
  599. } else {
  600. log.Println(color.HiRedString("Please input token..."))
  601. goto EnterToken
  602. }
  603. } else if strings.Contains(strings.ToLower(inputCreds), "login") {
  604. EnterEmail:
  605. log.Print(color.HiCyanString("Enter email: "))
  606. inputEmail, _ := reader.ReadString('\n')
  607. inputEmail = strings.ReplaceAll(inputEmail, "\n", "")
  608. inputEmail = strings.ReplaceAll(inputEmail, "\r", "")
  609. if strings.Contains(inputEmail, "@") {
  610. defaultConfig.Credentials.Email = inputEmail
  611. EnterPassword:
  612. log.Print(color.HiCyanString("Enter password: "))
  613. inputPassword, _ := reader.ReadString('\n')
  614. inputPassword = strings.ReplaceAll(inputPassword, "\n", "")
  615. inputPassword = strings.ReplaceAll(inputPassword, "\r", "")
  616. if inputPassword != "" {
  617. defaultConfig.Credentials.Password = inputPassword
  618. } else {
  619. log.Println(color.HiRedString("Please input password..."))
  620. goto EnterPassword
  621. }
  622. } else {
  623. log.Println(color.HiRedString("Please input email..."))
  624. goto EnterEmail
  625. }
  626. } else {
  627. log.Println(color.HiRedString("Please input \"token\" or \"login\"..."))
  628. goto EnterCreds
  629. }
  630. EnterAdmin:
  631. log.Print(color.HiCyanString("Input your Discord User ID: "))
  632. inputAdmin, _ := reader.ReadString('\n')
  633. inputAdmin = strings.ReplaceAll(inputAdmin, "\n", "")
  634. inputAdmin = strings.ReplaceAll(inputAdmin, "\r", "")
  635. if isNumeric(inputAdmin) {
  636. defaultConfig.Admins = []string{inputAdmin}
  637. } else {
  638. log.Println(color.HiRedString("Please input your Discord User ID..."))
  639. goto EnterAdmin
  640. }
  641. //TODO: Base channel setup? Would be kind of annoying and may limit options
  642. //TODO: Admin channel setup?
  643. }
  644. }
  645. log.Println(logPrefixSetup, color.MagentaString("The default settings will be missing some options to avoid clutter."))
  646. log.Println(logPrefixSetup, color.HiMagentaString("There are MANY MORE SETTINGS! If you would like to maximize customization, see the GitHub README for all available settings."))
  647. defaultJSON, err := json.MarshalIndent(defaultConfig, "", "\t")
  648. if err != nil {
  649. log.Println(logPrefixSetup, color.HiRedString("Failed to format new settings...\t%s", err))
  650. } else {
  651. err := ioutil.WriteFile(configFile, defaultJSON, 0644)
  652. if err != nil {
  653. log.Println(logPrefixSetup, color.HiRedString("Failed to save new settings file...\t%s", err))
  654. } else {
  655. log.Println(logPrefixSetup, color.HiYellowString("Created new settings file..."))
  656. log.Println(logPrefixSetup, color.HiYellowString("Please save your credentials & info into \"%s\" then restart...", configFile))
  657. log.Println(logPrefixSetup, color.MagentaString("You DO NOT NEED `Token` *AND* `Email`+`Password`, just one OR the other."))
  658. log.Println(logPrefixSetup, color.MagentaString("See README on GitHub for help and more info..."))
  659. }
  660. }
  661. }
  662. func channelDefault(channel *configurationChannel) {
  663. // These have to use the default variables since literal values and consts can't be set to the pointers
  664. // Setup
  665. if channel.Enabled == nil {
  666. channel.Enabled = &ccdEnabled
  667. }
  668. if channel.Save == nil {
  669. channel.Save = &ccdSave
  670. }
  671. if channel.AllowCommands == nil {
  672. channel.AllowCommands = &ccdAllowCommands
  673. }
  674. if channel.SendErrorMessages == nil {
  675. channel.SendErrorMessages = &ccdSendErrorMessages
  676. }
  677. if channel.ScanEdits == nil {
  678. channel.ScanEdits = &ccdScanEdits
  679. }
  680. if channel.IgnoreBots == nil {
  681. channel.IgnoreBots = &ccdIgnoreBots
  682. }
  683. if channel.SendFileDirectly == nil {
  684. channel.SendFileDirectly = &ccdSendFileDirectly
  685. }
  686. // Appearance
  687. if channel.UpdatePresence == nil {
  688. channel.UpdatePresence = &ccdUpdatePresence
  689. }
  690. if channel.ReactWhenDownloadedEmoji == nil {
  691. channel.ReactWhenDownloadedEmoji = &ccdReactWhenDownloadedEmoji
  692. }
  693. if channel.ReactWhenDownloadedHistory == nil {
  694. channel.ReactWhenDownloadedHistory = &ccdReactWhenDownloadedHistory
  695. }
  696. if channel.BlacklistReactEmojis == nil {
  697. channel.BlacklistReactEmojis = &ccdBlacklistReactEmojis
  698. }
  699. if channel.TypeWhileProcessing == nil {
  700. channel.TypeWhileProcessing = &ccdTypeWhileProcessing
  701. }
  702. // Rules for Saving
  703. if channel.DivideFoldersByServer == nil {
  704. channel.DivideFoldersByServer = &ccdDivideFoldersByServer
  705. }
  706. if channel.DivideFoldersByChannel == nil {
  707. channel.DivideFoldersByChannel = &ccdDivideFoldersByChannel
  708. }
  709. if channel.DivideFoldersByUser == nil {
  710. channel.DivideFoldersByUser = &ccdDivideFoldersByUser
  711. }
  712. if channel.DivideFoldersByType == nil {
  713. channel.DivideFoldersByType = &ccdDivideFoldersByType
  714. }
  715. if channel.DivideFoldersUseID == nil {
  716. channel.DivideFoldersUseID = &ccdDivideFoldersUseID
  717. }
  718. if channel.SaveImages == nil {
  719. channel.SaveImages = &ccdSaveImages
  720. }
  721. if channel.SaveVideos == nil {
  722. channel.SaveVideos = &ccdSaveVideos
  723. }
  724. if channel.SaveAudioFiles == nil {
  725. channel.SaveAudioFiles = &ccdSaveAudioFiles
  726. }
  727. if channel.SaveTextFiles == nil {
  728. channel.SaveTextFiles = &ccdSaveTextFiles
  729. }
  730. if channel.SaveOtherFiles == nil {
  731. channel.SaveOtherFiles = &ccdSaveOtherFiles
  732. }
  733. if channel.SavePossibleDuplicates == nil {
  734. channel.SavePossibleDuplicates = &ccdSavePossibleDuplicates
  735. }
  736. if channel.Filters == nil {
  737. channel.Filters = &configurationChannelFilters{}
  738. }
  739. if channel.Filters.BlockedExtensions == nil {
  740. channel.Filters.BlockedExtensions = &ccfdBlockedExtensions
  741. }
  742. if channel.Filters.BlockedPhrases == nil {
  743. channel.Filters.BlockedPhrases = &ccfdBlockedPhrases
  744. }
  745. if channel.LogLinks == nil {
  746. channel.LogLinks = &configurationChannelLog{}
  747. }
  748. if channel.LogLinks.DestinationIsFolder == nil {
  749. channel.LogLinks.DestinationIsFolder = &ccldDestinationIsFolder
  750. }
  751. if channel.LogLinks.DivideLogsByServer == nil {
  752. channel.LogLinks.DivideLogsByServer = &ccldDivideLogsByServer
  753. }
  754. if channel.LogLinks.DivideLogsByChannel == nil {
  755. channel.LogLinks.DivideLogsByChannel = &ccldDivideLogsByChannel
  756. }
  757. if channel.LogLinks.DivideLogsByUser == nil {
  758. channel.LogLinks.DivideLogsByUser = &ccldDivideLogsByUser
  759. }
  760. if channel.LogLinks.DivideLogsByStatus == nil {
  761. channel.LogLinks.DivideLogsByStatus = &ccldDivideLogsByStatus
  762. }
  763. if channel.LogLinks.LogDownloads == nil {
  764. channel.LogLinks.LogDownloads = &ccldLogDownloads
  765. }
  766. if channel.LogLinks.LogFailures == nil {
  767. channel.LogLinks.LogFailures = &ccldLogFailures
  768. }
  769. if channel.LogMessages == nil {
  770. channel.LogMessages = &configurationChannelLog{}
  771. }
  772. if channel.LogMessages.DestinationIsFolder == nil {
  773. channel.LogMessages.DestinationIsFolder = &ccldDestinationIsFolder
  774. }
  775. if channel.LogMessages.DivideLogsByServer == nil {
  776. channel.LogMessages.DivideLogsByServer = &ccldDivideLogsByServer
  777. }
  778. if channel.LogMessages.DivideLogsByChannel == nil {
  779. channel.LogMessages.DivideLogsByChannel = &ccldDivideLogsByChannel
  780. }
  781. if channel.LogMessages.DivideLogsByUser == nil {
  782. channel.LogMessages.DivideLogsByUser = &ccldDivideLogsByUser
  783. }
  784. }
  785. func adminChannelDefault(channel *configurationAdminChannel) {
  786. if channel.LogStatus == nil {
  787. channel.LogStatus = &acdLogStatus
  788. }
  789. if channel.LogErrors == nil {
  790. channel.LogErrors = &acdLogErrors
  791. }
  792. if channel.UnlockCommands == nil {
  793. channel.UnlockCommands = &acdUnlockCommands
  794. }
  795. }
  796. //#region Channel Checks/Returns
  797. func isNestedMessage(subjectMessage *discordgo.Message, targetChannel string) bool {
  798. _, err := bot.State.Message(targetChannel, subjectMessage.ChannelID)
  799. return err == nil
  800. }
  801. func channelRegistered(m *discordgo.Message) string {
  802. for _, item := range config.Channels {
  803. // Single Channel Config
  804. if m.ChannelID == item.ChannelID || isNestedMessage(m, item.ChannelID) {
  805. return item.ChannelID
  806. }
  807. // Multi-Channel Config
  808. if item.ChannelIDs != nil {
  809. if stringInSlice(m.ChannelID, *item.ChannelIDs) {
  810. return m.ChannelID
  811. }
  812. for _, channel := range *item.ChannelIDs {
  813. if m.ChannelID == channel || isNestedMessage(m, channel) {
  814. return channel
  815. }
  816. }
  817. }
  818. }
  819. // Server Config
  820. for _, item := range config.Servers {
  821. if item.ServerID != "" {
  822. guild, err := bot.State.Guild(item.ServerID)
  823. if err == nil {
  824. for _, channel := range guild.Channels {
  825. if m.ChannelID == channel.ID || isNestedMessage(m, channel.ID) {
  826. // Channel Blacklisting within Server
  827. if item.ServerBlacklist != nil {
  828. if stringInSlice(m.ChannelID, *item.ServerBlacklist) {
  829. return ""
  830. }
  831. // Categories
  832. if channel.ParentID != "" {
  833. if stringInSlice(channel.ParentID, *item.ServerBlacklist) {
  834. return ""
  835. }
  836. }
  837. }
  838. return channel.ID
  839. }
  840. }
  841. }
  842. }
  843. // Multi-Server Config
  844. if item.ServerIDs != nil {
  845. for _, subserver := range *item.ServerIDs {
  846. guild, err := bot.State.Guild(subserver)
  847. if err == nil {
  848. for _, channel := range guild.Channels {
  849. if m.ChannelID == channel.ID || isNestedMessage(m, channel.ID) {
  850. // Channel Blacklisting within Servers
  851. if item.ServerBlacklist != nil {
  852. if stringInSlice(m.ChannelID, *item.ServerBlacklist) {
  853. return ""
  854. }
  855. // Categories
  856. if channel.ParentID != "" {
  857. if stringInSlice(channel.ParentID, *item.ServerBlacklist) {
  858. return ""
  859. }
  860. }
  861. }
  862. return channel.ID
  863. }
  864. }
  865. }
  866. }
  867. }
  868. }
  869. // All
  870. if config.All != nil {
  871. if config.AllBlacklistChannels != nil {
  872. if stringInSlice(m.ChannelID, *config.AllBlacklistChannels) {
  873. return ""
  874. }
  875. }
  876. if config.AllBlacklistServers != nil {
  877. guild, err := bot.State.Guild(m.ChannelID)
  878. if err == nil {
  879. if stringInSlice(guild.ID, *config.AllBlacklistServers) {
  880. return ""
  881. }
  882. } else {
  883. log.Println(color.HiRedString("Error finding server info for channel:\t%s", err))
  884. }
  885. }
  886. return "1"
  887. }
  888. return ""
  889. }
  890. func getChannelConfig(ChannelID string) configurationChannel {
  891. for _, item := range config.Channels {
  892. // Single Channel Config
  893. if ChannelID == item.ChannelID {
  894. return item
  895. }
  896. // Multi-Channel Config
  897. if item.ChannelIDs != nil {
  898. for _, subchannel := range *item.ChannelIDs {
  899. if ChannelID == subchannel {
  900. return item
  901. }
  902. }
  903. }
  904. }
  905. // Server Config
  906. for _, item := range config.Servers {
  907. if item.ServerID != "" {
  908. guild, err := bot.State.Guild(item.ServerID)
  909. if err == nil {
  910. for _, channel := range guild.Channels {
  911. if ChannelID == channel.ID {
  912. return item
  913. }
  914. }
  915. }
  916. }
  917. // Multi-Server Config
  918. if item.ServerIDs != nil {
  919. for _, subserver := range *item.ServerIDs {
  920. guild, err := bot.State.Guild(subserver)
  921. if err == nil {
  922. for _, channel := range guild.Channels {
  923. if ChannelID == channel.ID {
  924. return item
  925. }
  926. }
  927. }
  928. }
  929. }
  930. }
  931. if config.All != nil {
  932. return *config.All
  933. }
  934. return configurationChannel{}
  935. }
  936. func isAdminChannelRegistered(ChannelID string) bool {
  937. if config.AdminChannels != nil {
  938. for _, item := range config.AdminChannels {
  939. // Single Channel Config
  940. if ChannelID == item.ChannelID {
  941. return true
  942. }
  943. // Multi-Channel Config
  944. if item.ChannelIDs != nil {
  945. if stringInSlice(ChannelID, *item.ChannelIDs) {
  946. return true
  947. }
  948. }
  949. }
  950. }
  951. return false
  952. }
  953. func getAdminChannelConfig(ChannelID string) configurationAdminChannel {
  954. if config.AdminChannels != nil {
  955. for _, item := range config.AdminChannels {
  956. // Single Channel Config
  957. if ChannelID == item.ChannelID {
  958. return item
  959. }
  960. // Multi-Channel Config
  961. if item.ChannelIDs != nil {
  962. for _, subchannel := range *item.ChannelIDs {
  963. if ChannelID == subchannel {
  964. return item
  965. }
  966. }
  967. }
  968. }
  969. }
  970. return configurationAdminChannel{}
  971. }
  972. func isCommandableChannel(m *discordgo.Message) bool {
  973. ch := channelRegistered(m)
  974. if isAdminChannelRegistered(m.ChannelID) {
  975. return true
  976. } else if ch != "" {
  977. channelConfig := getChannelConfig(ch)
  978. if *channelConfig.AllowCommands || isBotAdmin(m) || m.Author.ID == bot.State.User.ID {
  979. return true
  980. }
  981. }
  982. return false
  983. }
  984. func isGlobalCommandAllowed(m *discordgo.Message) bool {
  985. if config.AllowGlobalCommands || isCommandableChannel(m) {
  986. return true
  987. }
  988. return false
  989. }
  990. func getBoundServers() []string {
  991. var servers []string
  992. for _, item := range config.Servers {
  993. if item.ServerID != "" {
  994. if !stringInSlice(item.ServerID, servers) {
  995. servers = append(servers, item.ServerID)
  996. }
  997. } else if item.ServerIDs != nil {
  998. for _, subserver := range *item.ServerIDs {
  999. if subserver != "" {
  1000. if !stringInSlice(subserver, servers) {
  1001. servers = append(servers, subserver)
  1002. }
  1003. }
  1004. }
  1005. }
  1006. }
  1007. return servers
  1008. }
  1009. func getBoundServersCount() int {
  1010. return len(getBoundServers())
  1011. }
  1012. func getBoundChannels() []string {
  1013. var channels []string
  1014. for _, item := range config.Channels {
  1015. if item.ChannelID != "" {
  1016. if !stringInSlice(item.ChannelID, channels) {
  1017. channels = append(channels, item.ChannelID)
  1018. }
  1019. } else if item.ChannelIDs != nil {
  1020. for _, subchannel := range *item.ChannelIDs {
  1021. if subchannel != "" {
  1022. if !stringInSlice(subchannel, channels) {
  1023. channels = append(channels, subchannel)
  1024. }
  1025. }
  1026. }
  1027. }
  1028. }
  1029. return channels
  1030. }
  1031. func getBoundChannelsCount() int {
  1032. return len(getBoundChannels())
  1033. }
  1034. //#endregion