-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathbackground.js
More file actions
265 lines (219 loc) · 7.16 KB
/
background.js
File metadata and controls
265 lines (219 loc) · 7.16 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
// Background service worker for browsing time tracking
let activeTabId = null;
let activeTabStartTime = null;
let activeTabDomain = null;
let isIdle = false;
let idleStartTime = null;
const IDLE_THRESHOLD = 60; // 60 seconds to trigger idle state
// Initialize on extension load
chrome.runtime.onStartup.addListener(() => {
checkAndResetDailyData();
initializeTracking();
});
chrome.runtime.onInstalled.addListener(() => {
checkAndResetDailyData();
initializeTracking();
});
// Initialize tracking
async function initializeTracking() {
// Get currently active tab
const tabs = await chrome.tabs.query({ active: true, currentWindow: true });
if (tabs.length > 0) {
handleTabActivated(tabs[0]);
}
// Set up idle detection
chrome.idle.setDetectionInterval(IDLE_THRESHOLD);
chrome.idle.onStateChanged.addListener(handleIdleStateChange);
}
// Check if we need to reset data for a new day
async function checkAndResetDailyData() {
const today = new Date().toISOString().split('T')[0];
const data = await chrome.storage.local.get(['lastResetDate', 'siteData']);
if (data.lastResetDate !== today) {
// Reset for new day
await chrome.storage.local.set({
siteData: {},
lastResetDate: today
});
console.log('Data reset for new day:', today);
}
}
// Handle tab activation
chrome.tabs.onActivated.addListener(async (activeInfo) => {
if (isIdle) return; // Don't track when idle
// Save time for previous tab
await saveActiveTabTime();
// Get the newly activated tab
const tab = await chrome.tabs.get(activeInfo.tabId);
handleTabActivated(tab);
});
// Handle tab updates (URL changes)
chrome.tabs.onUpdated.addListener(async (tabId, changeInfo, tab) => {
if (isIdle) return;
if (tabId !== activeTabId) return;
if (!changeInfo.url) return;
// Save time for previous URL
await saveActiveTabTime();
// Start tracking new URL
handleTabActivated(tab);
});
// Handle tab removal
chrome.tabs.onRemoved.addListener(async (tabId) => {
if (tabId === activeTabId) {
await saveActiveTabTime();
activeTabId = null;
activeTabStartTime = null;
activeTabDomain = null;
}
});
// Handle window focus changes
chrome.windows.onFocusChanged.addListener(async (windowId) => {
if (isIdle) return;
if (windowId === chrome.windows.WINDOW_ID_NONE) {
// Window lost focus, save current tab time
await saveActiveTabTime();
activeTabId = null;
activeTabStartTime = null;
activeTabDomain = null;
} else {
// Window gained focus, get active tab
const tabs = await chrome.tabs.query({ active: true, windowId: windowId });
if (tabs.length > 0) {
await saveActiveTabTime();
handleTabActivated(tabs[0]);
}
}
});
// Handle idle state changes
async function handleIdleStateChange(newState) {
console.log('Idle state changed:', newState);
if (newState === 'active') {
// User is active again
if (isIdle && idleStartTime) {
const idleDuration = Date.now() - idleStartTime;
console.log('User was idle for:', Math.round(idleDuration / 1000), 'seconds');
}
isIdle = false;
idleStartTime = null;
// Resume tracking
const tabs = await chrome.tabs.query({ active: true, currentWindow: true });
if (tabs.length > 0) {
handleTabActivated(tabs[0]);
}
} else {
// User is idle or locked
isIdle = true;
idleStartTime = Date.now();
// Save current tab time
await saveActiveTabTime();
activeTabId = null;
activeTabStartTime = null;
activeTabDomain = null;
}
}
// Extract domain from URL
function getDomainFromUrl(url) {
if (!url) return null;
try {
const urlObj = new URL(url);
return urlObj.hostname.replace(/^www\./, '');
} catch (e) {
return null;
}
}
// Handle tab activation
function handleTabActivated(tab) {
if (!tab || !tab.url) return;
const domain = getDomainFromUrl(tab.url);
if (!domain) return;
// Ignore chrome:// and extension:// URLs
if (tab.url.startsWith('chrome://') ||
tab.url.startsWith('chrome-extension://') ||
tab.url.startsWith('edge://') ||
tab.url.startsWith('about:') ||
tab.url.startsWith('file://')) {
return;
}
activeTabId = tab.id;
activeTabStartTime = Date.now();
activeTabDomain = domain;
console.log('Tracking started for:', domain);
}
// Save time for active tab
async function saveActiveTabTime() {
if (!activeTabId || !activeTabStartTime || !activeTabDomain) return;
const endTime = Date.now();
const duration = Math.round((endTime - activeTabStartTime) / 1000); // Convert to seconds
if (duration < 1) return; // Ignore very short visits
// Get current data
const data = await chrome.storage.local.get(['siteData']);
const siteData = data.siteData || {};
// Add time to domain
siteData[activeTabDomain] = (siteData[activeTabDomain] || 0) + duration;
// Save updated data
await chrome.storage.local.set({ siteData });
console.log(`Saved ${duration}s for ${activeTabDomain}. Total: ${siteData[activeTabDomain]}s`);
}
// Message handler for popup
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
if (request.type === 'GET_DATA') {
chrome.storage.local.get(['siteData', 'lastResetDate']).then(data => {
// Include current active tab time if any
let currentExtraTime = 0;
if (activeTabDomain && activeTabStartTime && !isIdle) {
currentExtraTime = Math.round((Date.now() - activeTabStartTime) / 1000);
}
sendResponse({
siteData: data.siteData || {},
lastResetDate: data.lastResetDate,
currentDomain: activeTabDomain,
currentExtraTime: currentExtraTime,
isIdle: isIdle
});
});
return true; // Keep message channel open for async
}
if (request.type === 'EXPORT_CSV') {
exportToCSV().then(csv => {
sendResponse({ csv });
});
return true;
}
if (request.type === 'RESET_DATA') {
chrome.storage.local.set({
siteData: {},
lastResetDate: new Date().toISOString().split('T')[0]
}).then(() => {
sendResponse({ success: true });
});
return true;
}
});
// Export data to CSV
async function exportToCSV() {
const data = await chrome.storage.local.get(['siteData', 'lastResetDate']);
const siteData = data.siteData || {};
const date = data.lastResetDate || new Date().toISOString().split('T')[0];
let csv = 'Domain,Time (HH:MM),Total Seconds\n';
// Sort by time spent (descending)
const sortedDomains = Object.entries(siteData)
.sort((a, b) => b[1] - a[1]);
for (const [domain, seconds] of sortedDomains) {
const hours = Math.floor(seconds / 3600);
const mins = Math.floor((seconds % 3600) / 60);
const timeStr = `${hours.toString().padStart(2, '0')}:${mins.toString().padStart(2, '0')}`;
csv += `"${domain}","${timeStr}",${seconds}\n`;
}
return { csv, date };
}
// Periodically save active tab time (every 30 seconds)
setInterval(async () => {
if (activeTabId && activeTabStartTime && !isIdle) {
await saveActiveTabTime();
activeTabStartTime = Date.now(); // Reset start time
}
}, 30000);
// Check for daily reset every hour
setInterval(() => {
checkAndResetDailyData();
}, 3600000);