I create a telegram bot for downloading youtube videos.
I use telegraf api (javascripts) and youtube-dl. As I know telegram bot can currently send video files of up to 50 MB in size, but I need to configure downloading more, e.g 1 gb. How I can do this, any ideas?
Code:
const { Telegraf } = require('telegraf');
const fs = require('fs');
const youtubedl = require('youtube-dl');
const bot = new Telegraf('mytoken');
var DOWN_URL = "https://www.youtube.com/watch?v=";
var TeleMaxData = 50;
var videosize;
let downloaded = 0
bot.command('/video', async (ctx) => {
try {
//let userID = ctx.from["id"];
let videoURL = 'someYoutubeUrl';
ctx.reply(`Youtube video URL: ${videoURL}`);
var video = youtubedl(videoURL,
['--format=18'],
{ cwd: __dirname });
video.on('info', function (info) {
infor = info;
ctx.reply('info', info)
videosize = infor.size / 1000000;
if (videosize < TeleMaxData) {
ctx.reply('Download Started')
video.pipe(fs.createWriteStream(`test.mp4`, { flags: 'a' }));
video.on('end', async function () {
ctx.reply("Download completed");
try {
ctx.reply(`Download completed!\nVideo gets Send! - This might take a few Seconds! \n \n Title: \n ${infor.title}. It's ${videosize}mb big.`);
await ctx.replyWithVideo({
source: fs.createReadStream(`test.mp4`)
})
} catch (err) {
ctx.reply('Error: sendVideo' + err);
}
})
} else {
ctx.reply(`The Video is ${videosize}mb. The maximum size for sending videos from Telegram is ${TeleMaxData}mb.`);
}
});
} catch (err) {
ctx.reply("ERROR" + err);
}
})
I know some article, where person makes some agent who will upload file and bot just resend this message. This article in Russian, but i can translate some steps.
You should go to https://core.telegram.org and following the
instructions sign up your app
You should receive api_id and
api_hash
How it works?
App working on server through BOT API make file for sending
It invoke agent for downloading file on Telegram servers
It receives file_id from agent
Use this file
Btw, this person write on python, there some photos of his code, hope you will understand this.
Sorry for my English, it's not perfect
Link: https://habr.com/ru/post/348234/
Related
I want to share an image file directly to my whatsApp or add it to my whatsApp status i.e I don't want to see any other sharing option when I click on button to share any image.
Currently I am using the following code to share
import * as Sharing from 'expo-sharing';
import * as FileSystem from 'expo-file-system';
const customShare = async (image) => {
const base64result = image.split(',')[1];
try {
let filename = 'share.png'; // or some other way to generate filename
let filepath = `${FileSystem.documentDirectory}/${filename}`;
await FileSystem.writeAsStringAsync(filepath, base64result, { encoding: 'base64' });
await Sharing.shareAsync(filepath, { mimeType: 'image/gif' })
} catch (e) {
alert(e.message);
}
};
But here it is showing all sharing option to choose, is there any way to skip this step and directly open my WhatsApp
After around 1-2 minutes playin a song my bot says that the playing be finished whatever the songs length is. here is the link to it: https://github.com/Sheesher/amos
i guess this bug aint be caused due to the code...
const ytdl = require('ytdl-core-discord');
const validUrl = require('valid-url');
let servers = {};
const play = (msg) => {
const args = msg.content.substring(1).split(" ");
const link = args[1];
if (!link) {
return msg.channel.send('You must provide a link.');
};
if (!msg.member.voice.channel) {
return msg.channel.send('You have to be in a voice chat.');
}
if (!validUrl.isUri(link)) {
return msg.channel.send('That aint be link.');
}
if (!servers[msg.guild.id]) servers[msg.guild.id] = {
queque: []
}
let server = servers[msg.guild.id];
server.queque.push(link);
if (!msg.guild.voiceConnection) msg.member.voice.channel.join().then((connection) => {
playSong(connection, link, msg);
})
}
const playSong = async (connection, url, msg) => {
const server = servers[msg.guild.id];
server.dispatcher = connection.play(await ytdl(url), { type: 'opus' });
server.queque.shift();
server.dispatcher.on("end", () => {
if (server.queque[0]) {
playSong(connection, url);
} else {
connection.disconnect();
}
})
server.dispatcher.on('finish', () => log(s('playing finished')))
}```
This is actually any issue many others suffer from as well. It's because of how YTDL-Core (even the discord version) is handled with the streams on YouTube. If it loses connection then it tries to redirect too it, redirect too much and crash or skips the song. Even the music bot I recently created suffer from this but kept it that way for beginners to learn from it. The way to do this is honestly to just not use YTDL-Core. Use something like lavalink which handles all the music playing for you.
When I made a command to change my bot avatar, I made it like this:
client.on("message", async message => {
if (message.content.startsWith(prefix + "profile")) {
var image = message.attachments.first().url;
client.user.setAvatar(image);
}
});
However, I get this error when I use the command with a link to change the picture. So, if I want to change the picture, I must use attached pictures only, not a link to a picture.
Try this one. Looks like .first() function doesn't exists
var image = message.attachments[0].url;
you can`t use message.attachments as file to update you bot avatar.
You need to save it first, and then upload with patch to local storage.
const http = require('http');
const fs = require('fs');
client.on("message", async message => {
if (message.content.startsWith(prefix + "profile")) {
if (message.attachments.size === 0) return message.reply('you need add image to change bots avatar')
let file = fs.createWriteStream(`./${message.attachments.array()[0].name}`);
let request = http.get(message.attachments.array()[0].url, function(response) {
response.pipe(file);
file.on('finish', function() {
client.user.setAvatar(`./${message.attachments.array()[0].name}`)
});
});
}
});
I am creating a chat app (in React Native), but for now, I have made some tests in vanilla JavaScript. The server is a NodeJS-server.
It works with sending text messages, but now I have some questions about sending photos/videos/audio files. I'm doing a lot of research online on what's the best method to do this.
I came up with the idea to use the FileReader API and split up the file into chunks, and sending chunk by chunk via the socket.emit()-function.
This is my code so far (simplified):
Please note that I will create a React Native app, but for now (for testing), I've just created a HTML-file with an upload form.
// index.html
// the page where my upload form is
var reader = {};
var file = {};
var sliceSize = 1000 * 1024;
var socket = io('http://localhost:8080');
const startUpload = e => {
e.preventDefault();
reader = new FileReader();
file = $('#file)[0].files[0]
uploadFile(0)
}
$('#start-upload').on('click', startUpload)
const uploadFile = start => {
var slice = start + sliceSize + 1;
var blob = file.slice(start, slice)
reader.on('loadend', e => {
if (slice < file.size) {
socket.emit('message', JSON.stringify({
fileName: file.name,
fileType: file.type,
fileChunk: e.target.result
})
} else {
console.log('Upload completed!')
}
})
reader.readAsDataURl(blob)
}
// app.js
// my NodeJS server-file
var file;
var files = {};
io.on('connection', socket => {
console.log('User connected!');
// when a message is received
socket.on('message', data => {
file = JSON.parse(data)
if (!files[file.fileName]) {
// this is the first chunk received
// create a new string
files[file.fileName] = '';
}
// append the binary data
files[file.fileName] = files[file.fileName] + file.fileChunk;
})
// on disconnect
socket.on('disconnect', () => {
console.log('User disconnected!');
})
})
I did not include any checks for file type (I'm not at that point yet), I first want to make sure that this is the right thing to do.
Stuff I need to do:
Send a message (like socket.emit('uploaddone', ...)) from the client to the server to notify the server that the upload is done (and the server can emit the complete file to another user).
My questions are:
Is it okay to send chunks of binary data (base64) over a socket, or would it take up to much bandwidth?
Will I lose some quality (photos/videos/audio files) when splitting them up into chunks?
If there is a better way to do this, please let me know. I'm not asking for working code examples, just some guidance in the good direction.
You can send raw bytes over WebSocket, base64 has 33% size overhead.
Also you won't have to JSON.stringify all (and maybe large) body and parse it on client-side.
Will I lose some quality
No, underlying protocol (TCP) delivers data in-order and without corruption.
I realize this answer is a couple of months late, but just for future reference you should look into using the acknowledgment option with socket.io here
// with acknowledgement
let message = JSON.stringify({
fileName: file.name,
fileType: file.type,
fileChunk: e.target.result
})
socket.emit("message", message, (ack) => {
// send next chunk...
});
since monday i try to find the right way of fast and secure generating and displaying PDF Files with the following - maybe im just confused or to blind to see the answer:
Apache - runs my PHP Scripts for my actual project (port 443)
NodeJS - runs a single script for generating PDF files from HTML (port 8080)
What i need: Ensure, that the User is allowed to generate and view the PDF.
It is important to me to have the viewer bar (as seen in the screenshot) is available.
There is a cookie in which a Session-Hash is stored and on which the user authenticates whith on every request (for example via AJAX).
Description of the full procedure:
On one page of my project an iFrame is displayed. In this is a PDF-viewer (from PDF.js) is loaded and some buttons around it:
state before it all begins
Clicking on a button on the left (named with "Load PDF 1", ...) fires the following Event:
$(document).on("click", ".reportelement", function () {
//some data needs to be passed
let data = "report=birthdaylist";
//point iFrame to a new address
$("#pdfViewer").attr("src", "https://example.org/inc/javascript/web/viewer.html?file=https://example.org:8080?" + data);
});
At this point, the iFrame is going to reload the viewer, which takes the GET argument and executes it:
https://example.org/inc/javascript/web/viewer.html?file=https://example.org:8080?" + data //sends the data to the NodeJS script and recieves PDF
==> ?file=https://example.org:8080 //GET... it's bad... How to do a POST in iFrame?!
So, have a look at the NodeJS Script (I have to say I am not very famliar with async and NodeJS):
const https = require("https");
const fs = require("fs");
const puppeteer = require('puppeteer');
const url = require("url");
var qs = require('querystring');
const request = require("request-promise");
const options = {
key: fs.readFileSync("key.pem", "utf-8"),
cert: fs.readFileSync("cert.pem", "utf-8"),
passphrase: 'XXXXXXXX'
};
https.createServer(options, function (req, res) {
(async function () {
if (req.method == 'POST') {
var body = '';
req.on('data', function (data) {
body += data;
// Too much POST data, kill the connection!
// 1e6 === 1 * Math.pow(10, 6) === 1 * 1000000 ~~~ 1MB
if (body.length > 1e6)
req.connection.destroy();
});
req.on('end', function () {
//got a selfsigned certificate only, will change it soon!
process.env['NODE_TLS_REJECT_UNAUTHORIZED'] = 0
(async function () {
var result = await request.post('https://example.org/index.php', {
//htpasswd secured at the moment
'auth': {
'user': 'user',
'pass': 'pass',
'sendImmediately': false
},
//i would like to send the cookie oder the hash in it
//or something else to it ensure, that the user is allowed to
form: {
giveme: 'html'
}
},
function (error, response, body) {
//for debugging reasons
console.log("error: " + error);
console.log("response: " + response);
console.log("body: " + body);
}
);
const browser = await puppeteer.launch();
const main = async () => {
//generating pdf using result from request.post
}
const rendered_pdf = await main();
res.writeHead(200, {
"Access-Control-Allow-Headers": "Origin, X-Requested-With, Content-Type, Accept",
"Access-Control-Allow-Origin": "*",
'Content-Type': 'application/pdf',
'Content-Disposition': 'attachment; filename=mypdf.pdf',
'Content-Length': rendered_pdf.length
});
res.end(rendered_pdf);
})();
});
} else if (req.method == 'GET') {
console.log("we got a GET");
} else {
console.log("we got NOTHING");
}
})();
}).listen(8080);
Everything is working fine and PDF's are displayed well - but as i mentioned before, i dont know how to ensure, that the user is allowed to generate and see the PDF.
tldr;
Is there a way (maybe without an iFrame) to secure the user is permitted? It is important to me to have the viewer bar (as seen in the screenshot) is available.
diagram of current procedure
I think i found a solution.
diagram of new approach/token logic
Using a Token (hash or random string) for retrieving a PDF file only should do it.
The Token does not authenticate the user. I think this is an safer approach?
Feel free to comment/answer :)