const axios = require("axios"); const { google } = require("googleapis"); const fs = require("fs-extra"); const path = require("path"); const CREDENTIALS_PATH = path.join(process.cwd(), "credentials.json"); const DRIVE_SCOPES = ["https://www.googleapis.com/auth/drive"]; let drive = null; // প্রথমে চেষ্টা করা হচ্ছে GOOGLE_CREDENTIALS environment variable থেকে পড়তে // (Railway/Render-এর মতো হোস্টিং-এ যেখানে credentials.json ফাইল হিসেবে রাখা যায় না) let credentialsJSON = null; if (process.env.GOOGLE_CREDENTIALS) { try { credentialsJSON = JSON.parse(process.env.GOOGLE_CREDENTIALS); } catch (e) { console.log("❌ GOOGLE_CREDENTIALS environment variable ভ্যালিড JSON না:", e.message); } } else if (fs.existsSync(CREDENTIALS_PATH)) { // environment variable না থাকলে লোকাল credentials.json ফাইল থেকে পড়া হচ্ছে credentialsJSON = fs.readJsonSync(CREDENTIALS_PATH); } if (credentialsJSON) { const auth = new google.auth.GoogleAuth({ credentials: credentialsJSON, scopes: DRIVE_SCOPES }); drive = google.drive({ version: "v3", auth }); } const DB_PATH = path.join(__dirname, "cache", "gdrive_counter.json"); const LINKS_PATH = path.join(__dirname, "cache", "gdrive_links.json"); const USERS_PATH = path.join(__dirname, "cache", "gdrive_users.json"); fs.ensureDirSync(path.dirname(DB_PATH)); if (!fs.existsSync(DB_PATH)) fs.writeJsonSync(DB_PATH, { video: 0, audio: 0, image: 0, gif: 0, file: 0 }); if (!fs.existsSync(LINKS_PATH)) fs.writeJsonSync(LINKS_PATH, {}); if (!fs.existsSync(USERS_PATH)) fs.writeJsonSync(USERS_PATH, { allowedUsers: [] }); function getNextNumber(type) { const data = fs.readJsonSync(DB_PATH); data[type] = (data[type] || 0) + 1; fs.writeJsonSync(DB_PATH, data); return data[type]; } function saveFileMapping(name, fileId, type, webLink) { const data = fs.readJsonSync(LINKS_PATH); data[name.toLowerCase()] = { id: fileId, type: type, link: webLink }; fs.writeJsonSync(LINKS_PATH, data); } function getFileData(name) { const data = fs.readJsonSync(LINKS_PATH); return data[name.toLowerCase()] || null; } function extractAllUrls(text) { if (!text) return []; return text.match(/(https?:\/\/[^\s]+)/g) || []; } module.exports = { config: { name: "gdrive", aliases: ["gd", "drive"], version: "12.1", author: "Arafat & Sahu", countDown: 2, role: 0, shortDescription: { en: "Advanced Gmail Google Drive Control Panel" }, longDescription: { en: "Manage your Gmail Google drive easily with auto-numbering, permissions and list selection." }, category: "UTILITY", guide: { en: "{pn} help" } }, onStart: async function ({ api, event, args, message, role }) { if (!drive) return message.reply("❌ 'credentials.json' ফাইলটি মেইন ডিরেক্টরিতে সেটআপ করা নেই!"); const { senderID, messageReply } = event; const usersData = fs.readJsonSync(USERS_PATH); const isMainAdmin = (role >= 3); const isAllowedUser = usersData.allowedUsers.includes(senderID) || isMainAdmin; if (!isAllowedUser) { return message.reply("❌ আপনার এই ড্রাইভ কমান্ড প্যানেল ব্যবহার করার কোনো পারমিশন নেই!"); } const subCommand = args[0] ? args[0].toLowerCase() : ""; if (subCommand === "help") { let helpMsg = "━━━━━ 𝐆𝐃𝐑𝐈𝐕𝐄 𝐇𝐄𝐋𝐏 ━━━━━\n\n" + "🔹 [শুধু লিংক] ➔ ড্রাইভ সেভ ছাড়া ডিরেক্ট প্লে\n" + "🔹 .gdrive save ➔ অটো নাম্বারিংয়ে ফাইল সেভ\n" + "🔹 .gdrive save [নাম] ➔ কাস্টম নামে ফাইল সেভ\n" + "🔹 .gdrive [নাম/নাম্বার] ➔ ফাইল চ্যাটে প্রদর্শন/প্লে\n" + "🔹 .gdrive file [নাম/নাম্বার] ➔ ড্রাইভ ফাইল লিংক\n" + "🔹 .gdrive del [নাম/নাম্বার] ➔ ড্রাইভ থেকে স্থায়ী ডিলিট\n" + "🔹 .gdrive [ক্যাটাগরি] list ➔ ফাইলের তালিকা\n" + "🔹 .gdrive edit [পুরাতন_নাম] [নতুন_নাম] ➔ নাম পরিবর্তন\n\n" + "👑 𝐀𝐃𝐌𝐈𝐍 𝐂𝐎𝐌𝐌𝐀𝐍𝐃𝐒:\n" + "🔸 .gdrive user add [Reply/UID] ➔ ইউজার যুক্ত করা\n" + "🔸 .gdrive user ➔ ইউজার রিমুভ ও লিস্ট\n" + "━━━━━━━━━━━━━━━━━━"; return message.reply(helpMsg); } if (subCommand === "user") { if (!isMainAdmin) return message.reply("❌ এই ক্ষমতা শুধুমাত্র মেইন অ্যাডমিনের আছে!"); if (args[1] === "add") { let targetUID = args[2] || (messageReply ? messageReply.senderID : null); if (!targetUID) return message.reply("❌ অনুগ্রহ করে ইউজারের UID দিন অথবা তার মেসেজে রিপ্লাই দিন।"); if (!usersData.allowedUsers.includes(targetUID)) { usersData.allowedUsers.push(targetUID); fs.writeJsonSync(USERS_PATH, usersData); } return message.reply(`✅ ইউজার (UID: ${targetUID}) সফলভাবে ড্রাইভ এক্সেস তালিকায় যুক্ত হয়েছে।`); } if (usersData.allowedUsers.length === 0) return message.reply("⭕ পারমিশন পাওয়া কোনো ইউজারের তালিকা নেই।"); let uList = "👥 𝐆𝐃𝐑𝐈𝐕𝐄 𝐔𝐒𝐄𝐑 𝐋𝐈𝐒𝐓:\n\n"; for (let i = 0; i < usersData.allowedUsers.length; i++) { uList += `${i + 1}. UID: ${usersData.allowedUsers[i]}\n`; } uList += "\n👉 যে ইউজারকে রিমুভ করতে চান, এই মেসেজে তার নম্বর টাইপ করে রিপ্লাই দিন।"; return message.reply(uList).then(info => { global.GoatBot.onReply.set(info.messageID, { commandName: this.config.name, type: "user_remove", author: senderID, list: usersData.allowedUsers, messageID: info.messageID }); }); } if (subCommand === "edit") { const oldName = args[1]; const newName = args[2]; if (!oldName || !newName) return message.reply("❌ সঠিক নিয়ম: .gdrive edit [পুরাতন_নাম] [নতুন_নাম]"); const fileData = getFileData(oldName); if (!fileData) return message.reply("❌ এই নামের কোনো ফাইল ডাটাবেসে পাওয়া যায়নি!"); try { await drive.files.update({ fileId: fileData.id, requestBody: { name: newName } }); const allLinks = fs.readJsonSync(LINKS_PATH); allLinks[newName.toLowerCase()] = { id: fileData.id, type: fileData.type, link: fileData.link }; delete allLinks[oldName.toLowerCase()]; fs.writeJsonSync(LINKS_PATH, allLinks); return message.reply(`✅ ফাইলের নাম '${oldName}' থেকে বদলে সফলভাবে '${newName}' করা হয়েছে!`); } catch (err) { return message.reply(`❌ নাম পরিবর্তন ব্যর্থ হয়েছে: ${err.message}`); } } if (subCommand === "del" || subCommand === "delete") { const targetName = args[1]; if (!targetName) return message.reply("❌ অনুগ্রহ করে ফাইলের নাম বা নাম্বার দিন। যেমন: .gdrive del video_1"); const fileData = getFileData(targetName); if (!fileData) return message.reply("❌ এই নামের কোনো ফাইল ড্রাইভ ডাটাবেসে নেই।"); try { await drive.files.delete({ fileId: fileData.id }); const allLinks = fs.readJsonSync(LINKS_PATH); delete allLinks[targetName.toLowerCase()]; fs.writeJsonSync(LINKS_PATH, allLinks); return message.reply(`🗑️ '${targetName}' ফাইলটি ড্রাইভ থেকে সফলভাবে ডিলিট করা হয়েছে!`); } catch (err) { return message.reply(`❌ ডিলিট ব্যর্থ হয়েছে: ${err.message}`); } } if (subCommand === "file") { const targetName = args[1]; if (!targetName) return message.reply("❌ ফাইলের নাম দিন। যেমন: .gdrive file video_1"); const fileData = getFileData(targetName); if (!fileData) return message.reply("❌ ফাইলটি পাওয়া যায়নি।"); // লিংক টেক্সট আগে পাঠানো হচ্ছে await message.reply(`📁 𝐅𝐢𝐥𝐞: ${targetName}\n🔗 𝐃𝐨𝐰𝐧𝐥𝐨𝐚𝐝 𝐋𝐢𝐧𝐤:\n${fileData.link}`); // এরপর video/audio/image/gif হলে অটোমেটিক প্রিভিউ দেখানো হচ্ছে (শুধু প্লেব্যাক, নতুন করে সেভ হচ্ছে না) if (["video", "audio", "image", "gif"].includes(fileData.type)) { try { const wait = await message.reply(`⏳ '${targetName}' প্রিভিউ লোড হচ্ছে...`); const res = await drive.files.get({ fileId: fileData.id, alt: "media" }, { responseType: "stream" }); await message.unsend(wait.messageID); return message.reply({ body: `✅ Preview: ${targetName}`, attachment: res.data }); } catch (e) { return message.reply(`⚠️ লিংক পাওয়া গেছে কিন্তু প্রিভিউ লোড করতে সমস্যা হয়েছে: ${e.message}`); } } return; } if (subCommand === "save") { if (!messageReply || !messageReply.attachments || messageReply.attachments.length === 0) { return message.reply("❌ দয়া করে কোনো ছবি/ভিডিওতে রিপ্লাই দিয়ে .gdrive save লিখুন।"); } const attach = messageReply.attachments[0]; let fileType = "file"; let ext = "bin"; if (attach.type === "video") { fileType = "video"; ext = "mp4"; } else if (attach.type === "photo") { fileType = "image"; ext = "jpg"; } else if (attach.type === "audio") { fileType = "audio"; ext = "mp3"; } else if (attach.type === "animated_image") { fileType = "gif"; ext = "gif"; } let fileName = args.slice(1).join(" ").trim(); if (!fileName) { const currentCount = getNextNumber(fileType); fileName = `${fileType}_${currentCount}`; } const fullFileName = `${fileName}.${ext}`; const wait = await message.reply(`⏳ '${fullFileName}' নামে জিমেইল ড্রাইভে সেভ হচ্ছে...`); try { const responseStream = await axios({ method: "get", url: attach.url, responseType: "stream" }); const driveResponse = await drive.files.create({ requestBody: { name: fullFileName, mimeType: responseStream.headers["content-type"] }, media: { mimeType: responseStream.headers["content-type"], body: responseStream.data }, fields: "id, webViewLink" }); await drive.permissions.create({ fileId: driveResponse.data.id, requestBody: { role: "reader", type: "anyone" } }); saveFileMapping(fileName, driveResponse.data.id, fileType, driveResponse.data.webViewLink); await message.unsend(wait.messageID); return message.reply(`✅ 𝐒𝐚𝐯𝐞 𝐒𝐮𝐜𝐜𝐞𝐬𝐬𝐟𝐮𝐥!\n\n📁 Name: ${fileName}\n🆔 ID: ${driveResponse.data.id}\n🔗 Link: ${driveResponse.data.webViewLink}`); } catch (e) { return message.reply(`❌ সেভ করতে সমস্যা হয়েছে: ${e.message}`); } } if (args[1] === "list") { const catType = args[0].toLowerCase(); const allLinks = fs.readJsonSync(LINKS_PATH); const filtered = Object.keys(allLinks).filter(k => allLinks[k].type === catType); if (filtered.length === 0) return message.reply(`⭕ ${catType} ক্যাটাগরিতে কোনো ফাইল সেভ করা নেই।`); let listMsg = `📂 𝐆𝐃𝐑𝐈𝐕𝐄 ${catType.toUpperCase()} 𝐋𝐈𝐒𝐓:\n\n`; for (let i = 0; i < filtered.length; i++) { listMsg += `${i + 1}. ${filtered[i]}\n`; } listMsg += "\n👉 যে ফাইলটি প্লে করতে চান, তার নম্বর টাইপ করে রিপ্লাই দিন।"; return message.reply(listMsg).then(info => { global.GoatBot.onReply.set(info.messageID, { commandName: this.config.name, type: "list_choose", author: senderID, list: filtered, messageID: info.messageID }); }); } const urls = extractAllUrls(event.body); if (urls.length > 0) { try { const wait = await message.reply("⏳ লিংক থেকে ফাইলটি প্রসেস করা হচ্ছে (No Save)..."); const resStream = await axios({ method: "get", url: urls[0], responseType: "stream" }); await message.unsend(wait.messageID); return message.reply({ body: "✅ Temporary Playback:", attachment: resStream.data }); } catch (err) { return message.reply(`❌ লিংক প্লে করতে সমস্যা হয়েছে: ${err.message}`); } } const checkName = args.join(" ").trim(); if (checkName) { const fileData = getFileData(checkName); if (fileData) { try { const wait = await message.reply(`⏳ '${checkName}' ড্রাইভ থেকে লোড হচ্ছে...`); const res = await drive.files.get({ fileId: fileData.id, alt: "media" }, { responseType: "stream" }); await message.unsend(wait.messageID); return message.reply({ body: `✅ Playing: ${checkName}`, attachment: res.data }); } catch (e) { return message.reply(`❌ ফাইলটি প্লে করতে সমস্যা হয়েছে: ${e.message}`); } } else { return message.reply("❌ এই নামে বা নাম্বারে কোনো ফাইল বা কমান্ড পাওয়া যায়নি। সাহায্য পেতে লিখুন: .gdrive help"); } } }, onReply: async function ({ event, message, Reply }) { const { author, type, list, messageID } = Reply; if (event.senderID !== author) return; const choice = parseInt(event.body.trim()); if (isNaN(choice) || choice < 1 || choice > list.length) { global.GoatBot.onReply.delete(messageID); return message.reply("❌ বাতিল করা হয়েছে।"); } global.GoatBot.onReply.delete(messageID); const selectedItem = list[choice - 1]; if (type === "user_remove") { const usersData = fs.readJsonSync(USERS_PATH); usersData.allowedUsers = usersData.allowedUsers.filter(u => u !== selectedItem); fs.writeJsonSync(USERS_PATH, usersData); return message.reply(`🗑️ ইউজার (UID: ${selectedItem}) সফলভাবে অনুমতি তালিকা থেকে রিমুভ হয়েছে।`); } if (type === "list_choose") { const allLinks = fs.readJsonSync(LINKS_PATH); const fileData = allLinks[selectedItem.toLowerCase()]; try { const wait = await message.reply(`⏳ '${selectedItem}' ড্রাইভ থেকে লোড হচ্ছে...`); const localDrive = drive; const res = await localDrive.files.get({ fileId: fileData.id, alt: "media" }, { responseType: "stream" }); await message.unsend(wait.messageID); return message.reply({ body: `✅ Playing selected: ${selectedItem}`, attachment: res.data }); } catch (e) { return message.reply(`❌ ফাইলটি আনতে সমস্যা হয়েছে: ${e.message}`); } } } };