Compare commits
10 Commits
d29db3959c
..
master
| Author | SHA1 | Date | |
|---|---|---|---|
| 0e996a349a | |||
| 84c9032891 | |||
| c7727474c9 | |||
| 29f6c0cca1 | |||
| 85f031c33a | |||
| 5b07182020 | |||
| fe0c937fb2 | |||
| dcea3ce294 | |||
| 0ca35deb6e | |||
| 96af757961 |
@@ -5,34 +5,45 @@ HelBot v5 introduces an improved background logic structure, streamlined integra
|
|||||||
### Database Structure:
|
### Database Structure:
|
||||||
|
|
||||||
**client.credentials**:
|
**client.credentials**:
|
||||||
- `_id`
|
- `client_id` (twitch:discord)
|
||||||
- `client_id`
|
- `client_secret` (twitch:discord)
|
||||||
- `client_secret`
|
- `token` (access_token:token)
|
||||||
- `token`
|
- `service` (twitch:discord)
|
||||||
- `service`
|
- `mod_id` (twitch only)
|
||||||
- `mod_id`
|
|
||||||
|
|
||||||
**shoutouts.#channel**:
|
**shoutouts.#channel**:
|
||||||
- `_id`
|
|
||||||
- `user`
|
- `user`
|
||||||
- `created_at`
|
- `created_at`
|
||||||
|
|
||||||
**guilds.id**:
|
**guilds.id**:
|
||||||
- `_id`
|
- `event`
|
||||||
- `settings`
|
- `channel`
|
||||||
- `channels`
|
|
||||||
|
**commands.channel**:
|
||||||
|
- `name`
|
||||||
|
- `enabled`
|
||||||
|
|
||||||
|
**settings.channel**:
|
||||||
|
- `name`
|
||||||
|
- `enabled`
|
||||||
|
|
||||||
### Chat Commands:
|
### Chat Commands:
|
||||||
|
|
||||||
**Update Chat Mode** (Mods & Broadcaster only)
|
**Update Chat Mode** (Mods & Broadcaster only)
|
||||||
- `$mode [on:off]`
|
- `$mode [on:off]`
|
||||||
|
|
||||||
**Get a Random Positive Reminder**
|
**Get A Positive Reminder**
|
||||||
- `$positivity`
|
- `$positivity`
|
||||||
|
|
||||||
**View Donothon/Charity Event Information**
|
**View Donothon/Charity Event Information**
|
||||||
- `$donate`
|
- `$donate`
|
||||||
|
|
||||||
|
**View / Manage Settings**
|
||||||
|
- `$commands [enable:disable] [setting]`
|
||||||
|
|
||||||
|
**View / Manage Commands**
|
||||||
|
- `$commands [enable:disable] [command]`
|
||||||
|
|
||||||
### Behaviour:
|
### Behaviour:
|
||||||
|
|
||||||
- Automatically protects the chat by enabling **follow-only**, **sub-only**, or **emote-only** modes when the stream goes offline.
|
- Automatically protects the chat by enabling **follow-only**, **sub-only**, or **emote-only** modes when the stream goes offline.
|
||||||
|
|||||||
@@ -54,6 +54,29 @@ async function getChannel(interaction) {
|
|||||||
}, 5000))
|
}, 5000))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
async function unsetChannel(interaction) {
|
||||||
|
const event = interaction.options.getString('event')
|
||||||
|
const db = mClient.db('guilds')
|
||||||
|
const coll = db.collection(interaction.guild.id)
|
||||||
|
|
||||||
|
try {
|
||||||
|
await coll.deleteOne({
|
||||||
|
event: event
|
||||||
|
})
|
||||||
|
|
||||||
|
return interaction.editReply({
|
||||||
|
content: `Channel for Event: ${event} has been unset`,
|
||||||
|
flags: MessageFlags.Ephemeral
|
||||||
|
})
|
||||||
|
} catch (error) {
|
||||||
|
return interaction.editReply({
|
||||||
|
content: `**[ERROR]:** ${event} is currently not set to any channel`,
|
||||||
|
flags: MessageFlags.Ephemeral
|
||||||
|
}).then(setTimeout(() => {
|
||||||
|
interaction.deleteReply()
|
||||||
|
}, 5000))
|
||||||
|
}
|
||||||
|
}
|
||||||
module.exports = {
|
module.exports = {
|
||||||
data: new SlashCommandBuilder()
|
data: new SlashCommandBuilder()
|
||||||
.setName('channel')
|
.setName('channel')
|
||||||
@@ -100,6 +123,24 @@ module.exports = {
|
|||||||
])
|
])
|
||||||
.setRequired(true)
|
.setRequired(true)
|
||||||
)
|
)
|
||||||
|
)
|
||||||
|
.addSubcommand(s =>
|
||||||
|
s
|
||||||
|
.setName('unset')
|
||||||
|
.setDescription('unset channel for certain events')
|
||||||
|
.addStringOption(o =>
|
||||||
|
o
|
||||||
|
.setName('event')
|
||||||
|
.setDescription('choose the event')
|
||||||
|
.addChoices([
|
||||||
|
{ "name": "When a user joins this server", "value": "GuildMemberAdd" },
|
||||||
|
{ "name": "When a user left this server", "value": "GuildMemberRemove" },
|
||||||
|
{ "name": "When it's a users birthday", "value": "Discord/Birthday" },
|
||||||
|
{ "name": "When debug logs are sent", "value": "Discord/Logs" },
|
||||||
|
{ "name": "When stream is live", "value": "Twitch/Online" }
|
||||||
|
])
|
||||||
|
.setRequired(true)
|
||||||
|
)
|
||||||
),
|
),
|
||||||
async execute(interaction) {
|
async execute(interaction) {
|
||||||
if (!interaction.member.permissions.has("ADMINISTRATOR")) {
|
if (!interaction.member.permissions.has("ADMINISTRATOR")) {
|
||||||
@@ -116,6 +157,9 @@ module.exports = {
|
|||||||
case "get":
|
case "get":
|
||||||
getChannel(interaction)
|
getChannel(interaction)
|
||||||
break;
|
break;
|
||||||
|
case "unset":
|
||||||
|
unsetChannel(interaction)
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,29 +1,19 @@
|
|||||||
// Event triggered by client connected to server
|
// Event triggered by client connected to server
|
||||||
|
|
||||||
const { RWSConnect, RWSDisconnect } = require("../../functions")
|
const { mClient, dClient } = require("../..");
|
||||||
|
var { tClient } = require('../..')
|
||||||
|
const { refreshAccessToken } = require("../../functions")
|
||||||
|
const tmi = require('tmi.js')
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
name: 'Twitch/Disconnected',
|
name: 'Twitch/Disconnected',
|
||||||
once: false,
|
once: false,
|
||||||
async execute(reason) {
|
async execute(reason) {
|
||||||
console.log('Twitch disconnected:', reason);
|
console.log('Twitch disconnected:', reason);
|
||||||
try {
|
|
||||||
RWSDisconnect()
|
|
||||||
} catch (error) {
|
|
||||||
console.error
|
|
||||||
}
|
|
||||||
|
|
||||||
if (reason.includes('Login authentication failed')) {
|
if (reason.includes('Login authentication failed')) {
|
||||||
try {
|
try {
|
||||||
await refreshAccessToken();
|
await refreshAccessToken();
|
||||||
console.log('Reinitializing Twitch client after token refresh...');
|
console.log('Reinitializing Twitch client after token refresh...');
|
||||||
|
|
||||||
try {
|
|
||||||
await tClient.disconnect();
|
|
||||||
} catch (err) {
|
|
||||||
console.warn('Twitch client already disconnected:', err.message);
|
|
||||||
}
|
|
||||||
|
|
||||||
const db = mClient.db("clients");
|
const db = mClient.db("clients");
|
||||||
const credentialCollection = db.collection('credentials');
|
const credentialCollection = db.collection('credentials');
|
||||||
const tCreds = await credentialCollection.findOne({ service: 'twitch' });
|
const tCreds = await credentialCollection.findOne({ service: 'twitch' });
|
||||||
@@ -38,8 +28,8 @@ module.exports = {
|
|||||||
},
|
},
|
||||||
channels: tClient.channels,
|
channels: tClient.channels,
|
||||||
});
|
});
|
||||||
|
const { address, port } = await tClient.connect()
|
||||||
await tClient.connect();
|
dClient.emit("Twitch/Connected", address, port)
|
||||||
console.log('Twitch client reconnected successfully.');
|
console.log('Twitch client reconnected successfully.');
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Failed to refresh token and reconnect:', error);
|
console.error('Failed to refresh token and reconnect:', error);
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ module.exports = {
|
|||||||
name: 'Twitch/EventSub',
|
name: 'Twitch/EventSub',
|
||||||
once: false,
|
once: false,
|
||||||
async execute() {
|
async execute() {
|
||||||
|
console.log('Starting Event Subs...')
|
||||||
const endpoint = `wss://eventsub.wss.twitch.tv/ws`
|
const endpoint = `wss://eventsub.wss.twitch.tv/ws`
|
||||||
|
|
||||||
const db = mClient.db('clients')
|
const db = mClient.db('clients')
|
||||||
@@ -39,6 +40,9 @@ module.exports = {
|
|||||||
function onDisconnect(reason) {
|
function onDisconnect(reason) {
|
||||||
console.log(`Disconnecting due to reason`, reason)
|
console.log(`Disconnecting due to reason`, reason)
|
||||||
}
|
}
|
||||||
|
function onError(error){
|
||||||
|
console.log(error)
|
||||||
|
}
|
||||||
function connect() {
|
function connect() {
|
||||||
connection = new ReconnectingWebSocket(endpoint, [], {
|
connection = new ReconnectingWebSocket(endpoint, [], {
|
||||||
WebSocket: WebSocket,
|
WebSocket: WebSocket,
|
||||||
@@ -48,6 +52,7 @@ module.exports = {
|
|||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
connection.onclose = ({ reason }) => onDisconnect(reason, reject)
|
connection.onclose = ({ reason }) => onDisconnect(reason, reject)
|
||||||
connection.onmessage = ({ data }) => onMessage(data, resolve)
|
connection.onmessage = ({ data }) => onMessage(data, resolve)
|
||||||
|
connection.onerror = ({ error }) => onError(error)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
function onMessage(data) {
|
function onMessage(data) {
|
||||||
@@ -92,6 +97,7 @@ module.exports = {
|
|||||||
subscribedEvents[type] = listener
|
subscribedEvents[type] = listener
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
connect(options)
|
connect(options)
|
||||||
if (options.debug) {
|
if (options.debug) {
|
||||||
events.on(WebsocketEvents.CONNECTED, () => {
|
events.on(WebsocketEvents.CONNECTED, () => {
|
||||||
@@ -105,7 +111,7 @@ module.exports = {
|
|||||||
|
|
||||||
const conditions = [{
|
const conditions = [{
|
||||||
broadcaster_user_id: String(await getIDByName("x__hel__x"))
|
broadcaster_user_id: String(await getIDByName("x__hel__x"))
|
||||||
},{
|
}, {
|
||||||
broadcaster_user_id: String(await getIDByName("desq_blocki"))
|
broadcaster_user_id: String(await getIDByName("desq_blocki"))
|
||||||
}]
|
}]
|
||||||
|
|
||||||
|
|||||||
+12
-48
@@ -21,48 +21,6 @@ module.exports = {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
async function sendPositivity() {
|
|
||||||
// Function sends a random string of predetermined positivity, Donothon Top Donator Reward
|
|
||||||
let positive_Messages = [
|
|
||||||
"You are so very worthy of all the love and support that may come your way.",
|
|
||||||
"There are many things which draw us together. In this time and place, that lovely subject is you, Hel.",
|
|
||||||
"The happiness and joy you add to the world is worth more than most anything.",
|
|
||||||
"You deserve every warm laugh, bright smile, and all the genuine kindness given to you.",
|
|
||||||
"There are few things as precious as your time. Thank you for sharing with us.",
|
|
||||||
"Your feelings are valid and you are not less than for having them.",
|
|
||||||
"I've seen all the work you do and I'm so very proud of you.",
|
|
||||||
"You are dearly cherished and I want to thank you for being so wonderfully you.",
|
|
||||||
"You. Are. Worthy. Enough. And I will tell you as many times as it takes for you to believe it.",
|
|
||||||
"Every day you give your best and that is so admirable. Don't let anyone tell you otherwise.",
|
|
||||||
"Your light is like that of the full moon, brightening our lives even in our darkest moments.",
|
|
||||||
"It's okay to take a moment to catch your breath. Even machines require maintenance from time to time.",
|
|
||||||
"Watching you succeed and achieve your heart's desires gives me so much motivation and I am very grateful for it."
|
|
||||||
]
|
|
||||||
|
|
||||||
let rdm = Math.floor(Math.random() * positive_Messages.length)
|
|
||||||
return tClient.say(channel, positive_Messages[rdm])
|
|
||||||
}
|
|
||||||
async function sendDonationAd() {
|
|
||||||
// Function to send static donate ad
|
|
||||||
const links = [
|
|
||||||
"https://bit.ly/heltwittergoals",
|
|
||||||
"https://bit.ly/donatetohel",
|
|
||||||
"http://bit.ly/donothon_goals"
|
|
||||||
];
|
|
||||||
|
|
||||||
const messages = [
|
|
||||||
"Hel is currently celebrating her birthday with a donathon!",
|
|
||||||
`You can see goals and incentives here: ${links[0]}`,
|
|
||||||
`You can donate here: ${links[1]}`,
|
|
||||||
`Terms, conditions, rules and how rewards work are found here: ${links[2]}`,
|
|
||||||
"All donations and gifts are greatly appreciated, but please do so responsibly!"
|
|
||||||
];
|
|
||||||
|
|
||||||
for (const message of messages) {
|
|
||||||
await tClient.say(channel, message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (self) { return }
|
if (self) { return }
|
||||||
if (knownBots.has(userstate.username)) { return }
|
if (knownBots.has(userstate.username)) { return }
|
||||||
@@ -87,16 +45,22 @@ module.exports = {
|
|||||||
const cmd = args[0]
|
const cmd = args[0]
|
||||||
switch (cmd) {
|
switch (cmd) {
|
||||||
case "mode":
|
case "mode":
|
||||||
if (userstate.badges.moderator != 1 && userstate.badges.broadcaster != 1) { break } // return stops all further operations, so you should just break out of switch
|
dClient.emit('Command/mode', channel, userstate, message, self, args[1])
|
||||||
let regex = /^(on|off)$/
|
|
||||||
if (!args[1].match(regex)) { break }
|
|
||||||
updateChatMode(await getIDByName(channel.substring(1)), args[1])
|
|
||||||
break;
|
break;
|
||||||
case "donate":
|
case "donate":
|
||||||
sendDonationAd()
|
dClient.emit('Command/donate', channel, userstate, message, self)
|
||||||
break;
|
break;
|
||||||
case "positivity":
|
case "positivity":
|
||||||
sendPositivity()
|
dClient.emit('Command/positivity', channel, userstate, message, self)
|
||||||
|
break;
|
||||||
|
case "commands":
|
||||||
|
dClient.emit('Command/commands', channel, userstate, message, self, args[1], args[2])
|
||||||
|
break;
|
||||||
|
case "settings":
|
||||||
|
dClient.emit('Command/settings', channel, userstate, message, self, args[1], args[2])
|
||||||
|
break;
|
||||||
|
case "so":
|
||||||
|
dClient.emit('Command/so', channel, userstate, message, self, args[1])
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
|||||||
+31
-44
@@ -7,15 +7,15 @@ module.exports = {
|
|||||||
once: false,
|
once: false,
|
||||||
async execute(stream) {
|
async execute(stream) {
|
||||||
const db = mClient.db('guilds')
|
const db = mClient.db('guilds')
|
||||||
const res = await db.listCollections().toArray()
|
const guilds = await db.listCollections().toArray()
|
||||||
const streamer = stream.broadcaster_user_login
|
const streamer = stream.broadcaster_user_login
|
||||||
console.log(`${streamer} went live!`)
|
console.log(`${streamer} went live!`)
|
||||||
|
|
||||||
res.forEach(async (guildColl) => {
|
guilds.forEach(async (guildData) => {
|
||||||
const guildId = guildColl.name
|
const guildId = guildData.name
|
||||||
const coll = db.collection(guildId)
|
const coll = db.collection(guildId)
|
||||||
const res = await coll.findOne({ event: 'Twitch/Online' })
|
const res = await coll.findOne({ event: 'Twitch/Online' })
|
||||||
if(!res){
|
if (!res) {
|
||||||
return // ignore if no live channel set
|
return // ignore if no live channel set
|
||||||
}
|
}
|
||||||
const guild = dClient.guilds.cache.get(guildId)
|
const guild = dClient.guilds.cache.get(guildId)
|
||||||
@@ -23,47 +23,34 @@ module.exports = {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const streamData = await getStreams(streamer)
|
const streamData = await getStreams(streamer)
|
||||||
|
let liveData = {
|
||||||
if (streamData?.data[0]) {
|
streamer: streamData.data[0].user_name,
|
||||||
let liveData = {
|
game: streamData.data[0].game_name,
|
||||||
streamer: streamData.data[0].user_name,
|
title: streamData.data[0].title,
|
||||||
game: streamData.data[0].game_name,
|
thumbnail: streamData.data[0].thumbnail_url.replace('-{width}x{height}', ''),
|
||||||
title: streamData.data[0].title,
|
tags: streamData.data[0].tags
|
||||||
thumbnail: streamData.data[0].thumbnail_url.replace('-{width}x{height}', ''),
|
|
||||||
tags: streamData.data[0].tags
|
|
||||||
}
|
|
||||||
|
|
||||||
const embed = new EmbedBuilder()
|
|
||||||
.setTitle(`${escapeMarkdown(liveData.streamer)} is live!`)
|
|
||||||
.setDescription(`They're playing ${liveData.game}`)
|
|
||||||
.addFields(
|
|
||||||
{ name: '\u200B', value: `${liveData.title}` })
|
|
||||||
.setImage(liveData.thumbnail)
|
|
||||||
.setURL(`https://twitch.tv/${streamer}`)
|
|
||||||
let footer = ""
|
|
||||||
liveData.tags.forEach((tag) => {
|
|
||||||
footer += `#${tag} `
|
|
||||||
})
|
|
||||||
embed.setFooter({
|
|
||||||
text: footer
|
|
||||||
})
|
|
||||||
|
|
||||||
return channel.send({
|
|
||||||
embeds: [embed],
|
|
||||||
flags: MessageFlags.Ephemeral
|
|
||||||
}).then(message => setTimeout(() => {
|
|
||||||
message.deleteReply()
|
|
||||||
}, 60000))
|
|
||||||
} else {
|
|
||||||
const embed = new EmbedBuilder()
|
|
||||||
.setTitle(`${escapeMarkdown(streamer)} is currently offline!`)
|
|
||||||
.setImage('https://media.discordapp.net/attachments/1061304429724319794/1319800268770250883/no-signal-tv-descendant-network-rainbow-bars-abstract-background-vector.jpg?ex=67674748&is=6765f5c8&hm=d539944a67fccec461b0183a9f0300e19ac485deda7b23090165088567f2c84f&=&format=webp')
|
|
||||||
.setURL(`https://twitch.tv/${streamer}`)
|
|
||||||
return channel.send({
|
|
||||||
embeds: [embed],
|
|
||||||
flags: MessageFlags.Ephemeral
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const embed = new EmbedBuilder()
|
||||||
|
.setTitle(`${escapeMarkdown(liveData.streamer)} is live!`)
|
||||||
|
.setDescription(`They're playing ${liveData.game}`)
|
||||||
|
.addFields(
|
||||||
|
{ name: '\u200B', value: `${liveData.title}` })
|
||||||
|
.setImage(liveData.thumbnail)
|
||||||
|
.setURL(`https://twitch.tv/${streamer}`)
|
||||||
|
let footer = ""
|
||||||
|
liveData.tags.forEach((tag) => {
|
||||||
|
footer += `#${tag} `
|
||||||
|
})
|
||||||
|
embed.setFooter({
|
||||||
|
text: footer
|
||||||
|
})
|
||||||
|
|
||||||
|
return channel.send({
|
||||||
|
content: `@everyone ${escapeMarkdown(streamer)} is live`,
|
||||||
|
embeds: [embed]
|
||||||
|
})
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return console.error
|
return console.error
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
const { tClient } = require("../..");
|
const { tClient, mClient } = require("../..");
|
||||||
const { getChannelInformation } = require("../../functions");
|
const { getChannelInformation } = require("../../functions");
|
||||||
|
|
||||||
// Event triggered by Custom Shoutout emitted in Messages.js
|
// Event triggered by Custom Shoutout emitted in Messages.js
|
||||||
@@ -9,7 +9,21 @@ module.exports = {
|
|||||||
name: 'Twitch/Shoutout',
|
name: 'Twitch/Shoutout',
|
||||||
once: false,
|
once: false,
|
||||||
async execute(reason, channel, username) {
|
async execute(reason, channel, username) {
|
||||||
|
// Check if shoutout is enabled
|
||||||
|
const db = mClient.db('settings')
|
||||||
|
const coll = db.collection(channel)
|
||||||
|
const setting = await coll.findOne({ name: 'shoutout' })
|
||||||
|
|
||||||
|
// create in disabled state if not exists
|
||||||
|
if (!setting) {
|
||||||
|
await coll.insertOne({
|
||||||
|
name: 'shoutout',
|
||||||
|
enabled: false // default
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!setting?.enabled && reason != 'command' ){ return }
|
||||||
|
|
||||||
// Function to perform shoutout (Nightbot or custom)
|
// Function to perform shoutout (Nightbot or custom)
|
||||||
async function doShoutouts(channel, user) {
|
async function doShoutouts(channel, user) {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -0,0 +1,82 @@
|
|||||||
|
const { mClient, tClient } = require("../..");
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
name: 'Command/commands',
|
||||||
|
once: false,
|
||||||
|
async execute(channel, userstate, message, self, state, name) {
|
||||||
|
const db = mClient.db('commands')
|
||||||
|
const coll = db.collection(channel)
|
||||||
|
const defaultCommands = await coll.find({ default: true}).toArray()
|
||||||
|
var isDefault = false
|
||||||
|
defaultCommands.forEach((command) => {
|
||||||
|
if(command.default && command.name == name ){
|
||||||
|
isDefault = true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
if (isDefault){
|
||||||
|
return tClient.say(channel, `${name} can't be modified`)
|
||||||
|
}
|
||||||
|
const command = await coll.findOne({ name: 'commands' })
|
||||||
|
|
||||||
|
// create in disabled state if not exists
|
||||||
|
if (!command) {
|
||||||
|
await coll.insertOne({
|
||||||
|
name: 'commands',
|
||||||
|
enabled: true,
|
||||||
|
default: true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Default non-admin mode, give list of all enabled commands
|
||||||
|
if (!name) {
|
||||||
|
const commands = await coll.find({}).toArray()
|
||||||
|
var commandList = []
|
||||||
|
commands.forEach((command) => {
|
||||||
|
if(userstate.badges.moderator != 1 && userstate.badges.broadcaster != 1){
|
||||||
|
commandList.push(` ${command.name}`)
|
||||||
|
} else {
|
||||||
|
commandList.push(` ${command.name}(${command.enabled?'✅':'❌'})`)
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
if (commandList.length == 0) {
|
||||||
|
return await tClient.say(channel, `No commands available in this channel`)
|
||||||
|
}
|
||||||
|
return await tClient.say(channel, `Command List: ${commandList.toString()}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (userstate.badges.moderator != 1 && userstate.badges.broadcaster != 1) { return }
|
||||||
|
|
||||||
|
if (!state) { return }
|
||||||
|
|
||||||
|
// Admin Mode & Additional Parameters were given
|
||||||
|
|
||||||
|
// Parameters are valid
|
||||||
|
switch (state) {
|
||||||
|
case 'enable':
|
||||||
|
state = true
|
||||||
|
break;
|
||||||
|
case 'disable':
|
||||||
|
state = false
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return tClient.say(channel, `invalid state, expecting 'enable' or 'disable'`)
|
||||||
|
}
|
||||||
|
|
||||||
|
// command is valid
|
||||||
|
|
||||||
|
const findCommand = await coll.findOne({ name: name })
|
||||||
|
if (!findCommand) { return await tClient.say(channel, `Command [${name}] not found. Try using it first if it exists`) }
|
||||||
|
|
||||||
|
|
||||||
|
await coll.findOneAndUpdate({
|
||||||
|
name: name
|
||||||
|
}, {
|
||||||
|
$set: { enabled: state }
|
||||||
|
}, {
|
||||||
|
upsert: true
|
||||||
|
})
|
||||||
|
|
||||||
|
return await tClient.say(channel, `[${name}] has been set to [${state}]`)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
const { mClient, tClient } = require("../..");
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
name: 'Command/donate',
|
||||||
|
once: false,
|
||||||
|
async execute(channel, userstate, message, self) {
|
||||||
|
|
||||||
|
const db = mClient.db('commands')
|
||||||
|
const coll = db.collection(channel)
|
||||||
|
const command = await coll.findOne({ name: 'donate' })
|
||||||
|
|
||||||
|
// create in disabled state if not exists
|
||||||
|
if (!command) {
|
||||||
|
await coll.insertOne({
|
||||||
|
name: 'donate',
|
||||||
|
enabled: false // default
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!command?.enabled){ return tClient.say(channel, `This command is currently disabled `)}
|
||||||
|
|
||||||
|
async function sendDonationAd() {
|
||||||
|
// Function to send static donate ad
|
||||||
|
const links = [
|
||||||
|
"https://bit.ly/heltwittergoals",
|
||||||
|
"https://bit.ly/donatetohel",
|
||||||
|
"http://bit.ly/donothon_goals"
|
||||||
|
];
|
||||||
|
|
||||||
|
const messages = [
|
||||||
|
"Hel is currently celebrating her birthday with a donathon!",
|
||||||
|
`You can see goals and incentives here: ${links[0]}`,
|
||||||
|
`You can donate here: ${links[1]}`,
|
||||||
|
`Terms, conditions, rules and how rewards work are found here: ${links[2]}`,
|
||||||
|
"All donations and gifts are greatly appreciated, but please do so responsibly!"
|
||||||
|
];
|
||||||
|
|
||||||
|
for (const message of messages) {
|
||||||
|
await tClient.say(channel, message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sendDonationAd()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
const { mClient, tClient } = require('../..')
|
||||||
|
const { updateChatMode, getIDByName } = require('../../functions')
|
||||||
|
module.exports = {
|
||||||
|
name: 'Command/mode',
|
||||||
|
once: false,
|
||||||
|
async execute(channel, userstate, message, self, params) {
|
||||||
|
const db = mClient.db('commands')
|
||||||
|
const coll = db.collection(channel)
|
||||||
|
const command = await coll.findOne({ name: 'mode' })
|
||||||
|
|
||||||
|
// create in disabled state if not exists
|
||||||
|
if (!command) {
|
||||||
|
await coll.insertOne({
|
||||||
|
name: 'mode',
|
||||||
|
enabled: false // default
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if (!command?.enabled){ return tClient.say(channel, `This command is currently disabled `) }
|
||||||
|
|
||||||
|
if (userstate.badges.moderator != 1 && userstate.badges.broadcaster != 1) { return }
|
||||||
|
let regex = /^(on|off)$/
|
||||||
|
if (!params.match(regex)) { return }
|
||||||
|
updateChatMode(await getIDByName(channel.substring(1)), params)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
const { tClient, mClient } = require('../..')
|
||||||
|
module.exports = {
|
||||||
|
name: 'Command/positivity',
|
||||||
|
once: false,
|
||||||
|
async execute(channel, userstate, message, self) {
|
||||||
|
const db = mClient.db('commands')
|
||||||
|
const coll = db.collection(channel)
|
||||||
|
const command = await coll.findOne({ name: 'positivity' })
|
||||||
|
|
||||||
|
// create in disabled state if not exists
|
||||||
|
if (!command) {
|
||||||
|
await coll.insertOne({
|
||||||
|
name: 'positivity',
|
||||||
|
enabled: false // default
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!command?.enabled){ return tClient.say(channel, `This command is currently disabled `) }
|
||||||
|
|
||||||
|
async function sendPositivity() {
|
||||||
|
// Function sends a random string of predetermined positivity, Donothon Top Donator Reward
|
||||||
|
let positive_Messages = [
|
||||||
|
"You are so very worthy of all the love and support that may come your way.",
|
||||||
|
"There are many things which draw us together. In this time and place, that lovely subject is you, Hel.",
|
||||||
|
"The happiness and joy you add to the world is worth more than most anything.",
|
||||||
|
"You deserve every warm laugh, bright smile, and all the genuine kindness given to you.",
|
||||||
|
"There are few things as precious as your time. Thank you for sharing with us.",
|
||||||
|
"Your feelings are valid and you are not less than for having them.",
|
||||||
|
"I've seen all the work you do and I'm so very proud of you.",
|
||||||
|
"You are dearly cherished and I want to thank you for being so wonderfully you.",
|
||||||
|
"You. Are. Worthy. Enough. And I will tell you as many times as it takes for you to believe it.",
|
||||||
|
"Every day you give your best and that is so admirable. Don't let anyone tell you otherwise.",
|
||||||
|
"Your light is like that of the full moon, brightening our lives even in our darkest moments.",
|
||||||
|
"It's okay to take a moment to catch your breath. Even machines require maintenance from time to time.",
|
||||||
|
"Watching you succeed and achieve your heart's desires gives me so much motivation and I am very grateful for it."
|
||||||
|
]
|
||||||
|
|
||||||
|
let rdm = Math.floor(Math.random() * positive_Messages.length)
|
||||||
|
return tClient.say(channel, positive_Messages[rdm])
|
||||||
|
}
|
||||||
|
sendPositivity()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
const { mClient, tClient } = require("../..");
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
name: 'Command/settings',
|
||||||
|
once: false,
|
||||||
|
async execute(channel, userstate, message, self, state, name) {
|
||||||
|
if (userstate.badges.moderator != 1 && userstate.badges.broadcaster != 1) { return }
|
||||||
|
const db = mClient.db('commands')
|
||||||
|
const coll = db.collection(channel)
|
||||||
|
const command = await coll.findOne({ name: 'settings' })
|
||||||
|
|
||||||
|
// create in disabled state if not exists
|
||||||
|
if (!command) {
|
||||||
|
await coll.insertOne({
|
||||||
|
name: 'settings',
|
||||||
|
enabled: true,
|
||||||
|
default: true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if (!command?.enabled) { return tClient.say(channel, `This command is currently disabled `) }
|
||||||
|
|
||||||
|
const db2 = mClient.db('settings')
|
||||||
|
const coll2 = db2.collection(channel)
|
||||||
|
|
||||||
|
// Default non-admin mode, give list of all enabled commands
|
||||||
|
if (!name) {
|
||||||
|
const settings = await coll2.find({}).toArray()
|
||||||
|
var settingsList = []
|
||||||
|
console.log(settings)
|
||||||
|
settings.forEach((setting) => {
|
||||||
|
settingsList.push(` ${setting.name}(${setting.enabled?'✅':'❌'})`)
|
||||||
|
})
|
||||||
|
if (settingsList.length == 0) {
|
||||||
|
return await tClient.say(channel, `No settings available in this channel`)
|
||||||
|
}
|
||||||
|
return await tClient.say(channel, `Settings List: ${settingsList.toString()}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!state) { return }
|
||||||
|
|
||||||
|
// Parameters are valid
|
||||||
|
switch (state) {
|
||||||
|
case 'enable':
|
||||||
|
state = true
|
||||||
|
break;
|
||||||
|
case 'disable':
|
||||||
|
state = false
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return tClient.say(channel, `invalid state, expecting 'enable' or 'disable'`)
|
||||||
|
}
|
||||||
|
// command is valid
|
||||||
|
|
||||||
|
const findSetting = await coll2.findOne({ name: name })
|
||||||
|
if (!findSetting) { return await tClient.say(channel, `Setting [${name}] not found.`) }
|
||||||
|
|
||||||
|
|
||||||
|
await coll2.findOneAndUpdate({
|
||||||
|
name: name
|
||||||
|
}, {
|
||||||
|
$set: { enabled: state }
|
||||||
|
}, {
|
||||||
|
upsert: true
|
||||||
|
})
|
||||||
|
|
||||||
|
return await tClient.say(channel, `[${name}] has been set to [${state}]`)
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
const { mClient, dClient, tClient } = require('../..')
|
||||||
|
const { updateChatMode, getIDByName } = require('../../functions')
|
||||||
|
module.exports = {
|
||||||
|
name: 'Command/so',
|
||||||
|
once: false,
|
||||||
|
async execute(channel, userstate, message, self, name) {
|
||||||
|
if (userstate.badges.moderator != 1 && userstate.badges.broadcaster != 1) { return }
|
||||||
|
const db = mClient.db('commands')
|
||||||
|
const coll = db.collection(channel)
|
||||||
|
const command = await coll.findOne({ name: 'so' })
|
||||||
|
|
||||||
|
// create in disabled state if not exists
|
||||||
|
if (!command) {
|
||||||
|
await coll.insertOne({
|
||||||
|
name: 'so',
|
||||||
|
enabled: false // default
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if (!command?.enabled) { return tClient.say(channel, `This command is currently disabled `) }
|
||||||
|
|
||||||
|
dClient.emit('Twitch/Shoutout', 'command', channel, name)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,8 +1,5 @@
|
|||||||
const axios = require("axios");
|
const axios = require("axios");
|
||||||
const { mClient } = require(".");
|
const { mClient } = require(".");
|
||||||
const ReconnectingWebSocket = require("reconnecting-websocket");
|
|
||||||
const { WebSocket } = require("ws");
|
|
||||||
const twitchEventSubWsUrl = 'wss://eventsub.wss.twitch.tv/ws';
|
|
||||||
|
|
||||||
// Delay function for pauses
|
// Delay function for pauses
|
||||||
function delay(ms) { return new Promise(resolve => setTimeout(resolve, ms)); }
|
function delay(ms) { return new Promise(resolve => setTimeout(resolve, ms)); }
|
||||||
|
|||||||
+1
-4
@@ -1,9 +1,6 @@
|
|||||||
const fs = require('node:fs')
|
const fs = require('node:fs')
|
||||||
const path = require('node:path');
|
const path = require('node:path');
|
||||||
var { dClient, mClient, tClient } = require('..');
|
var { dClient, tClient } = require('..');
|
||||||
const { refreshAccessToken } = require('../functions');
|
|
||||||
const tmi = require('tmi.js')
|
|
||||||
|
|
||||||
const folderPath = path.join(__dirname, '../events')
|
const folderPath = path.join(__dirname, '../events')
|
||||||
const eventFolders = fs.readdirSync(folderPath)
|
const eventFolders = fs.readdirSync(folderPath)
|
||||||
|
|
||||||
|
|||||||
Generated
+31
-31
@@ -21,15 +21,15 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@discordjs/builders": {
|
"node_modules/@discordjs/builders": {
|
||||||
"version": "1.10.0",
|
"version": "1.10.1",
|
||||||
"resolved": "https://registry.npmjs.org/@discordjs/builders/-/builders-1.10.0.tgz",
|
"resolved": "https://registry.npmjs.org/@discordjs/builders/-/builders-1.10.1.tgz",
|
||||||
"integrity": "sha512-ikVZsZP+3shmVJ5S1oM+7SveUCK3L9fTyfA8aJ7uD9cNQlTqF+3Irbk2Y22KXTb3C3RNUahRkSInClJMkHrINg==",
|
"integrity": "sha512-OWo1fY4ztL1/M/DUyRPShB4d/EzVfuUvPTRRHRIt/YxBrUYSz0a+JicD5F5zHFoNs2oTuWavxCOVFV1UljHTng==",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@discordjs/formatters": "^0.6.0",
|
"@discordjs/formatters": "^0.6.0",
|
||||||
"@discordjs/util": "^1.1.1",
|
"@discordjs/util": "^1.1.1",
|
||||||
"@sapphire/shapeshift": "^4.0.0",
|
"@sapphire/shapeshift": "^4.0.0",
|
||||||
"discord-api-types": "^0.37.114",
|
"discord-api-types": "^0.37.119",
|
||||||
"fast-deep-equal": "^3.1.3",
|
"fast-deep-equal": "^3.1.3",
|
||||||
"ts-mixer": "^6.0.4",
|
"ts-mixer": "^6.0.4",
|
||||||
"tslib": "^2.6.3"
|
"tslib": "^2.6.3"
|
||||||
@@ -66,9 +66,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@discordjs/rest": {
|
"node_modules/@discordjs/rest": {
|
||||||
"version": "2.4.2",
|
"version": "2.4.3",
|
||||||
"resolved": "https://registry.npmjs.org/@discordjs/rest/-/rest-2.4.2.tgz",
|
"resolved": "https://registry.npmjs.org/@discordjs/rest/-/rest-2.4.3.tgz",
|
||||||
"integrity": "sha512-9bOvXYLQd5IBg/kKGuEFq3cstVxAMJ6wMxO2U3wjrgO+lHv8oNCT+BBRpuzVQh7BoXKvk/gpajceGvQUiRoJ8g==",
|
"integrity": "sha512-+SO4RKvWsM+y8uFHgYQrcTl/3+cY02uQOH7/7bKbVZsTfrfpoE62o5p+mmV+s7FVhTX82/kQUGGbu4YlV60RtA==",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@discordjs/collection": "^2.1.1",
|
"@discordjs/collection": "^2.1.1",
|
||||||
@@ -76,10 +76,10 @@
|
|||||||
"@sapphire/async-queue": "^1.5.3",
|
"@sapphire/async-queue": "^1.5.3",
|
||||||
"@sapphire/snowflake": "^3.5.3",
|
"@sapphire/snowflake": "^3.5.3",
|
||||||
"@vladfrangu/async_event_emitter": "^2.4.6",
|
"@vladfrangu/async_event_emitter": "^2.4.6",
|
||||||
"discord-api-types": "^0.37.114",
|
"discord-api-types": "^0.37.119",
|
||||||
"magic-bytes.js": "^1.10.0",
|
"magic-bytes.js": "^1.10.0",
|
||||||
"tslib": "^2.6.3",
|
"tslib": "^2.6.3",
|
||||||
"undici": "6.19.8"
|
"undici": "6.21.1"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18"
|
"node": ">=18"
|
||||||
@@ -113,18 +113,18 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@discordjs/ws": {
|
"node_modules/@discordjs/ws": {
|
||||||
"version": "1.2.0",
|
"version": "1.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/@discordjs/ws/-/ws-1.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/@discordjs/ws/-/ws-1.2.1.tgz",
|
||||||
"integrity": "sha512-QH5CAFe3wHDiedbO+EI3OOiyipwWd+Q6BdoFZUw/Wf2fw5Cv2fgU/9UEtJRmJa9RecI+TAhdGPadMaEIur5yJg==",
|
"integrity": "sha512-PBvenhZG56a6tMWF/f4P6f4GxZKJTBG95n7aiGSPTnodmz4N5g60t79rSIAq7ywMbv8A4jFtexMruH+oe51aQQ==",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@discordjs/collection": "^2.1.0",
|
"@discordjs/collection": "^2.1.0",
|
||||||
"@discordjs/rest": "^2.4.1",
|
"@discordjs/rest": "^2.4.3",
|
||||||
"@discordjs/util": "^1.1.0",
|
"@discordjs/util": "^1.1.0",
|
||||||
"@sapphire/async-queue": "^1.5.2",
|
"@sapphire/async-queue": "^1.5.2",
|
||||||
"@types/ws": "^8.5.10",
|
"@types/ws": "^8.5.10",
|
||||||
"@vladfrangu/async_event_emitter": "^2.2.4",
|
"@vladfrangu/async_event_emitter": "^2.2.4",
|
||||||
"discord-api-types": "^0.37.114",
|
"discord-api-types": "^0.37.119",
|
||||||
"tslib": "^2.6.2",
|
"tslib": "^2.6.2",
|
||||||
"ws": "^8.17.0"
|
"ws": "^8.17.0"
|
||||||
},
|
},
|
||||||
@@ -148,9 +148,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@mongodb-js/saslprep": {
|
"node_modules/@mongodb-js/saslprep": {
|
||||||
"version": "1.1.9",
|
"version": "1.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.1.9.tgz",
|
"resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.2.0.tgz",
|
||||||
"integrity": "sha512-tVkljjeEaAhCqTzajSdgbQ6gE6f3oneVwa3iXR6csiEwXXOFsiC6Uh9iAjAhXPtqa/XMDHWjjeNH/77m/Yq2dw==",
|
"integrity": "sha512-+ywrb0AqkfaYuhHs6LxKWgqbh3I72EpEgESCw37o+9qPx9WTCkgDm2B+eMrwehGtHBWHFU4GXvnSCNiFhhausg==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"sparse-bitfield": "^3.0.3"
|
"sparse-bitfield": "^3.0.3"
|
||||||
@@ -494,23 +494,23 @@
|
|||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/discord.js": {
|
"node_modules/discord.js": {
|
||||||
"version": "14.17.3",
|
"version": "14.18.0",
|
||||||
"resolved": "https://registry.npmjs.org/discord.js/-/discord.js-14.17.3.tgz",
|
"resolved": "https://registry.npmjs.org/discord.js/-/discord.js-14.18.0.tgz",
|
||||||
"integrity": "sha512-8/j8udc3CU7dz3Eqch64UaSHoJtUT6IXK4da5ixjbav4NAXJicloWswD/iwn1ImZEMoAV3LscsdO0zhBh6H+0Q==",
|
"integrity": "sha512-SvU5kVUvwunQhN2/+0t55QW/1EHfB1lp0TtLZUSXVHDmyHTrdOj5LRKdR0zLcybaA15F+NtdWuWmGOX9lE+CAw==",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@discordjs/builders": "^1.10.0",
|
"@discordjs/builders": "^1.10.1",
|
||||||
"@discordjs/collection": "1.5.3",
|
"@discordjs/collection": "1.5.3",
|
||||||
"@discordjs/formatters": "^0.6.0",
|
"@discordjs/formatters": "^0.6.0",
|
||||||
"@discordjs/rest": "^2.4.2",
|
"@discordjs/rest": "^2.4.3",
|
||||||
"@discordjs/util": "^1.1.1",
|
"@discordjs/util": "^1.1.1",
|
||||||
"@discordjs/ws": "^1.2.0",
|
"@discordjs/ws": "^1.2.1",
|
||||||
"@sapphire/snowflake": "3.5.3",
|
"@sapphire/snowflake": "3.5.3",
|
||||||
"discord-api-types": "^0.37.114",
|
"discord-api-types": "^0.37.119",
|
||||||
"fast-deep-equal": "3.1.3",
|
"fast-deep-equal": "3.1.3",
|
||||||
"lodash.snakecase": "4.1.1",
|
"lodash.snakecase": "4.1.1",
|
||||||
"tslib": "^2.6.3",
|
"tslib": "^2.6.3",
|
||||||
"undici": "6.19.8"
|
"undici": "6.21.1"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18"
|
"node": ">=18"
|
||||||
@@ -1335,9 +1335,9 @@
|
|||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/undici": {
|
"node_modules/undici": {
|
||||||
"version": "6.19.8",
|
"version": "6.21.1",
|
||||||
"resolved": "https://registry.npmjs.org/undici/-/undici-6.19.8.tgz",
|
"resolved": "https://registry.npmjs.org/undici/-/undici-6.21.1.tgz",
|
||||||
"integrity": "sha512-U8uCCl2x9TK3WANvmBavymRzxbfFYG+tAu+fgx3zxQy3qdagQqBLwJVrdyO1TBfUXvfKveMKJZhpvUYoOjM+4g==",
|
"integrity": "sha512-q/1rj5D0/zayJB2FraXdaWxbhWiNKDvu8naDT2dl1yTlvJp4BLtOcp2a5BvgGNQpYYJzau7tf1WgKv3b+7mqpQ==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18.17"
|
"node": ">=18.17"
|
||||||
@@ -1365,9 +1365,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/whatwg-url": {
|
"node_modules/whatwg-url": {
|
||||||
"version": "14.1.0",
|
"version": "14.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.1.1.tgz",
|
||||||
"integrity": "sha512-jlf/foYIKywAt3x/XWKZ/3rz8OSJPiWktjmk891alJUEjiVxKX9LEO92qH3hv4aJ0mN3MWPvGMCy8jQi95xK4w==",
|
"integrity": "sha512-mDGf9diDad/giZ/Sm9Xi2YcyzaFpbdLpJPr+E9fSkyQ7KpQD4SdFcugkRQYzhmfI4KeV4Qpnn2sKPdo+kmsgRQ==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"tr46": "^5.0.0",
|
"tr46": "^5.0.0",
|
||||||
|
|||||||
Reference in New Issue
Block a user