1. Introdução
Você vai participar de uma chamada do Meet, mas não quer ser o primeiro a fazer isso? Se esse for seu caso, temos a solução.
Depois deste codelab, você criará uma extensão do Chrome que alerta quando o primeiro participante entrar na chamada.
Você vai aprender os diferentes elementos de uma extensão do Chrome e, em seguida, conhecerá melhor cada parte da extensão. Você vai aprender sobre as funções de extensão, como scripts de conteúdo, service workers e transmissão de mensagens.
Você precisa aderir à versão do Manifest V3 para receber notificações sempre que um participante entrar em uma chamada do Meet.
2. Antes de começar
Pré-requisitos
Embora este codelab seja adequado para iniciantes, ter um conhecimento básico de JavaScript pode melhorar muito sua experiência.
Configuração/requisitos
- O navegador Chrome
- Uma configuração do ambiente de desenvolvimento integrado/editor no seu sistema local.
- Instale o gcloud cli se quiser ativar a API Gemini usando a gcloud.
Ativar a API Gemini
- No console do Google Cloud, na página de seletor de projetos, selecione ou crie um projeto do Google Cloud.
- Confira se o faturamento está ativado para seu projeto do Cloud. Saiba como verificar se o faturamento está ativado em um projeto.
- Navegue até a página do Gemini Marketplace para ativar a API. Também é possível usar a gcloud para ativar a API:
gcloud services enable cloudaicompanion.googleapis.com --project PROJECT_ID
- Acesse a página do console do Gemini para Cloud em uma nova guia e clique em "Iniciar chat".
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. Que a diversão comece
Instalação básica de extensão
Vamos criar um diretório que usaremos como raiz do nosso projeto.
mkdir gemini-chrome-ext
cd gemini-chrome-ext
Antes de começar a fazer perguntas específicas ao Gemini, vamos fazer algumas perguntas sobre a estrutura genérica de uma extensão do Chrome.
Comando:
What are the important parts to build a chrome extension?
Recebemos uma resposta especificando detalhes menores sobre o arquivo manifest
, o background script
e detalhes sobre a interface do usuário. Vamos conferir mais detalhes sobre esses arquivos específicos.
Comando:
Create a manifest.json file to build a chrome extension. Make the name of the extension "Meet Joinees Notifier" and the author "<YOUR_EMAIL>"
Você pode usar um nome e seu e-mail no campo de autor.
O Gemini retorna o conteúdo do arquivo de manifesto necessário, mas recebemos alguns campos extras que não são necessários, como o campo action
. Além disso, precisamos de uma descrição. Vamos corrigir isso.
Comando:
Remove the "action" field and make the description as "Adds the ability to receive a notification when a participant joins a Google meet".
Coloque esse conteúdo no arquivo manifest.json
, na raiz do seu projeto.
Nessa etapa, o arquivo de manifesto será parecido com este exemplo.
{
"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>"
}
Por enquanto, remova todos os outros campos gerados no arquivo de manifesto, já que este codelab considera esses campos no arquivo de manifesto.
Agora, como testamos se a extensão funciona? Vamos perguntar ao nosso amigo Gemini, certo?
Comando:
Guide me on the steps needed to test a chrome extension on my local filesystem.
Ele traz algumas etapas para testar. Vamos navegar até o "Extensions Page"
navegando até chrome://extensions
e ativando o botão "Developer Mode"
, que vai revelar o botão "Load unpacked"
, que pode ser usado para navegar até a pasta que contém os arquivos de extensão localmente. Depois disso, a extensão pode ser exibida no "Extensions Page"
.
Ótimo! Podemos ver nossa extensão, mas vamos começar a adicionar algumas funcionalidades.
4. Adicionar um script de conteúdo
Queremos executar um código JavaScript somente em https://meet.google.com
, o que pode ser feito usando scripts de conteúdo. Vamos perguntar ao Gemini como fazer isso na nossa extensão.
Comando:
How to add a content script in our chrome extension?
Ou, mais especificamente:
Comando:
How to add a content script to run on meet.google.com subdomain in our chrome extension?
Ou outra versão:
Comando:
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".
O Gemini fornece as mudanças exatas que precisamos fazer no arquivo manifest.json e no JavaScript necessário no arquivo content.js
.
Com a adição de content_scripts, o arquivo de manifesto se tornará:
{
"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"]
}
]
}
Isso instrui o Chrome a injetar o script de conteúdo content.js
sempre que navegarmos até uma página no subdomínio " https://meet.google.com". Vamos adicionar esse arquivo e testá-lo?
Vamos adicionar esse código ao arquivo content.js
.
console.log("Hello Gemini");
Com certeza! Ao acessar meet.google.com, aparece a mensagem "Olá, Gemini" no console JavaScript(Mac: Cmd + Opt + J
/ Win/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("Olá, Gemini!");
Ótimo! Agora, estamos em uma posição em que podemos adicionar algumas funcionalidades específicas de JavaScript ao nosso app. Vamos pensar um pouco sobre o que estamos tentando alcançar.
Aprimorar o script de conteúdo
Queremos receber uma notificação quando alguém entrar em uma reunião quando estivermos na página da reunião(quando temos a opção de participar). Para conseguir isso, vamos observar como a tela muda visualmente quando a reunião está vazia versus quando alguém entra.
É assim que fica quando não há ninguém na reunião.
Já estes são os recursos visuais quando há alguns participantes na reunião.
Há duas diferenças notáveis logo de cara:
- O texto de status muda de "Ninguém mais está aqui" para "[O usuário] está nesta chamada".
- Podemos ver as imagens dos usuários que entraram na chamada.
As duas alterações funcionarão para nós se quisermos saber se alguém entrou na reunião, mas a última tem algumas possibilidades de obter informações sobre os usuários que já estão participando, então vamos tentar usá-la.
Abra o "Inspetor de elementos". no Chrome com a tecla de atalho ( Mac: Cmd + Opt + C / Win: Ctrl + Shift + C
) e clique na imagem do usuário que está participando.
Percebemos que há uma imagem com poucas strings de classe e que o atributo title da imagem tem o nome do usuário que entrou na reunião. Além disso, essa tag de imagem é unida a um div com a classe U04fid
. Assim que adicionamos alguns participantes à nossa reunião de teste, podemos ver que esse div pai hospeda várias imagens(correspondentes a diferentes usuários).
Então, temos uma estratégia parcial em mente:
- Detecta quando o div com a classe
U04fid
contém elementos. - Se sim, isso significa que temos participantes na reunião.
- Notificar o usuário.
Vamos voltar ao Gemini e perguntar como podemos fazer isso passo a passo.
Comando:
How to detect for element changes in the HTML page?
Isso nos dá uma solução que envolve MutationObserver
, mas nada específico para nosso requisito. Vamos tentar modificar o comando.
Comando:
How can I detect if an element "div.U04fid" has any child images in the HTML page?
Desta vez, temos uma solução que não inclui o MutationObserver
, mas que verifica os mesclados usando o div pai.
Confira o que recebemos:
const divU04fid = document.querySelector('div.U04fid');
const childImages = divU04fid.querySelectorAll('img');
if (childImages.length > 0) {
// div.U04fid has at least one child image.
}
Vamos tentar modificar ainda mais nossa abordagem:
Comando:
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.
Ele retorna com o seguinte snippet de código:
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
});
Copie este código para o arquivo content.js
, atualize a extensão e atualize a página do Meet.
Agora, quando alguém entrar na reunião, poderemos ver o log statement no console.
5. Enviar uma notificação ao usuário
Agora que podemos detectar quando um participante entrou na reunião, vamos tentar adicionar a notificação na extensão do Chrome. Podemos conferir a documentação da extensão do Chrome ou até ajustar as solicitações para saber o que estamos procurando, mas basicamente precisamos usar a API chrome.notifications.create
, e a chamada para esse método precisa ser feita por um service worker em segundo plano.
Comando:
Using the documentation for chrome notifications tell me how to use the chrome.notifications.create method.
Confira algumas etapas detalhadas, e os principais destaques são:
- Adicione a permissão
notifications
ao arquivo de manifesto. - Fazer uma chamada para chrome.notifications.create
- A chamada deve estar em um script de segundo plano.
Para adicionar um script de plano de fundo a uma extensão do Chrome no manifest version 3
, precisamos da declaração background.service_worker
no arquivo manifest.json
.
Assim, criamos um arquivo chamado background.js e adicionamos o seguinte ao nosso arquivo manifest.json.
"background": {
"service_worker": "background.js"
},
"permissions": [
"notifications"
]
Com as adições acima, nosso arquivo de manifesto se torna:
{
"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"
]
}
Comando:
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
Salve esta imagem na raiz da sua pasta e renomeie-a como success.png
.
Em seguida, adicione o seguinte snippet de código ao 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");
Agora, atualize a extensão na página "Extensões" e um pop-up de notificação será exibido imediatamente.
6. Adicionar a transmissão de mensagens na sua extensão do Chrome
Agora, a última etapa importante é conectar a detecção de um participante do script de conteúdo e o método sendNotification
no script em segundo plano. No contexto das extensões do Chrome, é possível fazer isso usando uma técnica chamada message passing
.
Isso permite a comunicação entre diferentes partes de uma extensão do Chrome, neste caso, do script de conteúdo para o service worker em segundo plano. Vamos perguntar ao Gemini como fazer isso.
Comando:
How to send a message from the content script to the background script in a chrome extension
O Gemini responde com chamadas relevantes para chrome.runtime.sendMessage
e chrome.runtime.onMessage.addListener
.
Basicamente, vamos usar sendMessage
para enviar uma mensagem do script de conteúdo de que alguém entrou na chamada do Meet e o onMessage.addListener
como um listener de eventos para reagir à mensagem enviada pelo script de conteúdo. Nesse caso, acionaremos a chamada para o método sendNotification
a partir desse listener de eventos.
Vamos transmitir a mensagem de notificação e uma propriedade action
ao service worker em segundo plano. A propriedade action
descreve ao que o script em segundo plano está respondendo.
Este é o código 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"
});
}
E este é o nosso código 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"
});
}
Vamos tentar personalizar a mensagem de notificação e receber um ID de notificação exclusivo. Para a mensagem de notificação, podemos incluir o nome do usuário. Em uma etapa anterior, podemos ver o nome do usuário no atributo title da imagem. Podemos buscar o nome do participante usando document.querySelector('div.U04fid > img').getAttribute('title').
.
Em relação ao ID da notificação, podemos buscar o ID da guia do script de conteúdo e usá-lo como ID da notificação. Isso pode ser feito dentro do listener de eventos chrome.runtime.onMessage.addListener
usando sender.tab.id.
.
Por fim, nossos arquivos vão ficar assim:
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. Parabéns
Em pouco tempo, conseguimos criar uma extensão do Chrome com a ajuda do Gemini. Seja você um desenvolvedor experiente de extensões do Chrome ou um iniciante no mundo das extensões, o Gemini pode ajudar com as tarefas que você quiser.
Recomendo que você pergunte sobre o que é possível fazer com uma extensão do Chrome. Há muitas APIs que valem a pena pesquisar, como chrome.storage
, alarms
etc. Sempre que você não souber o que fazer, use o Gemini ou a documentação para saber o que está errado ou descobrir maneiras diferentes de resolver o problema.
Muitas vezes, é preciso modificar o comando para receber a ajuda necessária, mas podemos fazer isso em uma única guia que retém toda a nossa jornada contextual.