mirror of
https://github.com/jxpeng98/obsidian-to-NotionNext
synced 2026-07-29 16:35:57 +08:00
feat: add auto sync functionality with configurable delay in settings
This commit is contained in:
@@ -35,6 +35,11 @@ export const en = {
|
|||||||
NotionUserText: "Enter your notion ID",
|
NotionUserText: "Enter your notion ID",
|
||||||
NotionLinkDisplay: "Notion Link Display",
|
NotionLinkDisplay: "Notion Link Display",
|
||||||
NotionLinkDisplayDesc: "Default is ON, if you want to hide the link in the front matter, please turn it off",
|
NotionLinkDisplayDesc: "Default is ON, if you want to hide the link in the front matter, please turn it off",
|
||||||
|
AutoSync: "Auto Sync",
|
||||||
|
AutoSyncDesc: "Automatically sync to Notion when frontmatter or content is modified (requires existing NotionID)",
|
||||||
|
AutoSyncDelay: "Auto Sync Delay (seconds)",
|
||||||
|
AutoSyncDelayDesc: "How many seconds to wait after document modification before triggering auto sync (default: 5 seconds, minimum: 2 seconds)",
|
||||||
|
AutoSyncDelayText: "Enter delay in seconds",
|
||||||
NotionGeneralSettingHeader: "General Notion Database Settings",
|
NotionGeneralSettingHeader: "General Notion Database Settings",
|
||||||
NotionGeneralButton: "Notion General Sync",
|
NotionGeneralButton: "Notion General Sync",
|
||||||
NotionGeneralButtonDesc: "Open this option, Sync to Notion General Database command will be displayed in the command palette (default: ON)",
|
NotionGeneralButtonDesc: "Open this option, Sync to Notion General Database command will be displayed in the command palette (default: ON)",
|
||||||
|
|||||||
@@ -33,6 +33,11 @@ export const ja = {
|
|||||||
NotionUserText: "Notion IDを入力",
|
NotionUserText: "Notion IDを入力",
|
||||||
NotionLinkDisplay: "Notionリンク表示",
|
NotionLinkDisplay: "Notionリンク表示",
|
||||||
NotionLinkDisplayDesc: "デフォルトはONです。front matterにリンクを非表示にしたい場合は、オフにしてください",
|
NotionLinkDisplayDesc: "デフォルトはONです。front matterにリンクを非表示にしたい場合は、オフにしてください",
|
||||||
|
AutoSync: "自動同期",
|
||||||
|
AutoSyncDesc: "frontmatter またはコンテンツが変更されたときに自動的に Notion に同期します(NotionID が必要)",
|
||||||
|
AutoSyncDelay: "自動同期遅延時間(秒)",
|
||||||
|
AutoSyncDelayDesc: "ドキュメントの変更後、自動同期をトリガーするまでの待機時間(デフォルト:5秒、最小:2秒)",
|
||||||
|
AutoSyncDelayText: "遅延秒数を入力",
|
||||||
NotionGeneralSettingHeader: "一般的なNotionデータベース設定",
|
NotionGeneralSettingHeader: "一般的なNotionデータベース設定",
|
||||||
NotionGeneralButton: "一般的なNotion同期",
|
NotionGeneralButton: "一般的なNotion同期",
|
||||||
NotionGeneralButtonDesc: "このオプションを開くと、一般的なNotionデータベース同期コマンドがコマンドパレットに表示されます(デフォルト:ON)",
|
NotionGeneralButtonDesc: "このオプションを開くと、一般的なNotionデータベース同期コマンドがコマンドパレットに表示されます(デフォルト:ON)",
|
||||||
|
|||||||
@@ -35,6 +35,11 @@ export const zh = {
|
|||||||
NotionUserText: "输入你的 Notion ID",
|
NotionUserText: "输入你的 Notion ID",
|
||||||
NotionLinkDisplay: "Notion 链接显示",
|
NotionLinkDisplay: "Notion 链接显示",
|
||||||
NotionLinkDisplayDesc: "默认开启,如果你不想在front matter中显示链接,请关闭",
|
NotionLinkDisplayDesc: "默认开启,如果你不想在front matter中显示链接,请关闭",
|
||||||
|
AutoSync: "自动同步",
|
||||||
|
AutoSyncDesc: "当检测到文档的 frontmatter 或内容发生修改时,自动同步到 Notion(需要文档已有 NotionID)",
|
||||||
|
AutoSyncDelay: "自动同步延迟时间(秒)",
|
||||||
|
AutoSyncDelayDesc: "文档修改后等待多少秒才触发自动同步,避免频繁同步(默认:5秒,最小:2秒)",
|
||||||
|
AutoSyncDelayText: "输入延迟秒数",
|
||||||
NotionGeneralSettingHeader: "普通 Notion 数据库设置",
|
NotionGeneralSettingHeader: "普通 Notion 数据库设置",
|
||||||
NotionGeneralButton: "普通数据库同步",
|
NotionGeneralButton: "普通数据库同步",
|
||||||
NotionGeneralButtonDesc: "打开此选项,同步到普通数据库命令将显示在命令面板中(默认:开)",
|
NotionGeneralButtonDesc: "打开此选项,同步到普通数据库命令将显示在命令面板中(默认:开)",
|
||||||
|
|||||||
103
src/main.ts
103
src/main.ts
@@ -1,8 +1,9 @@
|
|||||||
import { App, Editor, MarkdownView, Notice, Plugin, PluginSettingTab, Setting } from "obsidian";
|
import { App, Editor, MarkdownView, Notice, Plugin, PluginSettingTab, Setting, TFile, EventRef } from "obsidian";
|
||||||
import { addIcons } from 'src/ui/icon';
|
import { addIcons } from 'src/ui/icon';
|
||||||
import { i18nConfig } from "src/lang/I18n";
|
import { i18nConfig } from "src/lang/I18n";
|
||||||
import ribbonCommands from "src/commands/NotionCommands";
|
import ribbonCommands from "src/commands/NotionCommands";
|
||||||
import { ObsidianSettingTab, PluginSettings, DEFAULT_SETTINGS, DatabaseDetails } from "src/ui/settingTabs";
|
import { ObsidianSettingTab, PluginSettings, DEFAULT_SETTINGS, DatabaseDetails } from "src/ui/settingTabs";
|
||||||
|
import { uploadCommandNext, uploadCommandGeneral, uploadCommandCustom } from "src/upload/uploadCommand";
|
||||||
|
|
||||||
// Remember to rename these classes and interfaces!
|
// Remember to rename these classes and interfaces!
|
||||||
|
|
||||||
@@ -11,6 +12,9 @@ export default class ObsidianSyncNotionPlugin extends Plugin {
|
|||||||
settings: PluginSettings;
|
settings: PluginSettings;
|
||||||
commands: ribbonCommands;
|
commands: ribbonCommands;
|
||||||
app: App;
|
app: App;
|
||||||
|
modifyEventRef: EventRef | null = null;
|
||||||
|
autoSyncTimeout: NodeJS.Timeout | null = null;
|
||||||
|
private syncingFiles: Set<string> = new Set();
|
||||||
|
|
||||||
async onload() {
|
async onload() {
|
||||||
await this.loadSettings();
|
await this.loadSettings();
|
||||||
@@ -36,9 +40,18 @@ export default class ObsidianSyncNotionPlugin extends Plugin {
|
|||||||
// This adds a settings tab so the user can configure various aspects of the plugin
|
// This adds a settings tab so the user can configure various aspects of the plugin
|
||||||
this.addSettingTab(new ObsidianSettingTab(this.app, this));
|
this.addSettingTab(new ObsidianSettingTab(this.app, this));
|
||||||
|
|
||||||
|
// Setup auto sync listener
|
||||||
|
this.setupAutoSync();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onunload() {
|
onunload() {
|
||||||
|
if (this.modifyEventRef) {
|
||||||
|
this.app.vault.offref(this.modifyEventRef);
|
||||||
|
}
|
||||||
|
if (this.autoSyncTimeout) {
|
||||||
|
clearTimeout(this.autoSyncTimeout);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async loadSettings() {
|
async loadSettings() {
|
||||||
@@ -80,6 +93,94 @@ export default class ObsidianSyncNotionPlugin extends Plugin {
|
|||||||
await this.saveSettings();
|
await this.saveSettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setupAutoSync() {
|
||||||
|
// Remove existing listener if any
|
||||||
|
if (this.modifyEventRef) {
|
||||||
|
this.app.vault.offref(this.modifyEventRef);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only setup if autoSync is enabled
|
||||||
|
if (!this.settings.autoSync) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Listen for file modifications
|
||||||
|
this.modifyEventRef = this.app.vault.on('modify', async (file: TFile) => {
|
||||||
|
// Only process markdown files
|
||||||
|
if (!(file instanceof TFile) || file.extension !== 'md') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Debounce: clear existing timeout
|
||||||
|
if (this.autoSyncTimeout) {
|
||||||
|
clearTimeout(this.autoSyncTimeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set a new timeout to trigger sync after user-configured delay (in seconds)
|
||||||
|
const delayMs = (this.settings.autoSyncDelay || 2) * 1000;
|
||||||
|
this.autoSyncTimeout = setTimeout(async () => {
|
||||||
|
await this.autoSyncFile(file);
|
||||||
|
}, delayMs);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async autoSyncFile(file: TFile) {
|
||||||
|
// Check if file is already being synced
|
||||||
|
if (this.syncingFiles.has(file.path)) {
|
||||||
|
console.log(`[AutoSync] File ${file.path} is already being synced, skipping`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
this.syncingFiles.add(file.path);
|
||||||
|
|
||||||
|
// Get file's frontmatter
|
||||||
|
const frontMatter = this.app.metadataCache.getFileCache(file)?.frontmatter;
|
||||||
|
if (!frontMatter) {
|
||||||
|
console.log(`[AutoSync] No frontmatter found in ${file.path}`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find which database this file belongs to by checking for NotionID-{abName}
|
||||||
|
let foundDbDetails: DatabaseDetails | null = null;
|
||||||
|
let notionId: string | null = null;
|
||||||
|
|
||||||
|
for (const key in this.settings.databaseDetails) {
|
||||||
|
const dbDetails = this.settings.databaseDetails[key];
|
||||||
|
const notionIDKey = `NotionID-${dbDetails.abName}`;
|
||||||
|
|
||||||
|
if (frontMatter[notionIDKey]) {
|
||||||
|
foundDbDetails = dbDetails;
|
||||||
|
notionId = String(frontMatter[notionIDKey]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If no NotionID found, skip auto sync
|
||||||
|
if (!foundDbDetails || !notionId) {
|
||||||
|
console.log(`[AutoSync] No NotionID found in ${file.path}, skipping auto sync`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`[AutoSync] ${new Date().toISOString()} Auto syncing ${file.basename} to ${foundDbDetails.fullName}`);
|
||||||
|
|
||||||
|
// Trigger appropriate upload command based on database format
|
||||||
|
if (foundDbDetails.format === 'next') {
|
||||||
|
await uploadCommandNext(this, this.settings, foundDbDetails, this.app);
|
||||||
|
} else if (foundDbDetails.format === 'general') {
|
||||||
|
await uploadCommandGeneral(this, this.settings, foundDbDetails, this.app);
|
||||||
|
} else if (foundDbDetails.format === 'custom') {
|
||||||
|
await uploadCommandCustom(this, this.settings, foundDbDetails, this.app);
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`[AutoSync] Error syncing file ${file.path}:`, error);
|
||||||
|
new Notice(`Auto sync failed for ${file.basename}: ${error.message}`);
|
||||||
|
} finally {
|
||||||
|
this.syncingFiles.delete(file.path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,8 @@ export interface PluginSettings {
|
|||||||
bannerUrl: string;
|
bannerUrl: string;
|
||||||
notionUser: string;
|
notionUser: string;
|
||||||
NotionLinkDisplay: boolean;
|
NotionLinkDisplay: boolean;
|
||||||
|
autoSync: boolean;
|
||||||
|
autoSyncDelay: number;
|
||||||
proxy: string;
|
proxy: string;
|
||||||
GeneralButton: boolean;
|
GeneralButton: boolean;
|
||||||
tagButton: boolean;
|
tagButton: boolean;
|
||||||
@@ -49,6 +51,8 @@ export const DEFAULT_SETTINGS: PluginSettings = {
|
|||||||
bannerUrl: "",
|
bannerUrl: "",
|
||||||
notionUser: "",
|
notionUser: "",
|
||||||
NotionLinkDisplay: true,
|
NotionLinkDisplay: true,
|
||||||
|
autoSync: false,
|
||||||
|
autoSyncDelay: 5,
|
||||||
proxy: "",
|
proxy: "",
|
||||||
GeneralButton: true,
|
GeneralButton: true,
|
||||||
tagButton: true,
|
tagButton: true,
|
||||||
@@ -67,6 +71,7 @@ export const DEFAULT_SETTINGS: PluginSettings = {
|
|||||||
export class ObsidianSettingTab extends PluginSettingTab {
|
export class ObsidianSettingTab extends PluginSettingTab {
|
||||||
plugin: ObsidianSyncNotionPlugin;
|
plugin: ObsidianSyncNotionPlugin;
|
||||||
databaseEl: HTMLDivElement;
|
databaseEl: HTMLDivElement;
|
||||||
|
autoSyncDelayContainer: HTMLElement | null = null;
|
||||||
|
|
||||||
constructor(app: App, plugin: ObsidianSyncNotionPlugin) {
|
constructor(app: App, plugin: ObsidianSyncNotionPlugin) {
|
||||||
super(app, plugin);
|
super(app, plugin);
|
||||||
@@ -87,6 +92,34 @@ export class ObsidianSettingTab extends PluginSettingTab {
|
|||||||
|
|
||||||
this.createSettingEl(containerEl, i18nConfig.NotionLinkDisplay, i18nConfig.NotionLinkDisplayDesc, 'toggle', i18nConfig.NotionLinkDisplay, this.plugin.settings.NotionLinkDisplay, 'NotionLinkDisplay')
|
this.createSettingEl(containerEl, i18nConfig.NotionLinkDisplay, i18nConfig.NotionLinkDisplayDesc, 'toggle', i18nConfig.NotionLinkDisplay, this.plugin.settings.NotionLinkDisplay, 'NotionLinkDisplay')
|
||||||
|
|
||||||
|
this.createSettingEl(containerEl, i18nConfig.AutoSync, i18nConfig.AutoSyncDesc, 'toggle', i18nConfig.AutoSync, this.plugin.settings.autoSync, 'autoSync')
|
||||||
|
|
||||||
|
// Auto Sync Delay setting - only visible when autoSync is enabled
|
||||||
|
this.autoSyncDelayContainer = containerEl.createDiv();
|
||||||
|
const delaySetting = new Setting(this.autoSyncDelayContainer)
|
||||||
|
.setName(i18nConfig.AutoSyncDelay)
|
||||||
|
.setDesc(i18nConfig.AutoSyncDelayDesc)
|
||||||
|
.addText((text) =>
|
||||||
|
text
|
||||||
|
.setPlaceholder(i18nConfig.AutoSyncDelayText)
|
||||||
|
.setValue(String(this.plugin.settings.autoSyncDelay))
|
||||||
|
.onChange(async (value) => {
|
||||||
|
const delay = parseFloat(value);
|
||||||
|
if (!isNaN(delay) && delay >= 2) {
|
||||||
|
this.plugin.settings.autoSyncDelay = delay;
|
||||||
|
await this.plugin.saveSettings();
|
||||||
|
} else if (!isNaN(delay) && delay < 2) {
|
||||||
|
// If user enters less than 2 seconds, set it to 2
|
||||||
|
this.plugin.settings.autoSyncDelay = 2;
|
||||||
|
await this.plugin.saveSettings();
|
||||||
|
text.setValue('2');
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
// Set initial visibility
|
||||||
|
this.updateAutoSyncDelayVisibility();
|
||||||
|
|
||||||
|
|
||||||
// add new button
|
// add new button
|
||||||
new Setting(containerEl)
|
new Setting(containerEl)
|
||||||
@@ -151,6 +184,13 @@ export class ObsidianSettingTab extends PluginSettingTab {
|
|||||||
element.style.alignItems = "center";
|
element.style.alignItems = "center";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Update visibility of autoSyncDelay setting based on autoSync toggle
|
||||||
|
public updateAutoSyncDelayVisibility() {
|
||||||
|
if (this.autoSyncDelayContainer) {
|
||||||
|
this.autoSyncDelayContainer.style.display = this.plugin.settings.autoSync ? "block" : "none";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// function to add one setting element in the setting tab.
|
// function to add one setting element in the setting tab.
|
||||||
public createSettingEl(containerEl: HTMLElement, name: string, desc: string, type: string, placeholder: string, holderValue: any, settingsKey: string) {
|
public createSettingEl(containerEl: HTMLElement, name: string, desc: string, type: string, placeholder: string, holderValue: any, settingsKey: string) {
|
||||||
if (type === 'password') {
|
if (type === 'password') {
|
||||||
@@ -178,6 +218,12 @@ export class ObsidianSettingTab extends PluginSettingTab {
|
|||||||
this.plugin.settings[settingsKey] = value; // Update the plugin settings directly
|
this.plugin.settings[settingsKey] = value; // Update the plugin settings directly
|
||||||
await this.plugin.saveSettings();
|
await this.plugin.saveSettings();
|
||||||
await this.plugin.commands.updateCommand();
|
await this.plugin.commands.updateCommand();
|
||||||
|
|
||||||
|
// If autoSync setting changed, update the listener and visibility
|
||||||
|
if (settingsKey === 'autoSync') {
|
||||||
|
this.plugin.setupAutoSync();
|
||||||
|
this.updateAutoSyncDelayVisibility();
|
||||||
|
}
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
} else if (type === 'text') {
|
} else if (type === 'text') {
|
||||||
|
|||||||
Reference in New Issue
Block a user