Reading file attachments (Ex; .txt file) - Discord.JS - javascript

Second time posting on StackOverflow so I apologize for any mistakes.
Please bear with me.
Same with the title; How do you read contents of a discord attachment let's say a .txt file and print the contents?
I have tried with fs but unfortunately failed and I have also searched the documentation but failed also.
Ideas?

You can't use the fs module for this as it only deals with local files. When you upload a file to the Discord server, it gets uploaded to a CDN and all you can do is grab the URL of this file from the MessageAttachment using the url property.
If you need to get a file from the web, you can fetch it from a URL using the built-in https module, or you can install one from npm, like the one I used below, node-fetch.
To install node-fetch, run npm i node-fetch in your root folder.
Check out the working code below, it works fine with text files:
const { Client } = require('discord.js');
const fetch = require('node-fetch');
const client = new Client();
client.on('message', async (message) => {
if (message.author.bot) return;
// get the file's URL
const file = message.attachments.first()?.url;
if (!file) return console.log('No attached file found');
try {
message.channel.send('Reading the file! Fetching data...');
// fetch the file from the external URL
const response = await fetch(file);
// if there was an error send a message with the status
if (!response.ok)
return message.channel.send(
'There was an error with fetching the file:',
response.statusText,
);
// take the response stream and read it to completion
const text = await response.text();
if (text) {
message.channel.send(`\`\`\`${text}\`\`\``);
}
} catch (error) {
console.log(error);
}
});

reply to #Andryxa, maybe you can use this with external APIs like a transcription service in case of audio files or to send requests to already created bots from services like dialogflow to replies to the messages

Related

Trying to get a stream link of a video file from GDRIVE API

I'm trying to get a stream link for my video files to stream it on my web app from google drive api, but its not working properly. I have double checked the docs for any errors in syntax and i can't seem to find any.
for context here is my code:
`
drive.files.get({fileId: myfileId,alt: 'media'},{responseType: 'stream'}, (err, res) => {
if (err) return console.log(`The API returned an error: ${err}`);
console.log(res)
});
`
I'm getting a passthrough object in res.data field and its giving an error of "Unknown output format: 'media' ". The file i'm trying to stream is a .mp4 file.
I have also double checked my authentication and its working fine because i was able to retrieve my folder id and file id using the api.
Am i doing anything wrong here? Any help would be appreciated.
THANKS.
Once you have authenticated the client library, you can use the following code to get a stream link for a video file stored in Google Drive
// Replace fileId with the ID of the video file you want to stream
const fileId = '1234567890';
// Get the file from Google Drive
const file = await drive.files.get({ fileId, alt: 'media' });
// Get the stream link for the file
const streamLink = file.data;

Downloading a zip file from a given path in express api + react

So I'm completely lost at this point. I have had a mixture of success and failure but I can't for the life of me get this working. So I'm building up a zip file and storing it in a folder structure that's based on uploadRequestIds and that all works fine. I'm fairly new to the node but all I want is to take the file that was built up which is completely valid and works if you open it once it's been constructed in the backend and then send that on to the client.
const prepareRequestForDownload = (dirToStoreRequestData, requestId) => {
const output = fs.createWriteStream(dirToStoreRequestData + `/Content-${requestId}.zip`);
const zip = archiver('zip', { zlib: { level: 9 } });
output.on('close', () => { console.log('archiver has been finalized.'); });
zip.on('error', (err) => { throw err; });
zip.pipe(output);
zip.directory(dirToStoreRequestData, false);
zip.finalize();
}
This is My function that builds up a zip file from all the files in a given directory and then stores it in said directory.
all I thought I would need to do is set some headers to have an attachment disposition type and create a read stream of the zip file into the res.send function and then react would be able to save the content. but that just doesn't seem to be the case. How should this be handled on both the API side from reading the zip and sending to the react side of receiving the response and the file auto-downloading/requesting a user saves the file.
This is what the temp structure looks like
There is some strategies to resolve it, all browser when you redirect to URL where extension ending with .zip, normally start downloading. What you can do is to return to your client the path for download something like that.
http://api.site.com.br/my-file.zip
and then you can use:
window.open('URL here','_blank')

Electron upload with progress

