Skip to content

Commit 19ebbb3

Browse files
committed
Track Teams as meeting category
1 parent 1d487d0 commit 19ebbb3

File tree

5 files changed

+57
-16
lines changed

5 files changed

+57
-16
lines changed

src/background.ts

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -60,12 +60,14 @@ browser.tabs.onUpdated.addListener(async (tabId, changeInfo) => {
6060
}
6161
});
6262

63-
browser.runtime.onMessage.addListener(async (request: { task: string }, sender) => {
64-
if (request.task === 'handleActivity') {
65-
if (!sender.tab?.id) return;
66-
await WakaTimeCore.handleActivity(sender.tab.id);
67-
}
68-
});
63+
browser.runtime.onMessage.addListener(
64+
async (request: { isPassiveActivity?: boolean; task: string }, sender) => {
65+
if (request.task === 'handleActivity') {
66+
if (!sender.tab?.id) return;
67+
await WakaTimeCore.handleActivity(sender.tab.id, request.isPassiveActivity);
68+
}
69+
},
70+
);
6971

7072
/**
7173
* "Persistent" service worker via bug exploit

src/core/WakaTimeCore.ts

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
import browser, { Tabs } from 'webextension-polyfill';
21
import { openDB } from 'idb';
32
import moment from 'moment';
43
import { v4 as uuid4 } from 'uuid';
4+
import browser, { Tabs } from 'webextension-polyfill';
55
import config, { ExtensionStatus } from '../config/config';
66
import { EntityType, Heartbeat, HeartbeatsBulkResponse } from '../types/heartbeats';
77
import getDomainFromUrl, { getDomain } from '../utils/getDomainFromUrl';
@@ -88,7 +88,7 @@ class WakaTimeCore {
8888
return site?.projectName;
8989
}
9090

91-
async handleActivity(tabId: number) {
91+
async handleActivity(tabId: number, isPassiveActivity: boolean = false) {
9292
const settings = await getSettings();
9393
if (!settings.loggingEnabled) {
9494
await changeExtensionStatus('trackingDisabled');
@@ -109,7 +109,10 @@ class WakaTimeCore {
109109
await changeExtensionStatus('allGood');
110110
}
111111

112-
const heartbeat = await this.buildHeartbeat(url, settings, activeTab);
112+
const heartbeat = await this.buildHeartbeat(url, settings, activeTab, isPassiveActivity);
113+
if (!heartbeat) {
114+
return;
115+
}
113116

114117
if (!this.shouldSendHeartbeat(heartbeat)) return;
115118

@@ -130,7 +133,12 @@ class WakaTimeCore {
130133
return activeTab;
131134
}
132135

133-
async buildHeartbeat(url: string, settings: Settings, tab: browser.Tabs.Tab): Promise<Heartbeat> {
136+
async buildHeartbeat(
137+
url: string,
138+
settings: Settings,
139+
tab: browser.Tabs.Tab,
140+
isPassiveActivity: boolean,
141+
): Promise<Heartbeat | undefined> {
134142
if (!tab.id) {
135143
throw Error('Missing tab id.');
136144
}
@@ -141,6 +149,10 @@ class WakaTimeCore {
141149
}
142150
).heartbeat;
143151

152+
if (isPassiveActivity && !heartbeat) {
153+
return;
154+
}
155+
144156
const entity = settings.loggingType === 'domain' ? getDomainFromUrl(url) : url;
145157

146158
const projectNameFromList = this.getProjectNameFromList(url, settings);

src/types/sites.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ export enum KnownSite {
88
github = 'github',
99
gitlab = 'gitlab',
1010
googlemeet = 'googlemeet',
11+
msteams = 'msteams',
1112
slack = 'slack',
1213
stackoverflow = 'stackoverflow',
1314
travisci = 'travisci',
@@ -29,6 +30,7 @@ export type HeartbeatParser = (url: string) => OptionalHeartbeat | undefined;
2930

3031
export interface SiteParser {
3132
parser: HeartbeatParser;
33+
trackWithoutMouseMoving?: boolean;
3234
urls: RegExp[] | string[];
3335
}
3436

src/utils/sites.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,23 @@ const GoogleMeet: HeartbeatParser = (_url: string): OptionalHeartbeat | undefine
281281
};
282282
};
283283

284+
const MicrosoftTeams: HeartbeatParser = (_url: string): OptionalHeartbeat | undefined => {
285+
const leaveButton = document.querySelector('#hangup-button');
286+
if (!leaveButton) return;
287+
288+
const title = document.querySelector('title')?.innerText;
289+
if (!title) return;
290+
291+
const meetingTitle = title.split(' | ')[1];
292+
if (!meetingTitle.trim()) return;
293+
294+
return {
295+
category: Category.meeting,
296+
plugin: 'Microsoft Teams',
297+
project: meetingTitle.trim(),
298+
};
299+
};
300+
284301
const Slack: HeartbeatParser = (_url: string): OptionalHeartbeat | undefined => {
285302
const title = document.querySelector('title')?.textContent?.split(' - ');
286303
if (!title || title.length < 3 || title[-1] !== 'Slack') {
@@ -374,8 +391,14 @@ const SITES: Record<KnownSite, SiteParser> = {
374391
},
375392
googlemeet: {
376393
parser: GoogleMeet,
394+
trackWithoutMouseMoving: true,
377395
urls: [/^https?:\/\/meet.google.com\//],
378396
},
397+
msteams: {
398+
parser: MicrosoftTeams,
399+
trackWithoutMouseMoving: true,
400+
urls: [/^https:\/\/teams.live.com\/v2\//, /^https:\/\/teams.microsoft.com\/v1\//],
401+
},
379402
slack: {
380403
parser: Slack,
381404
urls: [/^https:\/\/app.slack.com\/client\//],
@@ -394,6 +417,7 @@ const SITES: Record<KnownSite, SiteParser> = {
394417
},
395418
zoom: {
396419
parser: Zoom,
420+
trackWithoutMouseMoving: true,
397421
urls: [/^https:\/\/(.+\.)?zoom.us\/[^?]+\/join/],
398422
},
399423
};

src/wakatimeScript.ts

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,10 @@ const sendHeartbeat = debounce(async () => {
3030
void chrome.runtime.sendMessage({ task: 'handleActivity' });
3131
});
3232

33+
const sendHeartbeatMeeting = async () => {
34+
await chrome.runtime.sendMessage({ isPassiveActivity: true, task: 'handleActivity' });
35+
};
36+
3337
chrome.runtime.onMessage.addListener(
3438
(request: { task: string; url: string }, sender, sendResponse) => {
3539
if (request.task === 'getHeartbeatFromPage') {
@@ -49,17 +53,14 @@ document.body.addEventListener('click', sendHeartbeat, true);
4953
document.body.addEventListener('keypress', sendHeartbeat, true);
5054

5155
const checkIfInAMeeting = () => {
52-
if (!window.location.href.startsWith('https://meet.google.com/')) {
56+
const site = getSite(window.location.href);
57+
if (!site?.trackWithoutMouseMoving) {
5358
return;
5459
}
5560

56-
const isActiveMeeting = !!document.querySelector('[data-meeting-title]');
57-
if (isActiveMeeting) {
58-
sendHeartbeat();
59-
}
61+
void sendHeartbeatMeeting();
6062

6163
setTimeout(checkIfInAMeeting, oneMinute);
6264
};
6365

64-
// Google Meet
6566
checkIfInAMeeting();

0 commit comments

Comments
 (0)