mIRC Execute command after X lines of chat - timer

I'm a selflearned mIRC programmer and started very recently so my experience is quite limited. Here's the problem I have:
I'm creating a chat bot for Twitch and have created besides a raffle system a timed message for promting the stream it's on every few minutes. However, I'd also like to repeat the message after X lines of chat lines sent in the chat in-case the chat is going quickly so you don't miss out on social links and stuff for new visitors.
Pseudo-code for what I want to be done:
on !startpromote
if (broadcaster) then PromoteMessage every X amount of lines passed
else return
end
on !stoppromote
if (broadcaster) then PromoteMessage stop
else return
end

You could have a %msgCounter variable in the variables tab and then you could use the TEXT event:
on *:TEXT:#:{
INC %msgCounter
if (%msgCounter > 10) { msg $chan Promotion message. }
}
You'd have to keep track of the %msgCounter variable and reset it when it hits a certain threshold.
Not sure what you mean by broadcaster, however if you mean IRCOp than you can use isop and do:
if ($1 isop $chan) {
}
Where $1 is the user who typed the message, isop determines if the user is an operator (or maybe broadcaster) and $chan for the IRC Channel.

Related

How do I get the last message sent by a specific user?

I'm currently running discord.js v13 and I'm trying to find a way of finding the last message sent by a specific user. So far, I've come up with the idea of iterating on an array of user IDs, then iterating on each channel and comparing each timestamp with the pervious timestamp found until it finds the latest one and stores it. However, this doesn't seem to work and I just keep getting today's date for ALL the users even though the majority of them haven't sent a message today.
My Code:
for(var i = 0; i < array_of_users.length; i++) {
for (const channel of message.guild.channels.cache.values()) {
if (channel.isText()) {
let messages = await channel.messages.fetch().catch(e => console.log(e));
messages.each((msg) => {
if (msg.author.id === array_of_users[i]) {
if(x == 0) {
old_date = new Date(msg.createdTimestamp).toDateString();
snowflakes.push(old_date);
x += 1;
} else {
var new_date = new Date(msg.createdTimestamp).toDateString();
let splitOld = old_date.split(" ");
let splitNew = new_date.split(" ");
if(parseInt(splitNew[3]) >= parseInt(splitOld[3])) {
year = splitNew[3];
if(getMonthInt(splitNew[1]) >= getMonthInt(splitOld[1]) ) {
monthC = splitNew[1];
if(getDayInt(splitNew[2]) >= getDayInt(splitOld[2])) {
dayNum = splitNew[2];
} else {
dayNum = splitOld[2];
}
} else {
monthC = splitOld[1];
dayNum = splitOld[2];
}
} else {
year = splitOld[3];
dayNum = splitOld[2];
monthC = splitOld[1];
}
}
}
})
}
}
console.log(`${monthC}-${dayNum}-${year}`);
}
The code above I've written to sort the dates and get the latest one, However something is wrong that it keeps getting the latest date and sometimes even future dates that haven't occurred yet. I can't seem to find the issue but I am speculating that it is originating around the if (msg.author.id === array_of_users[i]) area.
I'm trying to find a way of finding the last message sent by a specific user.
Discord.JS provides no 'built in' way of doing this. The best you can do is by grabbing their messages and comparing each of them to one another until you've exhausted your options and are left with the optimal result. So your approach is (more or less) correct, although your implementation does have some function errors that are throwing you off.
So far, I've come up with the idea of iterating on an array of user IDs, then iterating on each channel and comparing each timestamp with the pervious timestamp found until it finds the latest one and stores it.
If you only are only looking for the most recent message for a specific User, then it is redundant to be dealing with an Array of Users altogether.
However, this doesn't seem to work and I just keep getting today's date for ALL the users even though the majority of them haven't sent a message today.
There are a number of errors in your approach which could be causing this. Here's a quick few of the more generalized / lack-of-experience related errors in your solution for you to work on:
The else block where you're comparing days split up from timestamps is super convoluted. Why not just use the createdTimestamp value from the Message instance itself, then reconstruct the whole monthC-dayNum-year thing again later on using that if you need to?
You're likely going to be hitting Discord's Rate limits (rather frequently) with your script as-is. To put it in perspective, you're basically spamming requests to their API for the next X messages in channels [A, B, ...ZA, ZB] repeatedly. You can optimize this a lot by making logical inferences as to when you can safely 'exclude' a Channel from your search (e.g. if the most recent message you've found in channel X was created on Jun 18 2022, and most recent message found in channel Y was created on Mar 13 2022, you can safely avoid asking Discord for more Messages for channel Y, as it won't have any information relevant to your use case). Writing some additional logic here will pay dividends to you both in how quickly your function can execute, and how frustrating it is to debug once Discord gets upset with you for your small-scale DDOS attack against them.
If I was to solve this problem, the way I would do it would be to employ the following logic:
Given GuildMember X, grab all the Channels in the Guild they belong to.
Filter those Channels so you're only working on TextChannels.
Recursively iterate through those Channels, keeping track of the 'latest message' found belonging to GuildMember X in that Channel (when/if found). Whenever you find a new message belonging to GuildMember X in Channel Y, check if that beats the most recent message found across the entire set thus far. If so, update the best message for the set accordingly. Continually filter the Channels you're working with as you go to exclude Channels that logically cannot hold anything relevant to your search-- any time you finish a recursion, you can go back over the set of Channels and look for any one where the 'best message' in that channel does not beat the current best message. Since you're fetching 'backwards in time' (asking Discord for progressively older and older messages as you continue to recurse), any time the best message in a given channel does not beat the best message across the entire set, you can be certain that the channel does not hold the droids that you are looking for. You're only going to be fetching even older messages than the earliest one already fetched if you continue to look in that Channel, which makes that Channel irrelevant to you at that point.
Lucky for you, I had some time to kill while travelling today, and for whatever reason trying to find an optimal solution to your problem interested me enough to give it a proper shot. The tips I wrote above should help you understand the code below, and if not, leave a comment and maybe I can help you out. Here's how I would solve your problem, while paying attention to logical exclusion and avoiding doing unnecessary work / API calls.
https://codesandbox.io/s/holy-surf-50vpmf?file=/index.js

