1- مقدمة
هل تريد الانضمام إلى مكالمة على Meet ولكنك لا تريد أن تكون أول من يفعل ذلك؟ إذا كان هذا يصفك، لدينا الحلّ المناسب لك.
باتّباع هذا الدرس التطبيقي، ستنشئ إضافة Chrome تنبّهك عندما ينضم أول مشارك إلى المكالمة.
ستتعرّف على العناصر المختلفة لإضافة Chrome، ثم ستتعمّق في كل جزء من الإضافة. ستتعرّف على وظائف الإضافة، مثل النصوص البرمجية للمحتوى والعاملين في الخلفية وتمرير الرسائل.
عليك الالتزام بـ إصدار البيان V3 لتلقّي إشعار في كل مرة ينضم فيها مشارك إلى مكالمة على Meet.
2. قبل البدء
المتطلبات الأساسية
على الرغم من أنّ هذا الدرس التطبيقي حول الترميز مناسب للمبتدئين، فإنّ امتلاك فهم أساسي للغة JavaScript يمكن أن يحسّن تجربتك إلى حد كبير.
الإعداد/المتطلبات
- متصفح Chrome
- بيئة تطوير متكاملة/محرّر تم إعداده على نظامك المحلي
- تثبيت واجهة سطر الأوامر gcloud إذا أردت تفعيل Gemini API باستخدام gcloud
تفعيل Gemini API
- في Google Cloud Console، في صفحة اختيار المشروع، اختَر مشروع Google Cloud أو أنشِئ مشروعًا.
- تأكَّد من تفعيل الفوترة لمشروعك على السحابة الإلكترونية. كيفية التحقّق مما إذا كانت الفوترة مفعَّلة في مشروع .
- انتقِل إلى صفحة Gemini Marketplace لتفعيل واجهة برمجة التطبيقات. يمكنك أيضًا استخدام gcloud لتفعيل واجهة برمجة التطبيقات:
gcloud services enable cloudaicompanion.googleapis.com --project PROJECT_ID - انتقِل إلى صفحة Gemini for Cloud Console في علامة تبويب جديدة وانقر على "بدء المحادثة".
Note that if you're writing the code in the Cloud Shell editor, then you will have to download the folder somewhere on your local filesystem to test the extension locally.
3- فلنبدأ اللعب
التثبيت الأساسي للإضافة
لننشئ دليلًا سنستخدمه كجذر لمشروعنا.
mkdir gemini-chrome-ext
cd gemini-chrome-ext
قبل أن نبدأ بطرح أسئلة محدّدة على Gemini، لنطرح بعض الأسئلة حول البنية العامة لإضافة Chrome.
الطلب:
What are the important parts to build a chrome extension?
نتلقّى ردًا يحدّد تفاصيل بسيطة حول ملف manifest وbackground script وتفاصيل حول واجهة المستخدم. لننتقل إلى مزيد من التفاصيل حول هذه الملفات المحدّدة.
الطلب:
Create a manifest.json file to build a chrome extension. Make the name of the extension "Meet Joinees Notifier" and the author "<YOUR_EMAIL>"
يمكنك استخدام الاسم الذي تريده وعنوان بريدك الإلكتروني في حقل المؤلف.
يعرض Gemini محتويات ملف البيان التي نحتاج إليها، ولكن نحصل على بعض الحقول الإضافية التي لن نحتاج إليها، مثل حقل action. نحتاج أيضًا إلى وصف. لنصلح ذلك.
الطلب:
Remove the "action" field and make the description as "Adds the ability to receive a notification when a participant joins a Google meet".
لنضع هذا المحتوى في ملف manifest.json في جذر مشروعك.
في هذه المرحلة، يجب أن يبدو ملف البيان على النحو التالي:
{
"name": "Meet Joinees Notifier",
"version": "1.0",
"manifest_version": 3,
"description": "Adds the ability to receive a notification when a participant joins a Google Meet",
"author": "<YOUR_EMAIL>"
}
أزِل أي حقول إضافية أخرى تم إنشاؤها في ملف البيان في الوقت الحالي لأنّ هذا الدرس التطبيقي حول الترميز يفترض وجود هذه الحقول في ملف البيان.
الآن، كيف نختبر ما إذا كانت الإضافة تعمل؟ لنطرح السؤال على صديقنا Gemini.
الطلب:
Guide me on the steps needed to test a chrome extension on my local filesystem.
يقدّم لي بعض الخطوات حول كيفية اختبارها. لننتقل إلى "Extensions Page" من خلال الانتقال إلى chrome://extensions وتأكَّد من تفعيل الزر "Developer Mode"، الذي من المفترض أن يكشف عن الزر "Load unpacked"، الذي يمكننا استخدامه للانتقال إلى المجلد الذي يحتوي على ملفات الإضافة محليًا. بعد إجراء ذلك، من المفترض أن نتمكّن من رؤية الإضافة في "Extensions Page".


