mirror of
https://github.com/saberzero1/quartz-syncer.git
synced 2026-07-22 12:50:25 +00:00
444 lines
9.9 KiB
TypeScript
444 lines
9.9 KiB
TypeScript
import { Notice, Platform, Plugin, Workspace, addIcon } from "obsidian";
|
|
import Publisher from "./src/publisher/Publisher";
|
|
import QuartzSyncerSettings from "./src/models/settings";
|
|
import { bookHeart } from "./src/ui/suggest/constants";
|
|
import { PublishStatusBar } from "./src/views/PublishStatusBar";
|
|
import { PublicationCenter } from "src/views/PublicationCenter/PublicationCenter";
|
|
import PublishStatusManager from "src/publisher/PublishStatusManager";
|
|
import ObsidianFrontMatterEngine from "src/publishFile/ObsidianFrontMatterEngine";
|
|
import QuartzSyncerSiteManager from "src/repositoryConnection/QuartzSyncerSiteManager";
|
|
import { QuartzSyncerSettingTab } from "./src/views/QuartzSyncerSettingTab";
|
|
import Logger from "js-logger";
|
|
import { PublishFile } from "./src/publishFile/PublishFile";
|
|
import { FRONTMATTER_KEYS } from "./src/publishFile/FileMetaDataManager";
|
|
|
|
const DEFAULT_SETTINGS: QuartzSyncerSettings = {
|
|
githubRepo: "",
|
|
githubToken: "",
|
|
githubUserName: "",
|
|
prHistory: [],
|
|
useFullResolutionImages: false,
|
|
noteSettingsIsInitialized: false,
|
|
siteName: "Quartz",
|
|
slugifyEnabled: true,
|
|
contentFolder: "content",
|
|
|
|
// Timestamp related settings
|
|
showCreatedTimestamp: false,
|
|
createdTimestampKey: "",
|
|
showUpdatedTimestamp: false,
|
|
updatedTimestampKey: "",
|
|
timestampFormat: "MMM dd, yyyy h:mm a",
|
|
|
|
styleSettingsCss: "",
|
|
styleSettingsBodyClasses: "",
|
|
pathRewriteRules: "",
|
|
customFilters: [],
|
|
|
|
contentClassesKey: "content-classes",
|
|
|
|
defaultNoteSettings: {
|
|
HomeLink: true,
|
|
PassFrontmatter: true,
|
|
},
|
|
logLevel: undefined,
|
|
};
|
|
|
|
Logger.useDefaults({
|
|
defaultLevel: Logger.WARN,
|
|
formatter: function (messages, _context) {
|
|
messages.unshift(new Date().toUTCString());
|
|
messages.unshift("QS: ");
|
|
},
|
|
});
|
|
export default class QuartzSyncer extends Plugin {
|
|
settings!: QuartzSyncerSettings;
|
|
appVersion!: string;
|
|
|
|
publishModal!: PublicationCenter;
|
|
|
|
async onload() {
|
|
this.appVersion = this.manifest.version;
|
|
|
|
console.log("Initializing QuartzSyncer plugin v" + this.appVersion);
|
|
await this.loadSettings();
|
|
|
|
this.settings.logLevel && Logger.setLevel(this.settings.logLevel);
|
|
|
|
Logger.info(
|
|
"Digital garden log level set to " + Logger.getLevel().name,
|
|
);
|
|
this.addSettingTab(new QuartzSyncerSettingTab(this.app, this));
|
|
|
|
await this.addCommands();
|
|
|
|
addIcon("quartz-syncer-icon", bookHeart);
|
|
|
|
this.addRibbonIcon(
|
|
"quartz-syncer-icon",
|
|
"Quartz Syncer Publication Center",
|
|
async () => {
|
|
this.openPublishModal();
|
|
},
|
|
);
|
|
}
|
|
|
|
onunload() {}
|
|
|
|
async loadSettings() {
|
|
this.settings = Object.assign(
|
|
{},
|
|
DEFAULT_SETTINGS,
|
|
await this.loadData(),
|
|
);
|
|
}
|
|
|
|
async saveSettings(): Promise<void> {
|
|
await this.saveData(this.settings);
|
|
}
|
|
|
|
async addCommands() {
|
|
this.addCommand({
|
|
id: "publish-note",
|
|
name: "Publish Single Note",
|
|
callback: async () => {
|
|
await this.publishSingleNote();
|
|
},
|
|
});
|
|
|
|
if (this.settings["ENABLE_DEVELOPER_TOOLS"] && Platform.isDesktop) {
|
|
Logger.info("Developer tools enabled");
|
|
|
|
const publisher = new Publisher(
|
|
this.app.vault,
|
|
this.app.metadataCache,
|
|
this.settings,
|
|
);
|
|
|
|
import("./src/test/snapshot/generateSyncerSnapshot")
|
|
.then((snapshotGen) => {
|
|
this.addCommand({
|
|
id: "generate-garden-snapshot",
|
|
name: "Generate Syncer Snapshot",
|
|
callback: async () => {
|
|
await snapshotGen.generateSyncerSnapshot(
|
|
this.settings,
|
|
publisher,
|
|
);
|
|
},
|
|
});
|
|
})
|
|
.catch((e) => {
|
|
Logger.error("Unable to load generateSyncerSnapshot", e);
|
|
});
|
|
}
|
|
|
|
this.addCommand({
|
|
id: "publish-multiple-notes",
|
|
name: "Publish Multiple Notes",
|
|
// TODO: move to publisher?
|
|
callback: async () => {
|
|
const statusBarItem = this.addStatusBarItem();
|
|
|
|
try {
|
|
new Notice("Processing files to publish...");
|
|
const { vault, metadataCache } = this.app;
|
|
|
|
const publisher = new Publisher(
|
|
vault,
|
|
metadataCache,
|
|
this.settings,
|
|
);
|
|
publisher.validateSettings();
|
|
|
|
const siteManager = new QuartzSyncerSiteManager(
|
|
metadataCache,
|
|
this.settings,
|
|
);
|
|
|
|
const publishStatusManager = new PublishStatusManager(
|
|
siteManager,
|
|
publisher,
|
|
);
|
|
|
|
const publishStatus =
|
|
await publishStatusManager.getPublishStatus();
|
|
|
|
const filesToPublish = publishStatus.changedNotes.concat(
|
|
publishStatus.unpublishedNotes,
|
|
);
|
|
const filesToDelete = publishStatus.deletedNotePaths;
|
|
const imagesToDelete = publishStatus.deletedImagePaths;
|
|
|
|
const totalItems =
|
|
filesToPublish.length +
|
|
filesToDelete.length +
|
|
imagesToDelete.length;
|
|
|
|
if (totalItems === 0) {
|
|
new Notice("Syncer is already fully synced!");
|
|
statusBarItem.remove();
|
|
|
|
return;
|
|
}
|
|
|
|
const statusBar = new PublishStatusBar(
|
|
statusBarItem,
|
|
filesToPublish.length +
|
|
filesToDelete.length +
|
|
imagesToDelete.length,
|
|
);
|
|
|
|
let errorFiles = 0;
|
|
let errorDeleteFiles = 0;
|
|
let errorDeleteImage = 0;
|
|
|
|
new Notice(
|
|
`Publishing ${filesToPublish.length} notes, deleting ${filesToDelete.length} notes and ${imagesToDelete.length} images. See the status bar in lower right corner for progress.`,
|
|
8000,
|
|
);
|
|
|
|
for (const file of filesToPublish) {
|
|
try {
|
|
statusBar.increment();
|
|
await publisher.publish(file);
|
|
} catch {
|
|
errorFiles++;
|
|
|
|
new Notice(
|
|
`Unable to publish note ${file.file.name}, skipping it.`,
|
|
);
|
|
}
|
|
}
|
|
|
|
for (const filePath of filesToDelete) {
|
|
try {
|
|
statusBar.increment();
|
|
|
|
// TODO: include sha from file.remoteHash to make faster!
|
|
await publisher.deleteNote(
|
|
filePath.path,
|
|
filePath.sha,
|
|
);
|
|
} catch {
|
|
errorDeleteFiles++;
|
|
|
|
new Notice(
|
|
`Unable to delete note ${filePath}, skipping it.`,
|
|
);
|
|
}
|
|
}
|
|
|
|
for (const filePath of imagesToDelete) {
|
|
try {
|
|
statusBar.increment();
|
|
|
|
await publisher.deleteImage(
|
|
filePath.path,
|
|
filePath.sha,
|
|
);
|
|
} catch {
|
|
errorDeleteImage++;
|
|
|
|
new Notice(
|
|
`Unable to delete image ${filePath}, skipping it.`,
|
|
);
|
|
}
|
|
}
|
|
|
|
statusBar.finish(8000);
|
|
|
|
new Notice(
|
|
`Successfully published ${
|
|
filesToPublish.length - errorFiles
|
|
} notes to your garden.`,
|
|
);
|
|
|
|
if (filesToDelete.length > 0) {
|
|
new Notice(
|
|
`Successfully deleted ${
|
|
filesToDelete.length - errorDeleteFiles
|
|
} notes from your garden.`,
|
|
);
|
|
}
|
|
|
|
if (imagesToDelete.length > 0) {
|
|
new Notice(
|
|
`Successfully deleted ${
|
|
imagesToDelete.length - errorDeleteImage
|
|
} images from your garden.`,
|
|
);
|
|
}
|
|
} catch (e) {
|
|
statusBarItem.remove();
|
|
console.error(e);
|
|
|
|
new Notice(
|
|
"Unable to publish multiple notes, something went wrong.",
|
|
);
|
|
}
|
|
},
|
|
});
|
|
|
|
this.addCommand({
|
|
id: "open-publish-modal",
|
|
name: "Open Publication Center",
|
|
callback: async () => {
|
|
this.openPublishModal();
|
|
},
|
|
});
|
|
|
|
this.addCommand({
|
|
id: "mark-note-for-publish",
|
|
name: "Add publish flag",
|
|
callback: async () => {
|
|
this.setPublishFlagValue(true);
|
|
},
|
|
});
|
|
|
|
this.addCommand({
|
|
id: "unmark-note-for-publish",
|
|
name: "Remove publish flag",
|
|
callback: async () => {
|
|
this.setPublishFlagValue(false);
|
|
},
|
|
});
|
|
|
|
this.addCommand({
|
|
id: "mark-toggle-publish-status",
|
|
name: "Toggle publication status",
|
|
callback: async () => {
|
|
this.togglePublishFlag();
|
|
},
|
|
});
|
|
}
|
|
|
|
private getActiveFile(workspace: Workspace) {
|
|
const activeFile = workspace.getActiveFile();
|
|
|
|
if (!activeFile) {
|
|
new Notice(
|
|
"No file is open/active. Please open a file and try again.",
|
|
);
|
|
|
|
return null;
|
|
}
|
|
|
|
return activeFile;
|
|
}
|
|
|
|
// TODO: move to publisher?
|
|
async publishSingleNote() {
|
|
try {
|
|
const { vault, workspace, metadataCache } = this.app;
|
|
|
|
const activeFile = this.getActiveFile(workspace);
|
|
|
|
if (!activeFile) {
|
|
return;
|
|
}
|
|
|
|
if (activeFile.extension !== "md") {
|
|
new Notice(
|
|
"The current file is not a markdown file. Please open a markdown file and try again.",
|
|
);
|
|
|
|
return;
|
|
}
|
|
|
|
new Notice("Publishing note...");
|
|
|
|
const publisher = new Publisher(
|
|
vault,
|
|
metadataCache,
|
|
this.settings,
|
|
);
|
|
publisher.validateSettings();
|
|
|
|
const publishFile = await new PublishFile({
|
|
file: activeFile,
|
|
vault: vault,
|
|
compiler: publisher.compiler,
|
|
metadataCache: metadataCache,
|
|
settings: this.settings,
|
|
}).compile();
|
|
|
|
const publishSuccessful = await publisher.publish(publishFile);
|
|
|
|
if (publishSuccessful) {
|
|
new Notice(`Successfully published note to your garden.`);
|
|
}
|
|
|
|
return publishSuccessful;
|
|
} catch (e) {
|
|
console.error(e);
|
|
new Notice("Unable to publish note, something went wrong.");
|
|
|
|
return false;
|
|
}
|
|
}
|
|
|
|
async setPublishFlagValue(value: boolean) {
|
|
const activeFile = this.getActiveFile(this.app.workspace);
|
|
|
|
if (!activeFile) {
|
|
return;
|
|
}
|
|
|
|
const engine = new ObsidianFrontMatterEngine(
|
|
this.app.vault,
|
|
this.app.metadataCache,
|
|
activeFile,
|
|
);
|
|
engine.set(FRONTMATTER_KEYS.PUBLISH, value).apply();
|
|
}
|
|
async togglePublishFlag() {
|
|
const activeFile = this.getActiveFile(this.app.workspace);
|
|
|
|
if (!activeFile) {
|
|
return;
|
|
}
|
|
|
|
const engine = new ObsidianFrontMatterEngine(
|
|
this.app.vault,
|
|
this.app.metadataCache,
|
|
activeFile,
|
|
);
|
|
|
|
engine
|
|
.set(
|
|
FRONTMATTER_KEYS.PUBLISH,
|
|
!engine.get(FRONTMATTER_KEYS.PUBLISH),
|
|
)
|
|
.apply();
|
|
}
|
|
|
|
openPublishModal() {
|
|
if (!this.publishModal) {
|
|
const siteManager = new QuartzSyncerSiteManager(
|
|
this.app.metadataCache,
|
|
this.settings,
|
|
);
|
|
|
|
const publisher = new Publisher(
|
|
this.app.vault,
|
|
this.app.metadataCache,
|
|
this.settings,
|
|
);
|
|
|
|
const publishStatusManager = new PublishStatusManager(
|
|
siteManager,
|
|
publisher,
|
|
);
|
|
|
|
this.publishModal = new PublicationCenter(
|
|
this.app,
|
|
publishStatusManager,
|
|
publisher,
|
|
siteManager,
|
|
this.settings,
|
|
);
|
|
}
|
|
this.publishModal.open();
|
|
}
|
|
}
|