how to make a discord bot mention someone in a specific channel (discord.js)

im making a "mini game chat bot" and i want the bot to have different endings.
when someone unlocks an ending i would like to be notified so i can keep track of how many endings that person has unlocked (no i wont add roles to keep track because if my calculations are correct the bot will have like 200 different endings).
i want to make it so that,
for example, someone says B3 in #general and the bot answers in #endings
#(person who used the command) unlocked the ending "I probably
shouldn't have said that..."
case 'B3':
message.channel.send('Umm.. What?');
const B3ending = new Discord.MessageEmbed()
.setTitle('Congratulations!)
.setColor(0x8CF1EC)
.setDescription('You unlocked the ending "I probably shouldn't have said that..."');
message.channel.send(B3ending);
break;
Well first you would need to get the channel somehow, maybe by id:
const endChannel = message.guild.channels.cache.get(id);
After that you can just use the send method alongside msg.author
endChannel.send(`${message.author} here's the ending`, { embed: B3ending });

Is there a way to pm an author and use the wait_for command to capture the value they type in?

I'm writing a discord bot using python to log options trade. What I'm looking to do with my bot is when a user type execute a command, !opentrade, the bot would private message the user with a series of questions. The bot would then capture the answer in a series of variables and use that to process the answer. Is this possible or does it have to be in the channel where the command is called. Additionally, is it by default multithread, meaning 2 or 3 people can call that command at the same time and it would fud up the answer
I have the following thus far and it isn't working:
async def opentrade(ctx):
def check(author):
def inner_check(message):
if message.author != author:
return False
try:
int(message.content)
return True
except ValueError:
return False
return inner_check
try:
await ctx.author.send('Enter the underlying: ')
underlying = await client.wait_for('message', check=check(ctx.author), timeout=30)
print (underlying)
except Exception as err:
await ctx.channel.send("Something went wrong: {}".format(err))
thanks
What I'm looking to do with my bot is when a user type execute a command, !opentrade, the bot would private message the user with a series of questions. The bot would then capture the answer in a series of variables and use that to process the answer. Is this possible or does it have to be in the channel where the command is called.
Possible. You need to put the whole logic into the coroutine that executes the command.
Additionally, is it by default multithread, meaning 2 or 3 people can call that command at the same time and it would fud up the answer
If you implement the checks properly it won't fud the answer. In your code you already implemented the logic that checks for the author so noone else can change it def check(author).
When executing the commands multiple times by different users it will also not fud the answer since the threads are independent.
You should extend this check so it checks for a message in a DM channel. The way your check is written now the caller can DM the bot or respond in a guild text channel.
I'm not sure what's saved in the ctx variable but I'm certain it has a message attribute.
Try await ctx.message.author.send(). If you are running into an error provide the error log.

delete bot message after 2 user messages prior

javascript is still vague to my knowledge, and I cannot be precise on the sensibility in the following code I have manufactured. I am programming a discord bot that categorizes messages into a variety of channels, and the question has approached me to how I can program the bot by deleting follow up bot messages after 2 user messages were sent subsequently after the bot message.
if (bot.on(client, user.msg = '2'));{
msg.channel('message' = msg.delete)
}
Help is to be requested and I hope my query makes sense in the context I am implying, Regards, Coder
P.S: How do I change the bot messages text color as well?
No offense, but your code was completely faulty, so I just made some new code.
bot.on('message', aysnc message => {
var messagenumber = 0; //Makes variable for the number of messages sent
if(message.member.user.username === bot.user.username) return; //If the person who posts a message is the bot, it doesn't the code below.
if(messagenumber = 1) return bulkDelete(100), messagenumber = 0 //Checks if the variable is 1, and if it is, this means it's the second time a message posted, so it deletes messages (Limit is 100) then resets variable.
messagenumber = 1; //Makes variable 1 (This is to make it know it is the the second time a message is posted for the next time).
});
I didn't test this code, so it may not work properly, but if it does work I hope it helps you with your bot.
For the P.S (Changing text color): You can use these (Replace "NoKeyWordsHere" with your message). I don't recommend this, cause it'd take a long time to add it to every message sent. (You can use these on your messages too)

discord.js user.speaking isn't working

//function fires after special command every 100 milliseconds
function searchSpeaking(roleSpeak){
//checks every channel; giving you member-channel and its chanId-id
bot.channels.forEach((channel, chanId) => {
//filters out text channels
if (channel.type == 'voice'){
//checks every member in voice channel; giving you guildMember-user and his/her id
channel.members.forEach((guildMember, memberId) => {
//debug
console.log(guildMember.nickname, guildMember.speaking)
console.log("-----------------------------------")
//activates when user speaks DOESN'T WORK
if (guildMember.speaking){
//adds 'score' it means how mayn milli seconds user talks
scoreboard[memberId] += 100
console.log("user is speaking!")
//if user talks for over 30s = 30 000 milliseconds and has option to talk
if ((scoreboard[memberId] > 30 * 1000) && guildMember.roles.has(roleSpeak.id)){
//reset his score and remove his option to speak
scoreboard[memberId] = 0
guildMember.removeRole(roleSpeak)
}
}
//if user isnt talking because his option/role to talk was removed
else if (!(guildMember.roles.has(roleSpeak.id))){
//we messure how much time he/she has been muted/without talking option
scoreboard[memberId] += 100
//if he/she was muted for a minute he/she will get his option/role to talk back
if (scoreboard[id] > 60 * 1000){
//reset score and give back role
scoreboard[memberId] = 0
guildMember.addRole(roleSpeak)
}
}
})
}
})
}
So in the line under a comment ( // ) stating that this doesn't work is an if statement that never passes even tho users are speaking in channels. It is console.loging as false as well (obvious). So i can't figure out why as i understand the docs it should turn to true every time member speaks. I will just say this again (as it says in first code comment) this function fires every 100ms = 0.1s and gets a role it is supposed to change based on score further explained in code comments.
Thanks for any help working with .speaking!
With the current API, there is no way to know if a user is talking in a voice channel without joining the voice channel.
You would need to join a voice channel, get a list of the users that are talking, and then switch to another channel (if there are any members in that channel).
You would probably get rate limited very quickly using this method.
Only way without joining the channels, would be getting the list of members in voice channels, and filter those with microphone muted. You still wouldn't know if they are really talking.
If you would want to join the channel and "listen" to the speaking, you could use the event guildMemberSpeaking. This would activate whenever a user starts/stops talking in the voice channel you are.

Resources