Files
NotionNext/lib/notion/getNotionData.js
tlyong1992 e1d0dd9f1b Merge branch 'main' into fix-article-cover
# Conflicts:
#	lib/notion/getAllPosts.js
#	lib/notion/getNotionData.js
2022-05-19 16:18:54 +08:00

302 lines
8.8 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import BLOG from '@/blog.config'
import { getDataFromCache, setDataToCache } from '@/lib/cache/cache_manager'
import { getPostBlocks } from '@/lib/notion/getPostBlocks'
import { idToUuid } from 'notion-utils'
import { defaultMapImageUrl } from 'react-notion-x'
import { deepClone, isIterable } from '../utils'
import getAllPageIds from './getAllPageIds'
import { getAllTags } from './getAllTags'
import getPageProperties from './getPageProperties'
/**
* 获取博客数据
* @param {*} pageId
* @param {*} from
* @param latestPostCount 截取最新文章数量
* @param categoryCount
* @param tagsCount 截取标签数量
* @param pageType 过滤的文章类型,数组格式 ['Page','Post']
* @returns
*
*/
export async function getGlobalNotionData({
pageId = BLOG.NOTION_PAGE_ID,
from,
pageType = ['Post']
}) {
// 获取Notion数据
const notionPageData = deepClone(await getNotionPageData({ pageId, from }))
// 获取文章列表
notionPageData.allPosts = await getAllPosts({ notionPageData, from, pageType })
delete notionPageData.block
delete notionPageData.collection
delete notionPageData.collectionQuery
delete notionPageData.schema
delete notionPageData.rawMetadata
delete notionPageData.pageIds
delete notionPageData.tagOptions
delete notionPageData.categoryOptions
return notionPageData
}
/**
* 获取最新文章 根据最后修改时间倒序排列
* @param {*}} param0
* @returns
*/
function getLatestPosts({ allPosts, from, latestPostCount }) {
const latestPosts = Object.create(allPosts).sort((a, b) => {
const dateA = new Date(a?.lastEditedTime || a?.createdTime || a?.date?.start_date)
const dateB = new Date(b?.lastEditedTime || b?.createdTime || b?.date?.start_date)
return dateB - dateA
})
return latestPosts.slice(0, latestPostCount)
}
/**
* 获取指定notion的collection数据
* @param pageId
* @param from 请求来源
* @returns {Promise<JSX.Element|*|*[]>}
*/
export async function getNotionPageData({ pageId, from }) {
// 尝试从缓存获取
const cacheKey = 'page_block_' + pageId
const data = await getDataFromCache(cacheKey)
if (data && data.pageIds?.length > 0) {
console.log('[命中缓存]:', `from:${from}`, `root-page-id:${pageId}`)
return data
}
const pageRecordMap = await getPageRecordMapByNotionAPI({ pageId, from })
// 存入缓存
if (pageRecordMap) {
await setDataToCache(cacheKey, pageRecordMap)
}
return pageRecordMap
}
/**
* 获取用户自定义单页菜单
* @param notionPageData
* @returns {Promise<[]|*[]>}
*/
function getCustomNav({ allPages }) {
const customNav = []
if (allPages && allPages.length > 0) {
allPages.forEach(p => {
if (p?.status?.[0] === 'Published') {
if (p?.slug?.indexOf('http') === 0) {
customNav.push({ icon: p.icon || null, name: p.title, to: p.slug, show: true })
} else {
customNav.push({ icon: p.icon || null, name: p.title, to: '/' + p.slug, show: true })
}
}
})
}
return customNav
}
/**
* 获取标签选项
* @param schema
* @returns {undefined}
*/
function getTagOptions(schema) {
if (!schema) return {}
const tagSchema = Object.values(schema).find(e => e.name === 'tags')
return tagSchema?.options || []
}
/**
* 获取分类选项
* @param schema
* @returns {{}|*|*[]}
*/
function getCategoryOptions(schema) {
if (!schema) return {}
const categorySchema = Object.values(schema).find(e => e.name === 'category')
return categorySchema?.options || []
}
/**
* 获取所有文章的分类
* @param allPosts
* @returns {Promise<{}|*[]>}
*/
function getAllCategories({ allPosts, categoryOptions, sliceCount = 0 }) {
if (!allPosts || !categoryOptions) {
return []
}
// 计数
let categories = allPosts.map(p => p.category)
categories = [...categories.flat()]
const categoryObj = {}
categories.forEach(category => {
if (category in categoryObj) {
categoryObj[category]++
} else {
categoryObj[category] = 1
}
})
const list = []
if (isIterable(categoryOptions)) {
for (const c of categoryOptions) {
const count = categoryObj[c.value]
if (count) {
list.push({ id: c.id, name: c.value, color: c.color, count })
}
}
}
// 按照数量排序
// list.sort((a, b) => b.count - a.count)
if (sliceCount && sliceCount > 0) {
return list.slice(0, sliceCount)
} else {
return list
}
}
/**
* 站点信息
* @param notionPageData
* @param from
* @returns {Promise<{title,description,pageCover,icon}>}
*/
function getBlogInfo({ collection, block }) {
const title = collection?.name?.[0][0] || BLOG.TITLE
const description = collection?.description ? Object.assign(collection).description[0][0] : BLOG.DESCRIPTION
const pageCover = collection?.cover ? (mapImgUrl(collection?.cover, block[idToUuid(BLOG.NOTION_PAGE_ID)]?.value)) : BLOG.HOME_BANNER_IMAGE
const icon = collection?.icon ? (mapCollectionImg(collection?.icon, collection)) : BLOG.AVATAR
return { title, description, pageCover, icon }
}
/**
* Notion图片映射
* @param pageCover
* @returns {string}
*/
const mapImgUrl = (img, value) => {
if (img) {
if (img.startsWith('/')) return 'https://www.notion.so' + img
if (img.startsWith('http')) return defaultMapImageUrl(img, value)
}
}
/**
* collection 图片映射
* @param {*} img
* @param {*} value
* @returns
*/
const mapCollectionImg = (img, value) => {
if (img) {
if (img.startsWith('/')) return 'https://www.notion.so' + img
if (img.startsWith('http')) {
return 'https://www.notion.so/image/' + encodeURIComponent(img) + '?table=collection&id=' + value.id
}
// 判断是否含有emoji表情
const emojiPattern = /\uD83C[\uDF00-\uDFFF]|\uD83D[\uDC00-\uDE4F]/g
if (emojiPattern.test(img)) {
console.error('请不要使用emoji作为站点图标', img)
return BLOG.AVATAR
}
console.error('非法的站点图标', img)
return BLOG.AVATAR
}
}
/**
* 调用NotionAPI获取Page数据
* @returns {Promise<JSX.Element|null|*>}
*/
async function getPageRecordMapByNotionAPI({ pageId, from }) {
const pageRecordMap = await getPostBlocks(pageId, from)
if (!pageRecordMap) {
return []
}
pageId = idToUuid(pageId)
const block = pageRecordMap.block
const rawMetadata = block[pageId]?.value
// Check Type Page-Database和Inline-Database
if (
rawMetadata?.type !== 'collection_view_page' &&
rawMetadata?.type !== 'collection_view'
) {
console.warn(`pageId "${pageId}" is not a database`)
return null
}
const collection = Object.values(pageRecordMap.collection)[0]?.value
const collectionId = rawMetadata?.collection_id
const collectionQuery = pageRecordMap.collection_query
const collectionView = pageRecordMap.collection_view
const schema = collection?.schema
const tagOptions = getTagOptions(schema)
const categoryOptions = getCategoryOptions(schema)
const viewIds = rawMetadata?.view_ids
const collectionData = []
const pageIds = getAllPageIds(collectionQuery, collectionId, collectionView, viewIds)
const siteInfo = getBlogInfo({ collection, block })
if (pageIds?.length === 0) {
console.error('获取到的文章列表为空请检查notion模板', collectionQuery, collection, collectionView, viewIds, pageRecordMap)
}
for (let i = 0; i < pageIds.length; i++) {
const id = pageIds[i]
const value = block[id]?.value
if (!value) {
continue
}
collectionData.push(properties)
const properties = (await getPageProperties(id, block, schema, null, tagOptions, siteInfo)) || null
if (properties) {
data.push(properties)
}
}
const allPages = collectionData.filter(post => {
return post.title && ['Page'].indexOf(post?.type?.[0]) > -1 && (post?.status?.[0] === 'Published' || post?.status?.[0] === 'Invisible')
})
const allPosts = collectionData.filter(post => {
return post.title && ['Post'].indexOf(post?.type?.[0]) > -1 && post?.status?.[0] === 'Published'
})
// Sort by date
if (BLOG.POSTS_SORT_BY === 'date') {
allPosts.sort((a, b) => {
const dateA = new Date(a?.date?.start_date || a.createdTime)
const dateB = new Date(b?.date?.start_date || b.createdTime)
return dateB - dateA
})
}
const customNav = getCustomNav({ allPages })
const postCount = allPosts?.length || 0
const categories = getAllCategories({ allPosts, categoryOptions, sliceCount: BLOG.PREVIEW_CATEGORY_COUNT })
const tags = getAllTags({ allPosts, tagOptions, sliceCount: BLOG.PREVIEW_TAG_COUNT })
const latestPosts = getLatestPosts({ allPosts, from, latestPostCount: 5 })
return {
siteInfo,
allPages,
allPosts,
collection,
collectionQuery,
collectionId,
collectionView,
viewIds,
block,
schema,
tagOptions,
categoryOptions,
rawMetadata,
customNav,
postCount,
pageIds,
categories,
tags,
latestPosts
}
}