gaber-elsayed

radio bot

Jul 11th, 2021
149
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 15.89 KB | None | 0 0
  1. const openradio = require("openradio");
  2. const slimbot = require("slimbot");
  3. const { Server } = require("http");
  4. const miniget = require("miniget");
  5. const ytdl = require("ytdl-core");
  6. const ytsr = require("ytsr");
  7. const ytpl = require("ytpl");
  8. const ms = require("ms");
  9. require("dotenv").config();
  10.  
  11. const bot = new slimbot(process.env.BOT_TOKEN);
  12. const server = new Server();
  13. const radios = new Map();
  14.  
  15. const listener = server.listen(process.env.PORT || 3000, () => {
  16. console.log("Server is now on port", listener.address().port);
  17. });
  18.  
  19. server.on('request', (req, res) => {
  20. let id = req.url.slice(1);
  21. if (isNaN(Number(id)) || !radios.has(id)) {
  22. res.writeHead(400);
  23. res.end("Invalid Request");
  24. } else {
  25. res.setHeader("content-type", "audio/mp3");
  26. radios.get(id).player.pipe(res);
  27. radios.get(id).metadata.listener++;
  28. radios.get(id).metadata.totalListener++;
  29.  
  30. req.on('close', () => {
  31. if (!radios.get(id)) return;
  32. radios.get(id).metadata.listener--;
  33. });
  34. }
  35. });
  36.  
  37. // Used for Validating URL
  38. function validateURL(str) {
  39.  
  40. let pattern = new RegExp('^(https?:\\/\\/)?'+ // protocol
  41.  
  42. '((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|'+ // domain name
  43.  
  44. '((\\d{1,3}\\.){3}\\d{1,3}))'+ // OR ip (v4) address
  45.  
  46. '(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*'+ // port and path
  47.  
  48. '(\\?[;&a-z\\d%_.~+=-]*)?'+ // query string
  49.  
  50. '(\\#[-a-z\\d_]*)?$','i'); // fragment locator
  51.  
  52. return !!pattern.test(str);
  53.  
  54. }
  55.  
  56. bot.on("message", message => {
  57. message.chat.id = message.chat.id.toString();
  58. message.reply = async (text, replyToId) => {
  59. if (!text || typeof text != "string") return Promise.resolve();
  60. if (text.length > 4096) {
  61. try {
  62. await bot.sendMessage(message.chat.id, text.slice(0, 4096), { parse_mode: "Markdown" });
  63. return await message.reply(text.slice(4096));
  64. } catch (error) {
  65. message.reply("An error occured: " + error.toString());
  66. }
  67. } else {
  68. if (!text.length) return Promise.resolve();
  69. try {
  70. await bot.sendMessage(message.chat.id, text, { parse_mode: "Markdown" });
  71. return Promise.resolve();
  72. } catch (error) {
  73. message.reply("An error occured: " + error.toString());
  74. }
  75. }
  76. };
  77. if (!message.text || !message.text.startsWith("/") || message.text.length < 3) return;
  78. let radio = radios.get(message.chat.id);
  79. switch (message.text.split(" ")[0].slice(1)) {
  80. case "new":
  81. if (radio) return message.reply("You already created your radio. To manage it, Type /manage. To destroy it, Type /destroy");
  82. radios.set(message.chat.id, {
  83. player: new openradio().on('error', (err) => message.reply(err.toString())),
  84. queue: [],
  85. metadata: {
  86. listener: 0,
  87. totalListener: 0,
  88. starttime: Date.now(),
  89. curSong: null,
  90. autoplay: false,
  91. loopType: "none"
  92. },
  93. play: function () {
  94. if (!radio) radio = radios.get(message.chat.id);
  95. if (!radio) return console.log("There's no radio. Aborting...");
  96. radio.queue = radio.queue.filter(song => song);
  97. if (radio.metadata.loopType == "queue" && typeof(radio.metadata.curSong) === "object") radio.queue.push(radio.metadata.curSong);
  98. if (radio.metadata.loopType == "single" && typeof(radio.metadata.curSong) === "object") radio.queue.unshift(radio.metadata.curSong);
  99. let nextSong = radio.queue.shift();
  100. radio.metadata.curSong = null;
  101. if (!nextSong) return false;
  102. bot.sendChatAction(message.chat.id, 'typing');
  103. if (nextSong.type === "raw") {
  104. let stream = miniget(nextSong.url);
  105. stream.on('response', () => {
  106. radio.player.play(stream).then(radio.play);
  107. if (nextSong.isAttachment) {
  108. radio.metadata.curSong = nextSong;
  109. return message.reply(`▶️Playing Voice/Audio Message....`);
  110. }
  111. radio.metadata.curSong = nextSong;
  112. message.reply(`▶️Now Playing: [Raw Stream](${nextSong.url})`);
  113. });
  114.  
  115. stream.on('request', () => {
  116. bot.sendChatAction(message.chat.id, 'typing');
  117. });
  118.  
  119. stream.on('error', (err) => message.reply(err.toString()));
  120. } else {
  121.  
  122. bot.sendChatAction(message.chat.id, 'typing');
  123. let stream = ytdl(nextSong.id || nextSong.videoDetails.videoId, { filter: "audioonly", quality: "highestaudio" });
  124.  
  125. stream.on('info', (info) => {
  126. bot.sendChatAction(message.chat.id, 'typing');
  127. radio.metadata.curSong = info;
  128. radio.player.play(stream).then(radio.play);
  129. if (radio.metadata.autoplay) {
  130. radio.queue.push(info.related_videos[0]);
  131. }
  132. message.reply(`▶️Now playing: [${radio.metadata.curSong.videoDetails.title}](${radio.metadata.curSong.video_url})`);
  133. });
  134.  
  135. stream.on('error', err => message.reply(err.toString()));
  136. }
  137. return true;
  138. }
  139. });
  140. message.reply("✔️Radio Created");
  141. break;
  142. case "destroy":
  143. if (!radio) return message.reply("You didn't created radio yet. Did you mean /new ?");
  144. radio.player.destroy();
  145. radios.delete(message.chat.id);
  146. message.reply("✔️Radio destroyed.");
  147. break;
  148. case "manage":
  149. if (!radio) return message.reply("You didn't created radio yet. Did you mean /new ?");
  150. (() => {
  151. let text = "*Your radio status*";
  152. text += `\nListener: \`${radio.metadata.listener}\``;
  153. text += `\nTotal Listener: \`${radio.metadata.totalListener}\``;
  154. text += `\nLoop Type: \`${radio.metadata.loopType}\``;
  155. text += `\nCreated Since: \`${ms(Date.now() - radio.metadata.starttime)}\``;
  156. if (radio.metadata.curSong && !radio.metadata.curSong.isAttachment) text +=
  157. `\nNow Playing: [${radio.metadata.curSong.title||radio.metadata.curSong.videoDetails.title}](${radio.metadata.curSong.url || radio.metadata.curSong.videoDetails.video_url})`;
  158. if (radio.metadata.curSong && radio.metadata.curSong.isAttachment) text += "\nNow Playing: Voice/Audio Message";
  159. text += `\nAutoplay Enabled?: \`${radio.metadata.autoplay ? "Yes" : "No"}\``;
  160. text += `\nTotal Queue: \`${radio.queue.length}\``;
  161. text += `\nLive on: [${process.env.SERVER_HOST||"http://localhost:3000"}/${message.chat.id}](http://localhost:3000/${message.chat.id})`;
  162. text += `\n\nTo check song queue, Type /queue`;
  163. message.reply(text);
  164. })();
  165. break;
  166. case "queue":
  167. if (!radio) return message.reply("You didn't created radio yet. Did you mean /new ?");
  168. if (!radio.queue.length) return message.reply("🏜️Nothing is in queue....");
  169. let method = message.text.split(" ").slice(1)[0];
  170. if (!method) return (() => {
  171. let text = "*Radio Queue*";
  172. radio.queue.slice(0, 20).forEach((song, songNum) => {
  173. songNum++;
  174. if (song.isAttachment) {
  175. text += `\n${songNum}. Voice/Audio Message`;
  176. } else {
  177. text += `\n${songNum}. [${song.title||song.videoDetails.title}](https://youtu.be/${song.id||song.videoDetails ? song.videoDetails.videoId : null||song.isAttachment ? 'https://t.me/' + song.id + '/' + song.messageID : song.url})`;
  178. }
  179. });
  180. text += "\n\n⚠️Some song is hidden due to a lot of request value. We'll improve this soon.\n\nYou may also manage these queue. For more information, Do `/queue help`";
  181. message.reply(text);
  182. })();
  183.  
  184. if (method === "help") {
  185. let text = "*Queue Managing*";
  186. text += "\nUsage: `/queue [method] [argument]`";
  187. text += "\n\nAvailable Method:";
  188. text += "\n remove - Remove a song in a queue";
  189. text += "\n move - Move a song in a queue";
  190. text += "\n shuffle - Sort queue into random order";
  191. text += "\n random - Alias of `shuffle`";
  192. message.reply(text);
  193. } else if (method === "remove") {
  194. let args = message.text.split(" ").slice(2)[0];
  195. if (!args) return message.reply("Usage: `/queue remove [Order number of song in /queue]`");
  196. if (!radio.queue[Number(args)-1]) return message.reply("No song was found in Queue Order number " + args);
  197. delete radio.queue[Number(args)-1];
  198. // Re-create. Ignore the undefined ones
  199. radio.queue = radio.queue.filter(song => song);
  200. message.reply(`✔️Song number ${args} has been removed.`);
  201. } else if (method === "move") {
  202. let args = message.text.split(" ").slice(2)[0];
  203. let to = message.text.split(" ").slice(3)[0];
  204. if (!args || !to) return message.reply("Usage: `/queue move [Order number] [To Order number]`");
  205. if (!radio.queue[Number(args)-1] || !radio.queue[Number(to)-1]) return message.reply("Song not found or invalid value.");
  206. let fromOrder = radio.queue[Number(args)-1];
  207. let toOrder = radio.queue[Number(to)-1];
  208. radio.queue[Number(args)-1] = toOrder;
  209. radio.queue[Number(to)-1] = fromOrder;
  210. message.reply(`✔️*${fromOrder.title}* order moved to *${toOrder.title}* order.`);
  211. } else if (method === "shuffle" || method === "random") {
  212. radio.queue.sort(() => 0.5 - Math.random());
  213. message.reply("✔️Queue order has been sorted randomly.");
  214. }
  215. break;
  216. case "play":
  217. if (!radio) return message.reply("You didn't created radio yet. Did you mean /new ?");
  218. let str = message.text.split(" ").slice(1).join(" ");
  219. let audio = message.reply_to_message ? message.reply_to_message.audio||message.reply_to_message.voice : null;
  220. if (!str.length && !audio) return message.reply("Usage: `/play [Song name|URL|Reply to Audio/Voice Message]`");
  221. if (str) message.reply(`Searching \`${str}\`...`);
  222. bot.sendChatAction(message.chat.id, 'typing');
  223.  
  224. if (audio) {
  225. let id = audio.file_id;
  226. bot.getFile(id).then(({ result }) => {
  227. let newQueue = {
  228. type: "raw",
  229. isAttachment: true,
  230. title: "Replied Audio",
  231. id: message.chat.id,
  232. messageID: message.id,
  233. url: `https://api.telegram.org/file/bot${bot._token}/${result.file_path}`
  234. }
  235.  
  236. if (!radio.queue.length && !radio.metadata.curSong) {
  237. radio.queue.push(newQueue);
  238. message.reply("Preparing to play...");
  239. bot.sendChatAction(message.chat.id, 'typing');
  240. radio.play();
  241. } else {
  242. radio.queue.push(newQueue);
  243. message.reply("✔️Voice has been added to queue");
  244. }
  245. });
  246. } else if (str.toLowerCase().includes("youtube.com/playlist?list=")) {
  247. ytpl(str, { limit: Infinity, page: Infinity }).then(res => {
  248. if (!res.items.length) return message.reply("🙅No Result.");
  249. if (!radio) return;
  250. message.reply(`✔️${res.items.length} Song has been added to queue`);
  251. if (!radio.queue.length && !radio.metadata.curSong) {
  252. radio.queue.push(res.items);
  253. radio.queue = radio.queue.flat(Infinity);
  254. message.reply("Preparing to play...");
  255. bot.sendChatAction(message.chat.id, 'typing');
  256. radio.play();
  257. } else {
  258. radio.queue.push(res.items);
  259. radio.queue = radio.queue.flat(Infinity);
  260. }
  261. });
  262. } else if (validateURL(str) && !ytdl.validateURL(str)) {
  263. let newQueue = {
  264. type: 'raw',
  265. title: `Raw Stream`,
  266. url: str
  267. }
  268. if (!radio.queue.length && !radio.metadata.curSong) {
  269. radio.queue.push(newQueue);
  270. message.reply("Preparing to play...");
  271. bot.sendChatAction(message.chat.id, 'typing');
  272. radio.play();
  273. } else {
  274. radio.queue.push(newQueue);
  275. bot.sendChatAction(message.chat.id, 'typing');
  276. message.reply("✔️A stream URL has been added to queue.");
  277. }
  278. } else if (ytdl.validateURL(str)) {
  279. ytdl.getInfo(str).then(info => {
  280. info.formats = info.formats.filter(format => !format.hasVideo && format.hasAudio);
  281. if (!info.formats.length) return message.reply("❌Sorry. We can't Play this video due to our server region lock.");
  282. if (!radio.queue.length && !radio.metadata.curSong) {
  283. radio.queue.push(info);
  284. message.reply("Preparing to play...");
  285. bot.sendChatAction(message.chat.id, 'typing');
  286. radio.play();
  287. } else {
  288. radio.queue.push(info);
  289. message.reply(`✔️[${info.videoDetails.title}](${info.videoDetails.video_url}) has been added to queue.`);
  290. }
  291. });
  292. } else {
  293. ytsr(str, { limit: 1 }).then(res => {
  294. bot.sendChatAction(message.chat.id, 'typing');
  295. res.items = res.items.filter(video => video.type == "video");
  296. if (!res.items.length) return message.reply("🙅No Result.");
  297. if (!radio) return;
  298. if (!radio.queue.length && !radio.metadata.curSong) {
  299. radio.queue.push(res.items[0]);
  300. message.reply("Preparing to play...");
  301. bot.sendChatAction(message.chat.id, 'typing');
  302. radio.play();
  303. } else {
  304. radio.queue.push(res.items[0]);
  305. message.reply(`✔️[${res.items[0].title}](https://youtu.be/${res.items[0].id}) has been added to queue.`);
  306. }
  307. }).catch(err => {
  308. message.reply(`An error occured: ${err.toString()}`);
  309. });
  310. }
  311. break;
  312. case "pause":
  313. if (!radio) return message.reply("You didn't created radio yet. Did you mean /new ?");
  314. if (!radio.player.stream) return message.reply("There's nothing playing. Glitched? Do /destroy");
  315. radio.player.pause();
  316. message.reply("⏸️Paused");
  317. break;
  318. case "resume":
  319. if (!radio) return message.reply("You didn't created radio yet. Did you mean /new ?");
  320. if (!radio.player.stream) return message.reply("There's nothing playing. Glitched? Do /destroy");
  321. radio.player.resume();
  322. message.reply("▶️Resumed");
  323. break;
  324. case "skip":
  325. if (!radio) return message.reply("You didn't created radio yet. Did you mean /new ?");
  326. if (!radio.player.stream) return message.reply("There's nothing playing. Glitched? Do /destroy");
  327. if (!radio.queue.length) return message.reply("There's nothing in queue!");
  328. radio.play();
  329. message.reply("⏩Skipping...");
  330. break;
  331. case "stop":
  332. if (!radio) return message.reply("You didn't created radio yet. Did you mean /new ?");
  333. if (!radio.player.stream) return message.reply("There's nothing playing. Glitched? Do /destroy");
  334. radio.player.stream.destroy();
  335. radio.queue = [];
  336. message.reply("⏹️Player Stopped");
  337. break;
  338. case "autoplay":
  339. if (!radio) return message.reply("You didn't created radio yet. Did you mean /new ?");
  340. let autoplay = radio.metadata.autoplay;
  341. if (radio.curSong.type == 'raw') return message.reply('Sorry. You can\'t use autoplay right now.');
  342. if (!autoplay) {
  343. radio.metadata.autoplay = true;
  344. let info = radio.metadata.curSong;
  345. radio.queue.push(info.related_videos[0]);
  346. message.reply("✔️Autoplay enabled");
  347. } else {
  348. radio.metadata.autoplay = false;
  349. message.reply("✔️Autoplay disabled");
  350. }
  351. break;
  352. case "loop":
  353. if (!radio) return message.reply("You didn't created radio yet. Did you mean /new ?");
  354. (() => {
  355. let loopType = message.text.split(" ").slice(1)[0];
  356. let availableLoopType = ["queue", "single", "none"];
  357. if (!loopType || !availableLoopType.includes(loopType)) return message.reply("Usage: `/loop [queue|single|none]`");
  358.  
  359. radio.metadata.loopType = loopType.toLowerCase();
  360. message.reply(`✔️Loop Type has been set as \`${loopType.toLowerCase()}\``);
  361. })();
  362. break;
  363. default:
  364. if (!message.text.startsWith("/start") || !message.text.startsWith("/help")) return;
  365. (() => {
  366. let text = "*OpenradioBot v0.0 Alpha*";
  367. text += "\n\n__Radio Managing__";
  368. text += "\n/new - Create new radio";
  369. text += "\n/destroy - Destroy current radio";
  370. text += "\n/manage - Manage your radio";
  371. text += "\n\n__Player Managing__";
  372. text += "\n/play - Play a song";
  373. text += "\n/pause - Pause a player";
  374. text += "\n/resume - Resume a player";
  375. text += "\n/skip - Skip current song";
  376. text += "\n/stop - Stop player";
  377. text += "\n/queue - See & Manage queue list.";
  378. text += "\n/autoplay - Auto play next song from youtube **Related Videos** query.";
  379. text += "\n/loop - Loop queue";
  380.  
  381. message.reply(text);
  382. })();
  383. break;
  384. }
  385. });
  386.  
  387. bot.startPolling(err => {
  388. if (err) console.error(err);
  389. }).then(async () => console.log('Ready'));
  390. process.on('unhandledRejection', err => console.log(err));
Advertisement
Add Comment
Please, Sign In to add comment