Last active
August 5, 2021 21:18
-
-
Save caiohamamura/098779d9e0a8335757c7f94844366e92 to your computer and use it in GitHub Desktop.
Tampermonkey - Google meet: csv list of attendance
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // ==UserScript== | |
| // @name Google meet: csv list of attendance | |
| // @namespace http://tampermonkey.net/ | |
| // @version 0.1 | |
| // @description try to take over the world! | |
| // @author You | |
| // @match https://meet.google.com/* | |
| // @grant none | |
| // ==/UserScript== | |
| (function() { | |
| class ColecaoPessoas { | |
| constructor() { | |
| this.pessoas = []; | |
| } | |
| add(pessoa) { | |
| this.pessoas.push(pessoa); | |
| } | |
| getOuAdd(nome) { | |
| let pessoa; | |
| if (this.contains(nome)) | |
| pessoa = this.pessoas.filter(pessoa => pessoa.nome == nome)[0]; | |
| else { | |
| pessoa = new Pessoa(); | |
| pessoa.nome = nome; | |
| this.pessoas.push(pessoa); | |
| } | |
| return pessoa; | |
| } | |
| contains(nome) { | |
| return this.pessoas.filter(e => e.nome == nome).length > 0; | |
| } | |
| getAsCSV() { | |
| var head = '"Name";"Conected";"Disconnected";"First login";"Last logoff";"NoDisconnections"\n'; | |
| let pessoas2 = this.pessoas.sort((a,b) => a.nome.trim().toLowerCase() > b.nome.trim().toLowerCase() ? 1 : -1); | |
| pessoas2 = pessoas2.filter(p => | |
| p.nome.indexOf("Caio Hamamura")===-1 && | |
| p.nome.indexOf("Você")===-1 && | |
| p.nome.indexOf("Abaixar")===-1 && | |
| p.nome.indexOf("Desativar")===-1 && | |
| p.nome.indexOf("keep_off")===-1 && | |
| p.nome.indexOf("Todos com o som")===-1 && | |
| p.nome.indexOf("Sua apresentação")===-1 && | |
| p.nome.indexOf("Mãos")===-1 | |
| ); | |
| this.pessoas = []; | |
| return head + pessoas2.map(pessoa => '"' + pessoa.nome.replace("\n", " ") + '";"' + pessoa.getTempo() + '";"' + pessoa.getTempoDesconectado() + '";"' + pessoa.primeiraEntrada.toLocaleTimeString() + '";"' + pessoa.ultimaSaida.toLocaleTimeString() + '";' + pessoa.quedas()).join("\n"); | |
| } | |
| } | |
| class Registro { | |
| constructor() { | |
| this.entrada = false; | |
| this.saida = false; | |
| } | |
| } | |
| const Ajudante = { | |
| getTimeString(delta) { | |
| delta /= 1000.0; | |
| // calculate (and subtract) whole hours | |
| var hours = Math.floor(delta / 3600) % 24; | |
| delta -= hours * 3600; | |
| // calculate (and subtract) whole minutes | |
| var minutes = Math.floor(delta / 60) % 60; | |
| delta -= minutes * 60; | |
| // what's left is seconds | |
| var seconds = delta % 60; | |
| return `${hours.toString().padStart(2, 0)}:${minutes.toString().padStart(2, 0)}:${seconds.toFixed(0).padStart(2, 0)}`; | |
| } | |
| } | |
| class Pessoa { | |
| constructor(nome) { | |
| this.nome = nome; | |
| this.primeiraEntrada = false; | |
| this.ultimaSaida = false; | |
| this.registros = []; | |
| this.ultimoRegistro = new Registro(); | |
| } | |
| saiu() { | |
| return this.ultimoRegistro.saida != false; | |
| } | |
| entrou() { | |
| return this.ultimoRegistro.entrada != false; | |
| } | |
| entrar() { | |
| if (this.entrou() && !this.saiu()) | |
| this.sair(); | |
| this.ultimoRegistro.entrada = new Date(); | |
| if (this.primeiraEntrada == false) | |
| this.primeiraEntrada = this.ultimoRegistro.entrada; | |
| } | |
| sair() { | |
| if (this.entrou()) { | |
| this.ultimoRegistro.saida = new Date(); | |
| this.ultimaSaida = this.ultimoRegistro.saida; | |
| this.addUltimoRegistro(); | |
| } | |
| } | |
| addUltimoRegistro() { | |
| this.registros.push(this.ultimoRegistro); | |
| this.ultimoRegistro = new Registro(); | |
| } | |
| quedas() { | |
| return this.registros.length + this.entrou() - 1; | |
| } | |
| getTempoDesconectado() { | |
| var deltaTotal = 0; | |
| this.registros.map(registro => registro.saida - registro.entrada).forEach(delta => deltaTotal += delta); | |
| if (this.entrou() && !this.saiu()) { | |
| deltaTotal += new Date() - this.ultimoRegistro.entrada; | |
| this.ultimaSaida = new Date(); | |
| } | |
| return Ajudante.getTimeString((this.ultimaSaida - this.primeiraEntrada) - deltaTotal); | |
| } | |
| getTempo() { | |
| let deltaTotal = 0; | |
| this.registros.map(registro => registro.saida - registro.entrada).forEach(delta => deltaTotal += delta); | |
| if (this.entrou() && !this.saiu()) | |
| deltaTotal += new Date() - this.ultimoRegistro.entrada; | |
| return Ajudante.getTimeString(deltaTotal); | |
| } | |
| } | |
| var totalPeople = {}; | |
| var lastTimeout = 0; | |
| var initialTab = 0; | |
| var isExpanded = false; | |
| var people = false; | |
| var pessoas = new ColecaoPessoas(); | |
| window.pessoas = pessoas; | |
| function personOut(nome) { | |
| let pessoa = pessoas.getOuAdd(nome); | |
| pessoa.sair(); | |
| } | |
| function personIn(nome) { | |
| let pessoa = pessoas.getOuAdd(nome); | |
| pessoa.entrar(); | |
| } | |
| //observer.disconnect() | |
| function startMonitor() { | |
| var targetNode3 = document.querySelector("[data-participant-id]").parentElement; | |
| var config3 = { attributes: false, childList: true, subtree: true, characterData: true }; | |
| // List of all connected users | |
| Array.from(document.querySelectorAll("[data-participant-id]")).map(item=>item.innerText).forEach(nome => personIn(nome)); | |
| var callback3 = function(mutationsList, observer) { | |
| // console.log(mutationsList); | |
| let todos = Array.from(document.querySelectorAll("[data-participant-id]")).map(item=>item.innerText); | |
| let nomesAdd = mutationsList.filter(el => el.type == "characterData").map(el => el.target.wholeText); | |
| let estavamDentro = pessoas.pessoas.filter(pessoa=>pessoa.entrou() && !pessoa.saiu()).map(pessoa => pessoa.nome); | |
| let nomesRemove = estavamDentro.filter(el => todos.indexOf(el) == -1); | |
| //var nomesRemove = Array.from(new Set(mutationsList.filter(el => el.removedNodes.length).map(el => el.removedNodes[0].innerText))); | |
| // if (nomesRemove.length > 0) console.log(mutationsList); | |
| nomesAdd.forEach(nome => personIn(nome)); | |
| nomesRemove.forEach(nome => personOut(nome)); | |
| }; | |
| var observer3 = new MutationObserver(callback3); | |
| // Start observing the target node for configured mutations | |
| observer3.observe(targetNode3, config3); | |
| } | |
| function stopMonitor() { | |
| if (pessoas.pessoas.length == 0) return; | |
| var res = pessoas.getAsCSV(); | |
| var a = document.createElement("a"); | |
| a.href = "data:text/csv;charset=utf-8,%EF%BB%BF" + res; | |
| a.download = "people_" + (new Date()).toLocaleString().replaceAll("/", "-").replace(/ (\d+):(\d+):(\d+)/g, "_$1h$2m$3s") + ".csv"; | |
| a.click(); | |
| return true; | |
| } | |
| var myDiv = document.createElement("div"); | |
| function pauseMonitor() { | |
| myDiv.innerText = "PLAY"; | |
| clearTimeout(lastTimeout); | |
| } | |
| myDiv.style.position = "absolute"; | |
| myDiv.innerText = "PLAY"; | |
| myDiv.style.top = "5px"; | |
| myDiv.style.left = "5px"; | |
| myDiv.style.zIndex = 9999999; | |
| myDiv.style.border = "2pt black solid"; | |
| myDiv.style.backgroundColor = "black"; | |
| myDiv.style.color = "white"; | |
| myDiv.style.fontWeight = 900; | |
| myDiv.style.opacity = 0.5; | |
| myDiv.style.cursor = "pointer"; | |
| myDiv.onclick = function() { | |
| if (myDiv.innerText == "PLAY") { | |
| window.onbeforeunload = function(evt) { | |
| stopMonitor(); | |
| } | |
| document.querySelector("[aria-label='Sair da chamada']").onmousedown = function(e) { | |
| stopMonitor(); | |
| return true; | |
| } | |
| myDiv.innerText = "PAUSE"; | |
| startMonitor(); | |
| } else { | |
| pauseMonitor(); | |
| } | |
| } | |
| document.querySelector("body").append(myDiv); | |
| document.addEventListener("DOMContentLoaded", function(event) { | |
| console.log("Start observing"); | |
| startMonitor(); | |
| }); | |
| })(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment