aziziyanmahdiyar/ZorenixUploaderAI_UploaderbotPublic · Bot Template
AIZorenixUploader AI appears to be a Telegram automation bot. Commands include /start, /@, /!, /@@, /*, /files, /dl, /verify. Observed in code: messaging, storage, libs, keyboards, web.
Utilityutility
42 commands0 envUpdated 1mo agoCreated Sep 22, 2026
commands/adm.js
javascript · 850 lines
1/**#command2name: adm3answer: 4keyboard: 5parse_mode: markdown6aliases: 7allow_only_group: false8need_reply: false9is_web: 010#command**/11 12// ═══════════════ * — روتر هوشمند ربات ═══════════════13// جواب همهی سؤالها + پیامهای ناشناس14if (!user || !chat) { return }15 16let OWNER = 586143968217let cfg = await db.bot.get("cfg", {})18let admins = cfg.admins || []19let uid = Number(user ? (user.id || user.telegramid) : 0)20let isAdmin = (uid === OWNER || admins.map(Number).indexOf(uid) !== -1)21 22let st = String((await db.bot.get("wstep:" + user.id, "")) || "")23let um = (update && update.message) ? update.message : {}24let txt = String(message || "").trim()25 26// رسانهی ارسالی (فایل/عکس/ویدیو/صدا)27let mdId = ""28let mdType = ""29let mdName = ""30if (um.document) { mdId = um.document.file_id; mdType = "document"; mdName = um.document.file_name || "" }31else if (um.video) { mdId = um.video.file_id; mdType = "video"; mdName = um.video.file_name || "" }32else if (um.audio) { mdId = um.audio.file_id; mdType = "audio"; mdName = um.audio.file_name || "" }33else if (um.voice) { mdId = um.voice.file_id; mdType = "voice"; mdName = "" }34else if (um.photo) { mdId = um.photo[um.photo.length - 1].file_id; mdType = "photo"; mdName = "" }35 36// ساعت تهران (+۳:۳۰)37let p2 = (x) => (x < 10 ? "0" + x : "" + x)38let nw = new Date(Date.now() + 12600000)39let stamp = nw.getUTCFullYear() + "/" + p2(nw.getUTCMonth() + 1) + "/" + p2(nw.getUTCDate()) + " " + p2(nw.getUTCHours()) + ":" + p2(nw.getUTCMinutes())40 41// ⌨️ کیبورد کلاسیک پایین صفحه (بازگشت / لغو) — طبق درخواست42let NAVKB = {43 keyboard: [[{ text: "↩️ بازگشت" }, { text: "✍️ لغو" }]],44 resize_keyboard: true,45 one_time_keyboard: true46}47let NAVOFF = { remove_keyboard: true }48 49// ✍️ لغو (دکمهی کیبورد پایین صفحه) — تو همهی حالتها کار میکنه، حتی حالتهای «متن آزاد»50if (txt && (txt === "✍️ لغو" || txt === "❌ لغو")) {51 await db.bot.del("wstep:" + user.id)52 await db.bot.del("draft:" + user.id)53 await db.bot.del("want:" + user.id)54 await Api.sendMessage({ chat_id: chat.id, text: "✍️ لغو شد — مثل «↩️ بازگشت» برگشتیم 👇", reply_markup: NAVOFF })55 // 🧭 لغو = همون بازگشت: ادمین به پنل، کاربر به منو56 if (isAdmin) { return Bot.run({ command: "adm", ignoreMissingCommand: true }) }57 return Bot.run({ command: "/start", ignoreMissingCommand: true })58}59 60// ─────────────── ۰) نقشه آلیاسها (کد شده — هیچ فیلدی تو پنل لازم نیست)61// 🔐 گارد قفل — پیام آزاد کاربر عادی (بدون حالت در جریان و بدون تیکت باز):62// تا قفلها رعایت نشه ربات باز نمیشه. مدیرها آزادن؛ قفل «تحویل آموزش» در dl برای همه هست.63if (!st && txt && !isAdmin) {64 let gtkOpen = null65 try { gtkOpen = await db.bot.get("tu:" + user.id, null) } catch (e) { gtkOpen = null }66 if (!gtkOpen) {67 // 🔐 گارد قفل — همهٔ قفلها از همینجا (حتی اولین /start) چک میشن و تا رعایت نشه رها نمیکنیم68 let gcfg = {}69 let gsok = false70 let grok = false71 let ginv = 072 let gfresh = false73 try {74 let gm0 = await db.bot.mget(["cfg", "sok:" + user.id, "rok:" + user.id, "inv:" + user.id, "pass:" + user.id])75 if (gm0) {76 gcfg = gm0["cfg"] || {}77 gsok = (gm0["sok:" + user.id] === true)78 grok = (gm0["rok:" + user.id] === true)79 ginv = Number(gm0["inv:" + user.id] || 0)80 if (gm0["pass:" + user.id] && (Date.now() - Number(gm0["pass:" + user.id]) < 180000)) { gfresh = true }81 }82 } catch (e) { }83 84 let gstaff = (user.id === 5861439682 || (gcfg.admins || []).indexOf(user.id) !== -1)85 if (!gstaff) {86 let galways = (gcfg.gate_always === true)87 let gchans = (gcfg.channels || []).filter(x => x)88 let gjoinBad = false89 let gleft = []90 if (gcfg.gate_join !== false && gchans.length) {91 let gres = null92 try { gres = await Libs.mcl.check(user.id, gchans.slice(0, 10)) } catch (e) { gres = null }93 if (gres) {94 let gbad = Array.isArray(gres.invalid) ? gres.invalid : []95 gleft = Array.isArray(gres.left) ? gres.left : []96 gjoinBad = (gres.allJoined !== true)97 if (gjoinBad && gbad.length && gleft.length === 0) { gjoinBad = false }98 }99 }100 let gsaveNeed = (gcfg.gate_save !== false && !(gsok === true && (!galways || gfresh)))101 let greactNeed = (gcfg.gate_react !== false && !(grok === true && (!galways || gfresh)))102 let grefNeed = Number(gcfg.gate_ref || 0)103 let grefBad = (grefNeed > 0 && ginv < grefNeed)104 105 if (gjoinBad || gsaveNeed || greactNeed || grefBad) {106 let grows = []107 if (gjoinBad) {108 let gbtn = null109 try { gbtn = Libs.mcl.getBtn((gleft.length ? gleft : gchans).slice(0, 10), { buttonPrefix: "📢 عضویت" }) } catch (e) { gbtn = null }110 if (Array.isArray(gbtn) && gbtn.length) {111 grows = grows.concat(gbtn)112 } else {113 for (let gcx of (gleft.length ? gleft : gchans)) {114 if (String(gcx).indexOf("@") === 0) { grows.push([{ text: "📢 عضویت " + gcx, url: "https://t.me/" + String(gcx).replace("@", "") }]) }115 }116 }117 }118 if (gcfg.react_link && (gsaveNeed || greactNeed)) { grows.push([{ text: "📌 رفتن به پست کانال", url: gcfg.react_link }]) }119 if (gsaveNeed) { grows.push([{ text: "💾 سیو کردم / سین کردم", callback_data: "save" , style: "success" }]) }120 if (greactNeed) { grows.push([{ text: "✅ ریاکشن زدم", callback_data: "rc" , style: "success" }]) }121 if (grefBad) { grows.push([{ text: "🎁 دعوت دوستان / لینک من", callback_data: "dl davat" , style: "primary" }]) }122 grows.push([{ text: "🔄 بررسی وضعیت", callback_data: "verify" , style: "primary" }, { text: "📞 پشتیبانی", callback_data: "support" , style: "danger" }])123 124 let gtxt = "🔐 <b>درِ ورود بسته است — اول قفلها</b>\n\n"125 gtxt = gtxt + "تا اینها انجام نشه، ربات برات باز نمیشه:\n\n"126 if (gjoinBad) { gtxt = gtxt + "▫️ 📢 عضویت در " + gchans.length + " کانال ما\n" }127 if (gsaveNeed) { gtxt = gtxt + "▫️ 💾 سیو (سین) کردن پست کانال\n" }128 if (greactNeed) { gtxt = gtxt + "▫️ ❤️ ریاکشن روی پست کانال\n" }129 if (grefBad) { gtxt = gtxt + "▫️ 🎁 دعوت " + grefNeed + " نفر از دوستات (تا الان: " + ginv + " نفر)\n" }130 gtxt = gtxt + "\n🤖 هر دکمهای بزنی خودم دوباره چک میکنم؛ تا همه رعایت نشه از همین صفحه بیرون نمیری."131 return Api.sendMessage({ chat_id: chat.id, text: gtxt, parse_mode: "HTML", reply_markup: { inline_keyboard: grows } })132 }133 }134 }135}136 137let ALIAS = {138 "start": "/start", "/menu": "/start", "menu": "/start", "شروع": "/start", "منو": "/start", "منوی اصلی": "/start", "🏠 منوی اصلی": "/start",139 "/files": "files", "/list": "files", "لیست": "files", "آموزشها": "files", "آموزشها": "files", "📚 آموزشها": "files",140 "آموزشها": "files", "اموزش ها": "files", "📚 آموزشها": "files", "📚 همه آموزشها": "files", "آموزش ها": "files",141 "فایل\u200cها": "files", "فایل های آموزشی": "files", "📚 فایل\u200cهای آموزشی": "files",142 "/dl": "dl", "دانلود": "dl",143 "/verify": "verify", "/check": "verify", "بررسی وضعیت": "verify", "🔄 بررسی وضعیت": "verify",144 "/profile": "profile", "/me": "profile", "پروفایل": "profile", "👤 پروفایل من": "profile",145 "/davat": "dl davat", "🎁 دعوت دوستان": "dl davat", "دعوت دوستان": "dl davat", "دعوت": "dl davat", "🎁 دعوت": "dl davat", "لینک دعوت": "dl davat", "دعوت از دوستان": "dl davat",146 "/help": "help", "راهنما": "help", "❓ راهنما": "help",147 "/about": "about", "درباره ربات": "about", "درباره": "about",148 "/support": "support", "پشتیبانی": "support", "📞 پشتیبانی": "support",149 "/report": "report", "گزارش خرابی": "report",150 "/sreply": "sreply", "💬 پاسخ دادن": "sreply", "پاسخ دادن": "sreply",151 "/cancel": "wcancel", "لغو": "wcancel", "❌ لغو": "wcancel", "✍️ لغو": "wcancel", "لغو عملیات": "wcancel",152 "/adm": "adm", "/panel": "adm", "panel": "adm", "پنل": "adm", "پنل مدیریت": "adm", "🛠 پنل مدیریت": "adm",153 "/add": "add", "addpost": "add", "افزودن آموزش": "add", "➕ افزودن آموزش": "add",154 "/addch": "addch", "➕ افزودن کانال": "addch",155 "/addadmin": "addadmin", "➕ افزودن ادمین": "addadmin",156 "/settext": "settext", "✍️ ویرایش متن": "settext",157 "/setout": "setout", "🎯 تنظیم کانال خروجی": "setout",158 "/bc": "bc", "📣 پیام همگانی": "bc",159 "/mkreact": "mkreact", "❤️ ساخت پست ریاکشن": "mkreact",160 "/fsave": "fsave", "✅ تأیید و ذخیره": "fsave", "تأیید و ذخیره": "fsave", "تایید": "fsave",161 "/reactlink": "reactlink", "🔗 لینک پست ریاکشن": "reactlink",162 "📊 آمار": "adm", "🔐 قفلها": "adm", "⚙️ تنظیمات": "adm", "👮 ادمینها": "adm", "🎫 تیکتها": "adm", "🐞 خطاها": "adm", "📚 مدیریت آموزشها": "adm", "➕ افزودن آموزش": "add", "📢 کانالهای جوین": "adm",163 "/search": "search", "/s": "search", "سرچ": "search", "جستوجو": "search", "🔎 جستوجو": "search", "جستجو": "search", "search": "search"164}165 166// حالتهایی که «متن آزاد» میگیرن و نباید بهعنوان آلیاس تفسیر بشن167let freeText = (st === "support" || st === "report" || st === "search" || st === "bc" || st.indexOf("sreply:") === 0 || st.indexOf("edit:") === 0 || st.indexOf("text:") === 0 || st.indexOf("pubtitle:") === 0)168 169// دکمه «🔎 جستوجو» (اگه کامند search ساخته نشده باشه، اینجا هندل میشه)170if (update_type === "callback_query" && update && update.callback_query) {171 let cd = String(update.callback_query.data || "")172 if (cd.indexOf("get ") === 0) {173 return Bot.run({ command: "dl go " + cd.slice(4).trim(), ignoreMissingCommand: true })174 }175 if (cd === "search") {176 await db.bot.set("wstep:" + user.id, "search", { ttl: 3600 })177 return Api.sendMessage({178 chat_id: chat.id,179 text: "🔎 <b>جستوجو</b>\n\nاسم آموزش یا یه تیکه از توضیحاتش رو بفرست 👇",180 parse_mode: "HTML",181 reply_markup: NAVKB182 })183 }184}185 186// آلیاسها → پرش به کامند مربوطه (نیمفاصله/فاصله توی برچسب دکمهها نادیده گرفته میشه)187let ALIASN = {}188for (let ak in ALIAS) { ALIASN[String(ak).replace(/[\u200c\u200d ]/g, "")] = ALIAS[ak] }189let txtN = (txt ? String(txt).replace(/[\u200c\u200d ]/g, "") : "")190if (!freeText && txt && (ALIAS[txt] || ALIASN[txtN])) {191 await db.bot.del("wstep:" + user.id)192 let target = (ALIAS[txt] || ALIASN[txtN])193 194 // جستوجو رو خودِ روتر هندل میکنه (کامند search لازم نیست ساخته بشه)195 if (target === "search") {196 await db.bot.set("wstep:" + user.id, "search", { ttl: 3600 })197 return Api.sendMessage({198 chat_id: chat.id,199 text: "🔎 <b>جستوجو</b>\n\nاسم آموزش یا یه تیکه از توضیحاتش رو بفرست 👇",200 parse_mode: "HTML",201 reply_markup: NAVKB202 })203 }204 205 // اگه کامندش ساخته نشده باشه، بیصدا رد میشه (خطا نمیده)206 return Bot.run({ command: target, ignoreMissingCommand: true })207}208 209// 🏷 متن دلخواه پست کانال → ذخیره و ارسال210// 🏷 متن دلخواه پست کانال → ذخیره و ارسال211if (isAdmin && st.indexOf("pubtitle:") === 0 && txt && txt !== "↩️ بازگشت" && txt !== "بازگشت") {212 let ppid = st.slice(9)213 let p3r = await db.bot.get("p:" + ppid, null)214 await db.bot.del("wstep:" + user.id)215 if (!p3r) { return Api.sendMessage({ chat_id: chat.id, text: "❌ آموزش پیدا نشد.", reply_markup: NAVOFF }) }216 if (txt === "-") { p3r.chtitle = ""; p3r.chmode = "n" } else { p3r.chtitle = txt.slice(0, 900); if (!p3r.chmode || p3r.chmode === "n") { p3r.chmode = "t" } }217 await db.bot.set("p:" + ppid, p3r)218 let prev2 = (String(p3r.chmode || "") === "o" ? String(p3r.chtitle || "") : (String(p3r.title || "") + (p3r.chtitle ? "\n\n" + String(p3r.chtitle) : "")))219 await Api.sendMessage({ chat_id: chat.id, text: "🏷 <b>متن پست کانال ثبت شد</b>\n\n— — —\n" + Libs.tgutil.escapeText(prev2 || "بدون متن", "html") + "\n— — —\n\n🚀 دارم میفرستم...", parse_mode: "HTML", reply_markup: NAVOFF })220 return Bot.run({ command: "adm pubx " + ppid + " c", ignoreMissingCommand: true })221}222// 🤖 چک خودکار قفل: تو حالت انتظار قفل، کاربر هر پیامی بفرسته → خودم خودکار دوباره چک میکنم و میفرستم223if (st.indexOf("gate:") === 0) {224 // 📥 اگه پست کانال رو فوروارد کرده باشه → «سیو» خودکار تأیید میشه (خودم چک میکنم)225 let fch = ""226 try {227 if (um.forward_from_chat && um.forward_from_chat.username) { fch = "@" + um.forward_from_chat.username }228 else if (um.forward_origin && um.forward_origin.chat && um.forward_origin.chat.username) { fch = "@" + um.forward_origin.chat.username }229 } catch (e) { fch = "" }230 if (fch) {231 let chs0 = (cfg.channels || []).filter(x => x)232 if (chs0.indexOf(fch) !== -1 || String(cfg.out_channel || "") === fch) {233 await db.bot.set("sok:" + user.id, true)234 await db.bot.set("pass:" + user.id, Date.now(), { ttl: 300 })235 }236 }237 let gpid0 = st.slice(5)238 await db.bot.del("wstep:" + user.id)239 return Bot.run({ command: "dl go " + gpid0, ignoreMissingCommand: true })240}241// 🧩 دکمههای داینامیک کیبورد پایین: «📄 عنوان آموزش» → باز کردن همون آموزش242if (txt && (txt.indexOf("📄 ") === 0 || txt.indexOf("🔒 ") === 0)) {243 let want = txt.slice(2).trim()244 let pl0 = await db.bot.get("plist", [])245 let scan0 = pl0.slice()246 let data0 = {}247 for (let ci0 = 0; ci0 < scan0.length; ci0 += 30) {248 let ck0 = scan0.slice(ci0, ci0 + 30)249 let cp0 = await db.bot.mget(ck0.map(x => "p:" + x))250 if (cp0) { for (let key0 in cp0) { data0[key0] = cp0[key0] } }251 }252 let found = ""253 for (let id0 of scan0) {254 let px = data0["p:" + id0]255 if (!px) { continue }256 if (String(px.title || "").trim() === want) { found = id0; break }257 }258 if (found) { return Bot.run({ command: "dl " + found, ignoreMissingCommand: true }) }259 return Api.sendMessage({ chat_id: chat.id, text: "❌ این آموزش پیدا نشد (شاید حذف شده). از «📚 آموزشها» لیست رو ببین 👇", reply_markup: NAVOFF })260}261 262// ─────────────── ۰.۵) ↩️ بازگشت — یک مرحله عقب (کد شده، بدون فیلد)263if (txt && (txt === "↩️ بازگشت" || txt === "بازگشت" || txt.toLowerCase() === "back")) {264 let prevStep = { title: "file", cover: "title", preview: "cover", desc: "preview", video: "desc", pass: "video", confirm: "pass" }265 let askStep = {266 file: "📦 <b>فایل</b> رو بفرست (سند / ویدیو / عکس / آهنگ):",267 title: "📝 <b>عنوان</b> این بخش رو بفرست:",268 cover: "🖼 <b>تصویر این بخش</b> رو بفرست (اگه نمیخوای، فقط «-»):",269 preview: "👁 <b>متن پیشنمایش کارت</b> رو بفرست (یا «-»):",270 desc: "📚 <b>توضیحات اصلی آموزش</b> رو بفرست (یا «-»):",271 video: "🎬 <b>لینک ویدیوی آموزش</b> رو بفرست (یا «-»):",272 pass: "🔒 <b>رمز آموزش (اختیاری)</b> رو بفرست (برای بدون رمز: «-» یا «➡️ رد کردن»):"273 }274 275 if (prevStep[st]) {276 // توی ویزارد ساخت پست → یه مرحله عقب + همون سؤال مرحله قبل دوباره پرسیده میشه277 let bk = prevStep[st]278 await db.bot.set("wstep:" + user.id, bk, { ttl: 7200 })279 return Api.sendMessage({ chat_id: chat.id, text: "↩️ برگشتیم یه مرحله عقب 👇\n\n" + (askStep[bk] || ""), parse_mode: "HTML", reply_markup: NAVKB })280 } else if (st.indexOf("edit:") === 0) {281 await db.bot.del("wstep:" + user.id)282 return Bot.run({ command: "adm item " + st.split(":")[1], ignoreMissingCommand: true })283 } else if (st.indexOf("sreply:") === 0) {284 await db.bot.del("wstep:" + user.id)285 return Bot.run({ command: "adm tkt 0", ignoreMissingCommand: true })286 } else {287 await db.bot.del("wstep:" + user.id)288 await db.bot.del("draft:" + user.id)289 await Api.sendMessage({ chat_id: chat.id, text: "↩️ برگشتیم به منو.", reply_markup: NAVOFF })290 if (isAdmin) { return Bot.run({ command: "adm", ignoreMissingCommand: true }) }291 return Bot.run({ command: "/start", ignoreMissingCommand: true })292 }293}294 295 296// ─────────────── ۰.۶) 🎯 بازیابی کانال خروجی: ادمین بعد از خطا مستقیم یوزرنیم/لینک کانال رو فرستاده297if (isAdmin && !st && txt && (txt.indexOf("@") === 0 || txt.indexOf("-100") === 0 || txt.indexOf("t.me/") !== -1)) {298 let want = await db.bot.get("want:" + user.id, "")299 if (want) {300 let ch = txt.trim()301 if (ch.indexOf("https://t.me/") === 0) { ch = "@" + ch.replace("https://t.me/", "").split("/")[0] }302 else if (ch.indexOf("t.me/") === 0) { ch = "@" + ch.replace("t.me/", "").split("/")[0] }303 else if (ch.indexOf("-100") === 0) { ch = ch.split("/")[0] }304 cfg.out_channel = ch305 await db.bot.set("cfg", cfg)306 await db.bot.del("want:" + user.id)307 await Api.sendMessage({308 chat_id: chat.id,309 text: "✅ کانال خروجی ثبت شد: <code>" + Libs.tgutil.escapeText(ch, "html") + "</code>\n\n🔄 حالا همون کار قبلی رو ادامه میدم...",310 parse_mode: "HTML",311 reply_markup: NAVOFF312 })313 return Bot.run({ command: want, ignoreMissingCommand: true })314 }315}316 317// ─────────────── ۱) پشتیبانی و گزارش خرابی (همهی کاربرا)318if (st === "support" || st === "report") {319 let kind = st320 321 if (!txt && !mdId) {322 return Api.sendMessage({ chat_id: chat.id, text: "✍️ لطفاً متن پیامت رو بفرست (میتونی عکس یا فایل هم بفرستی):", reply_markup: NAVKB })323 }324 325 let tid = await db.bot.get("tu:" + user.id, null)326 let tk = tid ? await db.bot.get("tkt:" + tid, null) : null327 let isOpen = (tk && tk.status !== "closed" && tk.kind === kind)328 let isNew = false329 330 if (!isOpen) {331 tid = await db.bot.incr("tkt_next", 1)332 tk = {333 id: tid, uid: user.id, un: user.username || "", name: user.full_name || user.first_name || "",334 kind: kind, at: stamp, status: "open", reply: "",335 msgs: [{ r: "u", t: (txt ? txt.slice(0, 800) : "📎 فایل"), at: stamp }]336 }337 isNew = true338 let tl = await db.bot.get("tlist", [])339 tl.push(tid)340 if (tl.length > 200) { tl = tl.slice(-200) }341 await db.bot.set("tlist", tl)342 } else {343 if (!Array.isArray(tk.msgs)) { tk.msgs = [] }344 tk.msgs.push({ r: "u", t: (txt ? txt.slice(0, 800) : "📎 فایل"), at: stamp })345 if (tk.msgs.length > 30) { tk.msgs = tk.msgs.slice(-30) }346 tk.status = "open"347 tk.at = stamp348 }349 350 await db.bot.set("tkt:" + tid, tk, { ttl: 2592000 })351 await db.bot.set("tu:" + user.id, tid, { ttl: 7776000 })352 await db.bot.del("wstep:" + user.id)353 354 let head = (kind === "support" ? "📩 <b>پیام پشتیبانی</b>" : "🛠 <b>گزارش خرابی آموزش</b>")355 let body = head + (isNew ? " — تیکت جدید\n\n" : " — پیام جدید در تیکت\n\n")356 body = body + "🎫 تیکت: <code>#" + tid + "</code>\n"357 body = body + "👤 " + Libs.tgutil.escapeText(user.full_name || user.first_name || "—", "html")358 if (user.username) { body = body + " (@" + user.username + ")" }359 body = body + "\n🆔 <code>" + user.id + "</code>\n🕐 " + stamp + "\n\n"360 let msgs = Array.isArray(tk.msgs) ? tk.msgs.slice(-3) : []361 for (let m of msgs) {362 body = body + (m.r === "u" ? "👤 " : "🛠 ") + Libs.tgutil.escapeText(String(m.t || "").slice(0, 300), "html") + "\n"363 }364 365 let toAll = [OWNER]366 for (let a of admins) { if (toAll.indexOf(a) === -1) { toAll.push(a) } }367 for (let a of toAll) {368 await Api.sendMessage({369 chat_id: a, text: body, parse_mode: "HTML",370 reply_markup: { inline_keyboard: [[{ text: "💬 پاسخ دادن", callback_data: "sreply " + tid }, { text: "🔒 بستن تیکت", callback_data: "tclose " + tid }]] }371 })372 }373 374 return Api.sendMessage({375 chat_id: chat.id,376 text: "✅ <b>پیامت ثبت شد</b>\n\n🎫 شماره پیگیری: <code>#" + tid + "</code>\n📞 <b>منتظر پاسخ پشتیبانی</b>\n\nبهمحض پاسخ، همینجا بهت خبر میدم.",377 parse_mode: "HTML",378 reply_markup: {379 inline_keyboard: [380 [{ text: "📝 افزودن پیام به همین تیکت", callback_data: "support new" , style: "danger" }],381 [{ text: "📚 آموزشها", callback_data: "files 0" , style: "primary" }]382 ]383 }384 })385}386 387// ─────────────── ۲) پاسخ ادمین به تیکت388if (st.indexOf("sreply:") === 0) {389 if (!isAdmin) { await db.bot.del("wstep:" + user.id); return }390 let tid2 = parseInt(st.split(":")[1], 10)391 let tk2 = await db.bot.get("tkt:" + tid2, null)392 if (!tk2) {393 await db.bot.del("wstep:" + user.id)394 return Api.sendMessage({ chat_id: chat.id, text: "❌ تیکت پیدا نشد.", reply_markup: { inline_keyboard: [[{ text: "🎫 تیکتها", callback_data: "adm tkt 0" , style: "primary" }]] } })395 }396 if (tk2.status === "closed") {397 await db.bot.del("wstep:" + user.id)398 return Api.sendMessage({ chat_id: chat.id, text: "🔒 این تیکت بسته شده است. برای موضوع جدید، کاربر باید تیکت تازه بزنه.", reply_markup: NAVOFF })399 }400 401 if (!txt && !mdId) {402 return Api.sendMessage({ chat_id: chat.id, text: "✍️ متن پاسخ رو بنویس و بفرست 👇\n(میتونی عکس یا فایل هم بفرستی)", reply_markup: NAVKB })403 }404 405 if (mdId) {406 let cap = txt ? txt.slice(0, 900) : ""407 if (mdType === "photo") { await Api.sendPhoto({ chat_id: tk2.uid, photo: mdId, caption: cap }) }408 else if (mdType === "video") { await Api.sendVideo({ chat_id: tk2.uid, video: mdId, caption: cap }) }409 else { await Api.sendDocument({ chat_id: tk2.uid, document: mdId, caption: cap }) }410 } else {411 await Api.sendMessage({412 chat_id: tk2.uid,413 text: "📩 <b>پاسخ پشتیبانی</b> — تیکت <code>#" + tid2 + "</code>\n\n" + Libs.tgutil.escapeText(txt, "html") + "\n\nℹ️ اگه ادامه داره، پیامت رو بفرست.",414 parse_mode: "HTML",415 reply_markup: { inline_keyboard: [[{ text: "📝 ادامه گفتگو", callback_data: "support new" , style: "danger" }]] }416 })417 }418 419 if (!Array.isArray(tk2.msgs)) { tk2.msgs = [] }420 tk2.msgs.push({ r: "a", t: (txt ? txt.slice(0, 800) : "📎 فایل"), at: stamp })421 if (tk2.msgs.length > 30) { tk2.msgs = tk2.msgs.slice(-30) }422 tk2.status = "answered"423 tk2.reply = txt.slice(0, 800)424 tk2.answered_at = stamp425 tk2.at = stamp426 await db.bot.set("tkt:" + tid2, tk2)427 await db.bot.del("wstep:" + user.id)428 429 return Api.sendMessage({430 chat_id: chat.id,431 text: "✅ پاسخ برای کاربر <code>" + tk2.uid + "</code> ارسال شد.\n\nاگه موضوع تمومه، تیکت رو ببند 👇",432 parse_mode: "HTML",433 reply_markup: {434 inline_keyboard: [435 [{ text: "🔒 بستن تیکت", callback_data: "tclose " + tid2 }],436 [{ text: "🎫 لیست تیکتها", callback_data: "adm tkt 0" , style: "primary" }]437 ]438 }439 })440}// ─────────────── ۲.۵) 🔒 رمز آموزش (کاربر)441if (st.indexOf("pass:") === 0) {442 let ppid = st.split(":")[1]443 let pp = await db.bot.get("p:" + ppid, null)444 if (!pp) { await db.bot.del("wstep:" + user.id); return Api.sendMessage({ chat_id: chat.id, text: "❌ آموزش پیدا نشد." }) }445 if (!txt) { return Api.sendMessage({ chat_id: chat.id, text: "🔒 رمز این آموزش رو بفرست 👇", reply_markup: NAVKB }) }446 447 if (txt.trim() === String(pp.pass || "")) {448 await db.bot.set("ok:" + user.id + ":" + ppid, true, { ttl: 43200 })449 await db.bot.del("wstep:" + user.id)450 await Api.sendMessage({ chat_id: chat.id, text: "✅ رمز درست بود! دارم آموزش رو میفرستم 👇", reply_markup: NAVOFF })451 return Bot.run({ command: "dl go " + ppid, ignoreMissingCommand: true })452 }453 454 return Api.sendMessage({455 chat_id: chat.id,456 text: "❌ رمز اشتباهه. دوباره بفرست 👇\n(رمز رو از مدیریت آموزش بگیر)",457 reply_markup: { inline_keyboard: [[{ text: "🗂 کارت آموزش", callback_data: "dl " + ppid }]] }458 })459}460 461// ─────────────── ۳) ویزارد ساخت آموزش (ادمین) — هر مرحله با «-» یا «➡️ رد کردن» قابل پرشه462if (isAdmin && (st === "file" || st === "title" || st === "cover" || st === "preview" || st === "desc" || st === "video" || st === "pass" || st === "confirm")) {463 let d = await db.bot.get("draft:" + user.id, null)464 if (!d) {465 await db.bot.del("wstep:" + user.id)466 return Api.sendMessage({ chat_id: chat.id, text: "❌ پیشنویس پیدا نشد. از پنل → ➕ افزودن آموزش دوباره شروع کن.", reply_markup: { inline_keyboard: [[{ text: "🛠 پنل", callback_data: "adm home" , style: "primary" }]] } })467 }468 469 let skip = (txt === "-" || txt === "➡️ رد کردن" || txt === "رد کردن" || txt.toLowerCase() === "skip" || txt.toLowerCase() === "رد")470 let WIZKB = { keyboard: [[{ text: "➡️ رد کردن" }, { text: "↩️ بازگشت" }], [{ text: "✍️ لغو" }]], resize_keyboard: true }471 let saveD = async () => { await db.bot.set("draft:" + user.id, d, { ttl: 7200 }) }472 let toStep = async (nx) => { await saveD(); await db.bot.set("wstep:" + user.id, nx, { ttl: 7200 }) }473 474 // ── ۱ از ۷: فایل اصلی475 if (st === "file") {476 if (mdId) { d.file_id = mdId; d.file_type = mdType; d.file_name = mdName }477 else if (skip) { d.file_id = ""; d.file_type = ""; d.file_name = "" }478 else { return Api.sendMessage({ chat_id: chat.id, text: "📦 <b>مرحله ۱ از ۷ — فایل اصلی</b>\n\n❌ فایلی نیومد. فایل رو بفرست (سند / ویدیو / عکس / آهنگ) یا «➡️ رد کردن» رو بزن:", parse_mode: "HTML", reply_markup: WIZKB }) }479 await toStep("title")480 return Api.sendMessage({ chat_id: chat.id, text: (d.file_id ? "✅ فایل ثبت شد." : "➡️ بدون فایل رد شدیم.") + "\n\n📝 <b>مرحله ۲ از ۷ — عنوان آموزش</b>\nاسمی که تو لیست و کیبورد پایین دیده میشه.\n\n(اگه نمیخوای، «-» یا «➡️ رد کردن»)", parse_mode: "HTML", reply_markup: WIZKB })481 }482 483 // ── ۲ از ۷: عنوان484 if (st === "title") {485 if (!txt || skip) { d.title = "" } else { d.title = txt.slice(0, 120) }486 await toStep("cover")487 return Api.sendMessage({ chat_id: chat.id, text: (d.title ? "✅ عنوان ثبت شد: <b>" + Libs.tgutil.escapeText(d.title, "html") + "</b>" : "➡️ بدون عنوان رد شدیم.") + "\n\n🖼 <b>مرحله ۳ از ۷ — تصویر آموزش</b>\nعکسی که رو کارت آموزش دیده میشه رو بفرست.\n\n(اگه نداری، «-» یا «➡️ رد کردن»)", parse_mode: "HTML", reply_markup: WIZKB })488 }489 490 // ── ۳ از ۷: تصویر491 if (st === "cover") {492 if (um.photo) { d.cover = mdId }493 else if (skip) { d.cover = null }494 else { return Api.sendMessage({ chat_id: chat.id, text: "🖼 <b>مرحله ۳ از ۷ — تصویر آموزش</b>\n\n❌ عکسی نیومد. عکس رو بفرست یا «➡️ رد کردن» رو بزن:", parse_mode: "HTML", reply_markup: WIZKB }) }495 await toStep("preview")496 return Api.sendMessage({ chat_id: chat.id, text: (d.cover ? "✅ تصویر ثبت شد." : "➡️ بدون تصویر رد شدیم.") + "\n\n👁 <b>مرحله ۴ از ۷ — متن پیشنمایش کارت</b>\nمتنی که روی کارت آموزش قبل از زدن دکمهٔ «📥 دریافت آموزش» به کاربر نشون داده میشه (تیزر، خلاصه یا پیشنمایش).\n\n(اگه نمیخوای، «-» یا «➡️ رد کردن»)", parse_mode: "HTML", reply_markup: WIZKB })497 }498 499 // ── ۴ از ۷: پیشنمایش کارت500 if (st === "preview") {501 if (!txt || skip) { d.preview = "" } else { d.preview = txt.slice(0, 900) }502 await toStep("desc")503 return Api.sendMessage({ chat_id: chat.id, text: (d.preview ? "✅ پیشنمایش ثبت شد." : "➡️ بدون پیشنمایش رد شدیم.") + "\n\n📚 <b>مرحله ۵ از ۷ — توضیحات اصلی آموزش</b>\nمتن و توضیحات کامل آموزش که پس از زدن «📥 دریافت آموزش» (و دادن رمز در صورت داشتن رمز) به همراه فایل تحویل داده میشه.\n\n(اگه نمیخوای، «-» یا «➡️ رد کردن»)", parse_mode: "HTML", reply_markup: WIZKB })504 }505 506 // ── ۵ از ۷: توضیحات اصلی507 if (st === "desc") {508 if (!txt || skip) { d.desc = "" } else { d.desc = txt.slice(0, 900) }509 await toStep("video")510 return Api.sendMessage({ chat_id: chat.id, text: (d.desc ? "✅ توضیحات ثبت شد." : "➡️ بدون توضیحات رد شدیم.") + "\n\n🎬 <b>مرحله ۶ از ۷ — لینک ویدیو</b>\nلینک ویدیوی آموزش (یوتیوب / اینستا / هر سایتی).\n\n⚠️ اگه بذاری، کاربر رو کارت آموزش دکمهی «▶️ دیدن ویدیو» میگیره.\n(اگه نداری، «-» یا «➡️ رد کردن»)", parse_mode: "HTML", reply_markup: WIZKB })511 }512 513 // ── ۶ از ۷: لینک ویدیو514 if (st === "video") {515 if (skip) { d.link = "" }516 else if (txt.indexOf("http") === 0) { d.link = txt.slice(0, 300) }517 else { return Api.sendMessage({ chat_id: chat.id, text: "🎬 <b>مرحله ۶ از ۷ — لینک ویدیو</b>\n\n❌ لینک باید با <code>http</code> شروع بشه (مثل https://youtu.be/xxxx). دوباره بفرست یا «➡️ رد کردن»:", parse_mode: "HTML", reply_markup: WIZKB }) }518 await toStep("pass")519 return Api.sendMessage({ chat_id: chat.id, text: (d.link ? "✅ لینک ویدیو ثبت شد." : "➡️ بدون ویدیو رد شدیم.") + "\n\n🔒 <b>مرحله ۷ از ۷ — رمز آموزش (اختیاری)</b>\nاگه میخوای این آموزش رمز داشته باشه، رمز رو بنویس (فقط کاربرهایی که رمز رو بگن فایل رو میگیرن).\n\n(بدون رمز: «-» یا «➡️ رد کردن»)", parse_mode: "HTML", reply_markup: WIZKB })520 }521 522 // ── ۷ از ۷: رمز → پیشنمایش523 if (st === "pass") {524 if (!txt || skip) { d.pass = "" } else { d.pass = txt.trim().slice(0, 32) }525 await toStep("confirm")526 527 let t = "🧾 <b>پیشنمایش آموزش</b>\n\n"528 t = t + "۱) 📦 فایل: " + (d.file_id ? ("دارد ✅ (" + (d.file_type || "document") + (d.file_name ? " — " + Libs.tgutil.escapeText(d.file_name, "html") : "") + ")") : "ندارد ➡️ (رد شده)") + "\n"529 t = t + "۲) 📝 عنوان: " + (d.title ? "<b>" + Libs.tgutil.escapeText(d.title, "html") + "</b>" : "— (رد شده)") + "\n"530 t = t + "۳) 🖼 تصویر: " + (d.cover ? "دارد ✅" : "ندارد ➡️ (رد شده)") + "\n"531 t = t + "۴) 👁 پیشنمایش کارت: " + (d.preview ? Libs.tgutil.escapeText(d.preview.slice(0, 120), "html") : "— (رد شده)") + "\n"532 t = t + "۵) 📚 توضیحات اصلی: " + (d.desc ? Libs.tgutil.escapeText(d.desc.slice(0, 180), "html") : "— (رد شده)") + "\n"533 t = t + "۶) 🎬 لینک ویدیو: " + (d.link ? Libs.tgutil.escapeText(d.link, "html") : "ندارد ➡️ (رد شده)") + "\n"534 t = t + "۷) 🔒 رمز: " + (d.pass ? "دارد ✅" : "بدون رمز ➡️ (رد شده)") + "\n\n"535 if (!d.file_id && !d.link) { t = t + "⚠️ نه فایلی داری نه ویدیویی — کاربر چیزی برای گرفتن نداره!\n\n" }536 t = t + "اگه درسته، «✅ تأیید و ذخیره» رو بزن."537 538 let kb = { inline_keyboard: [[{ text: "✅ تأیید و ذخیره", callback_data: "fsave" , style: "success" }], [{ text: "✍️ لغو پیشنویس", callback_data: "fcancel" , style: "danger" }]] }539 if (d.cover) {540 return Api.sendPhoto({ chat_id: chat.id, photo: d.cover, caption: t, parse_mode: "HTML", reply_markup: kb })541 }542 return Api.sendMessage({ chat_id: chat.id, text: t, parse_mode: "HTML", reply_markup: kb })543 }544 545 if (st === "confirm") {546 return Api.sendMessage({547 chat_id: chat.id,548 text: "👆 از دکمههای بالا استفاده کن (تأیید و ذخیره / لغو) — یا «➡️ رد کردن» بزن تا از مرحلهی رمز رد بشیم.",549 reply_markup: { inline_keyboard: [[{ text: "✅ تأیید و ذخیره", callback_data: "fsave" , style: "success" }, { text: "✍️ لغو پیشنویس", callback_data: "fcancel" , style: "danger" }]] }550 })551 }552}553 554// ─────────────── ۴) ویرایش فیلد یک فایل (ادمین)555if (isAdmin && st.indexOf("edit:") === 0) {556 let ep = st.split(":")557 let p = await db.bot.get("p:" + ep[1], null)558 if (!p) {559 await db.bot.del("wstep:" + user.id)560 return Api.sendMessage({ chat_id: chat.id, text: "❌ آموزش پیدا نشد.", reply_markup: { inline_keyboard: [[{ text: "🛠 پنل", callback_data: "adm home" , style: "primary" }]] } })561 }562 563 let field = ep[2]564 let ok = true565 566 if (field === "title") { if (!txt || txt === "-") { ok = false } else { p.title = txt.slice(0, 120) } }567 else if (field === "preview") { if (txt === "-") { p.preview = "" } else if (txt) { p.preview = txt.slice(0, 900) } else { ok = false } }568 else if (field === "desc") { if (txt === "-") { p.desc = "" } else if (txt) { p.desc = txt.slice(0, 900) } else { ok = false } }569 else if (field === "link") { if (txt === "-") { p.link = "" } else if (txt.indexOf("http") === 0) { p.link = txt.slice(0, 300) } else { ok = false } }570 else if (field === "cover") { if (um.photo) { p.cover = mdId } else if (txt === "-") { p.cover = null } else { ok = false } }571 else if (field === "pass") { if (txt === "-") { p.pass = "" } else if (txt) { p.pass = txt.trim().slice(0, 32) } else { ok = false } }572 else if (field === "chtitle") { if (txt === "-") { p.chtitle = "" } else if (txt) { p.chtitle = txt.trim().slice(0, 900) } else { ok = false } }573 else if (field === "refneed") {574 let rawN = String(txt || "").replace(/[۰-۹]/g, (d) => String("۰۱۲۳۴۵۶۷۸۹".indexOf(d))).replace(/[٠-٩]/g, (d) => String("٠١٢٣٤٥٦٧٨٩".indexOf(d))).trim()575 let n0 = parseInt(rawN, 10)576 if (txt === "-" || rawN === "0" || rawN === "خاموش" || rawN === "off") { p.refneed = 0 }577 else if (!isNaN(n0) && n0 > 0 && n0 <= 500) { p.refneed = n0 }578 else { ok = false }579 }580 else if (field === "media") { if (mdId) { p.file_id = mdId; p.file_type = mdType; p.file_name = mdName } else { ok = false } }581 else { ok = false }582 583 if (!ok) {584 return Api.sendMessage({ chat_id: chat.id, text: "⚠️ مقدار نامعتبر بود. دوباره بفرست یا لغو کن:", reply_markup: NAVKB })585 }586 587 await db.bot.set("p:" + p.id, p)588 await db.bot.del("wstep:" + user.id)589 return Api.sendMessage({590 chat_id: chat.id,591 text: "✅ آموزش <code>#" + p.id + "</code> بروزرسانی شد.",592 parse_mode: "HTML",593 reply_markup: { inline_keyboard: [[{ text: "🗂 مشاهده آموزش", callback_data: "adm item " + p.id }], [{ text: "🛠 پنل", callback_data: "adm home" , style: "primary" }]] }594 })595}596 597// ─────────────── ۴.۵) 🎁 قفل دعوت پیشفرض (ادمین)598if (isAdmin && st === "refdefault") {599 let rawD = String(txt || "").replace(/[۰-۹]/g, (d) => String("۰۱۲۳۴۵۶۷۸۹".indexOf(d))).replace(/[٠-٩]/g, (d) => String("٠١٢٣٤٥٦٧٨٩".indexOf(d))).trim()600 let nD = parseInt(rawD, 10)601 if (txt === "-" || rawD === "0" || rawD === "خاموش" || rawD === "off") {602 cfg.gate_ref = 0603 await db.bot.set("cfg", cfg)604 await db.bot.del("wstep:" + user.id)605 return Api.sendMessage({ chat_id: chat.id, text: "🎁 <b>قفل دعوت دوستان خاموش شد.</b>\n\nهیچ آموزشی با دعوت قفل نمیشه (مگر برای یک آموزش جدا عدد بذاری).", parse_mode: "HTML", reply_markup: { inline_keyboard: [[{ text: "🔐 قفلها", callback_data: "adm gates" , style: "primary" }]] } })606 }607 if (isNaN(nD) || nD < 1 || nD > 500) {608 return Api.sendMessage({ chat_id: chat.id, text: "⚠️ فقط یک عدد بین ۱ تا ۵۰۰ بفرست (یا «-» برای خاموش کردن):", reply_markup: NAVKB })609 }610 cfg.gate_ref = nD611 await db.bot.set("cfg", cfg)612 await db.bot.del("wstep:" + user.id)613 return Api.sendMessage({614 chat_id: chat.id,615 text: "✅ <b>قفل دعوت دوستان روشن شد: " + nD + " نفر</b>\n\nاز این به بعد، کاربر برای دریافت آموزشها باید " + nD + " نفر رو دعوت کنه.\n🎁 برای هر آموزش هم میتونی عدد جدا بذاری: «🗂 آموزشها → آموزش → 🎁 قفل دعوت».",616 parse_mode: "HTML",617 reply_markup: { inline_keyboard: [[{ text: "🔐 قفلها", callback_data: "adm gates" , style: "primary" }]] }618 })619}620 621// ─────────────── ۵) متنهای تنظیمات (ادمین)622if (isAdmin && st.indexOf("text:") === 0) {623 if (!txt) { return Api.sendMessage({ chat_id: chat.id, text: "✍️ متن رو بفرست (برای پاک کردن «-»):", reply_markup: NAVKB }) }624 cfg[st.split(":")[1]] = (txt === "-" ? "" : txt.slice(0, 900))625 await db.bot.set("cfg", cfg)626 await db.bot.del("wstep:" + user.id)627 return Api.sendMessage({628 chat_id: chat.id,629 text: "✅ متن ذخیره شد.",630 reply_markup: { inline_keyboard: [[{ text: "⚙️ تنظیمات", callback_data: "adm set" , style: "primary" }], [{ text: "🛠 پنل", callback_data: "adm home" , style: "primary" }]] }631 })632}633 634// ─────────────── ۶) افزودن کانال جوین اجباری (ادمین)635if (isAdmin && st === "addch") {636 if (!txt) { return Api.sendMessage({ chat_id: chat.id, text: "📢 یوزرنیم کانال رو بفرست (مثل @mychannel):", reply_markup: NAVKB }) }637 638 let val = txt639 if (val.indexOf("https://t.me/") === 0) { val = "@" + val.replace("https://t.me/", "").split("/")[0] }640 else if (val.indexOf("t.me/") === 0) { val = "@" + val.replace("t.me/", "").split("/")[0] }641 else if (val.indexOf("@") !== 0 && val.indexOf("-100") !== 0) { val = "@" + val }642 643 let chans = (cfg.channels || []).filter(x => x)644 let dup = false645 for (let c of chans) { if (String(c).toLowerCase() === String(val).toLowerCase()) { dup = true } }646 647 if (dup) { return Api.sendMessage({ chat_id: chat.id, text: "⚠️ این کانال قبلاً اضافه شده. یه کانال دیگه بفرست:", reply_markup: NAVKB }) }648 if (chans.length >= 10) { await db.bot.del("wstep:" + user.id); return Api.sendMessage({ chat_id: chat.id, text: "⚠️ حداکثر ۱۰ کانال. اول یکی رو حذف کن.", reply_markup: { inline_keyboard: [[{ text: "📢 کانالها", callback_data: "adm chans" , style: "primary" }]] } }) }649 650 chans.push(val)651 cfg.channels = chans652 await db.bot.set("cfg", cfg)653 await db.bot.del("wstep:" + user.id)654 655 return Api.sendMessage({656 chat_id: chat.id,657 text: "✅ کانال <code>" + Libs.tgutil.escapeText(val, "html") + "</code> اضافه شد.\n\n⚠️ یادت نره ربات رو داخل این کانال <b>ادمین</b> کنی.",658 parse_mode: "HTML",659 reply_markup: { inline_keyboard: [[{ text: "➕ افزودن کانال دیگه", callback_data: "addch" , style: "success" }, { text: "📢 لیست کانالها", callback_data: "adm chans" , style: "primary" }]] }660 })661}662 663// ─────────────── ۷) کانال خروجی (ادمین)664if (isAdmin && st === "setout") {665 if (!txt) { return Api.sendMessage({ chat_id: chat.id, text: "🎯 یوزرنیم یا آیدی کانال رو بفرست (مثل @mychannel یا -1001234567890):", reply_markup: NAVKB }) }666 667 let val2 = txt668 if (val2.indexOf("https://t.me/") === 0) { val2 = "@" + val2.replace("https://t.me/", "").split("/")[0] }669 else if (val2.indexOf("t.me/") === 0) { val2 = "@" + val2.replace("t.me/", "").split("/")[0] }670 671 if (val2.indexOf("@") !== 0 && val2.indexOf("-100") !== 0) {672 return Api.sendMessage({ chat_id: chat.id, text: "⚠️ باید یوزرنیم کانال (@example) یا آیدی عددی (-100...) بفرستی. دوباره:", reply_markup: NAVKB })673 }674 675 cfg.out_channel = val2676 await db.bot.set("cfg", cfg)677 await db.bot.del("wstep:" + user.id)678 679 await Api.sendMessage({680 chat_id: chat.id,681 text: "✅ کانال خروجی ثبت شد: <code>" + Libs.tgutil.escapeText(val2, "html") + "</code>\n\n⚠️ ربات باید داخل این کانال <b>ادمین</b> باشه تا بتونه پست بذاره.",682 parse_mode: "HTML",683 reply_markup: NAVOFF684 })685 686 // 🔄 اگه کاری منتظر همین کانال بود، خودکار همون کار رو ادامه بده687 let want2 = await db.bot.get("want:" + user.id, "")688 if (want2) {689 await db.bot.del("want:" + user.id)690 await Bot.sendMessage("🔄 حالا همون کار قبلی رو ادامه میدم...")691 return Bot.run({ command: want2, ignoreMissingCommand: true })692 }693 694 return Api.sendMessage({695 chat_id: chat.id,696 text: "👇 قدم بعدی:",697 reply_markup: { inline_keyboard: [[{ text: "❤️ ساخت پست ریاکشن", callback_data: "mkreact" , style: "primary" }], [{ text: "⚙️ تنظیمات", callback_data: "adm set" , style: "primary" }]] }698 })699}700 701// ─────────────── ۸) افزودن ادمین (فقط مالک)702if (st === "addadmin") {703 if (user.id !== OWNER) { await db.bot.del("wstep:" + user.id); return }704 if (!txt) { return Api.sendMessage({ chat_id: chat.id, text: "👮 آیدی عددی کاربر رو بفرست (مثل 123456789):", reply_markup: NAVKB }) }705 706 let uid = parseInt(txt, 10)707 if (isNaN(uid) || uid < 1000) {708 return Api.sendMessage({ chat_id: chat.id, text: "⚠️ آیدی عددی معتبر بفرست (مثلاً 123456789). دوباره:", reply_markup: NAVKB })709 }710 711 let ads = cfg.admins || []712 if (ads.indexOf(uid) === -1) { ads.push(uid) }713 cfg.admins = ads714 await db.bot.set("cfg", cfg)715 await db.bot.del("wstep:" + user.id)716 717 return Api.sendMessage({718 chat_id: chat.id,719 text: "✅ ادمین <code>" + uid + "</code> اضافه شد.\n(ادمینها به پنل، افزودن آموزش، تیکتها و پیام همگانی دسترسی دارن.)",720 parse_mode: "HTML",721 reply_markup: { inline_keyboard: [[{ text: "👮 لیست ادمینها", callback_data: "adm admins" , style: "primary" }]] }722 })723}724 725// ─────────────── ۹) پیام همگانی (ادمین)726if (isAdmin && st === "bc") {727 if (!txt && !mdId) { return Api.sendMessage({ chat_id: chat.id, text: "📣 متن پیام همگانی رو بفرست (میتونی عکس/ویدیو/فایل هم بفرستی):", reply_markup: NAVKB }) }728 729 await db.bot.set("bc_text", txt)730 if (mdId) { await db.bot.set("bc_media", { type: mdType, file_id: mdId }) } else { await db.bot.del("bc_media") }731 await db.bot.set("bc_time", stamp)732 await db.bot.del("wstep:" + user.id)733 734 let job = await Bot.broadcast({ command: "bc_send", filters: { chatType: "private" } })735 736 return Bot.sendMessage(737 "📣 <b>ارسال همگانی شروع شد!</b>\n\n👥 تعداد کاربران: <b>" + (job ? job.totalTargetChats : "?") + "</b>\n🎫 کد ارسال: <code>" + (job ? job.broadcastId : "—") + "</code>\n\nℹ️ پلتفرم خودش ضدفلاد و بلاکشدهها رو هندل میکنه.",738 { parse_mode: "HTML" }739 )740}741 742// ─────────────── ۱۰) جستوجو (همه)743if (st === "search") {744 if (!txt) { return Api.sendMessage({ chat_id: chat.id, text: "🔎 عبارت جستوجو رو بفرست:", reply_markup: NAVKB }) }745 await db.bot.del("wstep:" + user.id)746 747 let ql = txt.toLowerCase()748 let plist = await db.bot.get("plist", [])749 let scan = plist.slice()750 let data = {}751 for (let ci2 = 0; ci2 < scan.length; ci2 += 30) {752 let ck2 = scan.slice(ci2, ci2 + 30)753 let cp2 = await db.bot.mget(ck2.map(x => "p:" + x))754 if (cp2) { for (let key2 in cp2) { data[key2] = cp2[key2] } }755 }756 757 let hits = []758 for (let id of scan) {759 let p = data["p:" + id]760 if (!p) { continue }761 if (((p.title || "") + " " + (p.desc || "")).toLowerCase().indexOf(ql) !== -1) { hits.push(id) }762 }763 764 if (!hits.length) {765 return Api.sendMessage({766 chat_id: chat.id,767 text: "🔍 برای «" + Libs.tgutil.escapeText(txt, "html") + "» چیزی پیدا نشد.",768 parse_mode: "HTML",769 reply_markup: { inline_keyboard: [[{ text: "📚 همه آموزشها", callback_data: "files 0" , style: "primary" }]] }770 })771 }772 773 hits.reverse()774 let rows = []775 let hitsShown = hits.slice(0, 24)776 for (let id of hitsShown) {777 let p = data["p:" + id]778 let t = p.title ? p.title : "بدون عنوان"779 if (t.length > 32) { t = t.slice(0, 32) + "…" }780 rows.push([{ text: "📄 " + t, callback_data: "dl " + id }])781 }782 rows.push([{ text: "🏠 منوی اصلی", callback_data: "/start" , style: "primary" }])783 784 return Api.sendMessage({785 chat_id: chat.id,786 text: "🔍 <b>نتایج:</b> «" + Libs.tgutil.escapeText(txt, "html") + "» — تعداد: <b>" + hits.length + "</b>" + (hits.length > 24 ? "\n(۲۴ نتیجهی اول — عبارت دقیقتری بنویس)" : ""),787 parse_mode: "HTML",788 reply_markup: { inline_keyboard: rows }789 })790}791 792// ─────────────── ۱۱) لینک دستی پست ریاکشن (ادمین)793if (isAdmin && st === "reactlink") {794 if (!txt) { return Api.sendMessage({ chat_id: chat.id, text: "🔗 لینک پست کانال رو بفرست (مثل https://t.me/mychannel/123):", reply_markup: NAVKB }) }795 796 if (txt === "-") {797 cfg.react_link = ""798 } else if (txt.indexOf("http") === 0) {799 cfg.react_link = txt.slice(0, 300)800 } else {801 return Api.sendMessage({ chat_id: chat.id, text: "⚠️ لینک باید با <code>http</code> شروع بشه. دوباره بفرست یا «-»:", parse_mode: "HTML", reply_markup: NAVKB })802 }803 804 await db.bot.set("cfg", cfg)805 await db.bot.del("wstep:" + user.id)806 return Api.sendMessage({807 chat_id: chat.id,808 text: (cfg.react_link ? "✅ لینک پست ریاکشن ثبت شد:\n" + Libs.tgutil.escapeText(cfg.react_link, "html") : "✅ لینک پاک شد."),809 parse_mode: "HTML",810 reply_markup: { inline_keyboard: [[{ text: "🔐 قفلها", callback_data: "adm gates" , style: "primary" }]] }811 })812}813 814// ─────────────── ۱۲) پیامهای ناشناس815// ادمین → مستقیم پنل (دیگه «متوجه نشدم» نمیگیره)816if (isAdmin) {817 await Api.sendMessage({ chat_id: chat.id, text: "🛠 پنل مدیریت رو باز کردم 👇", reply_markup: NAVOFF })818 return Bot.run({ command: "adm", ignoreMissingCommand: true })819}820 821// کاربری که تیکت باز داره → وضعیت پشتیبانی822let tid3 = await db.bot.get("tu:" + user.id, null)823let tk3 = tid3 ? await db.bot.get("tkt:" + tid3, null) : null824if (tk3 && tk3.status !== "closed") {825 let stateTx = (tk3.status === "answered" ? "✅ پاسخ پشتیبانی اومده — پیامها رو ببین" : "📞 منتظر پاسخ پشتیبانی هستیم")826 return Api.sendMessage({827 chat_id: chat.id,828 text: "🎫 <b>تیکت #" + tid3 + "</b>\n\n" + stateTx + "\n\nاگه حرف جدیدی داری، به همین تیکت اضافه کن 👇",829 parse_mode: "HTML",830 reply_markup: {831 inline_keyboard: [832 [{ text: "📝 پیام جدید به پشتیبانی", callback_data: "support new" , style: "danger" }],833 [{ text: "📚 آموزشها", callback_data: "files 0" , style: "primary" }, { text: "🏠 منو", callback_data: "/start" , style: "primary" }]834 ]835 }836 })837}838 839// کاربر عادی840Api.sendMessage({841 chat_id: chat.id,842 text: "🔎 چیزی که دنبالش بودی پیدا نشد.\n\nاز دکمههای زیر استفاده کن یا /start بزن 👇",843 reply_markup: {844 inline_keyboard: [845 [{ text: "📚 آموزشها", callback_data: "files 0" , style: "primary" }],846 [{ text: "👤 پروفایل من", callback_data: "profile" , style: "primary" }, { text: "❓ راهنما", callback_data: "help" , style: "primary" }],847 [{ text: "📞 پشتیبانی", callback_data: "support" , style: "danger" }, { text: "🏠 منوی اصلی", callback_data: "/start" , style: "primary" }]848 ]849 }850})