mirror of
https://github.com/jxpeng98/obsidian-to-NotionNext
synced 2026-07-29 16:35:57 +08:00
Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fdb81f76a7 | ||
|
|
024b7f726e | ||
|
|
722ca7bb56 | ||
|
|
fb7294d607 | ||
|
|
4f06d81588 | ||
|
|
2434ddd532 | ||
|
|
55804e491a | ||
|
|
679e7ec4f1 |
@@ -27,6 +27,10 @@
|
||||
- password
|
||||
- icon
|
||||
|
||||
在最新的0.0.6版本,我还增加了以下内容:
|
||||
- titleicon: 标题的emoji图标,暂时只能支持emoji
|
||||
- coverurl: 封面图片的url, url可以是任何一种图片的url, 例如jpg,png,svg等等。
|
||||
|
||||
**如果你是直接复制的NotionNext的模板,这些内容应该已经有了。我在原作者的基础之上对本插件的内容进行了更改,所以你只需要保证你的数据库有如上内容,并且所有的字母都是小写!!!**
|
||||
|
||||
|
||||
@@ -50,6 +54,11 @@
|
||||
# for example, if you donot want to set password, you can delete password: "1234" or set it to password: ""
|
||||
# 我已经在插件中设置了默认值,如果有不需要的选项,可以直接删除。
|
||||
# 例如你不需要密码选项,你可以将password: "1234"删除,或者将它设置为空。
|
||||
# !!!!!!!!!!!!
|
||||
# 现在阶段一定不要修改表头的名字, please do not change the name of the header in YAML front matter
|
||||
# !!!!!!!!!!!!
|
||||
titleicon: 📎 # emoji icon, default is 📜, 默认是📜
|
||||
coverurl: https://img.jxpeng.dev/2023/08/843e27a210847f05a0f7cfb121fec100.jpg # default is empty, 默认是空
|
||||
type: Post # Post or Page, default is Post, 默认是Post
|
||||
slug: test # slug for url, default is empty, 默认是空
|
||||
stats: Draft # Draft, Invisible, Published, default is Draft, 默认是Draft
|
||||
|
||||
@@ -28,6 +28,10 @@ Before installing the plugin, you must have set up the following:
|
||||
- password
|
||||
- icon
|
||||
|
||||
In version 0.0.6, I also add the following contents:
|
||||
- titleicon: the unique icon for each post, it can only support emoji currently.
|
||||
- cover url: the cover image for each post, it should be end with a type of image, such as .jpg, .png, .gif, etc.
|
||||
|
||||
**If you've directly copied the NotionNext template, these contents should already exist. I've made changes to this plugin based on the original author's work. All you need to ensure is that your database has the above content, and every letter is in lowercase!!!**
|
||||
|
||||
**⚠️⚠️⚠️: All headers are in lowercase!!! The order doesn't matter!**
|
||||
@@ -50,6 +54,11 @@ If you don't want to use the template, you can also directly create a new file i
|
||||
# for example, if you donot want to set password, you can delete password: "1234" or set it to password: ""
|
||||
# 我已经在插件中设置了默认值,如果有不需要的选项,可以直接删除。
|
||||
# 例如你不需要密码选项,你可以将password: "1234"删除,或者将它设置为空。
|
||||
# !!!!!!!!!!!!
|
||||
# 现在阶段一定不要修改表头的名字, please do not change the name of the header in YAML front matter
|
||||
# !!!!!!!!!!!!
|
||||
titleicon: 📎 # emoji icon, default is 📜, 默认是📜
|
||||
coverurl: https://img.jxpeng.dev/2023/08/843e27a210847f05a0f7cfb121fec100.jpg # default is empty, 默认是空
|
||||
type: Post # Post or Page, default is Post, 默认是Post
|
||||
slug: test # slug for url, default is empty, 默认是空
|
||||
stats: Draft # Draft, Invisible, Published, default is Draft, 默认是Draft
|
||||
|
||||
195
Upload2Notion.ts
195
Upload2Notion.ts
@@ -1,195 +0,0 @@
|
||||
import { Notice, requestUrl,TFile,normalizePath, App } from "obsidian";
|
||||
import { Client } from "@notionhq/client";
|
||||
import { markdownToBlocks, } from "@tryfabric/martian";
|
||||
import * as yamlFrontMatter from "yaml-front-matter";
|
||||
import * as yaml from "yaml"
|
||||
import MyPlugin from "main";
|
||||
export class Upload2Notion {
|
||||
app: MyPlugin;
|
||||
notion: Client;
|
||||
agent: any;
|
||||
constructor(app: MyPlugin) {
|
||||
this.app = app;
|
||||
}
|
||||
|
||||
async deletePage(notionID:string){
|
||||
const response = await requestUrl({
|
||||
url: `https://api.notion.com/v1/blocks/${notionID}`,
|
||||
method: 'DELETE',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': 'Bearer ' + this.app.settings.notionAPI,
|
||||
'Notion-Version': '2022-06-28',
|
||||
},
|
||||
body: ''
|
||||
})
|
||||
return response;
|
||||
}
|
||||
|
||||
// 因为需要解析notion的block进行对比,非常的麻烦,
|
||||
// 暂时就直接删除,新建一个page
|
||||
async updatePage(notionID:string, title:string, allowTags:boolean, tags:string[], type:string, slug:string, stats:string, category:string, summary:string, paword:string, favicon:string, datetime:string, childArr:any) {
|
||||
await this.deletePage(notionID)
|
||||
const res = await this.createPage(title, allowTags, tags, type, slug, stats, category, summary, paword, favicon, datetime, childArr)
|
||||
return res
|
||||
}
|
||||
|
||||
async createPage(title:string, allowTags:boolean, tags:string[], type:string, slug:string, stats:string, category:string, summary:string, pawrod:string, favicon:string, datetime:string, childArr: any) {
|
||||
const bodyString:any = {
|
||||
parent: {
|
||||
database_id: this.app.settings.databaseID
|
||||
},
|
||||
properties: {
|
||||
title: {
|
||||
title: [
|
||||
{
|
||||
text: {
|
||||
content: title
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
tags: {
|
||||
multi_select: allowTags && tags !== undefined ? tags.map(tag => {
|
||||
return {"name": tag}
|
||||
}) : [],
|
||||
},
|
||||
type: {
|
||||
select: {
|
||||
name: type || 'Post'
|
||||
}
|
||||
},
|
||||
slug: {
|
||||
rich_text: [
|
||||
{
|
||||
text: {
|
||||
content: slug || ''
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
status: {
|
||||
select: {
|
||||
name: stats || 'Draft'
|
||||
}
|
||||
},
|
||||
category: {
|
||||
select: {
|
||||
name: category || 'Obsidian'
|
||||
}
|
||||
},
|
||||
summary: {
|
||||
rich_text: [
|
||||
{
|
||||
text: {
|
||||
content: summary || ''
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
password: {
|
||||
rich_text: [
|
||||
{
|
||||
text: {
|
||||
content: pawrod || ''
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
icon: {
|
||||
rich_text: [
|
||||
{
|
||||
text: {
|
||||
content: favicon || ''
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
date: {
|
||||
date: {
|
||||
start: datetime || new Date().toISOString()
|
||||
}
|
||||
}
|
||||
},
|
||||
children: childArr,
|
||||
}
|
||||
|
||||
if(this.app.settings.bannerUrl) {
|
||||
bodyString.cover = {
|
||||
type: "external",
|
||||
external: {
|
||||
url: this.app.settings.bannerUrl
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await requestUrl({
|
||||
url: `https://api.notion.com/v1/pages`,
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
// 'User-Agent': 'obsidian.md',
|
||||
'Authorization': 'Bearer ' + this.app.settings.notionAPI,
|
||||
'Notion-Version': '2022-06-28',
|
||||
},
|
||||
body: JSON.stringify(bodyString),
|
||||
})
|
||||
return response;
|
||||
} catch (error) {
|
||||
new Notice(`network error ${error}`)
|
||||
}
|
||||
}
|
||||
|
||||
async syncMarkdownToNotion(title:string, allowTags:boolean, tags:string[], type:string, slug:string, stats:string, category:string, summary:string, paword:string, favicon:string, datetime:string, markdown: string, nowFile: TFile, app:App, settings:any): Promise<any> {
|
||||
let res:any
|
||||
const yamlObj:any = yamlFrontMatter.loadFront(markdown);
|
||||
const __content = yamlObj.__content
|
||||
const file2Block = markdownToBlocks(__content);
|
||||
const frontmasster =await app.metadataCache.getFileCache(nowFile)?.frontmatter
|
||||
const notionID = frontmasster ? frontmasster.notionID : null
|
||||
|
||||
if(notionID){
|
||||
res = await this.updatePage(notionID, title, allowTags, tags, type, slug, stats, category, summary, paword, favicon, datetime, file2Block);
|
||||
} else {
|
||||
res = await this.createPage(title, allowTags, tags, type, slug, stats, category, summary, paword, favicon, datetime, file2Block);
|
||||
}
|
||||
if (res.status === 200) {
|
||||
await this.updateYamlInfo(markdown, nowFile, res, app, settings)
|
||||
} else {
|
||||
new Notice(`${res.text}`)
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
async updateYamlInfo(yamlContent: string, nowFile: TFile, res: any,app:App, settings:any) {
|
||||
const yamlObj:any = yamlFrontMatter.loadFront(yamlContent);
|
||||
let {url, id} = res.json
|
||||
// replace www to notionID
|
||||
const {notionID} = settings;
|
||||
if(notionID!=="") {
|
||||
// replace url str "www" to notionID
|
||||
url = url.replace("www.notion.so", `${notionID}.notion.site`)
|
||||
}
|
||||
yamlObj.link = url;
|
||||
try {
|
||||
await navigator.clipboard.writeText(url)
|
||||
} catch (error) {
|
||||
new Notice(`复制链接失败,请手动复制${error}`)
|
||||
}
|
||||
yamlObj.notionID = id;
|
||||
const __content = yamlObj.__content;
|
||||
delete yamlObj.__content
|
||||
const yamlhead = yaml.stringify(yamlObj)
|
||||
// if yamlhead hava last \n remove it
|
||||
const yamlhead_remove_n = yamlhead.replace(/\n$/, '')
|
||||
// if __content have start \n remove it
|
||||
const __content_remove_n = __content.replace(/^\n/, '')
|
||||
const content = '---\n' +yamlhead_remove_n +'\n---\n' + __content_remove_n;
|
||||
try {
|
||||
await nowFile.vault.modify(nowFile, content)
|
||||
} catch (error) {
|
||||
new Notice(`write file error ${error}`)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,45 +8,52 @@ THIS IS A GENERATED/BUNDLED FILE BY ESBUILD
|
||||
if you want to view the source, please visit the github repository of this plugin
|
||||
*/
|
||||
`;
|
||||
|
||||
const prod = (process.argv[2] === 'production');
|
||||
|
||||
esbuild.build({
|
||||
banner: {
|
||||
js: banner,
|
||||
},
|
||||
entryPoints: ['main.ts'],
|
||||
bundle: true,
|
||||
external: [
|
||||
'obsidian',
|
||||
'electron',
|
||||
'@codemirror/autocomplete',
|
||||
'@codemirror/closebrackets',
|
||||
'@codemirror/collab',
|
||||
'@codemirror/commands',
|
||||
'@codemirror/comment',
|
||||
'@codemirror/fold',
|
||||
'@codemirror/gutter',
|
||||
'@codemirror/highlight',
|
||||
'@codemirror/history',
|
||||
'@codemirror/language',
|
||||
'@codemirror/lint',
|
||||
'@codemirror/matchbrackets',
|
||||
'@codemirror/panel',
|
||||
'@codemirror/rangeset',
|
||||
'@codemirror/rectangular-selection',
|
||||
'@codemirror/search',
|
||||
'@codemirror/state',
|
||||
'@codemirror/stream-parser',
|
||||
'@codemirror/text',
|
||||
'@codemirror/tooltip',
|
||||
'@codemirror/view',
|
||||
...builtins],
|
||||
format: 'cjs',
|
||||
watch: !prod,
|
||||
target: 'es2016',
|
||||
logLevel: "info",
|
||||
sourcemap: prod ? false : 'inline',
|
||||
treeShaking: true,
|
||||
outfile: 'main.js',
|
||||
}).catch(() => process.exit(1));
|
||||
(async () => { // Enclose everything in an async function for using await
|
||||
const ctx = await esbuild.context({
|
||||
banner: {
|
||||
js: banner,
|
||||
},
|
||||
entryPoints: ['src/main.ts'],
|
||||
bundle: true,
|
||||
external: [
|
||||
'obsidian',
|
||||
'electron',
|
||||
'@codemirror/autocomplete',
|
||||
'@codemirror/closebrackets',
|
||||
'@codemirror/collab',
|
||||
'@codemirror/commands',
|
||||
'@codemirror/comment',
|
||||
'@codemirror/fold',
|
||||
'@codemirror/gutter',
|
||||
'@codemirror/highlight',
|
||||
'@codemirror/history',
|
||||
'@codemirror/language',
|
||||
'@codemirror/lint',
|
||||
'@codemirror/matchbrackets',
|
||||
'@codemirror/panel',
|
||||
'@codemirror/rangeset',
|
||||
'@codemirror/rectangular-selection',
|
||||
'@codemirror/search',
|
||||
'@codemirror/state',
|
||||
'@codemirror/stream-parser',
|
||||
'@codemirror/text',
|
||||
'@codemirror/tooltip',
|
||||
'@codemirror/view',
|
||||
...builtins
|
||||
],
|
||||
format: 'cjs',
|
||||
target: 'es2016',
|
||||
logLevel: "info",
|
||||
sourcemap: prod ? false : 'inline',
|
||||
treeShaking: true,
|
||||
outfile: 'main.js',
|
||||
});
|
||||
|
||||
if (!prod) {
|
||||
await ctx.watch();
|
||||
} else {
|
||||
await ctx.dispose();
|
||||
}
|
||||
})().catch(() => process.exit(1)); // Use .catch here to handle any errors
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
{
|
||||
"id": "share-to-notionnext",
|
||||
"name": "Share to NotionNext",
|
||||
"version": "0.0.5",
|
||||
"version": "0.1.1",
|
||||
"minAppVersion": "0.0.1",
|
||||
"description": "This is a plugin for Obsidian. This plugin shares obsidian md file to notion with notion api for NotionNext web deploy.",
|
||||
"author": "jxpeng98",
|
||||
"description": "Shares obsidian md file to notion with notion api for NotionNext web deploy, motivated by EasyChris/obsidian-to-notion.",
|
||||
"author": "EasyChris, jxpeng98",
|
||||
"authorUrl": "https://github.com/jxpeng98/obsidian-to-NotionNext",
|
||||
"isDesktopOnly": false
|
||||
}
|
||||
@@ -4,6 +4,11 @@
|
||||
# for example, if you donot want to set password, you can delete password: "1234" or set it to password: ""
|
||||
# 我已经在插件中设置了默认值,如果有不需要的选项,可以直接删除。
|
||||
# 例如你不需要密码选项,你可以将password: "1234"删除,或者将它设置为空。
|
||||
# !!!!!!!!!!!!
|
||||
# 现在阶段一定不要修改表头的名字, please do not change the name of the header in YAML front matter
|
||||
# !!!!!!!!!!!!
|
||||
titleicon: 📎 # default is 📜, 默认是📜
|
||||
coverurl: https://img.jxpeng.dev/2023/08/843e27a210847f05a0f7cfb121fec100.jpg # default is empty, 默认是空
|
||||
type: Post # Post or Page, default is Post, 默认是Post
|
||||
slug: test # slug for url, default is empty, 默认是空
|
||||
stats: Draft # Draft, Invisible, Published, default is Draft, 默认是Draft
|
||||
|
||||
19
package.json
19
package.json
@@ -1,8 +1,8 @@
|
||||
{
|
||||
"name": "share-to-notionnext",
|
||||
"version": "0.0.5",
|
||||
"version": "0.1.1",
|
||||
"type": "module",
|
||||
"description": "This is a plugin for Obsidian. This plugin share obsidian md file to notion with notion api for NotionNext web deploy.",
|
||||
"description": "Shares obsidian md file to notion with notion api for NotionNext web deploy, motivated by EasyChris/obsidian-to-notion.",
|
||||
"main": "main.js",
|
||||
"scripts": {
|
||||
"dev": "node esbuild.config.mjs",
|
||||
@@ -13,19 +13,20 @@
|
||||
"author": "",
|
||||
"license": "GNU GPLv3",
|
||||
"devDependencies": {
|
||||
"@types/node": "^17.0.35",
|
||||
"@types/node": "^20.5.7",
|
||||
"@types/yaml-front-matter": "^4.1.0",
|
||||
"@typescript-eslint/eslint-plugin": "^5.2.0",
|
||||
"@typescript-eslint/parser": "^5.2.0",
|
||||
"@typescript-eslint/eslint-plugin": "^6.5.0",
|
||||
"@typescript-eslint/parser": "^6.5.0",
|
||||
"builtin-modules": "^3.2.0",
|
||||
"esbuild": "0.13.12",
|
||||
"esbuild": "0.19.2",
|
||||
"obsidian": "latest",
|
||||
"tslib": "2.3.1",
|
||||
"typescript": "4.4.4"
|
||||
"tslib": "2.6.2",
|
||||
"typescript": "5.2.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"@tryfabric/martian": "^1.2.0",
|
||||
"https-proxy-agent": "^5.0.1",
|
||||
"https-proxy-agent": "^7.0.1",
|
||||
"process": "^0.11.10",
|
||||
"yaml": "^2.2.2",
|
||||
"yaml-front-matter": "^4.1.1"
|
||||
}
|
||||
|
||||
239
src/Upload2Notion.ts
Normal file
239
src/Upload2Notion.ts
Normal file
@@ -0,0 +1,239 @@
|
||||
import { App, Notice, requestUrl, TFile } from "obsidian";
|
||||
import { Client } from '@notionhq/client';
|
||||
import { markdownToBlocks, } from "@tryfabric/martian";
|
||||
import * as yamlFrontMatter from "yaml-front-matter";
|
||||
// import * as yaml from "yaml"
|
||||
import MyPlugin from "src/main";
|
||||
|
||||
export class Upload2Notion {
|
||||
plugin: MyPlugin;
|
||||
notion: Client;
|
||||
agent: any;
|
||||
constructor(plugin: MyPlugin) {
|
||||
this.plugin = plugin;
|
||||
}
|
||||
|
||||
async deletePage(notionID: string) {
|
||||
return requestUrl({
|
||||
url: `https://api.notion.com/v1/blocks/${notionID}`,
|
||||
method: 'DELETE',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': 'Bearer ' + this.plugin.settings.notionAPI,
|
||||
'Notion-Version': '2022-06-28',
|
||||
},
|
||||
body: ''
|
||||
});
|
||||
}
|
||||
|
||||
async getDataBase(databaseID: string) {
|
||||
const response = await requestUrl({
|
||||
url: `https://api.notion.com/v1/databases/${databaseID}`,
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'Authorization': 'Bearer ' + this.plugin.settings.notionAPI,
|
||||
'Notion-Version': '2022-06-28',
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
// Check if cover is present in the JSON response and then get the URL
|
||||
if (response.json.cover && response.json.cover.external) {
|
||||
return response.json.cover.external.url;
|
||||
} else {
|
||||
return null; // or some other default value, if you prefer
|
||||
}
|
||||
}
|
||||
|
||||
// 因为需要解析notion的block进行对比,非常的麻烦,
|
||||
// 暂时就直接删除,新建一个page
|
||||
async updatePage(notionID: string, title: string, allowTags: boolean, emoji: string, cover: string, tags: string[], type: string, slug: string, stats: string, category: string, summary: string, paword: string, favicon: string, datetime: string, childArr: any) {
|
||||
await this.deletePage(notionID)
|
||||
|
||||
const databasecover = await this.getDataBase(this.plugin.settings.databaseID)
|
||||
|
||||
if (cover == null) {
|
||||
cover = databasecover
|
||||
}
|
||||
|
||||
return await this.createPage(title, allowTags, emoji, cover, tags, type, slug, stats, category, summary, paword, favicon, datetime, childArr)
|
||||
}
|
||||
|
||||
async createPage(title: string, allowTags: boolean, emoji: string, cover: string, tags: string[], type: string, slug: string, stats: string, category: string, summary: string, pawrod: string, favicon: string, datetime: string, childArr: any) {
|
||||
const bodyString: any = {
|
||||
parent: {
|
||||
database_id: this.plugin.settings.databaseID
|
||||
},
|
||||
icon: {
|
||||
emoji: emoji || '📜'
|
||||
},
|
||||
properties: {
|
||||
title: {
|
||||
title: [
|
||||
{
|
||||
text: {
|
||||
content: title
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
tags: {
|
||||
multi_select: allowTags && tags !== undefined ? tags.map(tag => {
|
||||
return { "name": tag }
|
||||
}) : [],
|
||||
},
|
||||
type: {
|
||||
select: {
|
||||
name: type || 'Post'
|
||||
}
|
||||
},
|
||||
slug: {
|
||||
rich_text: [
|
||||
{
|
||||
text: {
|
||||
content: slug || ''
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
status: {
|
||||
select: {
|
||||
name: stats || 'Draft'
|
||||
}
|
||||
},
|
||||
category: {
|
||||
select: {
|
||||
name: category || 'Obsidian'
|
||||
}
|
||||
},
|
||||
summary: {
|
||||
rich_text: [
|
||||
{
|
||||
text: {
|
||||
content: summary || ''
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
password: {
|
||||
rich_text: [
|
||||
{
|
||||
text: {
|
||||
content: pawrod || ''
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
icon: {
|
||||
rich_text: [
|
||||
{
|
||||
text: {
|
||||
content: favicon || ''
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
date: {
|
||||
date: {
|
||||
start: datetime || new Date().toISOString()
|
||||
}
|
||||
}
|
||||
},
|
||||
children: childArr,
|
||||
}
|
||||
if (cover) {
|
||||
bodyString.cover = {
|
||||
type: "external",
|
||||
external: {
|
||||
url: cover
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!bodyString.cover && this.plugin.settings.bannerUrl) {
|
||||
bodyString.cover = {
|
||||
type: "external",
|
||||
external: {
|
||||
url: this.plugin.settings.bannerUrl
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
return await requestUrl({
|
||||
url: `https://api.notion.com/v1/pages`,
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
// 'User-Agent': 'obsidian.md',
|
||||
'Authorization': 'Bearer ' + this.plugin.settings.notionAPI,
|
||||
'Notion-Version': '2022-06-28',
|
||||
},
|
||||
body: JSON.stringify(bodyString),
|
||||
})
|
||||
} catch (error) {
|
||||
new Notice(`network error ${error}`)
|
||||
}
|
||||
}
|
||||
|
||||
async syncMarkdownToNotion(title: string, allowTags: boolean, emoji: string, cover: string, tags: string[], type: string, slug: string, stats: string, category: string, summary: string, paword: string, favicon: string, datetime: string, markdown: string, nowFile: TFile, app: App, settings: any): Promise<any> {
|
||||
let res: any
|
||||
const yamlContent: any = yamlFrontMatter.loadFront(markdown);
|
||||
const __content = yamlContent.__content
|
||||
const file2Block = markdownToBlocks(__content);
|
||||
const frontmasster = app.metadataCache.getFileCache(nowFile)?.frontmatter
|
||||
const notionID = frontmasster ? frontmasster.notionID : null
|
||||
|
||||
if (notionID) {
|
||||
res = await this.updatePage(notionID, title, allowTags, emoji, cover, tags, type, slug, stats, category, summary, paword, favicon, datetime, file2Block);
|
||||
} else {
|
||||
res = await this.createPage(title, allowTags, emoji, cover, tags, type, slug, stats, category, summary, paword, favicon, datetime, file2Block);
|
||||
}
|
||||
if (res.status === 200) {
|
||||
await this.updateYamlInfo(markdown, nowFile, res, app, settings)
|
||||
} else {
|
||||
new Notice(`${res.text}`)
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
async updateYamlInfo(yamlContent: string, nowFile: TFile, res: any, app: App, settings: any) {
|
||||
let { url, id } = res.json
|
||||
// replace www to notionID
|
||||
const { notionID } = settings;
|
||||
if (notionID !== "") {
|
||||
// replace url str "www" to notionID
|
||||
url = url.replace("www.notion.so", `${notionID}.notion.site`)
|
||||
}
|
||||
await app.fileManager.processFrontMatter(nowFile, yamlContent => {
|
||||
if (yamlContent['notionID']) {
|
||||
delete yamlContent['notionID']
|
||||
}
|
||||
if (yamlContent['link']) {
|
||||
delete yamlContent['link']
|
||||
}
|
||||
// add new notionID and link
|
||||
yamlContent.notionID = id;
|
||||
yamlContent.link = url;
|
||||
});
|
||||
|
||||
try {
|
||||
await navigator.clipboard.writeText(url)
|
||||
} catch (error) {
|
||||
new Notice(`复制链接失败,请手动复制${error}`)
|
||||
}
|
||||
// const __content = yamlContent.__content;
|
||||
// delete yamlContent.__content
|
||||
// const yamlhead = yaml.stringify(yamlContent)
|
||||
// // if yamlhead hava last \n remove it
|
||||
// const yamlhead_remove_n = yamlhead.replace(/\n$/, '')
|
||||
// // if __content have start \n remove it
|
||||
// const __content_remove_n = __content.replace(/^\n/, '')
|
||||
// const content = '---\n' +yamlhead_remove_n +'\n---\n' + __content_remove_n;
|
||||
// try {
|
||||
// await nowFile.vault.modify(nowFile, content)
|
||||
// } catch (error) {
|
||||
// new Notice(`write file error ${error}`)
|
||||
// }
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,7 @@ import { addIcon } from 'obsidian';
|
||||
const icons: Record<string, string> = {
|
||||
'notion-logo': `
|
||||
<!-- License: Apache. Made by lawnchairlauncher: https://github.com/lawnchairlauncher/lawnicons -->
|
||||
<svg width="100px" height="100px" viewBox="0 0 192 192" xmlns="http://www.w3.org/2000/svg" fill="none"><path fill="#000000" fill-rule="evenodd" d="m138.462 21.522 27.784 19.588.044.033.275.201c1.713 1.256 3.349 2.455 4.452 3.83 1.411 1.76 1.884 3.644 1.884 5.877v104.706c0 3.587-.635 7.178-3.058 9.934-2.451 2.789-6.145 4.067-10.732 4.394l-.018.001-98.629 5.971-.021.001c-3.242.154-6.094.035-8.669-.907-2.688-.984-4.719-2.727-6.604-5.129l-.01-.012-19.979-25.979-.012-.017c-3.81-5.086-5.723-9.348-5.723-14.509V34.509c0-3.12.688-6.394 2.745-9.033 2.124-2.727 5.356-4.328 9.503-4.686l.058-.005 84.854-4.344c5.192-.445 8.938-.576 12.286.185 3.459.787 6.208 2.452 9.57 4.896ZM56.43 157.336h.002v3.3c0 1.904.47 2.337.613 2.452.296.235 1.203.652 3.642.518l97.449-5.371c1.928-.106 2.256-.649 2.348-.801l.005-.008c.29-.476.486-1.407.486-3.357V60.001c0-1.635-.334-2.218-.421-2.327l-.005-.007-.002-.003-.006-.002a.117.117 0 0 1-.012-.004c-.053-.019-.263-.078-.724-.037l-.057.005-101.622 5.668c-.624.056-.973.163-1.152.242-.142.062-.173.104-.181.116l-.002.002c-.066.085-.36.586-.36 2.321v91.361Zm9.085-106.705 87.074-4.506-21.028-15.375-.039-.031c-1.259-.98-2.507-1.854-4.12-2.46-1.588-.597-3.695-.993-6.669-.734l-.05.005-87.009 4.898h-.01a6.453 6.453 0 0 0-.893.116L49.934 48.56c2.037 1.646 3.109 2.146 4.337 2.367 1.538.277 3.52.167 7.722-.115l3.522-.237v.056Zm-34.231-3.586v83.893c0 .538.175 1.061.498 1.49l13.174 17.464V61.224a2.47 2.47 0 0 0-.877-1.889l-.08-.068-12.715-12.222Zm109.871 35.062c.451 2.04 0 4.082-2.041 4.315l-3.393.673v49.881c-2.947 1.586-5.66 2.492-7.927 2.492-3.622 0-4.528-1.134-7.239-4.53l-.003-.003L98.36 100.02v33.78l7.02 1.59s0 4.082-5.664 4.082l-15.615.906c-.455-.91 0-3.176 1.582-3.627l4.078-1.131V90.955l-5.66-.459c-.454-2.04.677-4.987 3.85-5.216l16.754-1.128 23.09 35.367V88.231l-5.885-.677c-.455-2.499 1.356-4.315 3.618-4.536l15.627-.91v-.001Z" clip-rule="evenodd"/></svg>
|
||||
<svg width="110px" height="110px" viewBox="0 0 192 192" xmlns="http://www.w3.org/2000/svg" fill="none"><path fill="#817f7a" fill-rule="evenodd" d="m138.462 21.522 27.784 19.588.044.033.275.201c1.713 1.256 3.349 2.455 4.452 3.83 1.411 1.76 1.884 3.644 1.884 5.877v104.706c0 3.587-.635 7.178-3.058 9.934-2.451 2.789-6.145 4.067-10.732 4.394l-.018.001-98.629 5.971-.021.001c-3.242.154-6.094.035-8.669-.907-2.688-.984-4.719-2.727-6.604-5.129l-.01-.012-19.979-25.979-.012-.017c-3.81-5.086-5.723-9.348-5.723-14.509V34.509c0-3.12.688-6.394 2.745-9.033 2.124-2.727 5.356-4.328 9.503-4.686l.058-.005 84.854-4.344c5.192-.445 8.938-.576 12.286.185 3.459.787 6.208 2.452 9.57 4.896ZM56.43 157.336h.002v3.3c0 1.904.47 2.337.613 2.452.296.235 1.203.652 3.642.518l97.449-5.371c1.928-.106 2.256-.649 2.348-.801l.005-.008c.29-.476.486-1.407.486-3.357V60.001c0-1.635-.334-2.218-.421-2.327l-.005-.007-.002-.003-.006-.002a.117.117 0 0 1-.012-.004c-.053-.019-.263-.078-.724-.037l-.057.005-101.622 5.668c-.624.056-.973.163-1.152.242-.142.062-.173.104-.181.116l-.002.002c-.066.085-.36.586-.36 2.321v91.361Zm9.085-106.705 87.074-4.506-21.028-15.375-.039-.031c-1.259-.98-2.507-1.854-4.12-2.46-1.588-.597-3.695-.993-6.669-.734l-.05.005-87.009 4.898h-.01a6.453 6.453 0 0 0-.893.116L49.934 48.56c2.037 1.646 3.109 2.146 4.337 2.367 1.538.277 3.52.167 7.722-.115l3.522-.237v.056Zm-34.231-3.586v83.893c0 .538.175 1.061.498 1.49l13.174 17.464V61.224a2.47 2.47 0 0 0-.877-1.889l-.08-.068-12.715-12.222Zm109.871 35.062c.451 2.04 0 4.082-2.041 4.315l-3.393.673v49.881c-2.947 1.586-5.66 2.492-7.927 2.492-3.622 0-4.528-1.134-7.239-4.53l-.003-.003L98.36 100.02v33.78l7.02 1.59s0 4.082-5.664 4.082l-15.615.906c-.455-.91 0-3.176 1.582-3.627l4.078-1.131V90.955l-5.66-.459c-.454-2.04.677-4.987 3.85-5.216l16.754-1.128 23.09 35.367V88.231l-5.885-.677c-.455-2.499 1.356-4.315 3.618-4.536l15.627-.91v-.001Z" clip-rule="evenodd"/></svg>
|
||||
`
|
||||
};
|
||||
|
||||
@@ -1,18 +1,7 @@
|
||||
import {
|
||||
App,
|
||||
Editor,
|
||||
MarkdownView,
|
||||
Modal,
|
||||
Notice,
|
||||
Plugin,
|
||||
PluginSettingTab,
|
||||
Setting,
|
||||
normalizePath
|
||||
} from "obsidian";
|
||||
import {addIcons} from 'icon';
|
||||
import { Upload2Notion } from "Upload2Notion";
|
||||
import {NoticeMConfig} from "Message";
|
||||
import { CLIENT_RENEG_LIMIT } from "tls";
|
||||
import {App, Editor, MarkdownView, Notice, Plugin, PluginSettingTab, Setting} from "obsidian";
|
||||
import {addIcons} from 'src/icon';
|
||||
import {Upload2Notion} from "src/Upload2Notion";
|
||||
import {NoticeMConfig} from "src/Message";
|
||||
|
||||
|
||||
// Remember to rename these classes and interfaces!
|
||||
@@ -48,7 +37,7 @@ export default class ObsidianSyncNotionPlugin extends Plugin {
|
||||
"Share to NotionNext",
|
||||
async (evt: MouseEvent) => {
|
||||
// Called when the user clicks the icon.
|
||||
this.upload();
|
||||
await this.upload();
|
||||
}
|
||||
);
|
||||
|
||||
@@ -60,13 +49,13 @@ export default class ObsidianSyncNotionPlugin extends Plugin {
|
||||
id: "share-to-notionnext",
|
||||
name: "share to notionnext",
|
||||
editorCallback: async (editor: Editor, view: MarkdownView) => {
|
||||
this.upload()
|
||||
await this.upload()
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
// This adds a settings tab so the user can configure various aspects of the plugin
|
||||
this.addSettingTab(new SampleSettingTab(this.app, this));
|
||||
this.addSettingTab(new ObsidianSettingTab(this.app, this));
|
||||
|
||||
}
|
||||
|
||||
@@ -80,12 +69,12 @@ export default class ObsidianSyncNotionPlugin extends Plugin {
|
||||
);
|
||||
return;
|
||||
}
|
||||
const { markDownData, nowFile, tags, type, slug, stats, category, summary, paword, favicon, datetime } =await this.getNowFileMarkdownContent(this.app);
|
||||
const { markDownData, nowFile, emoji, cover, tags, type, slug, stats, category, summary, paword, favicon, datetime } =await this.getNowFileMarkdownContent(this.app);
|
||||
|
||||
if (markDownData) {
|
||||
const { basename } = nowFile;
|
||||
const upload = new Upload2Notion(this);
|
||||
const res = await upload.syncMarkdownToNotion(basename, allowTags, tags, type, slug, stats, category, summary, paword, favicon, datetime, markDownData, nowFile, this.app, this.settings)
|
||||
const res = await upload.syncMarkdownToNotion(basename, allowTags, emoji, cover, tags, type, slug, stats, category, summary, paword, favicon, datetime, markDownData, nowFile, this.app, this.settings)
|
||||
if(res.status === 200){
|
||||
new Notice(`${langConfig["sync-success"]}${basename}`)
|
||||
}else {
|
||||
@@ -97,6 +86,8 @@ export default class ObsidianSyncNotionPlugin extends Plugin {
|
||||
async getNowFileMarkdownContent(app: App) {
|
||||
const nowFile = app.workspace.getActiveFile();
|
||||
const { allowTags } = this.settings;
|
||||
let emoji = ''
|
||||
let cover = ''
|
||||
let tags = []
|
||||
let type = ''
|
||||
let slug = ''
|
||||
@@ -110,6 +101,8 @@ export default class ObsidianSyncNotionPlugin extends Plugin {
|
||||
const FileCache = app.metadataCache.getFileCache(nowFile)
|
||||
try {
|
||||
if(allowTags) {
|
||||
emoji = FileCache.frontmatter.titleicon;
|
||||
cover = FileCache.frontmatter.coverurl;
|
||||
tags = FileCache.frontmatter.tags;
|
||||
type = FileCache.frontmatter.type;
|
||||
slug = FileCache.frontmatter.slug;
|
||||
@@ -128,6 +121,8 @@ export default class ObsidianSyncNotionPlugin extends Plugin {
|
||||
return {
|
||||
markDownData,
|
||||
nowFile,
|
||||
emoji,
|
||||
cover,
|
||||
tags,
|
||||
type,
|
||||
slug,
|
||||
@@ -157,7 +152,7 @@ export default class ObsidianSyncNotionPlugin extends Plugin {
|
||||
}
|
||||
}
|
||||
|
||||
class SampleSettingTab extends PluginSettingTab {
|
||||
class ObsidianSettingTab extends PluginSettingTab {
|
||||
plugin: ObsidianSyncNotionPlugin;
|
||||
|
||||
constructor(app: App, plugin: ObsidianSyncNotionPlugin) {
|
||||
@@ -170,23 +165,18 @@ class SampleSettingTab extends PluginSettingTab {
|
||||
|
||||
containerEl.empty();
|
||||
|
||||
containerEl.createEl("h2", {
|
||||
text: "Settings for obsidian to NotionNext plugin.",
|
||||
});
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName("Notion API Token")
|
||||
.setDesc("It's a secret")
|
||||
.addText((text) =>{
|
||||
let t = text
|
||||
.setPlaceholder("Enter your Notion API Token")
|
||||
.setValue(this.plugin.settings.notionAPI)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.notionAPI = value;
|
||||
await this.plugin.saveSettings();
|
||||
})
|
||||
// t.inputEl.type = 'password'
|
||||
return t
|
||||
text.inputEl.type = 'password';
|
||||
return text
|
||||
.setPlaceholder("Enter your Notion API Token")
|
||||
.setValue(this.plugin.settings.notionAPI)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.notionAPI = value;
|
||||
await this.plugin.saveSettings();
|
||||
})
|
||||
});
|
||||
|
||||
|
||||
@@ -194,17 +184,15 @@ class SampleSettingTab extends PluginSettingTab {
|
||||
.setName("Database ID")
|
||||
.setDesc("It's a secret")
|
||||
.addText((text) => {
|
||||
let t = text
|
||||
.setPlaceholder("Enter your Database ID")
|
||||
.setValue(this.plugin.settings.databaseID)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.databaseID = value;
|
||||
await this.plugin.saveSettings();
|
||||
})
|
||||
// t.inputEl.type = 'password'
|
||||
return t
|
||||
text.inputEl.type = 'password';
|
||||
return text
|
||||
.setPlaceholder("Enter your Database ID")
|
||||
.setValue(this.plugin.settings.databaseID)
|
||||
.onChange(async (value) => {
|
||||
this.plugin.settings.databaseID = value;
|
||||
await this.plugin.saveSettings();
|
||||
})
|
||||
}
|
||||
|
||||
);
|
||||
|
||||
// notionDatabaseID.controlEl.querySelector('input').type='password'
|
||||
@@ -18,5 +18,7 @@
|
||||
},
|
||||
"include": [
|
||||
"**/*.ts"
|
||||
, "Upload2Notion.ts" ]
|
||||
,
|
||||
"src/Upload2Notion.ts"
|
||||
]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user