رائع! يمكننا رؤية الإضافة، ولكن لنبدأ بإضافة بعض الوظائف.
4. إضافة نص برمجي للمحتوى
نريد تشغيل بعض رموز JavaScript البرمجية على https://meet.google.com فقط، ويمكننا إجراء ذلك باستخدام النصوص البرمجية للمحتوى. لنسأل Gemini، كيف نحقق ذلك في الإضافة.
الطلب:
How to add a content script in our chrome extension?
أو بشكل أكثر تحديدًا:
الطلب:
How to add a content script to run on meet.google.com subdomain in our chrome extension?
أو إصدار آخر:
الطلب:
Help me add a content script named content.js to run on meet.google.com subdomain in our chrome extension. The content script should simply log "Hello Gemini" when we navigate to "meet.google.com".
يقدّم لنا Gemini التغييرات الدقيقة التي نحتاج إلى إجرائها في ملف manifest.json ورمز JavaScript الذي نحتاج إليه في ملف content.js.
بعد إضافة content_scripts، يصبح ملف البيان على النحو التالي:
{
"name": "Meet Joinees Notifier",
"version": "1.0",
"manifest_version": 3,
"description": "Adds the ability to receive a notification when a participant joins a Google Meet",
"author": "abc@example.com",
"content_scripts": [
{
"matches": ["https://meet.google.com/*"],
"js": ["content.js"]
}
]
}
يطلب هذا من Chrome إدخال النص البرمجي للمحتوى content.js كلما انتقلنا إلى صفحة في النطاق الفرعي " https://meet.google.com". لنضِف هذا الملف ونختبره.
لنضِف هذا الرمز في ملف content.js.
console.log("Hello Gemini");
بالتأكيد! عندما ننتقل إلى meet.google.com، نرى "Hello Gemini" في وحدة تحكّم JavaScript(في نظام التشغيل Mac: Cmd + Opt + J / في نظام التشغيل Windows/Linux: Ctrl + Shift + J).
manifest.json
{
"name": "Meet Joinees Notifier",
"version": "1.0",
"manifest_version": 3,
"description": "Adds the ability to receive a notification when a participant joins a Google Meet",
"author": "luke@cloudadvocacyorg.joonix.net",
"permissions": [
"tabs",
"notifications"
],
"content_scripts": [
{
"matches": [
"https://meet.google.com/*"
],
"js": [
"content.js"
]
}
]
}
content.js
console.log("Hello Gemini!");


رائع! الآن، يمكننا إضافة بعض الوظائف الخاصة بـ JavaScript إلى تطبيقنا. لنأخذ لحظة ونفكر في ما نحاول تحقيقه.
تحسين النص البرمجي للمحتوى
نريد أن نتمكّن من تلقّي إشعار عندما ينضم شخص إلى اجتماع عندما نكون في صفحة الاجتماع(حيث يتوفّر لنا خيار الانضمام إلى الاجتماع). لتحقيق ذلك، لنراقب كيف يتغيّر شكل الشاشة مرئيًا عندما يكون الاجتماع فارغًا مقابل عندما ينضم شخص إلى الاجتماع.
هذا هو الشكل عندما لا يكون هناك أحد في الاجتماع.