I have an Electron app which is able to upload very big files to the server via HTTP in renderer process without user input. I decided to use axios as my HTTP client and it was able to retrieve upload progress but with this I met few problems.
Browser's supported js and Node.js aren't "friendly" with each other in some moments. I used fs.createReadStream function to get the file but axios does not understand what ReadStream object is and I can't pipe (there are several topics on their GitHub issue tab but nothing was done with that till now) this stream to FormData (which I should place my file in).
I ended up using fs.readFileSync and then form-data module with its getBuffer() method but now my file is loaded entirely in the memory before upload and with how big my files are it kills Electron process.
Googling I found out about request library which in-fact is able to pipe a stream to request but it's deprecated, not supported anymore and apparently I can't get upload progress from it.
I'm running out of options. How do you upload files with Electron without user input (so without file input) not loading them in the memory upfront?
P.S. on form-data github page there is a piece of code explaining how to upload a file stream with axios but it doesn't work, nothing is sent and downgrading the library as one issue topic suggested didn't help either...
const form = new FormData();
const stream = fs.createReadStream(PATH_TO_FILE);
form.append('image', stream);
// In Node.js environment you need to set boundary in the header field 'Content-Type' by calling method `getHeaders`
const formHeaders = form.getHeaders();
axios.post('http://example.com', form, {
headers: {
...formHeaders,
},
})
.then(response => response)
.catch(error => error)
I was able to solve this and I hope it will help anyone facing the same problem.
Since request is deprecated I looked up for alternatives and found got.js for NodeJS HTTP requests. It has support of Stream, fs.ReadStream etc.
You will need form-data as well, it allows to put streams inside FormData and assign it to a key.
The following code solved my question:
import fs from 'fs'
import got from 'got'
import FormData from 'form-data'
const stream = fs.createReadStream('some_path')
// NOT native form data
const formData = new FormData()
formData.append('file', stream, 'filename');
try {
const res = await got.post('https://my_link.com/upload', {
body: formData,
headers: {
...formData.getHeaders() // sets the boundary and Content-Type header
}
}).on('uploadProgress', progress => {
// here we get our upload progress, progress.percent is a float number from 0 to 1
console.log(Math.round(progress.percent * 100))
});
if (res.statusCode === 200) {
// upload success
} else {
// error handler
}
} catch (e) {
console.log(e);
}
Works perfectly in Electron renderer process!

node fs read file from given URL or GCS

When run bellow code it's give error, Reading file from directory working perfect but when pass url it's give file not found error. I've check fs.statSync accept url.
const stat = fs.statSync('http://techslides.com/demos/sample-videos/small.mp4');
Error: ENOENT: no such file or directory, stat 'http://techslides.com/demos/sample-videos/small.mp4'
fs.statSync() can take a URL, but ONLY if that URL is a file:// URL.
It is not clear what you would want to do if the argument was actually an http:// URL. You could check to see if it was not a file URL and then attempt to fetch the contents of the URL to see if it exists using a library such as got().
But, fetching data from another server with http will not be synchronous so you will have to change the design of your function to return a promise instead of a synchronous API.
That's because its hosted on a web-server, you need to send a HTTP GET to fetch it locally.
Install the axios package and issue a HTTP GET request to fetch the remote resource from the web-server.
npm install --save axios
Here's a program of the general idea
const fs = require('fs');
const axios = require('axios');
const { promisify } = require('util');
const writeFilePromise = promisify(fs.writeFile);
(async () => {
const url = 'http://techslides.com/demos/sample-videos/small.mp4';
const response = await axios.get(url);
if (response.data) {
await writeFilePromise('small.mp4', response.data);
}
})();

Bot saving every image, gif or video sent in a specific channel on Discord

I would like my bot to save on my computer every image, video or even a gif that's sent in a specific channel. Is that possible to do?
I know that this kind of stuff can be made by fs directory but I'm not sure how would that code look like could you guys help me?
To get all the images, gifs and videos from a message you can use the .attachments property of a message. This will give you all the files from that message (if it contains files).
With this property you can create a loop where on every message send, you itterate through the message.attachments collection. Then, as stated by the documentation, you can call the .url property on every attachment to get the link from which to download the file.
Once you have the link, you can follow this answer from a different question to download the file. Here's the code copied from the answer:
var http = require('http');
var fs = require('fs');
var download = function(url, dest, cb) {
var file = fs.createWriteStream(dest);
var request = http.get(url, function(response) {
response.pipe(file);
file.on('finish', function() {
file.close(cb); // close() is async, call cb after close completes.
});
}).on('error', function(err) { // Handle errors
fs.unlink(dest); // Delete the file async. (But we don't check the result)
if (cb) cb(err.message);
});
};
This means you will have to use the Node.js modules fs and http. To use the code, the download method can be called like
download(<The file url to download>, <The file name you want to save it as>, <a callback function which can be called when an error occurs>);
This code must help you,
import shutil
from discord.ext import commands
import requests
TOKEN = ""
prefix = "?"
bot = commands.Bot(command_prefix=prefix)
bot.run(TOKEN)
#bot.event
async def on_message(message):
print("The message's content was", message.content)
url = message.attachments[0]['url']
if url[0:26] == "https://cnd.discordapp.com":
r = requests.get(url, stream=True)
with open(String.join(uuid.uuid4(),".png"), 'wb') as out_file:
shutil.copyfileobj(r.raw, out_file)
use this and create a bot and install package requests, discord.py to run the bot.
Finally, add this bot to your channel and give it a bot role.

Categories

Resources