fix(NewPostNotification): 修复RSS文章检测中的重复通知问题

修复因GUID处理不一致导致的重复通知。主要修改包括:
- 将数据库版本升级至3,确保对象存储使用正确的键路径
- 新增GUID规范化函数,统一处理不同格式的标识符
- 优化文章比较逻辑,使用规范化后的GUID进行匹配
- 改进SCOPE_ID生成方式,基于BASE_URL而非路径名
This commit is contained in:
二叉树树
2026-01-30 03:38:05 +08:00
parent 07a7448c3d
commit ea9e721d22

View File

@@ -53,14 +53,15 @@
(async function() {
const DB_NAME = 'fuwari-rss-store';
const DB_VERSION = 2;
const DB_VERSION = 3;
const STORE_NAME = 'posts';
const LOCAL_STORAGE_KEY = 'blog-posts-cache';
const NOTIFICATION_ID = 'new-post-notification';
const LIST_ID = 'new-post-list';
// Compute a context-aware ID for the current site/path
const SCOPE_ID = window.location.pathname.split('/')[1] || 'root';
const BASE_PATH = (import.meta.env.BASE_URL ?? '/');
const SCOPE_ID = BASE_PATH.replace(/^\/+|\/+$/g, '') || 'root';
// IndexedDB Helpers
function openDB() {
@@ -70,14 +71,30 @@
request.onsuccess = () => resolve(request.result);
request.onupgradeneeded = (event) => {
const db = event.target.result;
if (!db.objectStoreNames.contains(STORE_NAME)) {
// We use 'id' as the keyPath which will be a composite key
if (db.objectStoreNames.contains(STORE_NAME)) {
const existingStore = event.target.transaction.objectStore(STORE_NAME);
if (existingStore.keyPath !== 'id') {
db.deleteObjectStore(STORE_NAME);
db.createObjectStore(STORE_NAME, { keyPath: 'id' });
}
return;
}
db.createObjectStore(STORE_NAME, { keyPath: 'id' });
};
});
}
function normalizeGuid(guid, link) {
const value = (guid || link || '').trim();
if (!value) return '';
try {
const url = new URL(value, window.location.origin);
return `${url.pathname}${url.search}${url.hash}`;
} catch {
return value;
}
}
function generateId(guid) {
// Create a unique ID combining the scope (pathname root) and the article guid
return `${SCOPE_ID}:${guid}`;
@@ -120,8 +137,9 @@
return items.map(item => {
const title = item.querySelector('title')?.textContent || '';
const link = item.querySelector('link')?.textContent || '';
const guid = item.querySelector('guid')?.textContent || link;
const link = (item.querySelector('link')?.textContent || '').trim();
const rawGuid = (item.querySelector('guid')?.textContent || '').trim();
const guid = normalizeGuid(rawGuid || link, link);
const pubDate = new Date(item.querySelector('pubDate')?.textContent || '').getTime();
const description = item.querySelector('description')?.textContent || '';
@@ -432,7 +450,7 @@
diff: mockDiff
},
];
showNotification(mockPosts, Date.now(), true);
showNotification(mockPosts, Date.now(), true, Date.now());
return;
}
@@ -473,15 +491,13 @@
} else {
// Compare
const storedMap = new Map(
storedPosts
.filter(p => p.id && p.id.startsWith(`${SCOPE_ID}:`))
.map(p => [p.guid, p])
storedPosts.map(p => [p.id || generateId(p.guid || p.link || p.title), p])
);
const detectedChanges = [];
currentPosts.forEach(post => {
const stored = storedMap.get(post.guid);
const stored = storedMap.get(generateId(post.guid));
if (!stored) {
// New post
detectedChanges.push({ ...post, isUpdated: false });