Last active
January 30, 2021 09:13
-
-
Save arnav-t/5fef88f61e0dab92cc0470c8b6262db7 to your computer and use it in GitHub Desktop.
AutoTeams.js - Tampermonkey/Greasemonkey script for autojoining meetings
This file contains 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 AutoTeams | |
// @namespace http://tampermonkey.net/ | |
// @version 0.1 | |
// @description Auto Join MS Teams meetings | |
// @author arnav-t | |
// @match https://teams.microsoft.com/* | |
// @grant none | |
// ==/UserScript== | |
class AutoTeams { | |
constructor() { | |
this.teams = { | |
cfd: { | |
url: 'https://teams.microsoft.com/_#/school/conversations/General?threadId=19:e4cc42e390f54e1e80af6708a137178c@thread.tacv2&ctx=channel', | |
slots: [ | |
{day: 2, startHour: 8, startMinute: 0, endHour: 10, endMinute: 0}, | |
{day: 6, startHour: 14, startMinute: 30, endHour: 16, endMinute: 30} | |
] | |
}, | |
microfluidics: { | |
url: 'https://teams.microsoft.com/_#/school/conversations/General?threadId=19:58d9533c73f6476094cf9cc008b539e1@thread.tacv2&ctx=channel', | |
slots: [ | |
{day: 1, startHour: 8, startMinute: 0, endHour: 10, endMinute: 0}, | |
{day: 2, startHour: 12, startMinute: 0, endHour: 13, endMinute: 0}, | |
{day: 4, startHour: 17, startMinute: 0, endHour: 18, endMinute: 0} | |
] | |
}, | |
ecpackaging: { | |
url: 'https://teams.microsoft.com/_#/school/conversations/General?threadId=19:4287713e60414ede8d4db1542483eb10@thread.tacv2&ctx=channel', | |
slots: [ | |
{day: 1, startHour: 12, startMinute: 0, endHour: 13, endMinute: 0}, | |
{day: 2, startHour: 10, startMinute: 0, endHour: 12, endMinute: 0} | |
] | |
}, | |
laser: { | |
url: 'https://teams.microsoft.com/_#/school/conversations/General?threadId=19:284daeaaba1240429aade22c986a0ad1@thread.tacv2&ctx=channel', | |
slots: [ | |
{day: 3, startHour: 11, startMinute: 0, endHour: 12, endMinute: 0}, | |
{day: 4, startHour: 12, startMinute: 0, endHour: 13, endMinute: 0}, | |
{day: 5, startHour: 8, startMinute: 0, endHour: 9, endMinute: 0} | |
] | |
}, | |
npm: { | |
url: 'https://teams.microsoft.com/_#/school/conversations/General?threadId=19:642438518d3d44698b5633239b6d3d4c@thread.tacv2&ctx=channel', | |
slots: [ | |
{day: 3, startHour: 12, startMinute: 0, endHour: 13, endMinute: 0}, | |
{day: 4, startHour: 11, startMinute: 0, endHour: 12, endMinute: 0}, | |
{day: 5, startHour: 9, startMinute: 0, endHour: 11, endMinute: 0} | |
] | |
}, | |
human: { | |
url: 'https://teams.microsoft.com/_#/school/conversations/General?threadId=19:b000645cca6b4f668239f09d46a74c40@thread.tacv2&ctx=channel', | |
slots: [ | |
{day: 3, startHour: 10, startMinute: 0, endHour: 11, endMinute: 0}, | |
{day: 4, startHour: 9, startMinute: 0, endHour: 10, endMinute: 0}, | |
{day: 5, startHour: 11, startMinute: 0, endHour: 13, endMinute: 0} | |
] | |
} | |
}; | |
this.state = 'idle'; | |
this.initDelay = 1*60*1000; | |
this.slotRecheckTime = 1*60*1000; | |
this.loadTime = 15*1000; | |
this.retryTime = 30*1000; | |
this.jbMaxRetries = 3; | |
this.refreshUrl = 'https://teams.microsoft.com/_#/my/file-recent'; | |
this.join = this.join.bind(this); | |
this.init = this.init.bind(this); | |
this.init(); | |
} | |
asyncTimeout(delay) { | |
return new Promise(res => setTimeout(() => res(), delay)); | |
} | |
async init() { | |
console.log('[AT] Initializing AutoTeams.'); | |
this.asyncTimeout(this.initDelay); | |
// Check slots every slotRecheckTime | |
setInterval(() => { | |
if (this.state === 'meeting') { | |
// Verify that currently in meeting | |
if (!document.querySelector('#hangup-button')) this.state = 'idle'; | |
else return; | |
} else if (this.state === 'joining') return; | |
console.log('[AT] Checking slots.'); | |
const currentDay = (new Date()).getDay(); | |
for (const team in this.teams) { | |
for (const slot of this.teams[team].slots) { | |
if (slot.day !== currentDay) continue; | |
const startTime = new Date(); startTime.setHours(slot.startHour, slot.startMinute, 0, 0); | |
const endTime = new Date(); endTime.setHours(slot.endHour, slot.endMinute, 0, 0); | |
const currentTime = new Date(); | |
// If current time is in between start and end time, join meeting | |
if (currentTime >= startTime && currentTime < endTime) { | |
console.log(`[AT] Joining team "${team}".`); | |
const duration = endTime - currentTime; | |
this.join(team, duration); | |
return; | |
} | |
} | |
} | |
}, this.slotRecheckTime); | |
} | |
async join(team, duration) { | |
if (this.state === 'meeting') return; | |
this.state = 'joining'; | |
// Initalize startTime | |
const startTime = new Date(); | |
// Load team page | |
window.location.href = this.teams[team].url; | |
await this.asyncTimeout(this.loadTime); | |
console.log('[AT] Team page loaded.'); | |
let joinButton = null; | |
for (let attempt = 0; attempt < this.jbMaxRetries; ++attempt) { | |
// Try to fetch join button | |
console.log(`[AT] Attempting to find meeting (${attempt+1}).`); | |
joinButton = document.querySelector('.ts-calling-join-button'); | |
if (joinButton) break; | |
else await this.asyncTimeout(this.retryTime); | |
} | |
if (!joinButton) { | |
console.log('[AT] Meeting not found. Resetting to idle.'); | |
window.location.href = this.refreshUrl; | |
this.state = 'idle'; | |
return; | |
} | |
console.log('[AT] Fetched join button.'); | |
// Attempt to join meeting | |
joinButton.click(); | |
await this.asyncTimeout(this.loadTime); | |
console.log('[AT] Turning off camera and microphone.'); | |
// Turn camera and microphone off | |
document.querySelector('span[title="Mute microphone"]')?.click(); | |
document.querySelector('span[title="Turn camera off"]')?.click(); | |
// Finally join the meeting | |
joinButton = document.querySelector('.join-btn.ts-btn'); | |
if (!joinButton) { | |
console.log('[AT] Unable to join. Resetting to idle.'); | |
window.location.href = this.refreshUrl; | |
this.state = 'idle'; | |
return; | |
} | |
joinButton.click(); | |
const remaining = Math.max(duration - (new Date() - startTime), this.loadTime); | |
console.log(`[AT] Hanging up in ${(remaining/1000).toFixed()} seconds.`); | |
this.state = 'meeting'; | |
await this.asyncTimeout(remaining); | |
console.log('[AT] Hanging up.'); | |
// Hang up | |
document.querySelector('#hangup-button').click(); | |
this.state = 'idle'; | |
} | |
} | |
window.onload = () => { | |
window.at = new AutoTeams(); | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment