Skip to content

Commit

Permalink
convert to md
Browse files Browse the repository at this point in the history
  • Loading branch information
Chege Qumu committed Apr 5, 2022
1 parent d483c07 commit 283d940
Show file tree
Hide file tree
Showing 5 changed files with 80 additions and 55 deletions.
Binary file modified .DS_Store
Binary file not shown.
12 changes: 10 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

出于这些原因,我们有必要给一些重要的数据做备份

### use
## use

1. 把你需要备份的 notion 页面 share, 只要在点击 'Share', 打开 share to web 即可,然后复制 URL 后面那一串 id,这个 id 就是这个页面在 notion 的全局 id(注意,你不需要 share 一个页面下面的子页面,只要顶级页面 share 了,那么子页面也会被 share):

Expand Down Expand Up @@ -63,4 +63,12 @@

下载备份结果到本地,解压,只需要把顶级的 `index.html` 在浏览器打开,里面的子页面的链接会自动改成本地的地址,点击 `index.html` 里面的链接可以在浏览器自动打开子页面。

![](/readmeAssets/img/3.png)
![](/readmeAssets/img/3.png)

## 目前存在问题

1. 递归备份子页面只支持在父页面上创建的子页面,从其他 notion 页面复制的子页面链接不能被备份,但是点击这种子页面的链接会跳到 notion 的页面,不影响查看内容

2. 图片等非文字静态资源暂时不会备份,这些资源被 notion 放在 AWS 的服务器

3. 导出格式为 HTML 的时候格式和 notion 保持一样,但是转化为 markdown 的时候格式会失真
17 changes: 8 additions & 9 deletions scripts/index.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,15 @@ import AdmZip from 'adm-zip'
console.log('-----notion backup start-----', process.argv)
console.log('reading notion block id from your cmd argv ...')

const isDev = process.env.NODE_ENV === 'development'

if (!isDev && !process.argv[2]) {
throw 'can not get notion block id!'
}
// if (!process.argv[2]) {
// throw 'can not get notion block id!'
// }

// 测试 notion page id:917c1456eb6b472590f3611fb57b691c(子页面不是直接子页面,而是其他页面的链接)

// 713b6661d9904d57a1b310ef334257c0
const blockIdArr = process.argv[2].split(',').map(id => id.trim())
const exportFileType = 'html' // process.argv[3]

