دليل احترافي لإنشاء بوت ديسكورد باستخدام JavaScript واستضافته مجانًا

دقائق القراءة: 8

مقدمة: لماذا إنشاء بوت Discord باستخدام JavaScript؟

إذا كنت ترغب في بناء بوت خاص بك على منصة Discord دون تثبيت أدوات معقدة على جهازك، فهذه المقالة تقدم لك مسارًا عمليًا وواضحًا. ستتعلم كيفية استخدام JavaScript مع Node.js لإنشاء بوت يعمل سحابيًا بالكامل، مع إمكانية استضافته مجانًا وتشغيله على مدار الوقت.

يعتمد هذا الدليل على مجموعة أدوات مهمة، مثل Discord API، ومكتبة discord.js، ومنصة Replit للتطوير السحابي. والهدف هنا ليس مجرد نقل خطوات تقنية، بل تقديم شرح عربي احترافي يسهل تطبيقه ويضيف قيمة حقيقية للمطور والمستخدم.

شرح إنشاء بوت ديسكورد باستخدام جافاسكربت وNode.js مع استضافة مجانية

كيفية إنشاء حساب بوت على Discord

قبل كتابة أي سطر برمجي، يجب أولًا إنشاء تطبيق وبوت رسمي داخل منصة Discord. هذه الخطوة تمنحك رمز الوصول Token الذي يستخدمه البرنامج لتسجيل الدخول وتشغيل البوت.

خطوات إنشاء البوت

  1. سجّل الدخول إلى موقع Discord.
  2. انتقل إلى صفحة التطبيقات Developer Portal.
  3. اضغط على زر New Application.
  4. اكتب اسمًا مناسبًا للتطبيق ثم اضغط Create.
  5. افتح تبويب Bot ثم اختر Add Bot.
  6. أكّد العملية بالضغط على Yes, do it!.

زر إنشاء تطبيق جديد في بوابة مطوري ديسكوردتسمية تطبيق ديسكورد الجديد قبل إنشاء البوتإضافة بوت جديد داخل إعدادات تطبيق ديسكورد

من الأفضل الإبقاء على الإعدادات الافتراضية، مثل تفعيل Public Bot وتعطيل Require OAuth2 Code Grant إذا لم تكن بحاجة إلى إعدادات متقدمة.

بعد إنشاء البوت، انسخ Token الخاص به. هذا الرمز بمنزلة كلمة مرور للبوت، لذا يجب عدم مشاركته مع أي شخص. وإذا تم تسريبه، يمكنك توليد رمز جديد فورًا.

نسخ رمز التوكن الخاص ببوت ديسكورد بعد إنشائه

كيفية دعوة البوت إلى السيرفر

إنشاء البوت وحده لا يكفي، بل يجب إضافته إلى السيرفر الذي تريد أن يعمل بداخله.

توليد رابط الدعوة

  1. انتقل إلى تبويب OAuth2.
  2. ضمن قسم Scopes اختر bot.
  3. حدّد الصلاحيات المناسبة لعمل البوت.
  4. انسخ الرابط الناتج، ثم افتحه في المتصفح.
  5. اختر السيرفر المطلوب، ثم اضغط Authorize.

اختيار نطاق bot في إعدادات OAuth2 داخل ديسكوردتحديد صلاحيات بوت ديسكورد قبل إضافته إلى السيرفر

احرص على منح البوت أقل قدر ممكن من الصلاحيات، خاصة إذ كنت لا تحتاج إلى صلاحية Administrator. هذه الممارسة تعزز الأمان وتقلل المخاطر.

إعداد بيئة التطوير باستخدام Replit وdiscord.js

يمكنك تطوير البوت محليًا على جهازك، لكن استخدام Replit يجعل التجربة أسهل، لأنه يوفر محررًا سحابيًا، وتثبيتًا تلقائيًا للحزم، وإمكانية تشغيل المشروع مباشرة من المتصفح.

خطوات البدء

  1. انتقل إلى منصة Replit.
  2. أنشئ مشروعًا جديدًا واختر بيئة Node.js.
  3. افتح الملف main.js أو index.js بحسب بنية المشروع.
  4. أضف استيراد مكتبة discord.js.

بمجرد الضغط على زر التشغيل، ستقوم المنصة غالبًا بتثبيت التبعيات تلقائيًا.

كتابة أول بوت Discord بلغة JavaScript

تعتمد مكتبة discord.js على مفهوم الأحداث Events. أي إن البوت يستمع إلى مواقف معينة، مثل بدء التشغيل أو وصول رسالة جديدة، ثم يتفاعل معها.

كود بوت بسيط للرد على رسالة ping

const Discord = require("discord.js");
const client = new Discord.Client();

client.on("ready", () => {
  console.log(`Logged in as ${client.user.tag}!`);
});

