This commit is contained in:
Jay Nguyen
2022-06-11 18:51:13 +01:00
parent f6ecf4027f
commit 612c9e501e
5 changed files with 132 additions and 81 deletions

40
package-lock.json generated
View File

@@ -1,16 +1,13 @@
{
"name": "obsidian-ghost-publish",
"version": "1.0.0",
"version": "1.2.0",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "obsidian-ghost-publish",
"version": "1.0.0",
"version": "1.2.0",
"license": "MIT",
"dependencies": {
"gray-matter": "^4.0.3"
},
"devDependencies": {
"@types/jsonwebtoken": "^8.5.8",
"@types/markdown-it": "^12.2.3",
@@ -19,6 +16,7 @@
"@typescript-eslint/parser": "^5.2.0",
"builtin-modules": "^3.2.0",
"esbuild": "0.13.12",
"gray-matter": "^4.0.3",
"jsonwebtoken": "^8.5.1",
"markdown-it": "^12.3.2",
"obsidian": "^0.14.4",
@@ -1065,6 +1063,7 @@
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
"integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
"dev": true,
"bin": {
"esparse": "bin/esparse.js",
"esvalidate": "bin/esvalidate.js"
@@ -1140,6 +1139,7 @@
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
"integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
"dev": true,
"dependencies": {
"is-extendable": "^0.1.0"
},
@@ -1338,6 +1338,7 @@
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/gray-matter/-/gray-matter-4.0.3.tgz",
"integrity": "sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q==",
"dev": true,
"dependencies": {
"js-yaml": "^3.13.1",
"kind-of": "^6.0.2",
@@ -1352,6 +1353,7 @@
"version": "1.0.10",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
"integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
"dev": true,
"dependencies": {
"sprintf-js": "~1.0.2"
}
@@ -1360,6 +1362,7 @@
"version": "3.14.1",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz",
"integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==",
"dev": true,
"dependencies": {
"argparse": "^1.0.7",
"esprima": "^4.0.0"
@@ -1436,6 +1439,7 @@
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz",
"integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=",
"dev": true,
"engines": {
"node": ">=0.10.0"
}
@@ -1560,6 +1564,7 @@
"version": "6.0.3",
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
"integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==",
"dev": true,
"engines": {
"node": ">=0.10.0"
}
@@ -1953,6 +1958,7 @@
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/section-matter/-/section-matter-1.0.0.tgz",
"integrity": "sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA==",
"dev": true,
"dependencies": {
"extend-shallow": "^2.0.1",
"kind-of": "^6.0.0"
@@ -2011,7 +2017,8 @@
"node_modules/sprintf-js": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
"integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw="
"integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=",
"dev": true
},
"node_modules/strip-ansi": {
"version": "6.0.1",
@@ -2030,6 +2037,7 @@
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/strip-bom-string/-/strip-bom-string-1.0.0.tgz",
"integrity": "sha1-5SEekiQ2n7uB1jOi8ABE3IztrZI=",
"dev": true,
"engines": {
"node": ">=0.10.0"
}
@@ -2940,7 +2948,8 @@
"esprima": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
"integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A=="
"integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
"dev": true
},
"esquery": {
"version": "1.4.0",
@@ -2995,6 +3004,7 @@
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
"integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
"dev": true,
"requires": {
"is-extendable": "^0.1.0"
}
@@ -3156,6 +3166,7 @@
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/gray-matter/-/gray-matter-4.0.3.tgz",
"integrity": "sha512-5v6yZd4JK3eMI3FqqCouswVqwugaA9r4dNZB1wwcmrD02QkV5H0y7XBQW8QwQqEaZY1pM9aqORSORhJRdNK44Q==",
"dev": true,
"requires": {
"js-yaml": "^3.13.1",
"kind-of": "^6.0.2",
@@ -3167,6 +3178,7 @@
"version": "1.0.10",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
"integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
"dev": true,
"requires": {
"sprintf-js": "~1.0.2"
}
@@ -3175,6 +3187,7 @@
"version": "3.14.1",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz",
"integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==",
"dev": true,
"requires": {
"argparse": "^1.0.7",
"esprima": "^4.0.0"
@@ -3234,7 +3247,8 @@
"is-extendable": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz",
"integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik="
"integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=",
"dev": true
},
"is-extglob": {
"version": "2.1.1",
@@ -3338,7 +3352,8 @@
"kind-of": {
"version": "6.0.3",
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
"integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw=="
"integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==",
"dev": true
},
"levn": {
"version": "0.4.1",
@@ -3620,6 +3635,7 @@
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/section-matter/-/section-matter-1.0.0.tgz",
"integrity": "sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA==",
"dev": true,
"requires": {
"extend-shallow": "^2.0.1",
"kind-of": "^6.0.0"
@@ -3660,7 +3676,8 @@
"sprintf-js": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
"integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw="
"integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=",
"dev": true
},
"strip-ansi": {
"version": "6.0.1",
@@ -3675,7 +3692,8 @@
"strip-bom-string": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/strip-bom-string/-/strip-bom-string-1.0.0.tgz",
"integrity": "sha1-5SEekiQ2n7uB1jOi8ABE3IztrZI="
"integrity": "sha1-5SEekiQ2n7uB1jOi8ABE3IztrZI=",
"dev": true
},
"strip-json-comments": {
"version": "3.1.1",

View File

@@ -1,4 +1,4 @@
import { MarkdownView, Plugin } from "obsidian";
import { MarkdownView, Notice, Plugin } from "obsidian";
import { DEFAULT_SETTINGS, SettingsProp } from "./types/index";
import { SettingTab } from "./settingTab";
@@ -10,12 +10,17 @@ export default class MyPlugin extends Plugin {
// load the settings first
await this.loadSettings();
// 2 ways to publish post:
// 2 ways to publish:
// 1. Click on the ghost icon on the left
this.addRibbonIcon("ghost", "Publish Ghost", () => {
const view = this.app.workspace.getActiveViewOfType(MarkdownView);
// matter
if (!view) {
new Notice(
"Open the markdown file first before publish your post"
);
return;
}
publishPost(view, this.settings);
});
@@ -24,17 +29,19 @@ export default class MyPlugin extends Plugin {
id: "publish",
name: "Publish current document",
editorCallback: (_, view: MarkdownView) => {
if (!view) {
new Notice(
"Open the markdown file first before publish your post"
);
return;
}
publishPost(view, this.settings);
},
});
// This adds a settings tab so the user can configure various aspects of the plugin
this.addSettingTab(new SettingTab(this.app, this));
// When registering intervals, this function will automatically clear the interval when the plugin is disabled.
this.registerInterval(
window.setInterval(() => console.log("setInterval"), 5 * 60 * 1000)
);
}
onunload() {}

View File

@@ -1,20 +1,29 @@
import { SettingsProp, ViewProp, ContentProp } from "./../types/index";
import { Notice, request } from "obsidian";
/* eslint-disable @typescript-eslint/no-var-requires */
import { SettingsProp, ContentProp, DataProp } from "./../types/index";
import { MarkdownView, Notice, request } from "obsidian";
import { sign } from "jsonwebtoken";
const matter = require("gray-matter");
const MarkdownIt = require("markdown-it");
const md = new MarkdownIt();
const version = "v4";
export const publishPost = async (view: ViewProp, settings: SettingsProp) => {
const version = "v4";
const contentPost = (frontmatter: ContentProp, data: DataProp) => ({
posts: [
{
...frontmatter,
html: md.render(data.content),
},
],
});
// Admin API key goes here
export const publishPost = async (
view: MarkdownView,
settings: SettingsProp
) => {
// Ghost Url and Admin API key
const key = settings.adminToken;
// Split the key into ID and SECRET
const [id, secret] = key.split(":");
// Create the token (including decoding secret)
@@ -26,39 +35,29 @@ export const publishPost = async (view: ViewProp, settings: SettingsProp) => {
});
// get frontmatter
const m = matter(`${view.data}`);
const noteFile = app.workspace.getActiveFile();
const metaMatter = app.metadataCache.getFileCache(noteFile).frontmatter;
const data = matter(view.getViewData());
const frontmatter = {
title: m.data.title || view.file.basename,
tags: m.data.tags || undefined,
featured: m.data.featured || false,
status: m.data.status || "draft",
excerpt: m.data.excerpt || undefined,
feature_image: m.data.feature_image || undefined,
title: metaMatter.title || view.file.basename,
tags: metaMatter.tags || [],
featured: metaMatter.featured || false,
status: metaMatter.published ? "published" : "draft",
excerpt: metaMatter.excerpt || undefined,
feature_image: metaMatter.feature_image || undefined,
};
const contentPost = (frontmatter: ContentProp) => ({
posts: [
{
...frontmatter,
html: md.render(m.content),
},
],
});
const body = contentPost(frontmatter);
const result = await request({
url: `${settings.url}/ghost/api/${version}/admin/posts/?source=html`,
method: "POST",
contentType: "application/json",
headers: {
"Access-Control-Allow-Origin": "app://obsidian.md",
"Access-Control-Allow-Methods": "POST",
"Content-Type": "application/json;charset=utf-8",
Authorization: `Ghost ${token}`,
},
body: JSON.stringify(body),
body: JSON.stringify(contentPost(frontmatter, data)),
});
const json = JSON.parse(result);

View File

@@ -13,28 +13,58 @@ export class SettingTab extends PluginSettingTab {
const { containerEl } = this;
containerEl.empty();
containerEl.createEl("h2", { text: "Obsidian Ghost Integration" });
containerEl.createEl("h2", { text: "Obsidian Ghost Publish" });
new Setting(containerEl).setName("API URL").addText((text) =>
text
.setPlaceholder("nguyens.co")
.setValue(this.plugin.settings.url)
.onChange(async (value) => {
console.log("Blog URL: " + value);
this.plugin.settings.url = value;
await this.plugin.saveSettings();
})
);
const document = containerEl.createEl("p", {
text: `Need help? Take a look on how to use me on `,
});
new Setting(containerEl).setName("Admin API Key").addText((text) =>
text
.setPlaceholder("6251555c94ca6")
.setValue(this.plugin.settings.adminToken)
.onChange(async (value) => {
console.log("admin api key: " + value);
this.plugin.settings.adminToken = value;
await this.plugin.saveSettings();
})
);
document.createEl("a", {
attr: {
href: "https://github.com/jaynguyens/obsidian-ghost-publish/blob/master/README.md",
},
text: "the documentation",
});
const donation = containerEl.createEl("p", {
text: "You can support future development by ",
});
donation.createEl("a", {
attr: {
href: "https://www.buymeacoffee.com/jaynguyens",
},
text: "buy me a coffe ☕️",
});
containerEl.createEl("br");
new Setting(containerEl)
.setName("API URL")
.setDesc("Your domain name e.g: https://domain.com")
.addText((text) =>
text
.setPlaceholder("nguyens.co")
.setValue(this.plugin.settings.url)
.onChange(async (value) => {
console.log("Blog URL: " + value);
this.plugin.settings.url = value;
await this.plugin.saveSettings();
})
);
new Setting(containerEl)
.setName("Admin API Key")
.setDesc("Your custom integration Admin API Key")
.addText((text) =>
text
.setPlaceholder("6251555c94ca6")
.setValue(this.plugin.settings.adminToken)
.onChange(async (value) => {
console.log("admin api key: " + value);
this.plugin.settings.adminToken = value;
await this.plugin.saveSettings();
})
);
}
}

View File

@@ -8,18 +8,15 @@ export const DEFAULT_SETTINGS: SettingsProp = {
adminToken: "",
};
export interface ViewProp {
file: {
basename: string;
};
data: string;
}
export interface ContentProp {
title: string;
tags: string[];
featured: boolean;
status: "published" | "draft";
excerpt: string;
feature_image: string;
tags?: string[];
featured?: boolean;
status: string;
excerpt?: string | undefined;
feature_image?: string;
}
export interface DataProp {
content: string;
}