MB-X Bilibili Pipeline
6 days ago dda2d9f4270f7670d2746522cf11a4ce9f72567c
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
import {TrustedRuntimeSession} from "./protocol.js";
import {collectVisiblePage} from "./page_extract.js";
import {NativePortTransport, OwnedTabLifecycle, SlotCoordinator, SlotStateStore} from "./runtime.js";
 
const HOST = "com.project_info.bili_dynamic_refresh";
const ALARM = "project-info-dynamic-refresh-half-hour";
const PERIOD_MINUTES = 30;
 
async function hashSlot(value) {
  const material = new TextEncoder().encode(String(value));
  const digest = await crypto.subtle.digest("SHA-256", material);
  return [...new Uint8Array(digest)].map((byte) => byte.toString(16).padStart(2, "0")).join("");
}
 
function nextBoundary(now = Date.now()) {
  const interval = PERIOD_MINUTES * 60 * 1000;
  return Math.floor(now / interval) * interval + interval;
}
 
function createSession(api) {
  return new TrustedRuntimeSession(api, {
    extension_id: chrome.runtime.id,
    version: chrome.runtime.getManifest().version,
    manifest_name: chrome.runtime.getManifest().name
  });
}
 
const lifecycle = new OwnedTabLifecycle(chrome);
const slotStore = new SlotStateStore(chrome);
const coordinator = new SlotCoordinator({
  lifecycle,
  slotStore,
  connect: () => new NativePortTransport(chrome.runtime.connectNative(HOST)),
  createSession,
  hashSlot,
  collectPage: collectVisiblePage
});
 
function schedule() {
  chrome.alarms.create(ALARM, {when: nextBoundary(), periodInMinutes: PERIOD_MINUTES});
}
 
function recoverAtStartup() {
  // Never leak a raw storage/runtime exception from a startup event. The next
  // scheduled run will surface the same strict fixed code without acting.
  void coordinator.recover().catch(() => console.error("E_SLOT_STATE"));
}
 
chrome.runtime.onInstalled.addListener(() => {
  schedule();
  recoverAtStartup();
});
 
chrome.runtime.onStartup.addListener(() => {
  schedule();
  recoverAtStartup();
});
 
chrome.alarms.onAlarm.addListener((alarm) => {
  if (alarm?.name !== ALARM) return;
  // The slot material is deterministic at the half-hour boundary and carries
  // no session, cookie, profile, URL query, or page payload data.
  const slot = Math.floor(Number(alarm.scheduledTime) / (PERIOD_MINUTES * 60 * 1000));
  void coordinator.run(`dynamic-slot:${slot}`);
});