i was wondering how to make a Command Cool-down for a single command and not all the other commands? it would be much appreciated if someone helps me out on this, Thank you in advanced.
You are going to have to create a Collection() that will contain the users that have executed a command and then have a client.setTimeout() function to remove the users after a set time from the Collection() so that they can use commands again.
Here is an example from this guide:
const cooldowns = new Discord.Collection();
if (!cooldowns.has(command.name)) {
cooldowns.set(command.name, new Discord.Collection());
}
const now = Date.now();
const timestamps = cooldowns.get(command.name);
const cooldownAmount = (command.cooldown || 3) * 1000;
if (timestamps.has(message.author.id)) {
// ...
}
if (timestamps.has(message.author.id)) {
const expirationTime = timestamps.get(message.author.id) + cooldownAmount;
if (now < expirationTime) {
const timeLeft = (expirationTime - now) / 1000;
return message.reply(`please wait ${timeLeft.toFixed(1)} more second(s) before reusing the \`${command.name}\` command.`);
}
}
Related
I have a timestamp and I need to run my code 30 seconds before timestamp is reached.
Logic
Get current time
Get database timestamp
Run code 30 seconds before database timestamp
sample code
const now = moment(); // current time
const then = moment.unix(chainIds[i].timestamp); // returns: 2023-02-15T18:11:00+07:00
// run something (console log perhaps)
so based on my database timestamp my code has to be run at 18:10:30
actual code
Note: problem with this code is that its running even days after timestamp is passed.
const now = moment();
const then = moment.unix(chainIds[i].timestamp);
const delta = now.diff(then, 'seconds'); // get the seconds difference
var itstime = false;
if(moment.unix(delta).format("ss") <= 30){
itstime = false;
} else {
itstime = true;
}
I know I'm close to the solution but there is a bug that I can't figure it, any idea?
You can add a minimum value condition to make sure it won't run too far after the target. Here I'm giving it a 60 second buffer so that it will still run if the code isn't triggered exactly at 30 seconds, but you can adjust that to your needs.
var itstime = false;
var seconds = moment.unix(delta).format("ss");
if(seconds <= 30 && seconds >= -30){
itstime = false;
} else {
itstime = true;
}
You can make it a lot more simple
const now = moment();
const then = moment.unix(chainIds[i].timestamp);
const delta = now.diff(then, 'seconds');
var itstime = false;
if(delta < 30){
itstime = true;
}
I am not super sure but from what I understood, your difference is getting a second time, now.diff gets the result, see
https://www.geeksforgeeks.org/moment-js-moment-diff-function/
so I don´t think you need
moment.unix(delta).format("ss") <= 30
have you tried something like
const now = moment();
const then = moment().add('minutes', 1);
const delta = now.diff(then, 'seconds'); // get the seconds difference
var itstime = false;
if (delta <= 30) {
itstime = false;
} else {
itstime = true;
}
I made a 5 minute(300 seconds) cooldown for my discord.js bot, but when someone uses it more than once in under 5 minutes, it sends something like:
#Edward, please wait 250.32 second(s) until you can use this command!
Is there any way to change 250.32 seconds to something like 4 minutes 10 seconds or something close to that? I'm a noob at Node.js so help would be greatly appreciated.
if (!cooldowns.has(command)) {
cooldowns.set(command, new Discord.Collection());
}
const now = Date.now();
const timestamps = cooldowns.get(command);
const cooldownAmount = 1 * 300 * 1000;
if (timestamps.has(message.author.id)) {
const expirationTime = timestamps.get(message.author.id) + cooldownAmount;
if (now < expirationTime) {
const timeLeft = (expirationTime - now) / 1000;
return message.reply(`Please wait ${timeLeft.toFixed(1)} more second(s) before reusing the \`${command}\` command.`);
}
}
timestamps.set(message.author.id, now);
setTimeout(() => timestamps.delete(message.author.id), cooldownAmount);
Read this discussion.
Basically you need to divide seconds with 60 to get minutes and then you use % to get the reminder:
const cooldownAmount = 1 * 275.45 * 1000;
const timeLeft = cooldownAmount / 1000;
var quotient = Math.floor(timeLeft / 60); //minutes
var remainder = Math.floor(timeLeft % 60); //seconds
console.log(quotient); // 4
console.log(remainder); // 35
This code should work in your case:
if (!cooldowns.has(command)) {
cooldowns.set(command, new Discord.Collection());
}
const now = Date.now();
const timestamps = cooldowns.get(command);
const cooldownAmount = 1 * 300 * 1000;
if (timestamps.has(message.author.id)) {
const expirationTime = timestamps.get(message.author.id) + cooldownAmount;
if (now < expirationTime) {
const timeLeft = (expirationTime - now) / 1000;
var quotient = Math.floor(timeLeft / 60); //minutes
var remainder = Math.floor(timeLeft % 60); //seconds
return message.reply(`Please wait ${quotient} minutes and ${remainder} seconds before reusing the \`${command}\` command.`);
}
}
timestamps.set(message.author.id, now);
setTimeout(() => timestamps.delete(message.author.id), cooldownAmount);
I want to wait while a class other method running, current solution:
async waitForUnlock(ms: number) {
if (!this.locked) return
const start = new Date().getTime();
let time = 0;
while (time < ms) {
if (!this.locked) {
return;
}
const end = new Date().getTime();
time = end - start;
}
throw new Error(`timeout ${ms} ms. The queue is locked.`)
}
example usage:
async undoCommand(numberOfCommands: number = 1, timeout: number = 1000): Promise<void> {
await this.waitForUnlock(timeout)
// ....
it's oke? is there a better solution?
I have a template PDF file, and I want to replace some marker strings to generate new PDF files and save them. What's the best/simplest way to do this? I don't need to add graphics or anything fancy, just a simple text replacement, so I don't want anything too complicated.
Thanks!
Edit: Just found HummusJS, I'll see if I can make progress and post it here.
I found this question by searching, so I think it deserves the answer. I found the answer by BrighTide here: https://github.com/galkahana/HummusJS/issues/71#issuecomment-275956347
Basically, there is this very powerful Hummus package which uses library written in C++ (crossplatform of course). I think the answer given in that github comment can be functionalized like this:
var hummus = require('hummus');
/**
* Returns a byteArray string
*
* #param {string} str - input string
*/
function strToByteArray(str) {
var myBuffer = [];
var buffer = new Buffer(str);
for (var i = 0; i < buffer.length; i++) {
myBuffer.push(buffer[i]);
}
return myBuffer;
}
function replaceText(sourceFile, targetFile, pageNumber, findText, replaceText) {
var writer = hummus.createWriterToModify(sourceFile, {
modifiedFilePath: targetFile
});
var sourceParser = writer.createPDFCopyingContextForModifiedFile().getSourceDocumentParser();
var pageObject = sourceParser.parsePage(pageNumber);
var textObjectId = pageObject.getDictionary().toJSObject().Contents.getObjectID();
var textStream = sourceParser.queryDictionaryObject(pageObject.getDictionary(), 'Contents');
//read the original block of text data
var data = [];
var readStream = sourceParser.startReadingFromStream(textStream);
while(readStream.notEnded()){
Array.prototype.push.apply(data, readStream.read(10000));
}
var string = new Buffer(data).toString().replace(findText, replaceText);
//Create and write our new text object
var objectsContext = writer.getObjectsContext();
objectsContext.startModifiedIndirectObject(textObjectId);
var stream = objectsContext.startUnfilteredPDFStream();
stream.getWriteStream().write(strToByteArray(string));
objectsContext.endPDFStream(stream);
objectsContext.endIndirectObject();
writer.end();
}
// replaceText('source.pdf', 'output.pdf', 0, /REPLACEME/g, 'My New Custom Text');
UPDATE:
The version used at the time of writing an example was 1.0.83, things might change recently.
UPDATE 2:
Recently I got an issue with another PDF file which had a different font. For some reason the text got split into small chunks, i.e. string QWERTYUIOPASDFGHJKLZXCVBNM1234567890- got represented as -286(Q)9(WER)24(T)-8(YUIOP)116(ASDF)19(GHJKLZX)15(CVBNM1234567890-)
I had no idea what else to do rather than make up a regex.. So instead of this one line:
var string = new Buffer(data).toString().replace(findText, replaceText);
I have something like this now:
var string = Buffer.from(data).toString();
var characters = REPLACE_ME;
var match = [];
for (var a = 0; a < characters.length; a++) {
match.push('(-?[0-9]+)?(\\()?' + characters[a] + '(\\))?');
}
string = string.replace(new RegExp(match.join('')), function(m, m1) {
// m1 holds the first item which is a space
return m1 + '( ' + REPLACE_WITH_THIS + ')';
});
Building on Alex's (and other's) solution, I noticed an issue where some non-text data were becoming corrupted. I tracked this down to encoding/decoding the PDF text as utf-8 instead of as a binary string. Anyways here's a modified solution that:
Avoids corrupting non-text data
Uses streams instead of files
Allows multiple patterns/replacements
Uses the MuhammaraJS package which is a maintained fork of HummusJS (should be able to swap in HummusJS just fine as well)
Is written in TypeScript (feel free to remove the types for JS)
import muhammara from "muhammara";
interface Pattern {
searchValue: RegExp | string;
replaceValue: string;
}
/**
* Modify a PDF by replacing text in it
*/
const modifyPdf = ({
sourceStream,
targetStream,
patterns,
}: {
sourceStream: muhammara.ReadStream;
targetStream: muhammara.WriteStream;
patterns: Pattern[];
}): void => {
const modPdfWriter = muhammara.createWriterToModify(sourceStream, targetStream, { compress: false });
const numPages = modPdfWriter
.createPDFCopyingContextForModifiedFile()
.getSourceDocumentParser()
.getPagesCount();
for (let page = 0; page < numPages; page++) {
const copyingContext = modPdfWriter.createPDFCopyingContextForModifiedFile();
const objectsContext = modPdfWriter.getObjectsContext();
const pageObject = copyingContext.getSourceDocumentParser().parsePage(page);
const textStream = copyingContext
.getSourceDocumentParser()
.queryDictionaryObject(pageObject.getDictionary(), "Contents");
const textObjectID = pageObject.getDictionary().toJSObject().Contents.getObjectID();
let data: number[] = [];
const readStream = copyingContext.getSourceDocumentParser().startReadingFromStream(textStream);
while (readStream.notEnded()) {
const readData = readStream.read(10000);
data = data.concat(readData);
}
const pdfPageAsString = Buffer.from(data).toString("binary"); // key change 1
let modifiedPdfPageAsString = pdfPageAsString;
for (const pattern of patterns) {
modifiedPdfPageAsString = modifiedPdfPageAsString.replaceAll(pattern.searchValue, pattern.replaceValue);
}
// Create what will become our new text object
objectsContext.startModifiedIndirectObject(textObjectID);
const stream = objectsContext.startUnfilteredPDFStream();
stream.getWriteStream().write(strToByteArray(modifiedPdfPageAsString));
objectsContext.endPDFStream(stream);
objectsContext.endIndirectObject();
}
modPdfWriter.end();
};
/**
* Create a byte array from a string, as muhammara expects
*/
const strToByteArray = (str: string): number[] => {
const myBuffer = [];
const buffer = Buffer.from(str, "binary"); // key change 2
for (let i = 0; i < buffer.length; i++) {
myBuffer.push(buffer[i]);
}
return myBuffer;
};
And then to use it:
/**
* Fill a PDF with template data
*/
export const fillPdf = async (sourceBuffer: Buffer): Promise<Buffer> => {
const sourceStream = new muhammara.PDFRStreamForBuffer(sourceBuffer);
const targetStream = new muhammara.PDFWStreamForBuffer();
modifyPdf({
sourceStream,
targetStream,
patterns: [{ searchValue: "home", replaceValue: "emoh" }], // TODO use actual patterns
});
return targetStream.buffer;
};
There is another Node.js Package asposepdfcloud, Aspose.PDF Cloud SDK for Node.js. You can use it to replace text in your PDF document conveniently. Its free plan offers 150 credits monthly. Here is sample code to replace text in PDF document, don't forget to install asposepdfcloud first.
const { PdfApi } = require("asposepdfcloud");
const { TextReplaceListRequest }= require("asposepdfcloud/src/models/textReplaceListRequest");
const { TextReplace }= require("asposepdfcloud/src/models/textReplace");
// Get App key and App SID from https://aspose.cloud
pdfApi = new PdfApi("xxxxx-xxxxx-xxxx-xxxxxxxxxxx", "xxxxxxxxxxxxxxxxxxxxxb");
var fs = require('fs');
const name = "02_pages.pdf";
const remoteTempFolder = "Temp";
//const localTestDataFolder = "C:\\Temp";
//const path = remoteTempFolder + "\\" + name;
//var data = fs.readFileSync(localTestDataFolder + "\\" + name);
const textReplace= new TextReplace();
textReplace.oldValue= "origami";
textReplace.newValue= "aspose";
textReplace.regex= false;
const textReplace1= new TextReplace();
textReplace1.oldValue= "candy";
textReplace1.newValue= "biscuit";
textReplace1.regex= false;
const trr = new TextReplaceListRequest();
trr.textReplaces = [textReplace,textReplace1];
// Upload File
//pdfApi.uploadFile(path, data).then((result) => {
// console.log("Uploaded File");
// }).catch(function(err) {
// Deal with an error
// console.log(err);
//});
// Replace text
pdfApi.postDocumentTextReplace(name, trr, null, remoteTempFolder).then((result) => {
console.log(result.body.code);
}).catch(function(err) {
// Deal with an error
console.log(err);
});
P.S: I'm developer evangelist at aspose.
I have been developing in PHP for many years and now I´m trying to learn NodeJS, and I´m having problems with asynchronous functions...
I have this function in NodeJS (source is an array of users):
//userformat.js
var age = module.exports.age = function(date){
var diff = new Date - new Date(date);
var diffdays = diff / 1000 / (60 * 60 * 24);
var age = Math.floor(diffdays / 365.25);
return age;
}
...etc.
//index.js
function format(source, me, callback){
var len = source.length
for (var i = 0; i < len; i++){
source[i]['_age'] = userFormat.age(source[i]['birthday']);
source[i]['_rating'] = userFormat.rating(source[i]['votes']);
source[i]['_is_followed'] = userFormat.followed(source[i]['fllws'], me);
}
callback(null, source);
}
I know that function is wrong in Node, because is possible that the function calls the callback before the functions in the for() had finished, and the values in the array could be undefined, for this reason I changed the function using callbacks:
//userformat.js
var age = module.exports.age = function(date, callback){
var diff = new Date - new Date(date);
var diffdays = diff / 1000 / (60 * 60 * 24);
var age = Math.floor(diffdays / 365.25);
callback(age);
}
...etc.
//index.js
function format(source, me, callback){
var len = source.length
for (var i = 0; i < len; i++){
userFormat.age(source[i]['birthday'], function(resul){
source[i]['_age'] = resul;
userFormat.rating(source[i]['votes'], function(resul){
source[i]['_rating'] = resul;
userFormat.followed(source[i]['fllws'], me, function(resul){
source[i]['_is_followed'] = resul;
//Callback
if (i == len-1){
callback(null, source);
}
})
})
})
}
}
That is correct? I have another way to do it more efficient or elegant?
Thank you so much!
I think you misunderstood the concept of asynchronous in nodeJS. Your code isn't asynchronous and your callback will always be called after the loop.
Check this question : how do i create a non-blocking asynchronous function in node.js?