glide: intercept reddit at the network level
Assisted-by: GLM-5.3 via pi
change sqzvmotltlzytsnvxynsutuwwvwqyknx
commit a7e241bea1aa3dfaeb545b436ffe9d9497e307b6
author Alpha Chen <alpha@kejadlen.dev>
date
parent mtvtqotq
diff --git a/.config/glide/glide.ts b/.config/glide/glide.ts
index 8d82ad03..01e29eaf 100644
--- a/.config/glide/glide.ts
+++ b/.config/glide/glide.ts
@@ -71,7 +71,8 @@ glide.autocmds.create("UrlEnter", { hostname: "mail.google.com" }, async () => {
 });
 
 // new reddit is bad (but old.reddit.com doesn't serve media paths), and reddit
-// belongs in the Social container.
+// belongs in the Social container. Intercept at the network level so the
+// new-reddit interstitial never loads.
 type ContainerName = "Social";
 
 const containerStoreIds = new Map<ContainerName, string>();
@@ -86,55 +87,75 @@ async function containerStoreId(name: ContainerName): Promise<string | null> {
   return storeId;
 }
 
+// Prime the cache so the webRequest listener below can branch synchronously.
+void containerStoreId("Social");
+
 type MoveResult = "moved" | "already" | "missing";
 
 // A tab's container is fixed at creation, so "moving" it means reopening the
-// URL in a new container tab and dropping the original.
+// URL in a new container tab and dropping the original. Concurrent moves on
+// the same tab collapse — the listener can fire twice for one navigation.
+const movesInProgress = new Set<number>();
+
 async function moveToContainer(
   name: ContainerName,
   tabId: number,
   url?: string,
 ): Promise<MoveResult> {
-  const storeId = await containerStoreId(name);
-  if (!storeId) return "missing";
-
-  const tab = await browser.tabs.get(tabId);
-  if (tab.cookieStoreId === storeId) return "already";
-
-  await browser.tabs.create({
-    url: url ?? tab.url,
-    cookieStoreId: storeId,
-    windowId: tab.windowId,
-    index: tab.index,
-    active: tab.active,
-    pinned: tab.pinned,
-  });
-  await browser.tabs.remove(tabId);
-  return "moved";
+  if (movesInProgress.has(tabId)) return "already";
+  movesInProgress.add(tabId);
+  try {
+    const storeId = await containerStoreId(name);
+    if (!storeId) return "missing";
+
+    const tab = await browser.tabs.get(tabId);
+    if (tab.cookieStoreId === storeId) return "already";
+
+    await browser.tabs.create({
+      url: url ?? tab.url,
+      cookieStoreId: storeId,
+      windowId: tab.windowId,
+      index: tab.index,
+      active: tab.active,
+      pinned: tab.pinned,
+    });
+    await browser.tabs.remove(tabId);
+    return "moved";
+  } finally {
+    movesInProgress.delete(tabId);
+  }
 }
 
-glide.autocmds.create(
-  "UrlEnter",
-  /^https?:\/\/([a-z0-9-]+\.)*reddit\.com(\/|$)/i,
-  async ({ url, tab_id }) => {
-    const parsed = new URL(url);
+browser.webRequest.onBeforeRequest.addListener(
+  (details) => {
+    const url = new URL(details.url);
 
     // old reddit doesn't serve /media paths
-    if (parsed.hostname !== "old.reddit.com" && !parsed.pathname.startsWith("/media")) {
-      parsed.hostname = "old.reddit.com";
+    if (url.hostname !== "old.reddit.com" && !url.pathname.startsWith("/media")) {
+      url.hostname = "old.reddit.com";
     }
+    const target = url.toString();
 
-    const result = await moveToContainer("Social", tab_id, parsed.toString());
-    if (result === "missing") {
-      glide.g["dev.kejadlen"]!.notify(
-        'reddit: no "Social" container found',
-      );
-      return;
-    }
-    if (result === "already" && parsed.toString() !== url) {
-      await browser.tabs.update(tab_id, { url: parsed.toString() });
+    const socialId = containerStoreIds.get("Social");
+    if (socialId && details.cookieStoreId === socialId) {
+      return target === details.url ? undefined : { redirectUrl: target };
     }
+
+    // Reopen in the Social container rather than load here.
+    void moveToContainer("Social", details.tabId, target).then((result) => {
+      if (result === "missing") {
+        glide.g["dev.kejadlen"]!.notify('reddit: no "Social" container found');
+      }
+    });
+
+    // Cancel only once the container is known to exist — a missing one
+    // leaves the page readable instead of canceled. Until the cache warms,
+    // redirect so the navigation still lands on old reddit.
+    if (socialId) return { cancel: true };
+    return target === details.url ? undefined : { redirectUrl: target };
   },
+  { urls: ["*://*.reddit.com/*"], types: ["main_frame"] },
+  ["blocking"]
 );
 
 // strip tracking params (rewrites the request before it fires, no reload)