计时使用chrome.tab-api和chrome扩展集中在选项卡上的时间量



我正在尝试存储与一个人在特定选项卡/URL上停留的时间有关的信息。

使用铬API-https://developer.chrome.com/docs/extensions/reference/tabs/#type-选项卡-我可以跟踪选项卡的活动信息和突出显示的信息来完成此操作。

我目前正在用我的扩展程序跟踪几个不同的数据点,如下所示,我希望能够跟踪我在特定选项卡上的时间(因此我在该选项卡上的具体时间(,以及我在选项卡之间移动或创建新选项卡的频率。

export type TAB_USAGE = {
tabId: number;
index?: number;
highlighted: boolean;
url: string;
startTime: string;
endTime?: string;
startFocus?: string;
endFocus?: string;
};
const getHostname = (url: string) => {
// use URL constructor and return hostname
return new URL(url).hostname;
};
export function enableTabListener(
socket: any,
currentPages: TAB_USAGE[],
visitedPages: Partial<TAB_USAGE>[]
) {

chrome.tabs.onUpdated.addListener(

});

setInterval(async () => {
console.log('sent tab data:', visitedPages);
}, 50000);
}

我不能100%确定这里的最佳方法——我在想,检查一下旧数据是否有效,而新数据是否有效?

所以像

if (tabExisting.highlighted != tab.highlighted) {
//set endFocus?
} 

当使用这种方法时,它似乎不起作用,tabExisting基本上很多时候都是null。

或者使用另一个侦听器API,以便在突出显示更改时,在某个位置每小时设置一个计数器?我很想看看有多少个标签,我多久在它们之间切换一次,停留在其中一个标签上,真的是每小时一次,试图找到一个好的方法来做到这一点。

我喜欢这里的一些反馈——我的大脑因为盯着这些文档而有点兴奋,我希望得到一些指导。

您的方法在某种程度上是正确的。然而,对于您想要跟踪的活动类型,我会将类型TAB_USAGE更改为:

export type FocusPeriod = {
startTime: string,
endTime: string
}
export type TAB_USAGE = {
tabId: number;
index?: number;
active?: boolean;             //we're using active instead of highlighted
url?: string;                 //notice url is now optional
startTime: string;
endTime?: string;
focus?: Array<FocusPeriod>;   //storing multiple focus events of a tab
};

因为一个人会经常在选项卡之间切换,并且特定选项卡会有多个焦点时段。还要注意,url现在是可选的,因为我们将收听.onActivated事件,其中url可能在回调中不可用。

现在,为了跟踪选项卡之间的切换,我将使用.onActivated事件而不是.onHighlighted事件。请注意active选项卡和highlighted选项卡之间的区别。

活动选项卡始终高亮显示。每个窗口只有一个活动选项卡。在同一窗口中可以有多个高亮显示的选项卡。但是,所有突出显示的选项卡都不处于活动状态。示例:选择一个选项卡,按住Shift键,然后选择另一个选项卡。最后单击的选项卡将成为该窗口的活动选项卡,但它们之间的所有选项卡(包括两个限制选项卡(现在都会高亮显示。

.onActivated事件上的侦听器可以这样添加:

chrome.tabs.onActivated.addListener(
(activeInfo: object) => {
const previousActiveTabIndex = currentPages.findIndex((page) => page.active);
if(previousActiveTabIndex !== -1) {
currentPages[previousActiveTabIndex].active = false;
const focusLength = currentPages[previousActiveTabIndex].focus.length;
currentPages[previousActiveTabIndex].focus[focusLength - 1].endTime = new Date().toISOString();
}
const newActiveTabIndex = currentPages.findIndex((page) => page.tabId === activeInfo.tabId);
if(newActiveTabIndex > 0) {
currentPages[newActiveTabIndex].active = true;
currentPages[newActiveTabIndex].focus.push({
startTime: new Date().toISOString(),
endTime: ''
});
}
else {
currentPages = [
..currentPages,
{
tabId: activeInfo.tabId;
active: true;
startTime: new Date().toISOString();
focus: [{ startTime: new Date().toISOString(), endTime: '' }]; 
}
]
}
}
)

如果你只对跟踪用户实际访问的选项卡感兴趣,那么上面的代码对你来说应该很好。尽管在某些情况下,我们使用Cmd+ClickCtrl+Click在新选项卡中打开url,这不会使新创建的选项卡处于活动状态。如果用户从未选择该选项卡,那么即使用户由于以下条件关闭了该选项卡,您也将无法跟踪它:.onRemoved事件处理程序函数中的if (tabExists)。对于这些情况,我们应该添加.onCreated事件处理程序。

chrome.tabs.onCreated.addListener(
(tab: Tab) => {
const tabIndex = currentPages.findIndex((page) => page.tabId === tab.id);
if(tabIndex === -1) {
currentPages = [
..currentPages,
{
tabId: tab.id;
startTime: new Date().toISOString();
focus: [];
}
]
}
}
)

到目前为止还不错。我们添加了上面提到的事件处理程序。但在触发.onActivated.onCreated事件时,不能保证会有url。因此,当更新选项卡的url时,就会触发.onUpdated事件。这就是我们需要稍微更改代码的原因。只有当tabExisting.url存在(不是null、undefined或''(时,我们才会向visitedPages添加条目;

最后,为了在安装扩展时从所有窗口获得所有选项卡(初始化(,我们应该添加另一个事件处理程序,如下所示:

chrome.runtime.onInstalled.addListener((details) => {
if(['install', 'chrome_update'].includes(details.reason)) {
chrome.windows.getAll((windows: Window[]) => {
windows.forEach(window => {
chrome.tabs.getAllInWindow(window.id, (tabs: Tab[]) => {
tabs.forEach(tab => {
currentPages = [
..currentPages,
{
tabId: tab.id;
startTime: new Date().toISOString();
focus: [];
url: tab.url;
}
]
});
});
chrome.tabs.query({active: true, windowId: window.id}, (tab: Tab) => {
const tabIndex = currentPages.findIndex((page) => page.tabId === tab.id);
if(tabIndex > 0) {
currentPages[tabIndex - 1].active = true;
}
});
});
});
}
else if(details.reason == 'update') {
//do whatever necessary 
}
});

可以有许多正确的方法来实现这一点。我想我会这样做。如果有什么不清楚的地方,请评论。

最新更新