discord.js - music bot is buggy - javascript

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.

Related

Bot is not sending any messages even though there isnt any error messages

Im trying to make a discord bot that will send a message when a Minecraft server is online and when it turns off.
heres the code if you need it. (the only thing in the log is the bot has started so i will not be sending the logs
const Discord = require('discord.js');
const client = new Discord.Client();
const axios = require('axios');
let isServerOnline = false;
client.on('ready', () => {
console.log(`Bot is ready!`);
});
setInterval(async () => {
try {
const response = await axios.get('monkecraftsmp.feathermc.gg');
if (response.status === 200 && !isServerOnline) {
isServerOnline = true;
console.log("Server is online");
const channel = client.channels.cache.get('917953832431026276');
channel.send('âś… Server is online');
}
} catch (error) {
if (isServerOnline) {
isServerOnline = false;
console.log("Server has stopped");
const channel = client.channels.cache.get('917953832431026276');
channel.send('🛑 Server has stopped');
}
}
}, 6000);
also if you need it the discord.js version is 12
I have tried to check if the channel id is the right one and it is, then i checked if the token is right and its right.
i have checked the logs and nothing has shown up in it.
You might want to look into using an API, as this isn't (as far as i know) how Minecraft server statusses work. Check out this one as i've seen it's pretty good.
You're also not recieving an error because it's in a try catch statement. You can console.log the error for info on what's going wrong.

Quick.db, SQLite database file wiping on Bot reboot. Discord.js

I'm trying to save a value of the server being "Down" or "Up", it seems to be working fine, however, when I clear the console, then run the bot again, it looks to have reset the database fully, is there a way to make the database, work like a normal database would? (Save after restart)
I'm having a check to see if the server is up, then don't allow it to run the command and say it's already online.
I wasn't like this before, and I haven't used quick.db for a while, so sorry if I missed anything.
Code:
// Main requirements
const { ROLE_SSUPIN, CHANNEL_SSU, CHANNEL_ROLESEL, BOT_PREFIX } = require('../../config.json')
const commandName = 'ssu'
// Optional Requirements
const { MessageEmbed } = require('discord.js')
const { QuickDB } = require('quick.db');
const db = new QuickDB();
// Main Code
module.exports = async client => {
client.on('messageCreate', async message => {
if (message.author.bot) return;
if (!message.content.toLowerCase().startsWith(BOT_PREFIX)) return;
const command = message.content.split(' ')
const args = message.content.substring(1).split(' ')
if (command.toString().toLowerCase().replace(BOT_PREFIX, '').startsWith(commandName)) {
const ssuStatus = await db.get("ssu.status")
await db.set("ssu.status", "down");
console.log(ssuStatus)
if (!message.member.roles.cache.get('998320362234323026')) return message.reply("Only staff with `SSU Permissions` can use this command!")//.then(m => {setTimeout( function() { m.delete(), message.delete() }, 10000)});
if (!message.channel.id == CHANNEL_SSU) return message.reply(`Please use this command in <#${CHANNEL_SSU}>.`)
if (ssuStatus == 'up') return message.reply(`Server Status is already set to Online. Say \`${BOT_PREFIX}Server Status Set Offline\` if you believe this is a mistake.`)
message.channel.send(`
Start up done.
`)
.then(await db.set("ssu.status", "up"))
}
})
}
I had "await db.set("ssu.status", "down");" in the start of each function, so it was reseting it back to "Down", I didn't mean for it do that, if you have the same issue, make sure that you don't have anything that sets the database value in the start, as it might be the reason it's getting reset and you think it's wiping.

How can I send to download video above 50 mg in Telegram?

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/

Discord.js - Adding queue function to music system

Yes, I know there are a lot of threads on here regarding this topic. HOWEVER; I've found that in most cases, it is kind of dependant on what your music code looks like. Therefore, I decided to not mess too much around and potentially break my code and clutter it with stuff I won't need.
So here I go.
Below is the code I have in my play.js file. Most of it I got through a guide I found just to get me going then I tweaked it a bit to be more suitable for my use.
const discord = require('discord.js');
//Setting up constants
const ytdl = require("ytdl-core");
const ytSearch = require("yt-search");
const voiceChannel = msg.member.voice.channel;
// Check if user is in voiceChannel
if (!voiceChannel) return msg.channel.send(errorVoiceEmbed);
// Check if we have the correct permissions
const permissions = voiceChannel.permissionsFor(msg.client.user);
if (!permissions.has("CONNECT")) return msg.channel.send(permsEmbed);
if (!permissions.has("SPEAK")) return msg.channel.send(permsEmbed);
// Check if a second argument has been passed
if (!args.length) return msg.channel.send(playEmbed);
// Validating the passed URL
const validURL = (str) => {
var regex = /(http|https):\/\/(\w+:{0,1}\w*)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%!\-\/]))?/;
if (!regex.test(str)){
return false;
} else {
return true;
}
}
// If we have a valid URL, load it and play the audio
if(validURL (args[0])){
const connection = await voiceChannel.join();
const stream = ytdl(args[0], {filter: 'audioonly'});
connection.play(stream, {seek: 0, volume: 1})
// Leave when done
.on('finish', () => {
voiceChannel.leave();
msg.channel.send(completedEmbed);
});
await msg.reply(playingEmbed);
return
}
const connection = await voiceChannel.join();
// If a user enters a search query instead of a link, Search YouTube and play a result.
const videoFinder = async (query) => {
const videoResult = await ytSearch(query);
return (videoResult.videos.length > 1) ? videoResult.videos[0] : null;
}
const video = await videoFinder(args.join(' '));
if (video) {
const stream = ytdl(video.url, {filter: 'audioonly'});
connection.play(stream, {seek: 0, volume: 1})
.on('finish', () => {
voiceChannel.leave();
msg.channel.send(completedEmbed);
});
await msg.reply (playingEmbed);
} else {
msg.channel.send(noResultsEmbed);
}
So - How would I go about adding a proper queue to this? I'm looking for a separate queue command that ties in perfectly with the play command. Therefore - I'm gonna be using two different files that would need to communicate through a songlist of some sort. How this would be done tho, I'm unsure. I looked into just using arrays for this but didn't manage to get that working.
And before you ask - Those embeds that are used in those msg.channel.send statements are embeds configured earlier up in the file. I didn't include these in here but they're there.
PLEASE NOTE:
I'm not looking for a complete solution. I just want some tips and hints as to how I can solve this in a simple and effective way without having to clutter up the code I already have.
That being said - Just on it's own, the code for the play command works perfectly . It plays either the requested song from the link provided or a song from the search query. But when a new song is requested, the old one just stops and the new one plays. You all know how this should go. If no song is playing, play it. If a song is played, add the requested song to the queue and play that once the previous song is done etc etc.

