Skip to content

Commit 638ee93

Browse files
committed
feat: smi
1 parent fa4c362 commit 638ee93

5 files changed

Lines changed: 152 additions & 0 deletions

File tree

src/content-script/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { sendMsg2Runtime } from "@api/chrome/runtime"
99
import { initLocale } from "@i18n"
1010
import processLimit from "./limit"
1111
import printInfo from "./printer"
12+
import TimelineCollector from './timeline'
1213
import NormalTracker from "./tracker/normal"
1314
import RunTimeTracker from "./tracker/run-time"
1415

@@ -60,6 +61,8 @@ async function main() {
6061
normalTracker.init()
6162
const runTimeTracker = new RunTimeTracker(url)
6263
runTimeTracker.init()
64+
const timelineCollector = new TimelineCollector()
65+
timelineCollector.init()
6366

6467
// Execute only one time for each dom
6568
if (getOrSetFlag()) return

src/content-script/timeline.ts

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
import { sendMsg2Runtime } from '@api/chrome/runtime'
2+
3+
type Session = {
4+
startTime: number
5+
domain: string
6+
}
7+
8+
export default class TimelineCollector {
9+
private currentSession: Session | null = null;
10+
11+
private isActive: boolean = false;
12+
13+
/**
14+
* Bind page visibility and focus events
15+
*/
16+
init(): void {
17+
document.addEventListener('visibilitychange', () => {
18+
if (document.hidden) {
19+
this.pauseTracking()
20+
} else {
21+
this.startTracking()
22+
}
23+
})
24+
25+
window.addEventListener('focus', () => this.startTracking())
26+
window.addEventListener('blur', () => this.pauseTracking())
27+
window.addEventListener('beforeunload', () => this.endCurrentSession())
28+
29+
if (document.readyState === 'complete') {
30+
this.startTracking()
31+
} else {
32+
window.addEventListener('load', () => this.startTracking())
33+
}
34+
}
35+
36+
/**
37+
* Start tracking current page
38+
*/
39+
public startTracking(): void {
40+
if (this.isActive) return
41+
42+
this.isActive = true
43+
const now: number = Date.now()
44+
const domain: string = this.getCurrentDomain()
45+
46+
this.currentSession = {
47+
startTime: now,
48+
domain: domain,
49+
}
50+
}
51+
52+
/**
53+
* Pause tracking
54+
*/
55+
public pauseTracking(): void {
56+
if (!this.isActive || !this.currentSession) return
57+
58+
this.endCurrentSession()
59+
}
60+
61+
/**
62+
* End current session and generate event
63+
*/
64+
private endCurrentSession(): void {
65+
if (!this.currentSession) return
66+
67+
const now: number = Date.now()
68+
const duration: number = now - this.currentSession.startTime
69+
70+
const event = this.createEvent(
71+
this.currentSession.startTime,
72+
this.currentSession.domain,
73+
duration,
74+
)
75+
sendMsg2Runtime('cs.timelineEv', event)
76+
77+
this.currentSession = null
78+
this.isActive = false
79+
}
80+
81+
/**
82+
* Create event object
83+
*/
84+
private createEvent(startTime: number, domain: string, duration: number): timer.timeline.Event {
85+
return {
86+
startTime: startTime,
87+
domain: domain,
88+
duration: duration,
89+
}
90+
}
91+
92+
/**
93+
* Get current domain
94+
*/
95+
private getCurrentDomain(): string {
96+
try {
97+
return new URL(window.location.href).hostname
98+
} catch (error) {
99+
return window.location.hostname || 'unknown'
100+
}
101+
}
102+
103+
/**
104+
* Destroy collector and remove event listeners
105+
*/
106+
public destroy(): void {
107+
this.endCurrentSession()
108+
}
109+
}

src/database/timeline-database.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import BaseDatabase from './common/base-database'
2+
import { REMAIN_WORD_PREFIX } from './common/constant'
3+
4+
const DB_KEY = REMAIN_WORD_PREFIX + 'TL'
5+
6+
type Item = {
7+
// start
8+
s: number
9+
// duration
10+
d: number
11+
// host
12+
h: string
13+
}
14+
15+
type TimelineData = {
16+
date: []
17+
}
18+
19+
class TimelineDatabase extends BaseDatabase {
20+
21+
async save(ev: timer.timeline.Event): Promise<void> {
22+
23+
}
24+
25+
async importData(_: any): Promise<void> {
26+
// do nothing
27+
}
28+
}
29+
const timelineDatabase = new TimelineDatabase()
30+
31+
export default timelineDatabase

types/timer/mq.d.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ declare namespace timer.mq {
3636
| "cs.idleChange"
3737
// @since 3.2.0
3838
| "cs.getRunSites"
39+
// @since 3.6.1
40+
| "cs.timelineEv"
3941

4042
type ResCode = "success" | "fail" | "ignore"
4143

types/timer/timeline.d.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
declare namespace timer.timeline {
2+
type Event = {
3+
startTime: number
4+
domain: string
5+
duration: number
6+
}
7+
}

0 commit comments

Comments
 (0)