في المقابل، هذه هي العناصر المرئية عندما يكون هناك بعض المشاركين في الاجتماع.

يمكننا ملاحظة اختلافَين ملحوظَين على الفور:
- يتغيّر نص الحالة من "لا يوجد أحد آخر هنا" إلى "[اسم المستخدم] في هذه المكالمة".
- يمكننا رؤية صور المستخدمين الذين انضموا إلى المكالمة.
ستكون كلتا هاتَين التغييرَين مفيدتَين لنا إذا أردنا معرفة ما إذا انضم أي شخص إلى الاجتماع، ولكن الأخير يتيح بعض الإمكانيات للحصول على معلومات عن المستخدمين الذين انضموا بالفعل، لذا لنحاول استخدام ذلك.
افتح "أداة فحص العناصر" في Chrome باستخدام مفتاح الاختصار ( في نظام التشغيل Mac: Cmd + Opt + C / Win: Ctrl + Shift + C)، ثم انقر على صورة المستخدم الذي انضم.
يمكننا ملاحظة وجود صورة تحتوي على بعض سلاسل الفئات، ويحتوي السمة title للصورة على اسم المستخدم الذي انضم إلى الاجتماع. علاوةً على ذلك، يتم تضمين علامة الصورة هذه في عنصر div مع الفئة U04fid. بعد إضافة بعض المشاركين إلى اجتماعنا التجريبي، يمكننا ملاحظة أنّ عنصر div الرئيسي هذا يستضيف صورًا متعددة(تتوافق مع مستخدمين مختلفين).
لذا، لدينا استراتيجية جزئية في أذهاننا:
- رصد متى يحتوي عنصر div الذي يحمل الفئة
U04fidعلى أي عناصر - إذا كان الأمر كذلك، يعني ذلك أنّ لدينا مشاركين في اجتماعنا.
- إشعار المستخدم
لنرجع إلى Gemini ونسأله عن كيفية تحقيق ذلك خطوةً بخطوة.
الطلب:
How to detect for element changes in the HTML page?
يقدّم لنا Gemini حلاً يتضمّن MutationObserver، ولكن لا يقدّم أي شيء محدّدًا لمتطلباتنا، لذا لنحاول تعديل الطلب.
الطلب:
How can I detect if an element "div.U04fid" has any child images in the HTML page?
في هذه المرة، نحصل على حلّ لا يتضمّن MutationObserver، ولكنّه حلّ يتحقّق من المشاركين باستخدام عنصر div الرئيسي.
هذا ما تلقّيناه:
const divU04fid = document.querySelector('div.U04fid');
const childImages = divU04fid.querySelectorAll('img');
if (childImages.length > 0) {
// div.U04fid has at least one child image.
}
لنحاول تعديل طريقتنا بشكل أكبر:
الطلب:
Create a method which checks if the element div.U04fid has any child elements, if it does it should log it on the console. The method should be called checkJoinees and it should be called as a callback for MutationObserver which is observing the document.body.
يعرض Gemini مقتطف الرمز البرمجي التالي:
function checkJoinees(mutations) {
for (const mutation of mutations) {
if (mutation.type === 'childList') {
// A child node was added or removed.
if (document.querySelector('div.U04fid') && document.querySelector('div.U04fid').childElementCount > 0) {
// div.U04fid has at least one child element.
console.log('div.U04fid has at least one child element.');
}
}
}
return false;
}
const observer = new MutationObserver(checkJoinees);
observer.observe(document.body, {
childList: true,
delay: 1000
});
انسخ هذا الرمز في ملف content.js، وأعِد تحميل الإضافة(ثم أعِد تحميل صفحة Meet).
الآن، عندما ينضم شخص إلى اجتماعنا، يمكننا رؤية عبارة السجلّ في وحدة التحكّم.
5. إرسال إشعار إلى المستخدم
بعد أن أصبحنا قادرين على رصد انضمام أحد المشاركين إلى الاجتماع، لنحاول إضافة جزء الإشعار في إضافة Chrome. يمكننا تصفّح مستندات إضافة Chrome أو حتى تعديل الطلبات لمعرفة ما نبحث عنه، ولكننا نحتاج بشكل أساسي إلى استخدام chrome.notifications.create API ويجب أن يكون استدعاء هذا الإجراء من مشغّل خدمات في الخلفية.
الطلب:
Using the documentation for chrome notifications tell me how to use the chrome.notifications.create method.
نرى بعض الخطوات التفصيلية مع أهم النقاط البارزة:
- إضافة الإذن
notificationsفي ملف البيان - إجراء استدعاء إلى chrome.notifications.create
- يجب أن يكون الاستدعاء في نص برمجي في الخلفية.
لإضافة نص برمجي في الخلفية إلى إضافة Chrome في manifest version 3، نحتاج إلى الإعلان background.service_worker في ملف manifest.json.
لذا، لننشئ ملفًا باسم background.js ونضِف ما يلي إلى ملف manifest.json.
"background": {
"service_worker": "background.js"
},
"permissions": [
"notifications"
]
بعد إضافة ما سبق، يصبح ملف البيان على النحو التالي:
{
"name": "Meet Joinees Notifier",
"version": "1.0",
"manifest_version": 3,
"description": "Adds the ability to receive a notification when a participant joins a Google Meet",
"author": "<YOUR_EMAIL>",
"content_scripts": [
{
"matches": ["https://meet.google.com/*"],
"js": ["content.js"]
}
],
"background": {
"service_worker": "background.js"
},
"permissions": [
"notifications"
]
}
الطلب:
Create a method sendNotification that calls the chrome.notifications.create method with the message, "A user joined the call" for a chrome extension with manifest v3, the code is in the background service worker
احفظ هذه الصورة في جذر مجلدك وأعِد تسميتها إلى success.png.

