discord.js v13 What code would I use to collect the first attachment (image or video) from a MessageCollector? - node.js

I've looked everywhere and tried all I could think of but found nothing, everything seemed to fail.
One bit of code I've used before that failed:
Message.author.send({ embeds: [AttachmentEmbed] }).then(Msg => {
var Collector = Msg.channel.createMessageCollector({ MessageFilter, max: 1, time: 300000 });
Collector.on(`collect`, Collected => {
if (Collected.content.toLowerCase() !== `cancel`) {
console.log([Collected.attachments.values()].length);
if ([Collected.attachments.values()].length > 0) {
var Attachment = [Collected.attachments.values()];
var AttachmentType = `Image`;
PostApproval(false, Mode, Title, Description, Pricing, Contact, Attachment[0], AttachmentType);
} else if (Collected.content.startsWith(`https://` || `http://`) && !Collected.content.startsWith(`https://cdn.discordapp.com/attachments/`)) {
var Attachment = Collected.content.split(/[ ]+/)[0];
var AttachmentType = `Link`;
PostApproval(false, Mode, Title, Description, Pricing, Contact, Attachment, AttachmentType);
console.log(Attachment)
} else if (Collected.content.startsWith(`https://cdn.discordapp.com/attachments/`)) {
var Attachment = Collected.content.split(/[ ]+/)[0];
var AttachmentType = `ImageLink`;
PostApproval(false, Mode, Title, Description, Pricing, Contact, Attachment, AttachmentType);
console.log(Attachment)
}

[Collected.attachments.values()].length will always be 1. Why? Well you have these 2 possibilities:
[ [] ] //length 1
[ [someMessageAttachment] ] //length 1
The proper way to check is using the spread operator (...)
[...(Collected.attachments.values())].length //returns amount of attachments in the message

Related

How to remove specific object from object array in localStorage

Can anybody advise me how I should go about adapting this code to remove the found object within an array of objects in localStorage.
So far everything I have tried results in either only the 1st object being removed or none at all.
I have tried using the following adaptations to the splice request, but it has not removed the selected object.
favorites.splice(favorites, [i]);
favorites.splice(favorites, 1);
favorites.splice(favorites, favorites[i]);
ect ect
I have also tried using the ifIncludes request but then again removing the individual object has been troublesome.
function checkfave (theid) {
// get favorites from local storage or empty array
var favorites = JSON.parse(localStorage.getItem('favorites')) || [];
var theimage = $('#theimage'+theid).attr('src');
var thetitle = $('#thetitle'+theid).text();
var theprice = $('#theprice'+theid).text();
var added=true;
//Loop through the Favorites List and display in console (HIDDEN)
console.clear();
for (let i = 0; i < favorites.length; i++) {
console.log(i)+'items added';
if ( favorites[i].ID == theid ) {
var answer = window.confirm('You already Added To Your Favorites \r\r '+thetitle+' \r\r Do You Want To Remove It? ');
if (answer) { // choose to remove
favorites.splice(favorites[i], [i]);
alert(thetitle+' \r\r Has Been Removed From Your Favorites \r\r At Position'+[i]);
var added=false; break; //IMPORTANT KILLS THE LOOP ONLY IF favorites[i].ID == theid
}else {
var added=false; break;
}
}
}//for loop
if (added===true) {
favorites.push({ID:theid,IMAGE:theimage,TITLE:thetitle,PRICE:theprice});
localStorage.setItem('favorites', JSON.stringify(favorites));
alert('You Just Added To Your Favorites \r\r '+thetitle);
}
console.log(localStorage.favorites);
}//function
console log is returning in this format
favorites
(2) [{…}, {…}]
0
:
{ID: 32921, IMAGE: 'uploads/posts/2017-07/1500056645_apulsoft-apqualizr-2.png', TITLE: 'ApulSoft apQualizr 2 v2.5.2 ', PRICE: '19.99'}
1
:
{ID: 32920, IMAGE: 'uploads/posts/2022-03/1003229…cdj-lyrx-karaoke-player-software-for-mac-pc-1.png', TITLE: 'PCDJ LYRX v1.8.0.2 / v1.9.0.0 U2B ', PRICE: '19.99'}
length
:
2
[[Prototype]]
:
Array(0)
`
Finally figured it out on my own. Thanks
for (let i = 0; i < favorites.length; i++) {
console.log(i)+'items added';
if ( favorites[i].ID == theid ) {
var answer = window.confirm('You already Added To Your Favorites \r\r '+thetitle+' \r\r Do You Want To Remove It? ');
if (answer) { // choose to remove
favorites.splice(i, 1);
localStorage.setItem('favorites', JSON.stringify(favorites));
alert(thetitle+' \r\r Has Been Removed From Your Favorites \r\r At Position'+[i]);
var added=false; break; //IMPORTANT KILLS THE LOOP ONLY IF favorites[i].ID == theid
}else {
var added=false; break;
}
}
}//for loop
I was misunderstanding the nature of the splice function. i was trying to use favourites[i] = when favorites was already assumed in the 1st instance of the splice call.
I eventually came across the answer online in a similar situation.
the answer was to splice this way to remove at position i and remove 1 item
favorites.splice(i, 1);
Thanks anyway guys.

contentful getEntries published data only

Is there a way to query the results to show only data that has been published and is not in draft state? I looked in the documentation and didn't quite find it.
This is what I currently have:
export const getAllPages = async (context?) => {
const client = createClient({
space: process.env.CONTENTFUL_SPACE_ID,
accessToken: process.env.CONTENTFUL_ACCESS_TOKEN,
});
const pages = await client.getEntries({
content_type: "page",
include: 10,
"fields.slug[in]": `/${context.join().replace(",", "/")}`,
});
return pages?.items?.map((item) => {
const fields = item.fields;
return {
title: fields["title"],
};
});
};
You can detect that the entries you get are in Published state:
function isPublished(entity) {
return !!entity.sys.publishedVersion &&
entity.sys.version == entity.sys.publishedVersion + 1
}
In your case, I would look for both Published and Changed:
function isPublishedChanged(entity) {
return !!entity.sys.publishedVersion &&
entity.sys.version >= entity.sys.publishedVersion + 1
}
Check the documentation:
https://www.contentful.com/developers/docs/tutorials/general/determine-entry-asset-state/
To get only the published data you will need to use the Content Delivery API token. If you use the Content Preview API Token, you will receive both the published and draft entries.
You can read more about it here: https://www.contentful.com/developers/docs/references/content-delivery-api/
If using the Content Delivery API you need to filter on the sys.revision attribute for each item. A published item should have its revision attribute set to greater than 0.
const publishedItems = data.items.filter(item => item.sys.revision > 0)

Array list with 2 values and doing it to a top 10 list

im working on a Discord bot and have a reputation system with fs (npm package) and saving peoples reps in a file and doing the file name as they discord id
now im working on a top 10 command and would need some help here, i currently have this as code:
let users = [];
let reps = [];
fs.readdirSync('./data/reps/').forEach(obj => {
users.push(obj.replace('.json', ''))
let file = fs.readFileSync(`./data/reps/${obj}`)
let data = JSON.parse(file)
reps.push(data.reps)
})
let top = [...users, ...reps]
top.sort((a,b) => {a - b})
console.log(top)
the files form the users are like this:
{
"users": [
"437762415275278337"
],
"reps": 1
}
users are the current users that can't rep the persion anymore and don't need to use it in the command
i wan to get the top 10 of reps so that i can get the user id and how many reps they have, how could i do it with the code above?
You could try this
const topTen = fs.readdirSync('./data/reps/').map(obj => {
const file = fs.readFileSync(`./data/reps/${obj}`);
const data = JSON.parse(file);
return { ...data, name: obj.replace('.json', '') };
}).sort((a, b) => a.reps - b.reps).slice(0, 10);
console.log(topTen);
I would change how you push the data
const users = [];
fs.readdirSync('./data/reps/').forEach(obj => {
let file = fs.readFileSync(`./data/reps/${obj}`)
let data = JSON.parse(file)
reps.push({ reps: data.reps, id: obj.replace(".json", "") });
})
That way when you sort the array the id goes along with
//define this after the fs.readdirSync.forEach method
const top = users.sort((a,b)=> a.reps-b.reps).slice(0,10);
If you want an array of top ids
const topIds = top.map(e => e.id);
If you want a quick string of it:
const str = top.map(e => `${e.id}: ${e.reps}`).join("\n");
Also you should probably just have one or two json files, one would be the array of user id's and their reps and then the other could be of user id's and who they can't rep anymore

Gmail to Google Spread Sheet (only date, email and subject)

The code I have cobbled together does work, but it imports the wrong things from my email. I only want the date sent, the sender email address and the subject to import into the google sheet.
Can anyone help?
function onOpen() {
const spreadsheet = SpreadsheetApp.getActive();
let menuItems = [
{name: 'Gather emails', functionName: 'gather'},
];
spreadsheet.addMenu('SP LEGALS', menuItems);
}
function gather() {
let messages = getGmail();
let curSheet = SpreadsheetApp.getActive();
messages.forEach(message => {curSheet.appendRow(parseEmail(message))});
}
function getGmail() {
const query = "to:legals#salisburypost.com";
let threads = GmailApp.search(query,0,10);
let messages = [];
threads.forEach(thread => {
messages.push(thread.getMessages()[0].getPlainBody());
label.addToThread(thread);
});
return messages;
}
function parseEmail(message){
let parsed = message.replace(/,/g,'')
.replace(/\n*.+:/g,',')
.replace(/^,/,'')
.replace(/\n/g,'')
.split(',');
let result = [0,1,2,3,4,6].map(index => parsed[index]);
return result;
}
I believe your goal as follows.
You want to retrieve "the date, sender and subject" from the 1st message in the searched threads to the active sheet of Google Spreadsheet.
For this, how about this answer?
Modification points:
In this case, you can retrieve "the date, sender and subject" using the built-in methods for GmailApp.
When the values are put to the Spreadsheet, when appendRow is used in the loop, the process cost will become high.
It seems that label is not declared in your script.
When above points are reflected to your script, it becomes as follows.
Modified script:
In this modification, I modified gather() and getGmail() for achieving your goal.
function gather() {
let messages = getGmail();
if (messages.length > 0) {
let curSheet = SpreadsheetApp.getActiveSheet();
curSheet.getRange(curSheet.getLastRow() + 1, 1, messages.length, messages[0].length).setValues(messages);
}
}
function getGmail() {
const query = "to:legals#salisburypost.com";
let threads = GmailApp.search(query,0,10);
let messages = [];
threads.forEach(thread => {
const m = thread.getMessages()[0];
messages.push([m.getDate(), m.getFrom(), m.getSubject()]);
// label.addToThread(thread);
});
return messages;
}
When no threads are retrieved with "to:legals#salisburypost.com", the values are not put to the Spreadsheet. Please be careful this.
References:
getDate()
getFrom()
getSubject()
setValues(values)

Mailmerge pdf in nodejs and hummus-recipe

I'm trying to make a simple mail-merge where recipients information is inserted on top of a template pdf.
The template is 1 page, but the result can be up to several hundred pages.
I have all recipient in array objects, but need to find a way to loop over that and create a unique page for each recipient.
I'm not sure if hummus-recipe is the right tool, so would greatly appreciate any input as to how to do this.
My demo looks like this
const HummusRecipe = require('hummus-recipe')
const recepients = [
{name: "John Doe", address: "My Streetname 23", zip: "23456", city: "My City"},
{name: "Jane Doe", address: "Another Streetname 56 ", zip: "54432", city: "Her City"}
//'.......'
]
const template = 'template.pdf';
const pdfDoc = new HummusRecipe(template, 'output.pdf');
function createPdf(){
pdfDoc
.editPage(1)
.text(recepients[0].name, 30, 60)
.text(recepients[0].address, 30, 75)
.text(recepients[0].zip + ' ' + recepients[0].city, 30, 90)
.endPage()
//. appendpage(template) - tried versions of this in loops etc., but can't get it to work.
.endPDF();
}
createPdf();
This obviously only create a single page with recipient[0]. I have tried all sorts of ways to loop over using .appendpage(template), but I can't append and then edit the same page.
Any advice how to move forward from here?
After conversing with the creator of hummus-recipe and others, the solution became somewhat obvious. Its not possible to append a page and then modify it, and its not possible to modify the same page several times.
The solution then is to make the final pdf in two passes. First create a masterPdf where the template is appended in a for loop, save this file and then edit each of those pages.
I have created a working code as shown below. I have made the functions async as I need to run it on lambda an need som control over returns etc. Also this way its possible to save both the tmp-file and final pdf on AWS S3.
The code below takes about 60 seconds to create a 200 page pdf from a 1,6mb template. Any ideas for optimizations will be greatly appreciated.
const HummusRecipe = require('hummus-recipe');
const template = 'input/input.pdf';
const recipients = [
{name: 'John Doe', address: "My Streetname 23"},
{name: 'Jane Doe', address: "Another Streetname 44"},
//...etc.
]
async function createMasterPdf(recipientsLength) {
const key = `${(Date.now()).toString()}.pdf`;
const filePath = `output/tmp/${key}`;
const pdfDoc = new HummusRecipe(template, filePath)
for (i = 1; i < recipientsLength; i++) {
pdfDoc
.appendPage(template)
.endPage()
}
pdfDoc.endPDF();
return(filePath)
}
async function editMasterPdf(masterPdf, recipientsLength) {
const key = `${(Date.now()).toString()}.pdf`;
const filePath = `output/final/${key}`;
const pdfDoc = new HummusRecipe(masterPdf, filePath)
for (i = 0; i < recipientsLength; i++) {
pdfDoc
.editPage(i+1)
.text(recipients[i].name, 75, 100)
.text(recipients[i].address, 75, 115)
.endPage()
}
pdfDoc.endPDF()
return('Finished file: ' + filePath)
}
const run = async () => {
const masterPdf = await createMasterPdf(recipients.length);
const editMaster = await editMasterPdf(masterPdf, recipients.length)
console.log(editMaster)
}
run()

Resources