Skip to content

Commit cf17e74

Browse files
sheepzhzhanghengyang.zhy@alibaba-inc.com
authored andcommitted
Use content script to stat browsing time for mv3 (#71)
1 parent ce7e351 commit cf17e74

39 files changed

+262
-441
lines changed

global.d.ts

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -110,10 +110,6 @@ declare namespace timer {
110110
}
111111

112112
type StatisticsOption = {
113-
/**
114-
* Count when idle
115-
*/
116-
countWhenIdle: boolean
117113
/**
118114
* Whether to collect the site name
119115
*
@@ -230,6 +226,12 @@ declare namespace timer {
230226
| 'mn'
231227

232228
namespace stat {
229+
type Event = {
230+
start: number
231+
end: number
232+
url: string
233+
ignoreTabCheck: boolean
234+
}
233235
/**
234236
* The dimension to statistics
235237
*/
@@ -530,6 +532,7 @@ declare namespace timer {
530532
| "cs.getTodayInfo"
531533
| "cs.moreMinutes"
532534
| "cs.getLimitedRules"
535+
| "cs.trackTime"
533536
type ResCode = "success" | "fail" | "ignore"
534537

535538
/**
@@ -550,7 +553,7 @@ declare namespace timer {
550553
/**
551554
* @since 1.3.0
552555
*/
553-
type Handler<Req, Res> = (data: Req, sender: chrome.runtime.MessageSender) => Promise<Res>
556+
type Handler<Req, Res> = (data: Req, sender?: chrome.runtime.MessageSender) => Promise<Res>
554557
/**
555558
* @since 0.8.4
556559
*/
@@ -575,6 +578,4 @@ declare type ChromeAlarm = chrome.alarms.Alarm
575578
// chrome.runtime
576579
declare type ChromeOnInstalledReason = chrome.runtime.OnInstalledReason
577580
declare type ChromeMessageSender = chrome.runtime.MessageSender
578-
declare type ChromeMessageHandler<T = any, R = any> = (req: timer.mq.Request<T>, sender: ChromeMessageSender) => Promise<timer.mq.Response<R>>
579-
// chrome.idle
580-
declare type ChromeIdleState = chrome.idle.IdleState
581+
declare type ChromeMessageHandler<T = any, R = any> = (req: timer.mq.Request<T>, sender: ChromeMessageSender) => Promise<timer.mq.Response<R>>

script/crowdin/common.ts

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -214,13 +214,3 @@ export async function checkMainBranch(client: CrowdinClient) {
214214
}
215215
return branch
216216
}
217-
218-
// function main() {
219-
// const file = fs.readFileSync(path.join(MSG_BASE, 'app', 'habit.ts'), { encoding: 'utf-8' })
220-
// const result = /(const|let|var) _default(.*)=\s*\{\s*(\n?.*\n)+\}/.exec(file)
221-
// const origin = result[0]
222-
// console.log(origin)
223-
// console.log(file.indexOf(origin))
224-
// }
225-
226-
// main()

src/api/chrome/context-menu.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,19 @@
1+
import { IS_MV3 } from "@util/constant/environment"
12
import { handleError } from "./common"
23

4+
function onClick(id: string, handler: Function) {
5+
chrome.contextMenus.onClicked.addListener(({ menuItemId }) => menuItemId === id && handler?.())
6+
}
7+
38
export function createContextMenu(props: ChromeContextMenuCreateProps): Promise<void> {
9+
let clickHandler: Function = undefined
10+
if (IS_MV3) {
11+
clickHandler = props.onclick
12+
delete props.onclick
13+
}
414
return new Promise(resolve => chrome.contextMenus.create(props, () => {
515
handleError('createContextMenu')
16+
clickHandler && onClick(props.id, clickHandler)
617
resolve()
718
}))
819
}

src/api/chrome/idle.ts

Lines changed: 0 additions & 3 deletions
This file was deleted.

src/app/components/option/components/statistics.ts

Lines changed: 13 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -13,17 +13,12 @@ import { defaultStatistics } from "@util/constant/option"
1313
import { defineComponent, h, reactive, unref } from "vue"
1414
import { t } from "@app/locale"
1515
import { renderOptionItem, tagText, tooltip } from "../common"
16-
import { IS_SAFARI } from "@util/constant/environment"
1716

1817
function updateOptionVal(key: keyof timer.option.StatisticsOption, newVal: boolean, option: UnwrapRef<timer.option.StatisticsOption>) {
1918
option[key] = newVal
2019
optionService.setStatisticsOption(unref(option))
2120
}
2221

23-
const countWhenIdle = (option: UnwrapRef<timer.option.StatisticsOption>) => h(ElSwitch, {
24-
modelValue: option.countWhenIdle,
25-
onChange: (newVal: boolean) => updateOptionVal('countWhenIdle', newVal, option)
26-
})
2722

2823
const countLocalFiles = (option: UnwrapRef<timer.option.StatisticsOption>) => h(ElSwitch, {
2924
modelValue: option.countLocalFiles,
@@ -36,40 +31,10 @@ const collectSiteName = (option: UnwrapRef<timer.option.StatisticsOption>) => h(
3631
})
3732

3833
function copy(target: timer.option.StatisticsOption, source: timer.option.StatisticsOption) {
39-
target.countWhenIdle = source.countWhenIdle
4034
target.collectSiteName = source.collectSiteName
4135
target.countLocalFiles = source.countLocalFiles
4236
}
4337

44-
function renderOptionItems(option: timer.option.StatisticsOption) {
45-
const result = []
46-
if (!IS_SAFARI) {
47-
// chrome.idle does not work in Safari, so not to display this option
48-
result.push(
49-
renderOptionItem({
50-
input: countWhenIdle(option),
51-
idleTime: tagText(msg => msg.option.statistics.idleTime),
52-
info: tooltip(msg => msg.option.statistics.idleTimeInfo)
53-
}, msg => msg.statistics.countWhenIdle, t(msg => msg.option.yes)),
54-
h(ElDivider)
55-
)
56-
}
57-
result.push(
58-
renderOptionItem({
59-
input: countLocalFiles(option),
60-
localFileTime: tagText(msg => msg.option.statistics.localFileTime),
61-
info: tooltip(msg => msg.option.statistics.localFilesInfo)
62-
}, msg => msg.statistics.countLocalFiles, t(msg => msg.option.no)),
63-
h(ElDivider),
64-
renderOptionItem({
65-
input: collectSiteName(option),
66-
siteName: tagText(msg => msg.option.statistics.siteName),
67-
siteNameUsage: tooltip(msg => msg.option.statistics.siteNameUsage)
68-
}, msg => msg.statistics.collectSiteName, t(msg => msg.option.yes))
69-
)
70-
return result
71-
}
72-
7338
const _default = defineComponent({
7439
name: "StatisticsOptionContainer",
7540
setup(_props, ctx) {
@@ -81,7 +46,19 @@ const _default = defineComponent({
8146
await optionService.setStatisticsOption(unref(option))
8247
}
8348
})
84-
return () => h('div', renderOptionItems(option))
49+
return () => h('div', [
50+
renderOptionItem({
51+
input: countLocalFiles(option),
52+
localFileTime: tagText(msg => msg.option.statistics.localFileTime),
53+
info: tooltip(msg => msg.option.statistics.localFilesInfo)
54+
}, msg => msg.statistics.countLocalFiles, t(msg => msg.option.no)),
55+
h(ElDivider),
56+
renderOptionItem({
57+
input: collectSiteName(option),
58+
siteName: tagText(msg => msg.option.statistics.siteName),
59+
siteNameUsage: tooltip(msg => msg.option.statistics.siteNameUsage)
60+
}, msg => msg.statistics.collectSiteName, t(msg => msg.option.yes))
61+
])
8562
}
8663
})
8764

src/background/active-tab-listener.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ export default class ActiveTabListener {
3434
listen() {
3535
onTabActivated(async tabId => {
3636
const tab = await getTab(tabId)
37-
this.processWithTabInfo(tab)
37+
tab && this.processWithTabInfo(tab)
3838
})
3939
}
4040
}

src/background/badge-text-manager.ts

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ import TimerDatabase from "@db/timer-database"
1212
import whitelistHolder from "@service/components/whitelist-holder"
1313
import optionService from "@service/option-service"
1414
import { extractHostname, isBrowserUrl } from "@util/pattern"
15-
import alarmManager from "./alarm-manager"
1615

1716
const storage = chrome.storage.local
1817
const timerDb: TimerDatabase = new TimerDatabase(storage)
@@ -26,6 +25,7 @@ export type BadgeLocation = {
2625
* The url of tab
2726
*/
2827
url: string
28+
focus?: number
2929
}
3030

3131
function mill2Str(milliseconds: number) {
@@ -67,7 +67,7 @@ async function updateFocus(badgeLocation?: BadgeLocation, lastLocation?: BadgeLo
6767
if (!badgeLocation) {
6868
return badgeLocation
6969
}
70-
const { url, tabId } = badgeLocation
70+
const { url, tabId, focus } = badgeLocation
7171
if (!url || isBrowserUrl(url)) {
7272
return badgeLocation
7373
}
@@ -76,7 +76,7 @@ async function updateFocus(badgeLocation?: BadgeLocation, lastLocation?: BadgeLo
7676
setBadgeText('W', tabId)
7777
return badgeLocation
7878
}
79-
const milliseconds = host ? (await timerDb.get(host, new Date())).focus : undefined
79+
const milliseconds = focus || (host ? (await timerDb.get(host, new Date())).focus : undefined)
8080
setBadgeTextOfMills(milliseconds, tabId)
8181
return badgeLocation
8282
}
@@ -90,14 +90,12 @@ class BadgeTextManager {
9090
this.pauseOrResumeAccordingToOption(!!option.displayBadgeText)
9191
optionService.addOptionChangeListener(({ displayBadgeText }) => this.pauseOrResumeAccordingToOption(displayBadgeText))
9292
whitelistHolder.addPostHandler(updateFocus)
93-
94-
alarmManager.setInterval('badage-text-manager', 1000, () => !this.isPaused && updateFocus())
9593
}
9694

9795
/**
9896
* Hide the badge text
9997
*/
100-
async pause() {
98+
private async pause() {
10199
this.isPaused = true
102100
const tab = await findActiveTab()
103101
setBadgeText('', tab?.tabId)
@@ -106,7 +104,7 @@ class BadgeTextManager {
106104
/**
107105
* Show the badge text
108106
*/
109-
resume() {
107+
private resume() {
110108
this.isPaused = false
111109
// Update badge text immediately
112110
this.forceUpdate()

src/background/browser-action-menu-manager.ts

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,18 +8,15 @@
88
import { OPTION_ROUTE } from "../app/router/constants"
99
import { getAppPageUrl, getGuidePageUrl, SOURCE_CODE_PAGE, TU_CAO_PAGE } from "@util/constant/url"
1010
import { t2Chrome } from "@i18n/chrome/t"
11-
import { IS_MV3, IS_SAFARI } from "@util/constant/environment"
11+
import { IS_SAFARI } from "@util/constant/environment"
1212
import { createTab } from "@api/chrome/tab"
13-
import { createContextMenu } from "@api/chrome/context-menu"
1413
import { getRuntimeId } from "@api/chrome/runtime"
14+
import { createContextMenu } from "@api/chrome/context-menu"
1515

1616
const APP_PAGE_URL = getAppPageUrl(true)
1717

18-
const baseProps: Partial<ChromeContextMenuCreateProps> = {
19-
// Cast unknown to fix the error with manifestV2
20-
// Because 'browser_action' will be replaced with 'action' in union type chrome.contextMenus.ContextType since V3
21-
// But 'action' does not work in V2
22-
contexts: [IS_MV3 ? 'action' : 'browser_action'],
18+
const baseProps: Partial<chrome.contextMenus.CreateProperties> = {
19+
contexts: ['action'],
2320
visible: true
2421
}
2522

src/background/content-script-handler.ts

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -20,21 +20,13 @@ import MessageDispatcher from "./message-dispatcher"
2020
export default function init(dispatcher: MessageDispatcher) {
2121
dispatcher
2222
// Increase the visit time
23-
.register<string, void>('cs.incVisitCount', async host => {
24-
timerService.addOneTime(host)
25-
})
23+
.register<string, void>('cs.incVisitCount', host => timerService.addOneTime(host))
2624
// Judge is in whitelist
2725
.register<string, boolean>('cs.isInWhitelist', host => whitelistService.include(host))
2826
// Need to print the information of today
29-
.register<void, boolean>('cs.printTodayInfo', async () => {
30-
const option = await optionService.getAllOption()
31-
return !!option.printInConsole
32-
})
27+
.register<void, boolean>('cs.printTodayInfo', async () => !!(await optionService.getAllOption())?.printInConsole)
3328
// Get today info
34-
.register<string, timer.stat.Result>('cs.getTodayInfo', host => {
35-
const now = new Date()
36-
return timerService.getResult(host, now)
37-
})
29+
.register<string, timer.stat.Result>('cs.getTodayInfo', host => timerService.getResult(host, new Date()))
3830
// More minutes
3931
.register<string, timer.limit.Item[]>('cs.moreMinutes', url => limitService.moreMinutes(url))
4032
// cs.getLimitedRules

src/background/icon-and-alias-collector.ts

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import HostAliasDatabase from "@db/host-alias-database"
99
import IconUrlDatabase from "@db/icon-url-database"
1010
import OptionDatabase from "@db/option-database"
1111
import { IS_CHROME, IS_SAFARI } from "@util/constant/environment"
12-
import { iconUrlOfBrowser } from "@util/constant/url"
1312
import { extractHostname, isBrowserUrl, isHomepage } from "@util/pattern"
1413
import { defaultStatistics } from "@util/constant/option"
1514
import { extractSiteName } from "@util/site"
@@ -46,13 +45,11 @@ async function processTabInfo(tab: ChromeTab): Promise<void> {
4645
if (isBrowserUrl(url)) return
4746
const hostInfo = extractHostname(url)
4847
const host = hostInfo.host
49-
const protocol = hostInfo.protocol
5048
if (!host) return
5149
let favIconUrl = tab.favIconUrl
5250
// localhost hosts with Chrome use cache, so keep the favIcon url undefined
5351
IS_CHROME && /^localhost(:.+)?/.test(host) && (favIconUrl = undefined)
54-
const iconUrl = favIconUrl || iconUrlOfBrowser(protocol, host)
55-
iconUrl && iconUrlDatabase.put(host, iconUrl)
52+
favIconUrl && iconUrlDatabase.put(host, favIconUrl)
5653
collectAliasEnabled && !isBrowserUrl(url) && isHomepage(url) && collectAlias(host, tab.title)
5754
}
5855

0 commit comments

Comments
 (0)