diff --git a/components/NotionPage.js b/components/NotionPage.js
index 586e0c0c4a4..0a011968ac4 100644
--- a/components/NotionPage.js
+++ b/components/NotionPage.js
@@ -116,12 +116,15 @@ const NotionPage = ({ post, className }) => {
return () => clearTimeout(timer)
}, [post])
+ const cleanBlockMap = cleanBlocksWithWarn(post.blockMap);
+
+
return (
{
)
}
+function cleanBlocksWithWarn(blockMap) {
+ const cleanedBlocks = {};
+ const removedBlockIds = [];
+
+ for (const [id, block] of Object.entries(blockMap.block || {})) {
+ if (!block?.value?.id) {
+ removedBlockIds.push(id);
+ continue;
+ }
+
+ const newBlock = { ...block };
+
+ if (Array.isArray(newBlock.value.content)) {
+ // 递归清理 content 中无效的 blockId
+ newBlock.value.content = newBlock.value.content.filter((cid) => {
+ if (!blockMap.block[cid]?.value?.id) {
+ removedBlockIds.push(cid);
+ return false;
+ }
+ return true;
+ });
+ }
+
+ cleanedBlocks[id] = newBlock;
+ }
+
+ if (removedBlockIds.length) {
+ console.warn('Removed invalid blocks:', removedBlockIds);
+ }
+
+ return {
+ ...blockMap,
+ block: cleanedBlocks,
+ };
+}
+
+
+
/**
* 页面的数据库链接禁止跳转,只能查看
*/
diff --git a/lib/db/getSiteData.js b/lib/db/getSiteData.js
index e2d704e279a..9cb68813ddd 100755
--- a/lib/db/getSiteData.js
+++ b/lib/db/getSiteData.js
@@ -136,6 +136,106 @@ const EmptyData = pageId => {
return empty
}
+/**
+ * 可能由于Notion接口升级导致数据格式变化,这里进行统一处理
+ * @param {*} block
+ * @param {*} pageId
+ * @returns
+ */
+function normalizeNotionMetadata(block, pageId) {
+ const rawValue = block?.[pageId]?.value
+ if (!rawValue) return null
+ return rawValue.type ? rawValue : rawValue.value ?? null
+}
+
+/**
+ * 兼容新老 Notion collection 结构 , 新版会用space_id 包裹一层
+ * 统一返回真正的 collection.value(包含 schema 的那一层)
+ */
+function normalizeCollection(collection) {
+ let current = collection
+
+ // 最多剥 3 层,防止死循环
+ for (let i = 0; i < 3; i++) {
+ if (!current) break
+
+ // 已经是最终形态:有 schema
+ if (current.schema) {
+ return current
+ }
+
+ // 常见包装:{ value: {...}, role }
+ if (current.value) {
+ current = current.value
+ continue
+ }
+
+ break
+ }
+
+ return current ?? {}
+}
+
+/**
+ * 兼容 Notion schema
+ * 保留原始字段 id 作为 key
+ */
+/**
+ * 兼容 Notion schema
+ * 保留原始字段 id 作为 key
+ */
+function normalizeSchema(schema = {}) {
+ const result = {}
+
+ Object.entries(schema).forEach(([key, value]) => {
+ result[key] = {
+ ...value,
+ name: value?.name || '',
+ type: value?.type || ''
+ }
+ })
+
+ return result
+}
+
+
+/**
+ * ✅ 终极版:兼容 Notion 新老 Page Block 结构
+ * 最终一定返回:{ id, type, properties }
+ */
+function normalizePageBlock(blockItem) {
+ if (!blockItem) return null
+
+ let current = blockItem
+
+ for (let i = 0; i < 5; i++) {
+ if (!current) return null
+
+ // 针对 collection 兼容
+ if (
+ (current.type === 'collection_view_page' || current.type === 'collection_view') &&
+ current.collection_id
+ ) {
+ return current
+ }
+
+ if (current.type && current.properties) {
+ return current
+ }
+
+ if (current.value) {
+ current = current.value
+ continue
+ }
+
+ break
+ }
+
+ return null
+}
+
+
+
/**
* 将Notion数据转站点数据
* 这里统一对数据格式化
@@ -148,7 +248,7 @@ async function convertNotionToSiteData(pageId, from, pageRecordMap) {
}
pageId = idToUuid(pageId)
let block = pageRecordMap.block || {}
- const rawMetadata = block[pageId]?.value
+ const rawMetadata = normalizeNotionMetadata(block, pageId)
// Check Type Page-Database和Inline-Database
if (
rawMetadata?.type !== 'collection_view_page' &&
@@ -157,12 +257,17 @@ async function convertNotionToSiteData(pageId, from, pageRecordMap) {
console.error(`pageId "${pageId}" is not a database`)
return EmptyData(pageId)
}
- const collection = Object.values(pageRecordMap.collection)[0]?.value || {}
const collectionId = rawMetadata?.collection_id
+
+ const rawCollection =
+ pageRecordMap.collection?.[collectionId] ||
+ pageRecordMap.collection?.[idToUuid(collectionId)] ||
+ {}
+
+ const collection = normalizeCollection(rawCollection)
const collectionQuery = pageRecordMap.collection_query
const collectionView = pageRecordMap.collection_view
- const schema = collection?.schema
-
+ const schema = normalizeSchema(collection?.schema || {})
const viewIds = rawMetadata?.view_ids
const collectionData = []
@@ -186,26 +291,37 @@ async function convertNotionToSiteData(pageId, from, pageRecordMap) {
// console.log('有效Page数量', pageIds?.length)
}
- // 抓取主数据库最多抓取1000个blocks,溢出的数block这里统一抓取一遍
+ // 1️⃣ 找出需要 fetch 的 block
const blockIdsNeedFetch = []
for (let i = 0; i < pageIds.length; i++) {
const id = pageIds[i]
- const value = block[id]?.value
- if (!value) {
+ const pageBlock = normalizePageBlock(block[id])
+
+ if (!pageBlock) {
blockIdsNeedFetch.push(id)
}
}
+
+ // 2️⃣ fetch 缺失的 blocks
const fetchedBlocks = await fetchInBatches(blockIdsNeedFetch)
block = Object.assign({}, block, fetchedBlocks)
- // 获取每篇文章基础数据
+ // 3️⃣ 只执行一次:生成 collectionData
for (let i = 0; i < pageIds.length; i++) {
const id = pageIds[i]
- const value = block[id]?.value || fetchedBlocks[id]?.value
+
+ const rawBlock = block[id]
+ const pageBlock = normalizePageBlock(rawBlock)
+
+ if (!pageBlock) {
+ console.warn('⚠️ 无法解析 page block:', id, rawBlock)
+ continue
+ }
+
const properties =
(await getPageProperties(
id,
- value,
+ pageBlock,
schema,
null,
getTagOptions(schema)
diff --git a/package.json b/package.json
index 4607e4cf964..178ccef5f48 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "notion-next",
- "version": "4.9.2",
+ "version": "4.9.2.1",
"homepage": "https://github.com/tangly1024/NotionNext.git",
"license": "MIT",
"engines": {