Skip to content

Instantly share code, notes, and snippets.

@nicordev
Last active October 8, 2020 07:44
Show Gist options
  • Save nicordev/cbe6b0bc366f436b20757199d3364301 to your computer and use it in GitHub Desktop.
Save nicordev/cbe6b0bc366f436b20757199d3364301 to your computer and use it in GitHub Desktop.
Google meet script to get a list of who has already talked during a daily meeting.
// ==UserScript==
// @name Who has talked?
// @namespace http://tampermonkey.net/
// @version 0.1
// @description Show a list of attendees to see who has already talked. Click on a name to remove it. Double click on the list to remove the overlay.
// @author You
// @match https://meet.google.com/*
// @grant none
// ==/UserScript==
(function () {
displayNameList();
/**
* Fetch names from the main window
*/
function fetchVisibleNames() {
const elements = document.querySelectorAll('div[data-self-name]');
let names = [];
for (let element of elements) {
names.push(element.textContent);
}
return names
.filter((currentValue, currentIndex, elements) => {
return currentIndex === elements.indexOf(currentValue);
})
.sort();
}
/**
* Fetch names from the name list
*/
function fetchNamesFromUserList() {
const nameElements = [
...document.querySelectorAll('div[aria-label]'),
];
const names = nameElements.map(fetchName).filter((name) => name);
function fetchName(nameElement) {
let attributeValue = nameElement.getAttribute('aria-label');
let match =
attributeValue.match(
'^Afficher d\'autres actions pour (.+)$'
) || [];
return match[1] || null;
}
return names
.filter((currentValue, currentIndex, elements) => {
return currentIndex === elements.indexOf(currentValue);
})
.sort();
}
function displayNameList() {
const overlayElement = document.createElement('div');
const headerElement = document.createElement('div');
const titleElement = document.createElement('div');
const helpElement = document.createElement('div');
const refreshNameListButtonElement = document.createElement('button');
var isDown = false;
var offset = [0,0];
// Overlay
overlayElement.classList.add('whoHasTalkedNameList');
overlayElement.style.position = 'absolute';
overlayElement.style.backgroundColor = '#e8eaed';
overlayElement.style.boxShadow = '0 1px 2px 0 rgba(60,64,67,.30), 0 1px 3px 1px rgba(60,64,67,.15)';
overlayElement.style.padding = '1em';
overlayElement.style.top = '4px';
overlayElement.style.left = '4px';
overlayElement.style.zIndex = '999';
overlayElement.style.fontSize = '.85em';
overlayElement.style.borderRadius = '.85em';
overlayElement.addEventListener('dblclick', function (event) {
this.remove();
});
overlayElement.addEventListener('mousedown', function (event) {
if (event.button === 0) {
isDown=true;
offset = [
overlayElement.offsetLeft - event.clientX,
overlayElement.offsetTop - event.clientY
];
}
});
document.addEventListener('mouseup', function (event) {
isDown=false;
});
document.addEventListener('mousemove', function (event) {
event.preventDefault();
if (isDown) {
overlayElement.style.left = (event.clientX + offset[0]) + 'px';
overlayElement.style.top = (event.clientY + offset[1]) + 'px';
}
});
// Header
titleElement.textContent = 'Who has talked?';
titleElement.style.fontSize = '1.5em';
titleElement.style.padding = '0.5em';
helpElement.textContent = 'Click on a name to remove it from the list.';
helpElement.style.fontSize = '0.75em';
helpElement.style.padding = '0.5em';
helpElement.style.color = '#3c4043';
refreshNameListButtonElement.textContent = 'Refresh list';
refreshNameListButtonElement.style.border = 'none';
refreshNameListButtonElement.style.borderRadius = '1em';
refreshNameListButtonElement.style.padding = '.5em 1em';
refreshNameListButtonElement.style.boxShadow = '0 1px 2px 0 rgba(60,64,67,.30), 0 1px 3px 1px rgba(60,64,67,.15)';
refreshNameListButtonElement.style.backgroundColor = '#00796b';
refreshNameListButtonElement.style.color = '#fff';
refreshNameListButtonElement.style.fontWeight = 'bold';
headerElement.appendChild(titleElement);
headerElement.appendChild(helpElement);
headerElement.appendChild(refreshNameListButtonElement);
overlayElement.appendChild(headerElement);
// Name list
const nameListElement = document.createElement('ul');
overlayElement.appendChild(nameListElement);
refreshNameListButtonElement.addEventListener('click', function () {
let names = fetchNamesFromUserList();
if (0 === names.length) {
console.log(
'Fetching names from main window. Open user panel to get the full list of participants.'
);
names = fetchVisibleNames();
}
console.log(names.join('\n'));
refreshNameList(nameListElement, names);
});
document.body.appendChild(overlayElement);
}
function refreshNameList(nameListElement, names) {
nameListElement.innerHTML = '';
names.map(function (name) {
nameListElement.appendChild(createNameElement(name));
});
}
function createNameElement(name) {
const nameElement = document.createElement('li');
nameElement.textContent = name;
nameElement.style.margin = '0.5em';
nameElement.style.cursor = 'pointer';
nameElement.addEventListener('click', function () {
if (this.classList.contains('has-talked')) {
this.classList.remove('has-talked');
this.style.color = 'black';
this.style.textDecoration = 'none';
return;
}
this.classList.add('has-talked');
this.style.color = 'grey';
this.style.textDecoration = 'line-through';
});
return nameElement;
}
})();
@nicordev
Copy link
Author

nicordev commented Sep 9, 2020

The participant list is incomplete when a lot of participants are present.
We need to scroll to see missing participant, but it removes the first ones.

Maybe make a function to scroll and remember every participant.

@nicordev
Copy link
Author

nicordev commented Oct 2, 2020

TODO:

Remember who has already talked between refreshes.

Make a simpler version:

  • put a default starting list of names
  • right-click to set a name as away
  • left-click to set a name as already talked
  • add a field to add a name manually

@nicordev
Copy link
Author

nicordev commented Oct 8, 2020

Thanks Yann!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment