Update version to 0.1.8

This commit is contained in:
Jiaxin Peng
2023-10-31 23:56:50 +00:00
parent 4a2c59d13b
commit 4b6f1a1f1d
8 changed files with 511 additions and 282 deletions

87
src/BaseUpload2Notion.ts Normal file
View File

@@ -0,0 +1,87 @@
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 UploadBase {
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
}
}
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}`)
// }
}
}

View File

@@ -1,3 +1,4 @@
import {UploadBase} from "./BaseUpload2Notion";
import { App, Notice, requestUrl, TFile } from "obsidian";
import { Client } from '@notionhq/client';
import { markdownToBlocks, } from "@tryfabric/martian";
@@ -5,44 +6,9 @@ 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;
export class Upload2Notion extends UploadBase {
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
}
super(plugin);
}
// 因为需要解析notion的block进行对比非常的麻烦
@@ -56,7 +22,8 @@ export class Upload2Notion {
cover = databasecover
}
return await this.createPage(title,
return await this.createPage(
title,
emoji,
cover,
tags,
@@ -208,44 +175,4 @@ export class Upload2Notion {
}
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}`)
// }
}
}

179
src/Upload2Notion_NN.ts Normal file
View File

@@ -0,0 +1,179 @@
import {UploadBase} from "./BaseUpload2Notion";
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 Upload2NotionNext extends UploadBase {
constructor(plugin: MyPlugin) {
super(plugin);
}
// 因为需要解析notion的block进行对比非常的麻烦
// 暂时就直接删除新建一个page
async updatePage(notionID: string, title: string, 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,
emoji,
cover,
tags,
type,
slug,
stats,
category,
summary,
paword,
favicon,
datetime,
childArr)
}
async createPage(title: string, 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: tags && true ? 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, 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, emoji, cover, tags, type, slug, stats, category, summary, paword, favicon, datetime, file2Block);
} else {
res = await this.createPage(title, 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
}
}

View File

@@ -1,241 +1,273 @@
import {App, Editor, MarkdownView, Notice, Plugin, PluginSettingTab, Setting} from "obsidian";
import {addIcons} from 'src/icon';
import {Upload2Notion} from "src/Upload2Notion";
import {Upload2NotionNext} from "src/Upload2Notion_NN";
import {NoticeMConfig} from "src/Message";
// Remember to rename these classes and interfaces!
interface PluginSettings {
notionAPI: string;
databaseID: string;
bannerUrl: string;
notionID: string;
proxy: string;
allowTags: boolean;
NNon: boolean;
notionAPI: string;
databaseID: string;
bannerUrl: string;
notionID: string;
proxy: string;
}
const langConfig = NoticeMConfig( window.localStorage.getItem('language') || 'en')
const langConfig = NoticeMConfig(window.localStorage.getItem('language') || 'en')
const DEFAULT_SETTINGS: PluginSettings = {
notionAPI: "",
databaseID: "",
bannerUrl: "",
notionID: "",
proxy: "",
allowTags: false
NNon: true,
notionAPI: "",
databaseID: "",
bannerUrl: "",
notionID: "",
proxy: "",
};
export default class ObsidianSyncNotionPlugin extends Plugin {
settings: PluginSettings;
async onload() {
await this.loadSettings();
addIcons();
// This creates an icon in the left ribbon.
const ribbonIconEl = this.addRibbonIcon(
"notion-logo",
"Share to NotionNext",
async (evt: MouseEvent) => {
// Called when the user clicks the icon.
await this.upload();
}
);
settings: PluginSettings;
// This adds a status bar item to the bottom of the app. Does not work on mobile apps.
const statusBarItemEl = this.addStatusBarItem();
// statusBarItemEl.setText("share to notion");
async onload() {
await this.loadSettings();
addIcons();
// This creates an icon in the left ribbon.
const ribbonIconEl = this.addRibbonIcon(
"notion-logo",
"Share to NotionNext",
async (evt: MouseEvent) => {
// Called when the user clicks the icon.
await this.upload();
}
);
this.addCommand({
id: "share-to-notionnext",
name: "share to notionnext",
editorCallback: async (editor: Editor, view: MarkdownView) => {
await this.upload()
},
});
// This adds a status bar item to the bottom of the app. Does not work on mobile apps.
const statusBarItemEl = this.addStatusBarItem();
// statusBarItemEl.setText("share to notion");
this.addCommand({
id: "share-to-notionnext",
name: "share to notionnext",
editorCallback: async (editor: Editor, view: MarkdownView) => {
await this.upload()
},
});
// This adds a settings tab so the user can configure various aspects of the plugin
this.addSettingTab(new ObsidianSettingTab(this.app, this));
// This adds a settings tab so the user can configure various aspects of the plugin
this.addSettingTab(new ObsidianSettingTab(this.app, this));
}
}
onunload() {}
onunload() {
}
async upload(){
const { notionAPI, databaseID, allowTags } = this.settings;
if (notionAPI === "" || databaseID === "") {
new Notice(
"Please set up the notion API and database ID in the settings tab."
);
return;
}
const { markDownData, nowFile, emoji, cover, tags, type, slug, stats, category, summary, paword, favicon, datetime } =await this.getNowFileMarkdownContent(this.app);
async upload() {
const {NNon, notionAPI, databaseID} = this.settings;
if (notionAPI === "" || databaseID === "") {
new Notice(
"Please set up the notion API and database ID in the settings tab."
);
return;
}
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, 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 {
new Notice(`${langConfig["sync-fail"]}${basename}`, 5000)
}
}
}
async getNowFileMarkdownContent(app: App) {
const nowFile = app.workspace.getActiveFile();
const { allowTags } = this.settings;
let emoji = ''
let cover = ''
let tags = []
let type = ''
let slug = ''
let stats = ''
let category = ''
let summary = ''
let paword = ''
let favicon = ''
let datetime = ''
if (markDownData) {
const { basename } = nowFile;
let upload;
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;
stats = FileCache.frontmatter.stats;
category = FileCache.frontmatter.category;
summary = FileCache.frontmatter.summary;
paword = FileCache.frontmatter.password;
favicon = FileCache.frontmatter.icon;
datetime = FileCache.frontmatter.date;
}
} catch (error) {
new Notice(langConfig["set-tags-fail"]);
}
if (nowFile) {
const markDownData = await nowFile.vault.read(nowFile);
return {
markDownData,
nowFile,
emoji,
cover,
tags,
type,
slug,
stats,
category,
summary,
paword,
favicon,
datetime,
};
} else {
new Notice(langConfig["open-file"]);
return;
}
}
if (NNon) {
upload = new Upload2NotionNext(this);
} else {
upload = new Upload2Notion(this);
}
async loadSettings() {
this.settings = Object.assign(
{},
DEFAULT_SETTINGS,
await this.loadData()
);
}
const res = await upload.syncMarkdownToNotion(basename, emoji, cover, tags, type, slug, stats, category, summary, paword, favicon, datetime, markDownData, nowFile, this.app, this.settings);
async saveSettings() {
await this.saveData(this.settings);
}
if (res.status === 200) {
new Notice(`${langConfig["sync-success"]}${basename}`);
} else {
new Notice(`${langConfig["sync-fail"]}${basename}`, 5000);
}
}
}
async getNowFileMarkdownContent(app: App) {
const nowFile = app.workspace.getActiveFile();
const {NNon} = this.settings;
let emoji = ''
let cover = ''
let tags = []
let type = ''
let slug = ''
let stats = ''
let category = ''
let summary = ''
let paword = ''
let favicon = ''
let datetime = ''
const FileCache = app.metadataCache.getFileCache(nowFile)
try {
if (NNon) {
emoji = FileCache.frontmatter.titleicon;
cover = FileCache.frontmatter.coverurl;
tags = FileCache.frontmatter.tags;
type = FileCache.frontmatter.type;
slug = FileCache.frontmatter.slug;
stats = FileCache.frontmatter.stats;
category = FileCache.frontmatter.category;
summary = FileCache.frontmatter.summary;
paword = FileCache.frontmatter.password;
favicon = FileCache.frontmatter.icon;
datetime = FileCache.frontmatter.date;
}
} catch (error) {
new Notice(langConfig["set-tags-fail"]);
}
if (nowFile) {
const markDownData = await nowFile.vault.read(nowFile);
return {
markDownData,
nowFile,
emoji,
cover,
tags,
type,
slug,
stats,
category,
summary,
paword,
favicon,
datetime,
};
} else {
new Notice(langConfig["open-file"]);
return;
}
}
async loadSettings() {
this.settings = Object.assign(
{},
DEFAULT_SETTINGS,
await this.loadData()
);
}
async saveSettings() {
await this.saveData(this.settings);
}
}
class ObsidianSettingTab extends PluginSettingTab {
plugin: ObsidianSyncNotionPlugin;
plugin: ObsidianSyncNotionPlugin;
constructor(app: App, plugin: ObsidianSyncNotionPlugin) {
super(app, plugin);
this.plugin = plugin;
}
constructor(app: App, plugin: ObsidianSyncNotionPlugin) {
super(app, plugin);
this.plugin = plugin;
}
display(): void {
const { containerEl } = this;
display(): void {
const {containerEl} = this;
containerEl.empty();
containerEl.empty();
new Setting(containerEl)
.setName("NotionNext version")
.setDesc("Turn on this option if you are using NotionNext")
.addToggle((toggle) =>
toggle
.setValue(this.plugin.settings.NNon)
.onChange(async (value) => {
this.plugin.settings.NNon = value;
await this.plugin.saveSettings();
})
);
containerEl.createEl('h2', {text: 'NotionNext Database Settings'})
new Setting(containerEl)
.setName("Notion API Token")
.setDesc("It's a secret")
.addText((text) => {
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();
})
});
const notionDatabaseID = new Setting(containerEl)
.setName("Database ID")
.setDesc("It's a secret")
.addText((text) => {
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'
new Setting(containerEl)
.setName("Banner url(optional)")
.setDesc("page banner url(optional), default is empty, if you want to show a banner, please enter the url(like:https://raw.githubusercontent.com/EasyChris/obsidian-to-notion/ae7a9ac6cf427f3ca338a409ce6967ced9506f12/doc/2.png)")
.addText((text) =>
text
.setPlaceholder("Enter banner pic url: ")
.setValue(this.plugin.settings.bannerUrl)
.onChange(async (value) => {
this.plugin.settings.bannerUrl = value;
await this.plugin.saveSettings();
})
);
new Setting(containerEl)
.setName("Notion ID(username, optional)")
.setDesc("Your notion ID(optional),share link likes:https://username.notion.site/,your notion id is [username]")
.addText((text) =>
text
.setPlaceholder("Enter notion ID(options) ")
.setValue(this.plugin.settings.notionID)
.onChange(async (value) => {
this.plugin.settings.notionID = value;
await this.plugin.saveSettings();
})
);
// General Database Settings
containerEl.createEl('h2', {text: 'General Notion Database Settings'});
new Setting(containerEl)
.setName("Notion API Token")
.setDesc("It's a secret")
.addText((text) =>{
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();
})
});
.setName("Not finished")
.setDesc("This functio will be available in the next version");
const notionDatabaseID = new Setting(containerEl)
.setName("Database ID")
.setDesc("It's a secret")
.addText((text) => {
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'
new Setting(containerEl)
.setName("Banner url(optional)")
.setDesc("page banner url(optional), default is empty, if you want to show a banner, please enter the url(like:https://raw.githubusercontent.com/EasyChris/obsidian-to-notion/ae7a9ac6cf427f3ca338a409ce6967ced9506f12/doc/2.png)")
.addText((text) =>
text
.setPlaceholder("Enter banner pic url: ")
.setValue(this.plugin.settings.bannerUrl)
.onChange(async (value) => {
this.plugin.settings.bannerUrl = value;
await this.plugin.saveSettings();
})
);
new Setting(containerEl)
.setName("Notion ID(optional)")
.setDesc("Your notion ID(optional),share link likes:https://username.notion.site/,your notion id is [username]")
.addText((text) =>
text
.setPlaceholder("Enter notion ID(options) ")
.setValue(this.plugin.settings.notionID)
.onChange(async (value) => {
this.plugin.settings.notionID = value;
await this.plugin.saveSettings();
})
);
// new Setting(containerEl)
// .setName("Convert tags(optional)")
// .setDesc("Transfer the Obsidian tags to the Notion table. It requires the column with the name 'Tags'")
// .addToggle((toggle) =>
// toggle
// .setValue(this.plugin.settings.allowTags)
// .onChange(async (value) => {
// this.plugin.settings.allowTags = value;
// await this.plugin.saveSettings();
// })
// );
}
// new Setting(containerEl)
// .setName("Convert tags(optional)")
// .setDesc("Transfer the Obsidian tags to the Notion table. It requires the column with the name 'Tags'")
// .addToggle((toggle) =>
// toggle
// .setValue(this.plugin.settings.allowTags)
// .onChange(async (value) => {
// this.plugin.settings.allowTags = value;
// await this.plugin.saveSettings();
// })
// );
}
}