Codelab: Gemini'ı kullanarak JavaScript'te bir Chrome Uzantısı oluşturma

1. Giriş

Meet görüşmesine katılmak istiyor ancak ilk katılan olmak istemiyor musunuz? Bu durum sizi tanımlıyorsa çözümümüz var!

Bu codelab'i tamamladığınızda, ilk katılımcı görüşmeye katıldığında sizi uyaran bir Chrome uzantısı oluşturacaksınız.

Chrome uzantısının farklı öğelerini öğrenip ardından uzantının her bir bölümünü ayrıntılı olarak inceleyeceksiniz. İçerik komut dosyaları, hizmet çalışanları ve mesaj iletme gibi uzantı işlevleri hakkında bilgi edineceksiniz.

Bir katılımcı Meet görüşmesine katıldığında bildirim alabilmek için manifest v3 sürümüne uymanız gerekir.

2. Başlamadan önce

Ön koşullar

Bu codelab yeni başlayanlar için uygun olsa da JavaScript hakkında temel bilgilere sahip olmak deneyiminizi büyük ölçüde iyileştirebilir.

Kurulum/Gereksinimler

  • Chrome tarayıcı
  • Yerel sisteminizde bir IDE/Editor kurulumu.
  • Gemini API'yi gcloud kullanarak etkinleştirmek istiyorsanız gcloud CLI'yı yükleyin.

Gemini API'yi etkinleştirme

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. Eğlence başlasın

Temel Uzantı Yükleme

Projemizin kökü olarak kullanacağımız bir dizin oluşturalım.

mkdir gemini-chrome-ext
cd gemini-chrome-ext

Gemini'a belirli sorular sormaya başlamadan önce Chrome uzantısının genel yapısıyla ilgili bazı sorular soralım.

İstem:

What are the important parts to build a chrome extension?

manifest dosyası, background script ve kullanıcı arayüzüyle ilgili ayrıntıları belirten bir yanıt alıyoruz. Bu dosyalarla ilgili daha ayrıntılı bilgi verelim.

İstem:

Create a manifest.json file to build a chrome extension.
Make the name of the extension "Meet Joinees Notifier"
and the author "<YOUR_EMAIL>"

Yazar alanında istediğiniz adı ve e-posta adresinizi kullanabilirsiniz.

Gemini, ihtiyacımız olan manifest dosyasının içeriğini döndürüyor ancak action alanı gibi ihtiyacımız olmayan bazı ek alanlar da alıyoruz. Ayrıca, açıklama da eklemeniz gerekir. Gelin bu sorunu çözelim.

İstem:

Remove the "action" field and make the description as
"Adds the ability to receive a notification when a participant joins a Google meet".

Bu içeriği, projenizin kökündeki manifest.json dosyasına yerleştirelim.

Bu aşamada manifest dosyası aşağıdaki gibi görünmelidir.

{
    "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>"
}

Bu codelab, manifest dosyanızdaki bu alanları varsaydığı için şimdilik manifest dosyanızda oluşturulan diğer ek alanları kaldırın.

Peki uzantının çalıştığını nasıl test ederiz? Arkadaşımız Gemini'a soralım mı?

İstem:

Guide me on the steps needed to test a chrome extension on my local filesystem.

Bu özelliği nasıl test edeceğime dair bazı adımlar veriyor. "Extensions Page" bölümüne giderek chrome://extensions bölümüne gidelim ve "Developer Mode" düğmesini etkinleştirdiğimizden emin olalım. Bu düğme, uzantı dosyalarını yerel olarak içeren klasöre gitmek için kullanabileceğimiz "Load unpacked" düğmesini gösterir. Bu işlemi tamamladığımızda uzantıyı "Extensions Page" bölümünde görebiliriz.

3d802a497ce0cfc2.png

92db1999a1800ecd.png

Mükemmel! Uzantımızı görüyoruz ancak biraz işlevsellik eklemeye başlayalım.

4. İçerik komut dosyası ekleme

Yalnızca https://meet.google.com üzerinde bazı JavaScript kodları çalıştırmak istiyoruz. Bunu içerik komut dosyalarını kullanarak yapabiliriz. Gemini'a uzantımızda bunu nasıl yapacağımızı soralım.

İstem:

How to add a content script in our chrome extension?

Daha ayrıntılı bilgi de verebilirsiniz:

İstem:

How to add a content script to run on meet.google.com subdomain in our chrome extension?

Veya başka bir sürüm:

İstem:

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 dosyamızda yapmamız gereken değişiklikleri ve content.js dosyamızda kullanmamız gereken JavaScript'i tam olarak veriyor.

content_scripts eklenince manifest dosyamız şu şekilde olur:

{
    "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"]
        }
    ]
}

Bu, "https://meet.google.com" alt alan adındaki bir sayfaya her gittiğimizde Chrome'a içerik komut dosyasını content.js eklemesini söyler. Bu dosyayı ekleyip test edelim.

Bu kodu content.js dosyasına ekleyelim.

console.log("Hello Gemini");

Elbette. meet.google.com adresini ziyaret ettiğimizde JavaScript konsolunda(Mac: Cmd + Opt + J / Win/Linux: Ctrl + Shift + J) "Merhaba Gemini" mesajını görüyoruz.

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!");

6216bab627c31e6c.png

d61631cd9962ffe5.png

Mükemmel! Artık uygulamamıza JavaScript'e özgü bazı işlevler ekleyebileceğimiz bir konumdayız. Ne yapmaya çalıştığımızı düşünmek için biraz zaman ayıralım.

İçerik komut dosyasını iyileştirme

Toplantı sayfasındayken(toplantıya katılma seçeneğinin bulunduğu yer) bir kullanıcı toplantıya katıldığında bildirim almak istiyoruz. Bunu başarmak için toplantı boşken ve bir kullanıcı toplantıya katıldığında ekranın görsel olarak nasıl değiştiğini inceleyelim.

Toplantıda kimse yokken görünüm şu şekildedir.

fe5a0c95b20e7f72.png

Toplantıda bazı katılımcılar olduğunda ise aşağıdaki görseller gösterilir.

7a5ef60521d961cc.png

Hemen göze çarpan 2 önemli fark var:

  1. Durum metni "Başka kimse yok"tan "[Kullanıcı] bu görüşmede" olarak değişir.
  2. Aramaya katılan kullanıcıların görüntülerini görebiliriz.

Bu iki değişiklik de toplantıya katılan olup olmadığını öğrenmek istediğimizde işimize yarar. Ancak ikincisi, toplantıya zaten katılmış olan kullanıcılar hakkında bilgi edinme konusunda bazı olanaklar sunar. Bu nedenle, ikincisini kullanmayı deneyelim.

Kısayol tuşunu ( Mac: Cmd + Opt + C / Win: Ctrl + Shift + C) kullanarak Chrome'da "Öğeler Denetçisi"ni açın, ardından katılan kullanıcının resmini tıklayın.

Birkaç sınıf dizesi içeren bir resim olduğunu ve resmin başlık özelliğinde toplantıya katılan kullanıcının adının yer aldığını fark edebiliriz. Ayrıca bu resim etiketi, U04fid sınıfına sahip bir div ile sarmalanmıştır. Test toplantımıza bazı katılımcılar ekledikten sonra bu üst div'in birden fazla resim(farklı kullanıcılara karşılık gelen) barındırdığını görebiliriz.

Bu nedenle, kısmi bir strateji planlıyoruz:

  1. U04fid sınıfına sahip div'in herhangi bir öğe içerip içermediğini algılar.
  2. Bu durumda, toplantımıza katılanlar olduğu anlamına gelir.
  3. Kullanıcıyı bilgilendirin.

Gemini'a dönelim ve bu işlemi adım adım nasıl yapabileceğimizi soralım.

İstem:

How to detect for element changes in the HTML page?

MutationObserver ile ilgili bir çözüm sunuyor ancak ihtiyacımıza özel bir şey söylemiyor. İstemde değişiklik yapmayı deneyelim.

İstem:

How can I detect if an element "div.U04fid" has any child images in the HTML page?

Bu kez, MutationObserver içermeyen ancak üst div'i kullanarak katılımcıları kontrol eden bir çözüm elde ediyoruz.

Aldığımız bilgiler şöyledir:

const divU04fid = document.querySelector('div.U04fid');
const childImages = divU04fid.querySelectorAll('img');
if (childImages.length > 0) {
  // div.U04fid has at least one child image.
}

Yaklaşımımızı daha da değiştirmeyi deneyelim:

İstem:

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.

Aşağıdaki kod snippet'iyle birlikte döndürülür:

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
});

Bu kodu content.js dosyasına kopyalayın, uzantıyı yeniden yükleyin(ardından Meet sayfasını yeniden yükleyin).

Artık toplantımıza katılan kullanıcıların günlük ifadesini konsolda görebiliyoruz.

5. Kullanıcıya bildirim gönderme

Artık bir katılımcının toplantıya ne zaman katıldığını algılayabildiğimize göre, Chrome uzantımıza bildirim bölümünü eklemeyi deneyelim. Chrome uzantısının dokümanlarına göz atabilir veya ne aradığımızı öğrenmek için istemleri değiştirebiliriz. Ancak temelde chrome.notifications.create API'sini kullanmamız gerekir ve bu yönteme yapılan çağrı bir arka plan hizmeti çalışanı tarafından yapılmalıdır.