بعد ذلك، أضِف مقتطف الرمز البرمجي التالي إلى background.js.
function sendNotification(notificationId, message) {
chrome.notifications.create(notificationId, {
type: "basic",
title: "A user joined the call",
message: message,
iconUrl: "./success.png"
});
}
sendNotification("notif-id", "test message");
الآن، أعِد تحميل الإضافة من صفحة الإضافات، ومن المفترض أن تظهر لك نافذة منبثقة للإشعار على الفور.
6. إضافة تمرير الرسائل في إضافة Chrome
الآن، آخر خطوة رئيسية نحتاج إليها هي ربط رصد النص البرمجي للمحتوى لمشارك وطريقة sendNotification في النص البرمجي في الخلفية. في سياق إضافات Chrome، تتمثل طريقة إجراء ذلك في تقنية تُعرف باسم message passing.
يتيح ذلك التواصل بين أجزاء مختلفة من إضافة Chrome، في حالتنا من النص البرمجي للمحتوى إلى مشغّل الخدمات الذي يعمل في الخلفية. لنطرح على صديقنا Gemini سؤالًا حول كيفية تحقيق ذلك.
الطلب:
How to send a message from the content script to the background script in a chrome extension
يردّ Gemini باستدعاءات ذات صلة لـ chrome.runtime.sendMessage وchrome.runtime.onMessage.addListener.
سنستخدم بشكل أساسي sendMessage لإرسال رسالة من النص البرمجي للمحتوى تفيد بانضمام شخص إلى مكالمة على Meet، وonMessage.addListener كمتتبِّع للأحداث للردّ على الرسالة التي أرسلها النص البرمجي للمحتوى. في هذه الحالة، سنفعِّل استدعاء طريقة sendNotification من متتبِّع الأحداث هذا.
سنمرِّر رسالة الإشعار وسمة action إلى مشغّل الخدمات الذي يعمل في الخلفية. تصف السمة action ما يردّ عليه النص البرمجي في الخلفية.
إليك رمز content.js البرمجي:
function checkJoinees(mutations) {
for (const mutation of mutations) {
if (mutation.type === 'childList') {
// A child node was added or removed.
if (document.querySelector('div.U04fid') && document.querySelector('div.U04fid').childElementCount > 0) {
// div.U04fid has at least one child element.
sendMessage();
}
}
}
return false;
}
const observer = new MutationObserver(checkJoinees);
observer.observe(document.body, {
childList: true,
delay: 1000
});
function sendMessage() {
chrome.runtime.sendMessage({
txt: "A user has joined the call!",
action: "people_joined"
});
}
وهذا هو رمز background.js البرمجي:
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
if (message.action === "people_joined") {
sendNotification("notif-id", message.txt);
}
});
function sendNotification(notificationId, message) {
chrome.notifications.create(notificationId, {
type: "basic",
title: "A user joined the call",
message: message,
iconUrl: "./success.png"
});
}
لنحاول تخصيص رسالة الإشعار والحصول على معرّف إشعار فريد. بالنسبة إلى رسالة الإشعار، يمكننا تضمين اسم المستخدم. إذا تذكرنا من خطوة سابقة، يمكننا رؤية اسم المستخدم في السمة title للصورة. لذا، يمكننا جلب اسم المشارك باستخدام document.querySelector('div.U04fid > img').getAttribute('title').
في ما يتعلق بمعرّف الإشعار، يمكننا جلب معرّف علامة التبويب للنص البرمجي للمحتوى واستخدامه كمعرّف إشعار. يمكن إجراء ذلك داخل متتبِّع الأحداث chrome.runtime.onMessage.addListener باستخدام sender.tab.id.
أخيرًا، يجب أن تبدو ملفاتنا على النحو التالي:
manifest.json
{
"name": "Meet Joinees Notifier",
"version": "1.0",
"manifest_version": 3,
"description": "Adds the ability to receive a notification when a participant joins a Google Meet",
"author": "<YOUR_EMAIL>",
"content_scripts": [
{
"matches": ["https://meet.google.com/*"],
"js": ["content.js"]
}
],
"background": {
"service_worker": "background.js"
},
"permissions": [
"notifications"
]
}
content.js
function checkJoinees(mutations) {
for (const mutation of mutations) {
if (mutation.type === 'childList') {
// A child node was added or removed.
if (document.querySelector('div.U04fid') && document.querySelector('div.U04fid').childElementCount > 0) {
const name = document.querySelector('div.U04fid > img').getAttribute('title');
sendMessage(name);
}
}
}
return false;
}
const observer = new MutationObserver(checkJoinees);
observer.observe(document.body, {
childList: true,
delay: 1000
});
function sendMessage(name) {
const joinee = (name === null ? 'Someone' : name),
txt = `${joinee} has joined the call!`;
chrome.runtime.sendMessage({
txt,
action: "people_joined",
});
}
background.js
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
if (message.action === "people_joined") {
sendNotification("" + sender.tab.id, message.txt); // We are casting this to string as notificationId is expected to be a string while sender.tab.id is an integer.
}
});
function sendNotification(notificationId, message) {
chrome.notifications.create(notificationId, {
type: "basic",
title: "A user joined the call",
message: message,
iconUrl: "./success.png"
});
}
7. تهانينا
في وقت قصير، تمكّنا من إنشاء إضافة Chrome بمساعدة Gemini. سواء كنت مطوّر إضافات Chrome متمرسًا أو جديدًا في عالم الإضافات، يمكن أن يساعدك Gemini في أي مهام تريد تحقيقها.
أشجعك على طرح أسئلة حول الأشياء المختلفة التي يمكنك إجراؤها باستخدام إضافة Chrome. هناك العديد من واجهات برمجة التطبيقات التي تستحق التصفّح، مثل chrome.storage وalarms وما إلى ذلك. أينما شعرت بأنّك عالق، استخدِم Gemini أو المستندات لمعرفة ما تفعله بشكل غير صحيح أو لجمع طرق مختلفة لحلّ المشكلة.
غالبًا ما يتطلّب الأمر تعديل الطلب للحصول على المساعدة المطلوبة، ولكن يمكننا إجراء ذلك من علامة تبويب واحدة تحتفظ بجميع رحلتنا السياقية.