WebRTC both remote and local video is displayed with local stream

hello i am newbie in WebRTC and i tried this code
const yourVideo = document.querySelector("#face_cam_vid");
const theirVideo = document.querySelector("#thevid");
(async () => {
if (!("mediaDevices" in navigator) || !("RTCPeerConnection" in window)) {
alert("Sorry, your browser does not support WebRTC.");
return;
}
const stream = await navigator.mediaDevices.getUserMedia({video: true,
audio: true});
yourVideo.srcObject = stream;
const configuration = {
iceServers: [{urls: "stun:stun.1.google.com:19302"}]
};
const yours = new RTCPeerConnection(configuration);
const theirs = new RTCPeerConnection(configuration);
for (const track of stream.getTracks()) {
yours.addTrack(track, stream);
}
theirs.ontrack = e => theirVideo.srcObject = e.streams[0];
yours.onicecandidate = e => theirs.addIceCandidate(e.candidate);
theirs.onicecandidate = e => yours.addIceCandidate(e.candidate);
const offer = await yours.createOffer();
await yours.setLocalDescription(offer);
await theirs.setRemoteDescription(offer);
const answer = await theirs.createAnswer();
await theirs.setLocalDescription(answer);
await yours.setRemoteDescription(answer);
})();
and it works but partly https://imgur.com/a/nG7Xif6 . in short i am creating ONE-to-ONE random video chatting like in omegle but this code displays both "remote"(stranger's) and "local"("mine") video with my local stream but all i want is , user wait for second user to have video chat and when third user enters it should wait for fourth and etc. i hope someone will help me with that
You're confusing a local-loop demo—what you have—with a chat room.
A local-loop demo is a short-circuit client-only proof-of-concept, linking two peer connections on the same page to each other. Utterly useless, except to prove the API works and the browser can talk to itself.
It contains localPeerConnection and remotePeerConnection—or pc1 and pc2—and is not how one would typically write WebRTC code. It leaves out signaling.
Signaling is hard to demo without a server, but I show people this tab demo. Right-click and open it in two adjacent windows, and click the Call! button on one to call the other. It uses localSocket, a non-production hack I made using localStorage for signaling.
Just as useless, a tab-demo looks more like real code:
const pc = new RTCPeerConnection();
call.onclick = async () => {
video.srcObject = await navigator.mediaDevices.getUserMedia({video:true, audio:true});
for (const track of video.srcObject.getTracks()) {
pc.addTrack(track, video.srcObject);
}
};
pc.ontrack = e => video.srcObject = e.streams[0];
pc.oniceconnectionstatechange = e => console.log(pc.iceConnectionState);
pc.onicecandidate = ({candidate}) => sc.send({candidate});
pc.onnegotiationneeded = async e => {
await pc.setLocalDescription(await pc.createOffer());
sc.send({sdp: pc.localDescription});
}
const sc = new localSocket();
sc.onmessage = async ({data: {sdp, candidate}}) => {
if (sdp) {
await pc.setRemoteDescription(sdp);
if (sdp.type == "offer") {
await pc.setLocalDescription(await pc.createAnswer());
sc.send({sdp: pc.localDescription});
}
} else if (candidate) await pc.addIceCandidate(candidate);
}
There's a single pc—your half of the call—and there's an onmessage signaling callback to handle the timing-critical asymmetric offer/answer negotiation correctly. Same JS on both sides.
This still isn't a chat-room. For that you need server logic to determine how people meet, and a web socket server for signaling. Try this tutorial on MDN which culminates in a chat demo.

Categories