client.on("message", msg => {
  if (msg.content === "ping") {
    msg.reply("pong");
  }
});

client.login(process.env.TOKEN);

تخزين رمز البوت داخل ملف .env

حتى لا تضع بيانات حساسة داخل الشيفرة مباشرة، أنشئ ملفًا باسم .env وأضف داخله السطر التالي:

TOKEN=[paste token here]

يستخدم هذا الملف لتخزين متغيرات البيئة Environment Variables. وفي Replit يعد هذا الأسلوب أكثر أمانًا من كتابة الرمز مباشرة داخل الكود.

كيف يعمل هذا الكود؟

  • require("discord.js"): يستورد المكتبة المسؤولة عن التعامل مع Discord API.
  • new Discord.Client(): ينشئ اتصال البوت مع منصة ديسكورد.
  • client.on("ready"): ينفذ كودًا عند نجاح تشغيل البوت.
  • client.on("message"): يستمع إلى الرسائل الجديدة في القنوات.
  • msg.reply("pong"): يرسل ردًا مباشرًا على المستخدم.
  • client.login(process.env.TOKEN): يسجّل دخول البوت عبر الرمز المحفوظ.

تشغيل البوت واختباره

بعد تشغيل المشروع من داخل Replit، انتقل إلى السيرفر في Discord واكتب ping. إذا كان كل شيء صحيحًا، فسيقوم البوت بالرد بكلمة pong.

اختبار بوت ديسكورد والرد على أمر ping داخل القناة

تطوير البوت: جلب اقتباسات تحفيزية عبر API

الآن سننتقل من بوت بسيط إلى بوت أكثر فائدة. سنضيف أمرًا باسم $inspire ليجلب اقتباسًا تحفيزيًا عشوائيًا من خدمة خارجية.

الكود بعد إضافة node-fetch

const Discord = require("discord.js");
const fetch = require("node-fetch");
const client = new Discord.Client();

function getQuote() {
  return fetch("https://zenquotes.io/api/random")
    .then(res => {
      return res.json();
    })
    .then(data => {
      return data[0]["q"] + " -" + data[0]["a"];
    });
}

client.on("ready", () => {
  console.log(`Logged in as ${client.user.tag}!`);
});

client.on("message", msg => {
  if (msg.author.bot) return;
  if (msg.content === "$inspire") {
    getQuote().then(quote => msg.channel.send(quote));
  }
});

client.login(process.env.TOKEN);

فائدة هذه الإضافة

  • استخدام node-fetch لإجراء طلب HTTP.
  • جلب بيانات من خدمة zenquotes.io.
  • تحويل الاستجابة إلى صيغة JSON.
  • إرسال الاقتباس إلى القناة عند كتابة الأمر $inspire.

التحقق من msg.author.bot يمنع البوت من الرد على نفسه أو على بوتات أخرى، وهي خطوة مهمة لتجنب الحلقات غير المنتهية.

إضافة رسائل تشجيعية عند اكتشاف كلمات حزينة

يمكن جعل البوت أكثر تفاعلًا من خلال تحليل محتوى الرسائل والرد برسائل تشجيعية عندما يلاحظ كلمات سلبية أو حزينة.

تعريف الكلمات الحزينة والرسائل التشجيعية

const sadWords = ["sad", "depressed", "unhappy", "angry", "miserable"];
const encouragements = [
  "Cheer up!",
  "Hang in there.",
  "You are a great person / bot!"
];

تحديث حدث الرسائل

client.on("message", msg => {
  if (msg.content === "$inspire") {
    getQuote().then(quote => msg.channel.send(quote));
  }

  if (sadWords.some(word => msg.content.includes(word))) {
    const encouragement = encouragements[Math.floor(Math.random() * encouragements.length)];
    msg.reply(encouragement);
  }
});

في هذا الجزء يتم فحص الرسالة باستخدام some() لمعرفة ما إذا كانت تحتوي على أي كلمة من القائمة sadWords. وعند تحقق الشرط، يختار البوت رسالة عشوائية من المصفوفة encouragements.

تخزين الرسائل المضافة من المستخدمين باستخدام قاعدة بيانات Replit

إذا أردت أن تسمح للمستخدمين بإضافة رسائل تشجيعية جديدة مباشرة من داخل الدردشة، فستحتاج إلى تخزين هذه البيانات في قاعدة بسيطة. هنا تأتي فائدة حزمة @replit/database.

ربط قاعدة البيانات

const Database = require("@replit/database");
const db = new Database();

تهيئة الرسائل الافتراضية

db.get("encouragements").then(encouragements => {
  if (!encouragements || encouragements.length < 1) {
    db.set("encouragements", starterEncouragements);
  }
});