console.log('this is notion block id you want to back up:\n')
console.log(blockIdArr)
Expand All @@ -38,13 +38,13 @@ async function backupNotionPage(parentDir = '', blockId) {
failPageIdArr.push(blockId.replaceAll('-', ''))
throw 'page fetch error'
}
// blockId === '713b6661d9904d57a1b310ef334257c0' &&
// blockId === '917c1456eb6b472590f3611fb57b691c' &&
// fs.writeFileSync(path.resolve(__dirname, '../log' + `/res${blockId}.json`), JSON.stringify(res2))
// console.log({res2})
const dirPath = `${parentDir}/${pureBlockId(blockId)}`
fs.mkdirSync(dirPath, { recursive: true })
const { htmlStr, childPages: childPagesId } = renderNotionPage(dirPath, res2, blockId)
fs.writeFileSync(`${dirPath}/index.html`, htmlStr)
const { str, childPages: childPagesId } = renderNotionPage(dirPath, res2, blockId, exportFileType)
fs.writeFileSync(`${dirPath}/index.${exportFileType}`, str)
// console.log(
// {
// blockId,
Expand Down Expand Up @@ -90,7 +90,6 @@ Promise.allSettled(
})
).then(resultArr => {
console.log('backup done')
isDev && console.log(resultArr)
const successIds = resultArr.filter(({ status, value }) => {
return status === 'fulfilled'
}).map(i => i.value)
Expand Down
15 changes: 15 additions & 0 deletions scripts/render/convertHtmlToMd.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { NodeHtmlMarkdown, NodeHtmlMarkdownOptions } from 'node-html-markdown'

const nhm = new NodeHtmlMarkdown(
/* options (optional) */
{
preferNativeParser: true,

},
/* customTransformers (optional) */ undefined,
/* customCodeBlockTranslators (optional) */ undefined
);

export default function convertHtmlToMd(htmlStr) {
return nhm.translate(htmlStr)
}
91 changes: 47 additions & 44 deletions scripts/render/renderToHtmlString.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,8 @@
import React from 'react';
import { renderToString } from 'react-dom/server'
import { NotionRenderer, Equation, Collection, CollectionRow, Code } from 'react-notion-x'
// import { NodeHtmlMarkdown, NodeHtmlMarkdownOptions } from 'node-html-markdown'
// import '../style/notion-render.css'
import convertHtmlToMd from './convertHtmlToMd'

// const nhm = new NodeHtmlMarkdown(
// /* options (optional) */ {},
// /* customTransformers (optional) */ undefined,
// /* customCodeBlockTranslators (optional) */ undefined
// );
const CHILD_BLOCK_TYPE = [
'page'
]
Expand All @@ -21,12 +15,11 @@ function findPageBlockId(parentId, blockValue, blocks = [], collectionView = {})
// isSubPage 直接子页面
const isSubPage = blockValue.content.includes(block.value.id) &&
CHILD_BLOCK_TYPE.includes(block.value.type)
// && block.value.id !== generatePageId(parentId)
if (isSubPage) {
childIds.push(block.value.id)
}

// todo 间接子页面,比如复制的其他 notion 页面的链接(非直接子页面)

// collection page
let collectionSubPageIds = []
if (block.value.type === 'collection_view') {
Expand All @@ -47,26 +40,38 @@ function findPageBlockId(parentId, blockValue, blocks = [], collectionView = {})
}

const PageLink = (
redirectBaseUrl
fileType, // html/md
childPagesIdArr = []
) => (props) => {
// console.log({props})
// console.log({props, childPagesIdArr})
const id = props.href.match(/\/(.*)/)[1]
const isSubPage = childPagesIdArr.includes(generatePageId(id))
return <a
{...props}
className={props.className + ' notion-link-rewrite-base-path'}
className={props.className + (isSubPage ? ' notion-link-rewrite-base-path' : '')}
href={
// relativePath +
'/childPages' +
props.href +
'/index.html'
isSubPage
?
('/childPages' +
props.href +
`/index.${fileType}`)
: ('https://www.notion.so' + props.href)
}
target='_blank'
>
{props.children}
</a>
}

export function renderNotionPage(parentDir, recordMap, blockId) {
const htmlStr = renderToString(
export function renderNotionPage(parentDir, recordMap, blockId, fileType) { // fileType html/md
const childPages = findPageBlockId(
blockId,
recordMap.block[generatePageId(blockId)].value,
Object.values(recordMap.block),
recordMap['collection_view']
).filter(id => id !== blockId)

let htmlStr = renderToString(
<NotionRenderer
recordMap={recordMap}
previewImages
Expand All @@ -79,39 +84,37 @@ export function renderNotionPage(parentDir, recordMap, blockId) {
code: Code,
collection: Collection,
collectionRow: CollectionRow,
pageLink: PageLink(parentDir)
pageLink: PageLink(fileType, childPages)
}}
/>
)
const notionRenderCSSCDN = 'https://cdn.jsdelivr.net/npm/[email protected]/src/styles.css'
htmlStr = `<html>
<head>
<meta charset='utf-8'/>
<meta name="viewport" content="width=device-width,user-scalable=0,initial-scale=1,maximum-scale=1, minimum-scale=1">
<link rel='stylesheet' href='${notionRenderCSSCDN}'/>
<script type='text/javascript'>
window.onload = () => {
const pageLinks = document.getElementsByClassName('notion-link-rewrite-base-path')
console.log({pageLinks})
for(let i = 0; i < pageLinks.length; i++) {
const linkNode = pageLinks[i]
linkNode.href = window.location.href.replace('/index.html', '') + linkNode.href.replace('file:///', '/')
}
}
</script>
</head>
<body>
${htmlStr}
</body>
</html>`
return {
htmlStr: `<html>
<head>
<link rel='stylesheet' href='${notionRenderCSSCDN}'/>
<script type='text/javascript'>
window.onload = () => {
const pageLinks = document.getElementsByClassName('notion-link-rewrite-base-path')
console.log({pageLinks})
for(let i = 0; i < pageLinks.length; i++) {
const linkNode = pageLinks[i]
linkNode.href = window.location.href.replace('/index.html', '') + linkNode.href.replace('file:///', '/')
}
}
</script>
</head>
<body>
${htmlStr}
</body>
</html>`,

childPages: findPageBlockId(
blockId,
recordMap.block[generatePageId(blockId)].value,
Object.values(recordMap.block),
recordMap['collection_view']
).filter(id => id !== blockId)
str: fileType === 'html' ? htmlStr : convertHtmlToMd(htmlStr),
childPages
}
}

function generatePageId(rawPageId) {
if (/[^-]{8}-[^-]{4}-[^-]{4}-[^-]{4}-[^-]{12}/.test(rawPageId)) {
return rawPageId
Expand Down

0 comments on commit 283d940

Please sign in to comment.