İstem:

Using the documentation for chrome notifications tell me how to use the chrome.notifications.create method.

Aşağıda, önemli noktaların vurgulandığı ayrıntılı adımları görebilirsiniz:

  • Manifest dosyasına notifications iznini ekleyin.
  • chrome.notifications.create işlevini çağırma
  • Çağrı, arka plan komut dosyasında olmalıdır.

manifest version 3 içinde bir Chrome uzantısına arka plan komut dosyası eklemek için manifest.json dosyamızda background.service_worker bildirimi gerekir.

Bu nedenle, background.js adlı bir dosya oluşturup manifest.json dosyamıza aşağıdakileri ekliyoruz.

"background": {
        "service_worker": "background.js"
},
"permissions": [
        "notifications"
]

Yukarıdaki eklemelerle birlikte manifest dosyamız şu şekilde olur:

{
    "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"
    ]
}

İstem:

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

Bu resmi klasörünüzün kök dizinine kaydedin ve success.png olarak yeniden adlandırın.

b2c22f064a3f2d9c.png

Ardından, aşağıdaki kod snippet'ini background.js dosyasına ekleyin.

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");

Şimdi uzantıyı, uzantılar sayfasından yeniden yükleyin. Anında bir bildirim pop-up'ı görmeniz gerekir.

6. Chrome uzantınıza mesaj iletme özelliği ekleme

Şimdi, içerik komut dosyasının bir katılımcıyı algılaması ile arka plan komut dosyasındaki sendNotification yöntemini bağlamamız gerekiyor. Chrome uzantıları bağlamında bu işlem, message passing adı verilen bir teknikle yapılır.

Bu, bir Chrome uzantısının farklı bölümleri arasında iletişimi sağlar. Bizim durumumuzda bu, içerik komut dosyasından arka plan hizmeti çalışanına iletişimdir. Bu konuda arkadaşımız Gemini'dan yardım alalım.

İstem:

How to send a message from the content script to the background script in a chrome extension

Gemini, chrome.runtime.sendMessage ve chrome.runtime.onMessage.addListener ile ilgili aramaları yanıtlar.

Temel olarak, bir kullanıcının toplantı görüşmesine katıldığına dair içerik komut dosyasından mesaj göndermek için sendMessage, içerik komut dosyası tarafından gönderilen mesaja yanıt vermek için de onMessage.addListener öğesini etkinlik dinleyici olarak kullanırız. Bu durumda, bu etkinlik işleyiciden sendNotification yöntemine yapılan çağrıyı tetikleriz.

Bildirim mesajını ve bir action özelliğini arka plan hizmeti çalışanına ileteceğiz. action özelliği, arka plan komut dosyasının neye yanıt verdiğini açıklar.

content.js kodumuz:

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 kodumuz:

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"
    });
}

Bildirim mesajını özelleştirmeyi ve benzersiz bir bildirim kimliği almayı deneyelim. Bildirim mesajına kullanıcının adını ekleyebiliriz. Önceki bir adımdan hatırlayacağınız üzere, resmin başlık özelliğinde kullanıcının adını görebiliyorduk. Bu nedenle, katılımcının adını document.querySelector('div.U04fid > img').getAttribute('title'). kullanarak getirebiliriz.

Bildirim kimliğiyle ilgili olarak, içerik komut dosyasının sekme kimliğini getirebilir ve bunu bildirim kimliği olarak kullanabiliriz. Bu işlem, chrome.runtime.onMessage.addListener etkinlik işleyicimizde sender.tab.id. kullanılarak gerçekleştirilebilir.

Son olarak, dosyalarımız şöyle görünmelidir:

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. Tebrikler

Kısa sürede Gemini'ın yardımıyla bir Chrome uzantısı oluşturabildik. İster deneyimli bir Chrome uzantısı geliştiricisi olun ister uzantı dünyasına yeni adım atmış olun, Gemini ile istediğiniz görevleri gerçekleştirebilirsiniz.

Chrome uzantısıyla yapabileceğiniz farklı şeyler hakkında soru sormanızı öneririz. chrome.storage ve alarms gibi göz atmaya değer birçok API vardır. Takıldığınız her yerde neyi yanlış yaptığınızı öğrenmek veya sorunu çözmenin farklı yollarını bulmak için Gemini'ı ya da dokümanları kullanın.

Gerekli yardımı almak için istemi değiştirmeniz gerekebilir. Ancak bunu, bağlamsal yolculuğumuzun tamamını koruyan tek bir sekmeden yapabilirsiniz.