هنا يتم فحص وجود مفتاح encouragements داخل قاعدة البيانات. وإذا لم يكن موجودًا، تُخزن الرسائل الافتراضية تلقائيًا.

دوال إضافة الرسائل وحذفها

function updateEncouragements(encouragingMessage) {
  db.get("encouragements").then(encouragements => {
    encouragements.push([encouragingMessage]);
    db.set("encouragements", encouragements);
  });
}

function deleteEncouragment(index) {
  db.get("encouragements").then(encouragements => {
    if (encouragements.length > index) {
      encouragements.splice(index, 1);
      db.set("encouragements", encouragements);
    }
  });
}

وظيفة updateEncouragements() تضيف رسالة جديدة إلى القائمة، بينما تقوم deleteEncouragment() بحذف عنصر بناءً على رقمه.

إضافة أوامر $new و$del و$list

بعد توصيل قاعدة البيانات، يمكن تطوير البوت ليستقبل أوامر جديدة من المستخدمين.

تحديث منطق الرسائل

client.on("message", msg => {
  if (msg.content === "$inspire") {
    getQuote().then(quote => msg.channel.send(quote));
  }

  if (sadWords.some(word => msg.content.includes(word))) {
    db.get("encouragements").then(encouragements => {
      const encouragement = encouragements[Math.floor(Math.random() * encouragements.length)];
      msg.reply(encouragement);
    });
  }

  if (msg.content.startsWith("$new")) {
    encouragingMessage = msg.content.split("$new ")[1];
    updateEncouragements(encouragingMessage);
    msg.channel.send("New encouraging message added.");
  }

  if (msg.content.startsWith("$del")) {
    index = parseInt(msg.content.split("$del ")[1]);
    deleteEncouragment(index);
    msg.channel.send("Encouraging message deleted.");
  }
}

شرح الأوامر

  • $new: يضيف رسالة تشجيعية جديدة بعد الأمر.
  • $del: يحذف رسالة حسب رقم الفهرس.
  • يمكن استخدام split() لاستخراج الجزء المطلوب من نص الرسالة.

مثلًا، عند كتابة $new أنت قادر على تجاوز هذه المرحلة، سيقوم البوت بحفظ هذه العبارة لاستخدامها لاحقًا.

النسخة النهائية من البوت مع التحكم في التفاعل

في النسخة النهائية سنضيف ميزتين مهمتين:

  • عرض قائمة الرسائل التشجيعية بالأمر $list.
  • تشغيل أو إيقاف الرد على الكلمات الحزينة بالأمر $responding.
const Discord = require("discord.js");
const fetch = require("node-fetch");
const Database = require("@replit/database");
const db = new Database();
const client = new Discord.Client();

const sadWords = ["sad", "depressed", "unhappy", "angry", "miserable"];
const starterEncouragements = [
  "Cheer up!",
  "Hang in there.",
  "You are a great person / bot!"
];

db.get("encouragements").then(encouragements => {
  console.log(encouragements);
  if (!encouragements || encouragements.length < 1) {
    db.set("encouragements", starterEncouragements);
  }
});

db.get("responding").then(value => {
  if (value == null) {
    db.set("responding", true);
  }
});

function getQuote() {
  return fetch("https://zenquotes.io/api/random")
    .then(res => {
      return res.json();
    })
    .then(data => {
      return data[0]["q"] + " -" + data[0]["a"];
    });
}

function updateEncouragements(encouragingMessage) {
  db.get("encouragements").then(encouragements => {
    encouragements.push([encouragingMessage]);
    db.set("encouragements", encouragements);
  });
}

function deleteEncouragment(index) {
  db.get("encouragements").then(encouragements => {
    if (encouragements.length > index) {
      encouragements.splice(index, 1);
      db.set("encouragements", encouragements);
    }
  });
}

client.on("ready", () => {
  console.log(`Logged in as ${client.user.tag}!`);
});

client.on("message", msg => {
  if (msg.content === "$inspire") {
    getQuote().then(quote => msg.channel.send(quote));
  }

  db.get("responding").then(responding => {
    if (responding && sadWords.some(word => msg.content.includes(word))) {
      db.get("encouragements").then(encouragements => {
        const encouragement = encouragements[Math.floor(Math.random() * encouragements.length)];
        msg.reply(encouragement);
      });
    }
  });

  if (msg.content.startsWith("$new")) {
    encouragingMessage = msg.content.split("$new ")[1];
    updateEncouragements(encouragingMessage);
    msg.channel.send("New encouraging message added.");
  }

  if (msg.content.startsWith("$del")) {
    index = parseInt(msg.content.split("$del ")[1]);
    deleteEncouragment(index);
    msg.channel.send("Encouraging message deleted.");
  }

  if (msg.content.startsWith("$list")) {
    db.get("encouragements").then(encouragements => {
      msg.channel.send(encouragements);
    });
  }

  if (msg.content.startsWith("$responding")) {
    value = msg.content.split("$responding ")[1];
    if (value.toLowerCase() == "true") {
      db.set("responding", true);
      msg.channel.send("Responding is on.");
    } else {
      db.set("responding", false);
      msg.channel.send("Responding is off.");
    }
  }
});

client.login(process.env.TOKEN);

أهمية مفتاح responding

يسمح هذا المفتاح بالتحكم في سلوك البوت دون تعديل الشيفرة. فإذا أرسل المستخدم الأمر $responding true سيُفعّل الردود، وإذا أرسل $responding false ستتوقف.

تشغيل البوت باستمرار مجانًا

من أكبر التحديات في الاستضافة المجانية أن المشروع قد يتوقف عند إغلاق التبويب أو بعد فترة من عدم النشاط. ولحل هذه المشكلة، يمكن الجمع بين خادم ويب بسيط وخدمة خارجية للمراقبة.

الطريقة الأولى: خطة مدفوعة في Replit

إذا كنت تريد حلًا مباشرًا وسهلًا، يمكنك استخدام خيار Always On ضمن الخطط المدفوعة في Replit. هذه الطريقة مناسبة لمن يريد استقرارًا أعلى دون إعدادات إضافية.

تفعيل خيار التشغيل المستمر Always On في منصة Replit

الطريقة الثانية: إنشاء خادم ويب واستخدام Uptime Robot

في الخطة المجانية، يمكن إبقاء المشروع نشطًا من خلال إنشاء خادم ويب بسيط يتلقى طلبات دورية كل عدة دقائق.

إنشاء الملف server.js

const express = require("express");
const server = express();

server.all("/", (req, res) => {
  res.send("Bot is running!");
});

function keepAlive() {
  server.listen(3000, () => {
    console.log("Server is ready.");
  });
}

module.exports = keepAlive;

استيراد الخادم داخل الملف الرئيسي

const keepAlive = require("./server");

ثم أضف الاستدعاء التالي قبل تسجيل دخول البوت:

keepAlive()

بعد التشغيل، سيظهر لك رابط خاص بخادم الويب، وهذا الرابط ستحتاج إليه في الخطوة التالية.

ظهور رابط خادم الويب داخل مشروع Replit لتشغيل البوت باستمرار

إعداد Uptime Robot للحفاظ على تشغيل البوت

خدمة Uptime Robot مجانية وتسمح بإرسال طلبات دورية إلى رابط الخادم، وبذلك يظل المشروع مستيقظًا ولا يدخل في وضع السكون.

خطوات الإعداد

  1. أنشئ حسابًا مجانيًا على https://uptimerobot.com/.
  2. بعد تسجيل الدخول، اضغط Add New Monitor.
  3. اختر نوع المراقبة HTTP(s).
  4. ضع اسمًا مناسبًا للخدمة.
  5. ألصق رابط الخادم الخاص بمشروعك.
  6. احفظ الإعداد بالضغط على Create Monitor.

إضافة مراقب جديد في خدمة Uptime Robotإعداد مراقبة HTTP في Uptime Robot لرابط مشروع Replit

أفضل ممارسات لتحسين جودة البوت والمقال تقنيًا

  • احفظ جميع البيانات الحساسة مثل Token داخل .env.
  • لا تمنح البوت صلاحيات أكبر من حاجته الفعلية.
  • اختبر الأوامر واحدة تلو الأخرى قبل إضافة ميزات جديدة.
  • استخدم أسماء أوامر واضحة وسهلة التذكر مثل $list و$new.
  • إذا كان مشروعك سيتوسع، ففكر لاحقًا في تنظيم الكود داخل ملفات متعددة.

الخلاصة التقنية

إنشاء بوت Discord باستخدام JavaScript لم يعد مهمة معقدة، خصوصًا مع وجود مكتبات مثل discord.js ومنصات سحابية مثل Replit. القيمة الحقيقية لا تكمن فقط في تشغيل البوت، بل في فهم بنية الأحداث، وإدارة الأوامر، والتعامل مع API وقواعد البيانات البسيطة. إذا أتقنت هذا النموذج، فستكون قادرًا على تطوير بوتات أكثر تقدمًا تشمل أنظمة ترحيب، وإدارة أعضاء، وردودًا ذكية، وتكاملات خارجية أوسع. من الناحية التقنية، هذا المشروع يعد نقطة انطلاق ممتازة لأي مطور يريد الدخول إلى عالم الأتمتة المجتمعية داخل Discord.

اترك تعليقاً

لن يتم نشر عنوان بريدك الإلكتروني. الحقول الإلزامية مشار إليها بـ *