goat
command
ytb
No description
0
views
0
likes
0
installs
Aliases: youtube, yt, ভিডিও
raw source
const axios = require("axios");
const fs = require("fs");
const path = require("path");
const yts = require("yt-search");
const { alldown } = require("shaon-video-downloader");
module.exports = {
config: {
name: "ytb",
aliases: ["youtube", "yt", "ভিডিও"],
version: "3.1.0",
author: "SUJON - BOSS",
countDown: 10,
role: 0,
description: {
bn: "YouTube থেকে ৬টি ভিডিও thumbnail সহ দেখিয়ে পছন্দের ভিডিও download করুন",
en: "Search 6 YouTube videos with thumbnails and download selected video"
},
category: "media",
guide: {
bn: "{pn} <ভিডিওর নাম>\nউদাহরণ: {pn} Tum Hi Ho",
en: "{pn} <video name>\nExample: {pn} Tum Hi Ho"
}
},
langs: {
bn: {
noInput:
"❌ ভিডিওর নাম লিখো!\n\nউদাহরণ:\n&ytb Tum Hi Ho",
searching:
"🔎 YouTube-এ খোঁজা হচ্ছে...\n\n⏳ একটু অপেক্ষা করো...",
noResult:
"❌ কোনো ভিডিও পাওয়া যায়নি।",
result:
"╭━━━〔 🎬 YOUTUBE SEARCH 〕━━━╮\n" +
"┃\n" +
"┃ 🎵 ৬টি ভিডিও পাওয়া গেছে\n" +
"┃\n" +
"%1" +
"┃\n" +
"╰━━━━━━━━━━━━━━━━━━━━━━╯\n\n" +
"👉 পছন্দের ভিডিওর নম্বর Reply করো\n" +
"🔢 উদাহরণ: 1",
invalid:
"❌ ভুল নম্বর!\n\n👉 শুধু 1 থেকে 6 এর মধ্যে একটি নম্বর Reply করো।",
downloading:
"⏳ ভিডিও Download হচ্ছে...\n\n" +
"🎬 %1\n\n" +
"📥 Video: MP4\n" +
"⚡ একটু অপেক্ষা করো...",
success:
"╭━━━〔 🎬 SUJON - BOSS 〕━━━╮\n" +
"┃\n" +
"┃ 🎥 %1\n" +
"┃\n" +
"┃ ✅ Video Download Complete\n" +
"┃ ❤️ Enjoy!\n" +
"╰━━━━━━━━━━━━━━━━━━━━╯",
error:
"❌ ভিডিও Download করতে সমস্যা হয়েছে।\n\n%1"
},
en: {
noInput:
"❌ Please enter a video name!\n\nExample:\n&ytb Tum Hi Ho",
searching:
"🔎 Searching YouTube...\n\n⏳ Please wait...",
noResult:
"❌ No videos found.",
result:
"╭━━━〔 🎬 YOUTUBE SEARCH 〕━━━╮\n" +
"┃\n" +
"┃ 🎵 6 videos found\n" +
"┃\n" +
"%1" +
"┃\n" +
"╰━━━━━━━━━━━━━━━━━━━━━━╯\n\n" +
"👉 Reply with the video number\n" +
"🔢 Example: 1",
invalid:
"❌ Invalid number!\n\n👉 Reply with a number from 1 to 6.",
downloading:
"⏳ Downloading video...\n\n" +
"🎬 %1\n\n" +
"📥 Video: MP4\n" +
"⚡ Please wait...",
success:
"╭━━━〔 🎬 SUJON - BOSS 〕━━━╮\n" +
"┃\n" +
"┃ 🎥 %1\n" +
"┃\n" +
"┃ ✅ Video Download Complete\n" +
"┃ ❤️ Enjoy!\n" +
"╰━━━━━━━━━━━━━━━━━━━━╯",
error:
"❌ Failed to download video.\n\n%1"
}
},
// =====================================================
// 🔎 YOUTUBE SEARCH
// =====================================================
onStart: async function ({
api,
event,
args,
message,
getLang
}) {
if (!args.length) {
return message.reply(
getLang("noInput")
);
}
const query =
args.join(" ").trim();
let searchingMessage = null;
try {
// =============================================
// 🔎 SEARCHING MESSAGE
// =============================================
searchingMessage =
await new Promise(
(resolve, reject) => {
api.sendMessage(
getLang("searching"),
event.threadID,
(err, info) => {
if (err) {
reject(err);
return;
}
resolve(info);
},
event.messageID
);
}
);
// =============================================
// 🔍 SEARCH YOUTUBE
// =============================================
const search =
await yts(query);
if (
!search ||
!search.videos ||
!search.videos.length
) {
if (
searchingMessage?.messageID
) {
try {
api.unsendMessage(
searchingMessage.messageID,
() => {}
);
} catch {}
}
return api.sendMessage(
getLang("noResult"),
event.threadID,
event.messageID
);
}
// =============================================
// 🎬 TAKE FIRST 6
// =============================================
const videos =
search.videos.slice(0, 6);
const cacheDir =
path.join(
__dirname,
"cache"
);
if (!fs.existsSync(cacheDir)) {
fs.mkdirSync(
cacheDir,
{
recursive: true
}
);
}
// =============================================
// 📝 BUILD LIST
// =============================================
let list = "";
videos.forEach(
(video, index) => {
const duration =
video.timestamp ||
"Unknown";
const author =
video.author?.name ||
"YouTube";
list +=
`┃ ${index + 1}. 🎬 ${video.title}\n` +
`┃ ⏱️ ${duration}\n` +
`┃ 👤 ${author}\n` +
`┃\n`;
}
);
// =============================================
// 🖼️ DOWNLOAD THUMBNAILS
// =============================================
const attachments = [];
for (
let i = 0;
i < videos.length;
i++
) {
const video =
videos[i];
try {
const thumbnail =
video.thumbnail ||
`https://i.ytimg.com/vi/${video.videoId}/hqdefault.jpg`;
const thumbPath =
path.join(
cacheDir,
`ytb_thumb_${event.threadID}_${Date.now()}_${i}.jpg`
);
const thumbResponse =
await axios.get(
thumbnail,
{
responseType:
"arraybuffer",
timeout:
15000,
headers: {
"User-Agent":
"Mozilla/5.0"
}
}
);
fs.writeFileSync(
thumbPath,
Buffer.from(
thumbResponse.data
)
);
video.__thumbPath =
thumbPath;
attachments.push(
fs.createReadStream(
thumbPath
)
);
} catch (err) {
console.log(
"⚠️ Thumbnail error:",
err.message
);
}
}
// =============================================
// 📩 SEND SEARCH RESULT
// =============================================
const resultBody =
getLang(
"result",
list
);
const payload = {
body: resultBody
};
if (attachments.length) {
payload.attachment =
attachments;
}
return api.sendMessage(
payload,
event.threadID,
(err, info) => {
// =====================================
// 🗑️ DELETE SEARCHING MESSAGE
// =====================================
if (
searchingMessage?.messageID
) {
try {
api.unsendMessage(
searchingMessage.messageID,
() => {}
);
} catch {}
}
if (err) {
console.error(
"❌ YTB result error:",
err
);
return;
}
// =====================================
// ⭐ REGISTER REPLY
// =====================================
global.GoatBot.onReply.set(
info.messageID,
{
commandName:
module.exports.config.name,
messageID:
info.messageID,
author:
event.senderID,
type:
"ytbSelect",
videos:
videos
}
);
console.log(
"✅ YTB Reply Registered:",
info.messageID
);
// =====================================
// 🧹 THUMBNAIL CLEANUP
// =====================================
setTimeout(
() => {
for (
const video of videos
) {
if (
video.__thumbPath &&
fs.existsSync(
video.__thumbPath
)
) {
try {
fs.unlinkSync(
video.__thumbPath
);
} catch {}
}
}
},
120000
);
},
event.messageID
);
} catch (error) {
console.error(
"❌ YTB Search Error:",
error
);
if (
searchingMessage?.messageID
) {
try {
api.unsendMessage(
searchingMessage.messageID,
() => {}
);
} catch {}
}
return api.sendMessage(
getLang(
"error",
error.message
),
event.threadID,
event.messageID
);
}
},
// =====================================================
// 🔢 REPLY → SELECT VIDEO
// =====================================================
onReply: async function ({
api,
event,
Reply,
getLang
}) {
if (
!Reply ||
Reply.type !== "ytbSelect"
) {
return;
}
// =============================================
// 👤 ONLY ORIGINAL USER
// =============================================
if (
Reply.author &&
event.senderID !== Reply.author
) {
return;
}
const text =
event.body?.trim();
if (!text) {
return;
}
const number =
parseInt(text, 10);
// =============================================
// 🔢 VALIDATE NUMBER
// =============================================
if (
!Number.isInteger(number) ||
number < 1 ||
number > Reply.videos.length
) {
return api.sendMessage(
getLang("invalid"),
event.threadID,
event.messageID
);
}
const video =
Reply.videos[number - 1];
if (!video) {
return api.sendMessage(
getLang(
"error",
"Video information পাওয়া যায়নি।"
),
event.threadID,
event.messageID
);
}
const title =
video.title ||
"YouTube Video";
const youtubeUrl =
video.url ||
`https://www.youtube.com/watch?v=${video.videoId}`;
const cacheDir =
path.join(
__dirname,
"cache"
);
if (!fs.existsSync(cacheDir)) {
fs.mkdirSync(
cacheDir,
{
recursive: true
}
);
}
const filePath =
path.join(
cacheDir,
`ytb_${event.threadID}_${Date.now()}.mp4`
);
let downloadingMessage = null;
try {
// =============================================
// 🗑️ REMOVE REPLY REGISTRY
// =============================================
try {
global.GoatBot.onReply.delete(
Reply.messageID
);
} catch {}
// =============================================
// ⏳ DOWNLOADING MESSAGE
// =============================================
downloadingMessage =
await new Promise(
(resolve, reject) => {
api.sendMessage(
getLang(
"downloading",
title
),
event.threadID,
(err, info) => {
if (err) {
reject(err);
return;
}
resolve(info);
},
event.messageID
);
}
);
// =============================================
// 🎬 SHAON ALLDOWN
// =============================================
console.log(
"================================="
);
console.log(
"🎬 YTB VIDEO DOWNLOAD"
);
console.log(
"🎵 Title:",
title
);
console.log(
"🔗 URL:",
youtubeUrl
);
const data =
await alldown(
youtubeUrl
);
console.log(
"📦 SHAON RESULT:",
JSON.stringify(
data,
null,
2
)
);
if (
!data ||
data.status !== true
) {
throw new Error(
data?.message ||
"Downloader failed."
);
}
// =============================================
// 🎥 IMPORTANT
//
// SHAON 1.0.1 এর response অনুযায়ী
// VIDEO URL হলো data.url
//
// data.audio = শুধু AUDIO
// তাই audio কখনো ব্যবহার করা হচ্ছে না।
// =============================================
const videoDownloadUrl =
typeof data.url === "string"
? data.url
: null;
if (!videoDownloadUrl) {
throw new Error(
"Video URL পাওয়া যায়নি।"
);
}
// =============================================
// 🛡️ MAKE SURE IT IS VIDEO
// =============================================
const urlLower =
videoDownloadUrl.toLowerCase();
if (
urlLower.includes(
"mime=audio"
)
) {
throw new Error(
"Downloader audio URL দিয়েছে, video নয়।"
);
}
if (
data.ext &&
data.ext !== "mp4"
) {
console.log(
"⚠️ Extension:",
data.ext
);
}
console.log(
"🎥 VIDEO URL FOUND"
);
console.log(
"📺 Quality:",
data.quality ||
"Unknown"
);
// =============================================
// 📥 DOWNLOAD MP4 VIDEO
// =============================================
let response;
try {
response =
await axios.get(
videoDownloadUrl,
{
responseType:
"arraybuffer",
timeout:
300000,
maxContentLength:
Infinity,
maxBodyLength:
Infinity,
headers: {
"User-Agent":
"Mozilla/5.0 (Linux; Android 11) AppleWebKit/537.36 Chrome/120 Mobile Safari/537.36",
"Accept":
"*/*",
"Referer":
"https://www.youtube.com/"
}
}
);
} catch (firstError) {
console.log(
"⚠️ First video request failed:",
firstError.message
);
// =========================================
// 🔁 RETRY WITHOUT HEADERS
// =========================================
response =
await axios.get(
videoDownloadUrl,
{
responseType:
"arraybuffer",
timeout:
300000,
maxContentLength:
Infinity,
maxBodyLength:
Infinity
}
);
}
if (
!response ||
!response.data
) {
throw new Error(
"Video download failed."
);
}
// =============================================
// 📄 CHECK CONTENT TYPE
// =============================================
const contentType =
String(
response.headers[
"content-type"
] || ""
).toLowerCase();
if (
contentType.includes(
"text/html"
)
) {
throw new Error(
"YouTube video এর বদলে HTML response এসেছে।"
);
}
// =============================================
// 💾 SAVE MP4
// =============================================
fs.writeFileSync(
filePath,
Buffer.from(
response.data
)
);
// =============================================
// 📊 CHECK FILE
// =============================================
if (
!fs.existsSync(
filePath
)
) {
throw new Error(
"Video file তৈরি হয়নি।"
);
}
const stats =
fs.statSync(
filePath
);
if (
stats.size < 50000
) {
throw new Error(
"Video file খুব ছোট/invalid হয়েছে।"
);
}
console.log(
`✅ VIDEO SAVED: ${(stats.size / 1024 / 1024).toFixed(2)} MB`
);
// =============================================
// 🎥 SEND VIDEO
// =============================================
await new Promise(
(resolve, reject) => {
api.sendMessage(
{
body:
getLang(
"success",
title
),
attachment:
fs.createReadStream(
filePath
)
},
event.threadID,
(err, info) => {
if (err) {
reject(err);
return;
}
resolve(info);
},
event.messageID
);
}
);
console.log(
"✅ VIDEO SENT SUCCESSFULLY"
);
// =============================================
// 🗑️ AUTO DELETE DOWNLOADING MESSAGE
// =============================================
if (
downloadingMessage?.messageID
) {
try {
api.unsendMessage(
downloadingMessage.messageID,
() => {}
);
} catch {}
}
// =============================================
// 🗑️ AUTO DELETE SEARCH RESULT
// =============================================
if (
Reply.messageID
) {
try {
api.unsendMessage(
Reply.messageID,
() => {}
);
} catch {}
}
// =============================================
// 🧹 DELETE LOCAL VIDEO
// =============================================
setTimeout(
() => {
if (
fs.existsSync(
filePath
)
) {
try {
fs.unlinkSync(
filePath
);
console.log(
"🧹 Video cache deleted."
);
} catch {}
}
},
30000
);
} catch (error) {
console.error(
"❌ YTB VIDEO ERROR:",
error
);
// =============================================
// 🗑️ DELETE DOWNLOADING MESSAGE
// =============================================
if (
downloadingMessage?.messageID
) {
try {
api.unsendMessage(
downloadingMessage.messageID,
() => {}
);
} catch {}
}
// =============================================
// 🧹 DELETE BROKEN FILE
// =============================================
if (
fs.existsSync(
filePath
)
) {
try {
fs.unlinkSync(
filePath
);
} catch {}
}
return api.sendMessage(
getLang(
"error",
error.message
),
event.threadID,
event.messageID
);
}
}
};