Global hash strip: suppress re-scan on anchor-only URL changes

This commit is contained in:
admin
2026-05-27 00:50:15 +02:00
parent 2d6a95682f
commit 87d3f6d12c
2 changed files with 27 additions and 3 deletions
+26 -2
View File
@@ -639,24 +639,42 @@ async function persistTabResult(tab, result) {
} catch {} } catch {}
} }
// URL fragment (hash) never affects server response or our ID extraction. Strip it
// when comparing URLs so in-page anchor jumps (e.g. `#gallery-1`, `#gallery-2`) don't
// invalidate the tab cache or re-trigger scans. See exoticaz.to gallery navigation.
function stripHash(url) {
if (typeof url !== "string") return url;
const i = url.indexOf("#");
return i === -1 ? url : url.slice(0, i);
}
// Tracks the last full URL we saw per tab so we can detect hash-only changes
// (which Chrome still reports via `chrome.tabs.onUpdated` with `changeInfo.url`).
const tabLastUrl = new Map(); // tabId -> last full url seen
async function getTabResult(tab) { async function getTabResult(tab) {
if (!tab || tab.id == null) return null; if (!tab || tab.id == null) return null;
try { try {
const got = await chrome.storage.session.get(tabCacheKey(tab.id)); const got = await chrome.storage.session.get(tabCacheKey(tab.id));
const entry = got[tabCacheKey(tab.id)]; const entry = got[tabCacheKey(tab.id)];
if (!entry) return null; if (!entry) return null;
if (entry.url !== (tab.url || "")) return null; if (stripHash(entry.url) !== stripHash(tab.url || "")) return null;
return entry; return entry;
} catch { return null; } } catch { return null; }
} }
chrome.tabs.onUpdated.addListener((tabId, changeInfo) => { chrome.tabs.onUpdated.addListener((tabId, changeInfo) => {
if (changeInfo.url) chrome.storage.session.remove(tabCacheKey(tabId)); if (!changeInfo.url) return;
const prev = tabLastUrl.get(tabId);
// Hash-only change → keep the cached result; same page, just a fragment jump.
if (prev && stripHash(prev) === stripHash(changeInfo.url)) return;
chrome.storage.session.remove(tabCacheKey(tabId));
}); });
chrome.tabs.onRemoved.addListener((tabId) => { chrome.tabs.onRemoved.addListener((tabId) => {
stopBadgeSpinner(tabId); stopBadgeSpinner(tabId);
chrome.storage.session.remove(tabCacheKey(tabId)); chrome.storage.session.remove(tabCacheKey(tabId));
lastAutoCheck.delete(tabId); lastAutoCheck.delete(tabId);
tabLastUrl.delete(tabId);
const t = pendingSpaTimer.get(tabId); const t = pendingSpaTimer.get(tabId);
if (t) { clearTimeout(t); pendingSpaTimer.delete(tabId); } if (t) { clearTimeout(t); pendingSpaTimer.delete(tabId); }
}); });
@@ -999,6 +1017,7 @@ chrome.tabs.onUpdated.addListener((tabId, changeInfo, tab) => {
if (changeInfo.status === "complete") { if (changeInfo.status === "complete") {
const t = pendingSpaTimer.get(tabId); const t = pendingSpaTimer.get(tabId);
if (t) { clearTimeout(t); pendingSpaTimer.delete(tabId); } if (t) { clearTimeout(t); pendingSpaTimer.delete(tabId); }
tabLastUrl.set(tabId, tab.url);
maybeAutoCheck(tabId, tab, "complete"); maybeAutoCheck(tabId, tab, "complete");
return; return;
} }
@@ -1006,6 +1025,11 @@ chrome.tabs.onUpdated.addListener((tabId, changeInfo, tab) => {
// the page has a chance to update its title/DOM, and so a real reload (which // the page has a chance to update its title/DOM, and so a real reload (which
// also emits a url change before complete) doesn't double-fire. // also emits a url change before complete) doesn't double-fire.
if (typeof changeInfo.url === "string") { if (typeof changeInfo.url === "string") {
const prevUrl = tabLastUrl.get(tabId);
tabLastUrl.set(tabId, changeInfo.url);
// Hash-only change (e.g. `#gallery-2` anchor jump) is purely client-side UI
// state. Suppress the SPA scan trigger so anchor navigation doesn't re-fire.
if (prevUrl && stripHash(prevUrl) === stripHash(changeInfo.url)) return;
const prev = pendingSpaTimer.get(tabId); const prev = pendingSpaTimer.get(tabId);
if (prev) clearTimeout(prev); if (prev) clearTimeout(prev);
const handle = setTimeout(() => { const handle = setTimeout(() => {
+1 -1
View File
@@ -1,7 +1,7 @@
{ {
"manifest_version": 3, "manifest_version": 3,
"name": "rclone-jav", "name": "rclone-jav",
"version": "0.1.52", "version": "0.1.53",
"description": "Check current page title against your rc-jav library via native messaging.", "description": "Check current page title against your rc-jav library via native messaging.",
"permissions": [ "permissions": [
"nativeMessaging", "nativeMessaging",