使用 chrome.tab api 和 chrome 扩展来计时专注于选项卡的时间量

Mic*_*orn 5 javascript google-chrome-extension reactjs

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

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

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

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);
}
Run Code Online (Sandbox Code Playgroud)

我不是 100% 确定这里的最佳方法 - 我在想,检查一下旧数据是否处于活动状态,而新数据是否处于活动状态?

所以像

if (tabExisting.highlighted != tab.highlighted) {
//set endFocus?
} 
Run Code Online (Sandbox Code Playgroud)

当执行这种方法时,它似乎不起作用,tabExisting 基本上很多时候都显示为 null。

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

喜欢这里的一些反馈 - 我的大脑因为盯着这个文档而有点焦躁,并且希望得到一些指导。

Rah*_*rma 2

你的做法有些正确。但是,您想要跟踪的活动类型我会将类型更改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
};
Run Code Online (Sandbox Code Playgroud)

因为人们会在选项卡之间频繁切换,并且特定选项卡会有多个焦点时段。另请注意,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: '' }]; 
        }
      ]
    }
  }
)
Run Code Online (Sandbox Code Playgroud)

如果您只对跟踪用户实际访问的选项卡感兴趣,则上述代码应该适合您。尽管在某些情况下,我们这样做Cmd+ClickCtrl+Click在新选项卡中打开网址不会使新创建的选项卡处于活动状态。如果用户从未选择该选项卡,即使用户由于这种情况关闭该选项卡,您也将无法跟踪它:if (tabExists)在您的.onRemoved事件处理函数中。对于这些情况,我们应该添加.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: [];
        }
      ]
    }
  }
)
Run Code Online (Sandbox Code Playgroud)

到目前为止,一切都很好。我们添加了上面提到的事件处理程序。.onActivated但在或事件被触发时.onCreated,并不能保证会有一个 url。因此,当选项卡的 url 更新时,.onUpdated会触发该事件。这就是为什么我们需要稍微更改一下代码。visitedPages我们仅在存在时添加一个条目tabExisting.url(不为空、未定义或“”);

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

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 
  }
});
Run Code Online (Sandbox Code Playgroud)

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