mirror of
				https://github.com/keanuplayz/TravBot-v3.git
				synced 2024-08-15 02:33:12 +00:00 
			
		
		
		
	Merge branch 'typescript' of https://github.com/keanuplayz/TravBot-v3 into experimental-core-rollout
This commit is contained in:
		
						commit
						9137231768
					
				
					 10 changed files with 365 additions and 3 deletions
				
			
		|  | @ -3,6 +3,7 @@ import {isAuthorized, getMoneyEmbed} from "./modules/eco-utils"; | ||||||
| import {DailyCommand, PayCommand, GuildCommand, LeaderboardCommand} from "./modules/eco-core"; | import {DailyCommand, PayCommand, GuildCommand, LeaderboardCommand} from "./modules/eco-core"; | ||||||
| import {BuyCommand, ShopCommand} from "./modules/eco-shop"; | import {BuyCommand, ShopCommand} from "./modules/eco-shop"; | ||||||
| import {MondayCommand} from "./modules/eco-extras"; | import {MondayCommand} from "./modules/eco-extras"; | ||||||
|  | import {BetCommand} from "./modules/eco-bet"; | ||||||
| 
 | 
 | ||||||
| export default new NamedCommand({ | export default new NamedCommand({ | ||||||
|     description: "Economy command for Monika.", |     description: "Economy command for Monika.", | ||||||
|  | @ -16,7 +17,8 @@ export default new NamedCommand({ | ||||||
|         leaderboard: LeaderboardCommand, |         leaderboard: LeaderboardCommand, | ||||||
|         buy: BuyCommand, |         buy: BuyCommand, | ||||||
|         shop: ShopCommand, |         shop: ShopCommand, | ||||||
|         monday: MondayCommand |         monday: MondayCommand, | ||||||
|  |         bet: BetCommand | ||||||
|     }, |     }, | ||||||
|     id: "user", |     id: "user", | ||||||
|     user: new Command({ |     user: new Command({ | ||||||
|  |  | ||||||
							
								
								
									
										198
									
								
								src/commands/fun/modules/eco-bet.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										198
									
								
								src/commands/fun/modules/eco-bet.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,198 @@ | ||||||
|  | import {Command, NamedCommand, askYesOrNo} from "../../../core"; | ||||||
|  | import {pluralise} from "../../../lib"; | ||||||
|  | import {Storage} from "../../../structures"; | ||||||
|  | import {isAuthorized, getMoneyEmbed, getSendEmbed, ECO_EMBED_COLOR} from "./eco-utils"; | ||||||
|  | import {User} from "discord.js"; | ||||||
|  | 
 | ||||||
|  | export const BetCommand = new NamedCommand({ | ||||||
|  |     description: "Bet your Mons with other people.", | ||||||
|  |     usage: "<user> <amount> <duration>", | ||||||
|  |     run: "Who are you betting with?", | ||||||
|  |     user: new Command({ | ||||||
|  |         description: "User to bet with.", | ||||||
|  |         // handles missing amount argument
 | ||||||
|  |         async run({args, author, channel, guild}) { | ||||||
|  |             if (isAuthorized(guild, channel)) { | ||||||
|  |                 const target = args[0]; | ||||||
|  | 
 | ||||||
|  |                 // handle invalid target
 | ||||||
|  |                 if (target.id == author.id) return channel.send("You can't bet Mons with yourself!"); | ||||||
|  |                 else if (target.bot && process.argv[2] !== "dev") return channel.send("You can't bet Mons with a bot!"); | ||||||
|  | 
 | ||||||
|  |                 return channel.send("How much are you betting?"); | ||||||
|  |             } else return; | ||||||
|  |         }, | ||||||
|  |         number: new Command({ | ||||||
|  |             description: "Amount of Mons to bet.", | ||||||
|  |             // handles missing duration argument
 | ||||||
|  |             async run({args, author, channel, guild}) { | ||||||
|  |                 if (isAuthorized(guild, channel)) { | ||||||
|  |                     const sender = Storage.getUser(author.id); | ||||||
|  |                     const target = args[0] as User; | ||||||
|  |                     const receiver = Storage.getUser(target.id); | ||||||
|  |                     const amount = Math.floor(args[1]); | ||||||
|  | 
 | ||||||
|  |                     // handle invalid target
 | ||||||
|  |                     if (target.id == author.id) return channel.send("You can't bet Mons with yourself!"); | ||||||
|  |                     else if (target.bot && process.argv[2] !== "dev") | ||||||
|  |                         return channel.send("You can't bet Mons with a bot!"); | ||||||
|  | 
 | ||||||
|  |                     // handle invalid amount
 | ||||||
|  |                     if (amount <= 0) return channel.send("You must bet at least one Mon!"); | ||||||
|  |                     else if (sender.money < amount) | ||||||
|  |                         return channel.send("You don't have enough Mons for that.", getMoneyEmbed(author)); | ||||||
|  |                     else if (receiver.money < amount) | ||||||
|  |                         return channel.send("They don't have enough Mons for that.", getMoneyEmbed(target)); | ||||||
|  | 
 | ||||||
|  |                     return channel.send("How long until the bet ends?"); | ||||||
|  |                 } else return; | ||||||
|  |             }, | ||||||
|  |             any: new Command({ | ||||||
|  |                 description: "Duration of the bet.", | ||||||
|  |                 async run({client, args, author, message, channel, guild}) { | ||||||
|  |                     if (isAuthorized(guild, channel)) { | ||||||
|  |                         // [Pertinence to make configurable on the fly.]
 | ||||||
|  |                         // Lower and upper bounds for bet
 | ||||||
|  |                         const durationBounds = {min: "1m", max: "1d"}; | ||||||
|  | 
 | ||||||
|  |                         const sender = Storage.getUser(author.id); | ||||||
|  |                         const target = args[0] as User; | ||||||
|  |                         const receiver = Storage.getUser(target.id); | ||||||
|  |                         const amount = Math.floor(args[1]); | ||||||
|  |                         const duration = parseDuration(args[2].trim()); | ||||||
|  | 
 | ||||||
|  |                         // handle invalid target
 | ||||||
|  |                         if (target.id == author.id) return channel.send("You can't bet Mons with yourself!"); | ||||||
|  |                         else if (target.bot && process.argv[2] !== "dev") | ||||||
|  |                             return channel.send("You can't bet Mons with a bot!"); | ||||||
|  | 
 | ||||||
|  |                         // handle invalid amount
 | ||||||
|  |                         if (amount <= 0) return channel.send("You must bet at least one Mon!"); | ||||||
|  |                         else if (sender.money < amount) | ||||||
|  |                             return channel.send("You don't have enough Mons for that.", getMoneyEmbed(author)); | ||||||
|  |                         else if (receiver.money < amount) | ||||||
|  |                             return channel.send("They don't have enough Mons for that.", getMoneyEmbed(target)); | ||||||
|  | 
 | ||||||
|  |                         // handle invalid duration
 | ||||||
|  |                         if (duration <= 0) return channel.send("Invalid bet duration"); | ||||||
|  |                         else if (duration <= parseDuration(durationBounds.min)) | ||||||
|  |                             return channel.send(`Bet duration is too short, maximum duration is ${durationBounds.min}`); | ||||||
|  |                         else if (duration >= parseDuration(durationBounds.max)) | ||||||
|  |                             return channel.send(`Bet duration is too long, maximum duration is ${durationBounds.max}`); | ||||||
|  | 
 | ||||||
|  |                         // Ask target whether or not they want to take the bet.
 | ||||||
|  |                         const takeBet = await askYesOrNo( | ||||||
|  |                             await channel.send( | ||||||
|  |                                 `<@${target.id}>, do you want to take this bet of ${pluralise(amount, "Mon", "s")}` | ||||||
|  |                             ), | ||||||
|  |                             target.id | ||||||
|  |                         ); | ||||||
|  | 
 | ||||||
|  |                         if (takeBet) { | ||||||
|  |                             // [MEDIUM PRIORITY: bet persistence to prevent losses in case of shutdown.]
 | ||||||
|  |                             // Remove amount money from both parts at the start to avoid duplication of money.
 | ||||||
|  |                             sender.money -= amount; | ||||||
|  |                             receiver.money -= amount; | ||||||
|  |                             // Very hacky solution for persistence but better than no solution, backup returns runs during the bot's setup code.
 | ||||||
|  |                             sender.ecoBetInsurance += amount; | ||||||
|  |                             receiver.ecoBetInsurance += amount; | ||||||
|  |                             Storage.save(); | ||||||
|  | 
 | ||||||
|  |                             // Notify both users.
 | ||||||
|  |                             await channel.send( | ||||||
|  |                                 `<@${target.id}> has taken <@${author.id}>'s bet, the bet amount of ${pluralise( | ||||||
|  |                                     amount, | ||||||
|  |                                     "Mon", | ||||||
|  |                                     "s" | ||||||
|  |                                 )} has been deducted from each of them.` | ||||||
|  |                             ); | ||||||
|  | 
 | ||||||
|  |                             // Wait for the duration of the bet.
 | ||||||
|  |                             return client.setTimeout(async () => { | ||||||
|  |                                 // In debug mode, saving the storage will break the references, so you have to redeclare sender and receiver for it to actually save.
 | ||||||
|  |                                 const sender = Storage.getUser(author.id); | ||||||
|  |                                 const receiver = Storage.getUser(target.id); | ||||||
|  |                                 // [TODO: when D.JSv13 comes out, inline reply to clean up.]
 | ||||||
|  |                                 // When bet is over, give a vote to ask people their thoughts.
 | ||||||
|  |                                 const voteMsg = await channel.send( | ||||||
|  |                                     `VOTE: do you think that <@${ | ||||||
|  |                                         target.id | ||||||
|  |                                     }> has won the bet?\nhttps://discord.com/channels/${guild!.id}/${channel.id}/${
 | ||||||
|  |                                         message.id | ||||||
|  |                                     }` | ||||||
|  |                                 ); | ||||||
|  |                                 await voteMsg.react("✅"); | ||||||
|  |                                 await voteMsg.react("❌"); | ||||||
|  | 
 | ||||||
|  |                                 // Filter reactions to only collect the pertinent ones.
 | ||||||
|  |                                 voteMsg | ||||||
|  |                                     .awaitReactions( | ||||||
|  |                                         (reaction, user) => { | ||||||
|  |                                             return ["✅", "❌"].includes(reaction.emoji.name); | ||||||
|  |                                         }, | ||||||
|  |                                         // [Pertinence to make configurable on the fly.]
 | ||||||
|  |                                         {time: parseDuration("2m")} | ||||||
|  |                                     ) | ||||||
|  |                                     .then((reactions) => { | ||||||
|  |                                         // Count votes
 | ||||||
|  |                                         const okReaction = reactions.get("✅"); | ||||||
|  |                                         const noReaction = reactions.get("❌"); | ||||||
|  |                                         const ok = okReaction ? (okReaction.count ?? 1) - 1 : 0; | ||||||
|  |                                         const no = noReaction ? (noReaction.count ?? 1) - 1 : 0; | ||||||
|  | 
 | ||||||
|  |                                         if (ok > no) { | ||||||
|  |                                             receiver.money += amount * 2; | ||||||
|  |                                             channel.send( | ||||||
|  |                                                 `By the people's votes, <@${target.id}> has won the bet that <@${author.id}> had sent them.` | ||||||
|  |                                             ); | ||||||
|  |                                         } else if (ok < no) { | ||||||
|  |                                             sender.money += amount * 2; | ||||||
|  |                                             channel.send( | ||||||
|  |                                                 `By the people's votes, <@${target.id}> has lost the bet that <@${author.id}> had sent them.` | ||||||
|  |                                             ); | ||||||
|  |                                         } else { | ||||||
|  |                                             sender.money += amount; | ||||||
|  |                                             receiver.money += amount; | ||||||
|  |                                             channel.send( | ||||||
|  |                                                 `By the people's votes, <@${target.id}> couldn't be determined to have won or lost the bet that <@${author.id}> had sent them.` | ||||||
|  |                                             ); | ||||||
|  |                                         } | ||||||
|  |                                         sender.ecoBetInsurance -= amount; | ||||||
|  |                                         receiver.ecoBetInsurance -= amount; | ||||||
|  |                                         Storage.save(); | ||||||
|  |                                     }); | ||||||
|  |                             }, duration); | ||||||
|  |                         } else return await channel.send(`<@${target.id}> has rejected your bet, <@${author.id}>`); | ||||||
|  |                     } else return; | ||||||
|  |                 } | ||||||
|  |             }) | ||||||
|  |         }) | ||||||
|  |     }) | ||||||
|  | }); | ||||||
|  | 
 | ||||||
|  | /** | ||||||
|  |  * Parses a duration string into milliseconds | ||||||
|  |  * Examples: | ||||||
|  |  * - 3d -> 3 days    -> 259200000ms | ||||||
|  |  * - 2h -> 2 hours   -> 7200000ms | ||||||
|  |  * - 7m -> 7 minutes -> 420000ms | ||||||
|  |  * - 3s -> 3 seconds -> 3000ms | ||||||
|  |  */ | ||||||
|  | function parseDuration(duration: string): number { | ||||||
|  |     // extract last char as unit
 | ||||||
|  |     const unit = duration[duration.length - 1].toLowerCase(); | ||||||
|  |     // get the rest as value
 | ||||||
|  |     let value: number = +duration.substring(0, duration.length - 1); | ||||||
|  | 
 | ||||||
|  |     if (!["d", "h", "m", "s"].includes(unit) || isNaN(value)) return 0; | ||||||
|  | 
 | ||||||
|  |     if (unit === "d") value *= 86400000; | ||||||
|  |     // 1000ms * 60s * 60m * 24h
 | ||||||
|  |     else if (unit === "h") value *= 3600000; | ||||||
|  |     // 1000ms * 60s * 60m
 | ||||||
|  |     else if (unit === "m") value *= 60000; | ||||||
|  |     // 1000ms * 60s
 | ||||||
|  |     else if (unit === "s") value *= 1000; // 1000ms
 | ||||||
|  | 
 | ||||||
|  |     return value; | ||||||
|  | } | ||||||
|  | @ -32,6 +32,8 @@ const registry: {[id: string]: string} = { | ||||||
|         "You are, uhh, Stay Put, Soft Puppy, Es-Pee, Swift Pacemaker, Smug Poyo, and many more.\n...Seriously, this woman has too many names.", |         "You are, uhh, Stay Put, Soft Puppy, Es-Pee, Swift Pacemaker, Smug Poyo, and many more.\n...Seriously, this woman has too many names.", | ||||||
|     "243061915281129472": |     "243061915281129472": | ||||||
|         "Some random conlanger, worldbuilder and programmer doofus. ~~May also secretly be a nyan. :3~~", |         "Some random conlanger, worldbuilder and programmer doofus. ~~May also secretly be a nyan. :3~~", | ||||||
|  |     "792751612904603668": | ||||||
|  |         "Some random nyan. :3 ~~May also secretly be a conlanger, worldbuilder and programmer doofus.~~", | ||||||
|     "367439475153829892": "A weeb.", |     "367439475153829892": "A weeb.", | ||||||
|     "760375501775700038": "˙qǝǝʍ ∀", |     "760375501775700038": "˙qǝǝʍ ∀", | ||||||
|     "389178357302034442": "In his dreams, he is the star. its him. <:itsMe:808174425253871657>", |     "389178357302034442": "In his dreams, he is the star. its him. <:itsMe:808174425253871657>", | ||||||
|  |  | ||||||
|  | @ -119,6 +119,32 @@ export default new NamedCommand({ | ||||||
|                             }) |                             }) | ||||||
|                         }) |                         }) | ||||||
|                     } |                     } | ||||||
|  |                 }), | ||||||
|  |                 stream: new NamedCommand({ | ||||||
|  |                     description: "Set a channel to send stream notifications. Type `#` to reference the channel.", | ||||||
|  |                     usage: "(<channel mention>)", | ||||||
|  |                     async run({message, channel, guild, author, member, client, args}) { | ||||||
|  |                         const targetGuild = Storage.getGuild(guild!.id); | ||||||
|  | 
 | ||||||
|  |                         if (targetGuild.streamingChannel) { | ||||||
|  |                             targetGuild.streamingChannel = null; | ||||||
|  |                             channel.send("Removed your server's stream notifications channel."); | ||||||
|  |                         } else { | ||||||
|  |                             targetGuild.streamingChannel = channel.id; | ||||||
|  |                             channel.send(`Set your server's stream notifications channel to ${channel}.`); | ||||||
|  |                         } | ||||||
|  | 
 | ||||||
|  |                         Storage.save(); | ||||||
|  |                     }, | ||||||
|  |                     id: "channel", | ||||||
|  |                     channel: new Command({ | ||||||
|  |                         async run({message, channel, guild, author, member, client, args}) { | ||||||
|  |                             const result = args[0] as TextChannel; | ||||||
|  |                             Storage.getGuild(guild!.id).streamingChannel = result.id; | ||||||
|  |                             Storage.save(); | ||||||
|  |                             channel.send(`Successfully set this server's stream notifications channel to ${result}.`); | ||||||
|  |                         } | ||||||
|  |                     }) | ||||||
|                 }) |                 }) | ||||||
|             } |             } | ||||||
|         }), |         }), | ||||||
|  |  | ||||||
|  | @ -10,7 +10,18 @@ export default new NamedCommand({ | ||||||
|         let target: Message | undefined; |         let target: Message | undefined; | ||||||
|         let distance = 1; |         let distance = 1; | ||||||
| 
 | 
 | ||||||
|         if (args.length >= 2) { |         // allows reactions by using an in-line reply
 | ||||||
|  |         if (message.reference) { | ||||||
|  |             const messageID = message.reference.messageID; | ||||||
|  |             try { | ||||||
|  |                 target = await channel.messages.fetch(messageID!); | ||||||
|  |             } catch { | ||||||
|  |                 return channel.send("Unknown error occurred!"); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         // handles reacts by message id/distance
 | ||||||
|  |         else if (args.length >= 2) { | ||||||
|             const last = args[args.length - 1]; // Because this is optional, do not .pop() unless you're sure it's a message link indicator.
 |             const last = args[args.length - 1]; // Because this is optional, do not .pop() unless you're sure it's a message link indicator.
 | ||||||
|             const URLPattern = /^(?:https:\/\/discord.com\/channels\/(\d{17,19})\/(\d{17,19})\/(\d{17,19}))$/; |             const URLPattern = /^(?:https:\/\/discord.com\/channels\/(\d{17,19})\/(\d{17,19})\/(\d{17,19}))$/; | ||||||
|             const copyIDPattern = /^(?:(\d{17,19})-(\d{17,19}))$/; |             const copyIDPattern = /^(?:(\d{17,19})-(\d{17,19}))$/; | ||||||
|  |  | ||||||
							
								
								
									
										18
									
								
								src/commands/utility/streaminfo.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								src/commands/utility/streaminfo.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,18 @@ | ||||||
|  | import {Command, NamedCommand} from "../../core"; | ||||||
|  | import {streamList} from "../../modules/streamNotifications"; | ||||||
|  | 
 | ||||||
|  | export default new NamedCommand({ | ||||||
|  |     description: "Sets the description of your stream. You can embed links by writing `[some name](some link)`", | ||||||
|  |     async run({message, channel, guild, author, member, client, args}) { | ||||||
|  |         const userID = author.id; | ||||||
|  | 
 | ||||||
|  |         if (streamList.has(userID)) { | ||||||
|  |             const stream = streamList.get(userID)!; | ||||||
|  |             stream.description = args.join(" ") || "No description set."; | ||||||
|  |             stream.update(); | ||||||
|  |         } else { | ||||||
|  |             // Alternatively, I could make descriptions last outside of just one stream.
 | ||||||
|  |             channel.send("You can only use this command when streaming."); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | }); | ||||||
|  | @ -70,3 +70,4 @@ import "./modules/channelListener"; | ||||||
| import "./modules/intercept"; | import "./modules/intercept"; | ||||||
| import "./modules/messageEmbed"; | import "./modules/messageEmbed"; | ||||||
| import "./modules/guildMemberAdd"; | import "./modules/guildMemberAdd"; | ||||||
|  | import "./modules/streamNotifications"; | ||||||
|  |  | ||||||
|  | @ -1,5 +1,5 @@ | ||||||
| import {client} from "../index"; | import {client} from "../index"; | ||||||
| import {Config} from "../structures"; | import {Config, Storage} from "../structures"; | ||||||
| 
 | 
 | ||||||
| client.once("ready", () => { | client.once("ready", () => { | ||||||
|     if (client.user) { |     if (client.user) { | ||||||
|  | @ -10,5 +10,21 @@ client.once("ready", () => { | ||||||
|             type: "LISTENING", |             type: "LISTENING", | ||||||
|             name: `${Config.prefix}help` |             name: `${Config.prefix}help` | ||||||
|         }); |         }); | ||||||
|  | 
 | ||||||
|  |         // Run this setup block once to restore eco bet money in case the bot went down. (And I guess search the client for those users to let them know too.)
 | ||||||
|  |         for (const id in Storage.users) { | ||||||
|  |             const user = Storage.users[id]; | ||||||
|  | 
 | ||||||
|  |             if (user.ecoBetInsurance > 0) { | ||||||
|  |                 client.users.cache | ||||||
|  |                     .get(id) | ||||||
|  |                     ?.send( | ||||||
|  |                         `Because my system either crashed or restarted while you had a pending bet, the total amount of money that you bet, which was \`${user.ecoBetInsurance}\`, has been restored.` | ||||||
|  |                     ); | ||||||
|  |                 user.money += user.ecoBetInsurance; | ||||||
|  |                 user.ecoBetInsurance = 0; | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         Storage.save(); | ||||||
|     } |     } | ||||||
| }); | }); | ||||||
|  |  | ||||||
							
								
								
									
										84
									
								
								src/modules/streamNotifications.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										84
									
								
								src/modules/streamNotifications.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,84 @@ | ||||||
|  | import {GuildMember, VoiceChannel, MessageEmbed, TextChannel, Permissions, Message, Collection} from "discord.js"; | ||||||
|  | import {client} from "../index"; | ||||||
|  | import {Storage} from "../structures"; | ||||||
|  | 
 | ||||||
|  | type Stream = { | ||||||
|  |     streamer: GuildMember; | ||||||
|  |     channel: VoiceChannel; | ||||||
|  |     description?: string; | ||||||
|  |     message: Message; | ||||||
|  |     update: () => void; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | // A list of user IDs and message embeds.
 | ||||||
|  | export const streamList = new Collection<string, Stream>(); | ||||||
|  | 
 | ||||||
|  | // Probably find a better, DRY way of doing this.
 | ||||||
|  | function getStreamEmbed(streamer: GuildMember, channel: VoiceChannel, description?: string): MessageEmbed { | ||||||
|  |     const user = streamer.user; | ||||||
|  |     const embed = new MessageEmbed() | ||||||
|  |         .setTitle(`Stream: \`#${channel.name}\``) | ||||||
|  |         .setAuthor( | ||||||
|  |             streamer.nickname ?? user.username, | ||||||
|  |             user.avatarURL({ | ||||||
|  |                 dynamic: true, | ||||||
|  |                 format: "png" | ||||||
|  |             }) ?? user.defaultAvatarURL | ||||||
|  |         ) | ||||||
|  |         .setColor(streamer.displayColor); | ||||||
|  | 
 | ||||||
|  |     if (description) { | ||||||
|  |         embed.setDescription(description); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return embed; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | client.on("voiceStateUpdate", async (before, after) => { | ||||||
|  |     const isStartStreamEvent = !before.streaming && after.streaming; | ||||||
|  |     const isStopStreamEvent = before.streaming && (!after.streaming || !after.channel); // If you were streaming before but now are either not streaming or have left the channel.
 | ||||||
|  |     // Note: isStopStreamEvent can be called twice in a row - If Discord crashes/quits while you're streaming, it'll call once with a null channel and a second time with a channel.
 | ||||||
|  | 
 | ||||||
|  |     if (isStartStreamEvent || isStopStreamEvent) { | ||||||
|  |         const {streamingChannel} = Storage.getGuild(after.guild.id); | ||||||
|  | 
 | ||||||
|  |         if (streamingChannel) { | ||||||
|  |             const member = after.member!; | ||||||
|  |             const voiceChannel = after.channel!; | ||||||
|  |             const textChannel = client.channels.cache.get(streamingChannel); | ||||||
|  | 
 | ||||||
|  |             if (textChannel instanceof TextChannel) { | ||||||
|  |                 if (isStartStreamEvent) { | ||||||
|  |                     streamList.set(member.id, { | ||||||
|  |                         streamer: member, | ||||||
|  |                         channel: voiceChannel, | ||||||
|  |                         message: await textChannel.send(getStreamEmbed(member, voiceChannel)), | ||||||
|  |                         update(this: Stream) { | ||||||
|  |                             this.message.edit(getStreamEmbed(this.streamer, this.channel, this.description)); | ||||||
|  |                         } | ||||||
|  |                     }); | ||||||
|  |                 } else if (isStopStreamEvent) { | ||||||
|  |                     if (streamList.has(member.id)) { | ||||||
|  |                         const {message} = streamList.get(member.id)!; | ||||||
|  |                         message.delete(); | ||||||
|  |                         streamList.delete(member.id); | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             } else { | ||||||
|  |                 console.error( | ||||||
|  |                     `The streaming notifications channel ${streamingChannel} for guild ${after.guild.id} either doesn't exist or isn't a text channel.` | ||||||
|  |                 ); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | }); | ||||||
|  | 
 | ||||||
|  | client.on("channelUpdate", (before, after) => { | ||||||
|  |     if (before.type === "voice" && after.type === "voice") { | ||||||
|  |         for (const stream of streamList.values()) { | ||||||
|  |             if (after.id === stream.channel.id) { | ||||||
|  |                 stream.update(); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | }); | ||||||
|  | @ -31,6 +31,7 @@ class User { | ||||||
|     public timezone: number | null; // This is for the standard timezone only, not the daylight savings timezone
 |     public timezone: number | null; // This is for the standard timezone only, not the daylight savings timezone
 | ||||||
|     public daylightSavingsRegion: "na" | "eu" | "sh" | null; |     public daylightSavingsRegion: "na" | "eu" | "sh" | null; | ||||||
|     public todoList: {[timestamp: string]: string}; |     public todoList: {[timestamp: string]: string}; | ||||||
|  |     public ecoBetInsurance: number; | ||||||
| 
 | 
 | ||||||
|     constructor(data?: GenericJSON) { |     constructor(data?: GenericJSON) { | ||||||
|         this.money = select(data?.money, 0, Number); |         this.money = select(data?.money, 0, Number); | ||||||
|  | @ -41,6 +42,7 @@ class User { | ||||||
|             ? data?.daylightSavingsRegion |             ? data?.daylightSavingsRegion | ||||||
|             : null; |             : null; | ||||||
|         this.todoList = {}; |         this.todoList = {}; | ||||||
|  |         this.ecoBetInsurance = select(data?.ecoBetInsurance, 0, Number); | ||||||
| 
 | 
 | ||||||
|         if (data) { |         if (data) { | ||||||
|             for (const timestamp in data.todoList) { |             for (const timestamp in data.todoList) { | ||||||
|  | @ -58,11 +60,13 @@ class Guild { | ||||||
|     public welcomeType: "none" | "text" | "graphical"; |     public welcomeType: "none" | "text" | "graphical"; | ||||||
|     public welcomeChannel: string | null; |     public welcomeChannel: string | null; | ||||||
|     public welcomeMessage: string | null; |     public welcomeMessage: string | null; | ||||||
|  |     public streamingChannel: string | null; | ||||||
| 
 | 
 | ||||||
|     constructor(data?: GenericJSON) { |     constructor(data?: GenericJSON) { | ||||||
|         this.prefix = select(data?.prefix, null, String); |         this.prefix = select(data?.prefix, null, String); | ||||||
|         this.welcomeChannel = select(data?.welcomeChannel, null, String); |         this.welcomeChannel = select(data?.welcomeChannel, null, String); | ||||||
|         this.welcomeMessage = select(data?.welcomeMessage, null, String); |         this.welcomeMessage = select(data?.welcomeMessage, null, String); | ||||||
|  |         this.streamingChannel = select(data?.streamingChannel, null, String); | ||||||
| 
 | 
 | ||||||
|         switch (data?.welcomeType) { |         switch (data?.welcomeType) { | ||||||
|             case "text": |             case "text": | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue