Skip to content

Commit

Permalink
Merge pull request #73 from omnivore-app/fix/front-matter-template
Browse files Browse the repository at this point in the history
fix/front matter template
  • Loading branch information
sywhb authored May 31, 2023
2 parents 4c6df1e + f07a4c6 commit d93245c
Show file tree
Hide file tree
Showing 4 changed files with 160 additions and 43 deletions.
103 changes: 88 additions & 15 deletions src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,7 @@ export default class OmnivorePlugin extends Plugin {
folderDateFormat,
isSingleFile,
frontMatterVariables,
frontMatterTemplate,
} = this.settings;

if (syncing) {
Expand All @@ -196,7 +197,15 @@ export default class OmnivorePlugin extends Plugin {
manualSync && new Notice("🚀 Fetching articles ...");

// pre-parse template
preParseTemplate(template);
frontMatterTemplate && preParseTemplate(frontMatterTemplate);
const templateSpans = preParseTemplate(template);
// check if we need to include content or file attachment
const includeContent = templateSpans.some(
(templateSpan) => templateSpan[1] === "content"
);
const includeFileAttachment = templateSpans.some(
(templateSpan) => templateSpan[1] === "fileAttachment"
);

const size = 50;
for (
Expand All @@ -211,7 +220,7 @@ export default class OmnivorePlugin extends Plugin {
size,
parseDateTime(syncAt).toISO(),
getQueryFromFilter(filter, customQuery),
true,
includeContent,
"highlightedMarkdown"
);

Expand All @@ -229,7 +238,7 @@ export default class OmnivorePlugin extends Plugin {
await this.app.vault.createFolder(folderName);
}
const fileAttachment =
article.pageType === PageType.File
article.pageType === PageType.File && includeFileAttachment
? await this.downloadFileAsAttachment(article)
: undefined;
const content = await renderArticleContnet(
Expand All @@ -240,6 +249,7 @@ export default class OmnivorePlugin extends Plugin {
this.settings.dateSavedFormat,
isSingleFile,
frontMatterVariables,
frontMatterTemplate,
fileAttachment
);
// use the custom filename
Expand Down Expand Up @@ -478,13 +488,27 @@ class OmnivoreSettingTab extends PluginSettingTab {
});

new Setting(containerEl)
.setName("Front Matter Variables")
.setName("Front Matter")
.setDesc(
"Enter the front matter variables to be used in the template separated by commas. Available variables are title, author, tags, date_saved, date_published"
createFragment((fragment) => {
fragment.append(
"Enter the metadata to be used in your note separated by commas. You can also use custom aliases in the format of metatdata::alias, e.g. date_saved::date. ",
fragment.createEl("br"),
fragment.createEl("br"),
"Available metadata can be found at ",
fragment.createEl("a", {
text: "Reference",
href: "https://docs.omnivore.app/integrations/obsidian.html#front-matter",
}),
fragment.createEl("br"),
fragment.createEl("br"),
"If you want to use a custom front matter template, you can enter it below under the advanced settings"
);
})
)
.addTextArea((text) => {
text
.setPlaceholder("Enter the front matter variables")
.setPlaceholder("Enter the metadata")
.setValue(this.plugin.settings.frontMatterVariables.join(","))
.onChange(async (value) => {
// validate front matter variables and deduplicate
Expand All @@ -493,24 +517,28 @@ class OmnivoreSettingTab extends PluginSettingTab {
.map((v) => v.trim())
.filter(
(v, i, a) =>
FRONT_MATTER_VARIABLES.includes(v) && a.indexOf(v) === i
FRONT_MATTER_VARIABLES.includes(v.split("::")[0]) &&
a.indexOf(v) === i
);
await this.plugin.saveSettings();
});
text.inputEl.setAttr("rows", 2);
text.inputEl.setAttr("cols", 40);
text.inputEl.setAttr("rows", 4);
text.inputEl.setAttr("cols", 30);
});

new Setting(containerEl)
.setName("Template")
.setName("Article Template")
.setDesc(
createFragment((fragment) => {
fragment.append(
"Enter template to render articles with ",
fragment.createEl("a", {
text: "Reference",
href: "https://docs.omnivore.app/integrations/obsidian.html#controlling-the-layout-of-the-data-imported-to-obsidian",
})
}),
fragment.createEl("br"),
fragment.createEl("br"),
"If you want to use a custom front matter template, you can enter it below under the advanced settings"
);
})
)
Expand All @@ -525,8 +553,8 @@ class OmnivoreSettingTab extends PluginSettingTab {
: DEFAULT_SETTINGS.template;
await this.plugin.saveSettings();
});
text.inputEl.setAttr("rows", 30);
text.inputEl.setAttr("cols", 60);
text.inputEl.setAttr("rows", 25);
text.inputEl.setAttr("cols", 50);
})
.addExtraButton((button) => {
// add a button to reset template
Expand Down Expand Up @@ -675,7 +703,7 @@ class OmnivoreSettingTab extends PluginSettingTab {
})
);

containerEl.createEl("h3", {
containerEl.createEl("h5", {
cls: "omnivore-collapsible",
text: "Advanced Settings",
});
Expand All @@ -697,8 +725,53 @@ class OmnivoreSettingTab extends PluginSettingTab {
})
);

new Setting(advancedSettings)
.setName("Front Matter Template")
.setDesc(
createFragment((fragment) => {
fragment.append(
"Enter YAML template to render the front matter with ",
fragment.createEl("a", {
text: "Reference",
href: "https://docs.omnivore.app/integrations/obsidian.html#front-matter-template",
}),
fragment.createEl("br"),
fragment.createEl("br"),
"We recommend you to use Front Matter section under the basic settings to define the metadata.",
fragment.createEl("br"),
fragment.createEl("br"),
"If this template is set, it will override the Front Matter so please make sure your template is a valid YAML."
);
})
)
.addTextArea((text) => {
text
.setPlaceholder("Enter the template")
.setValue(this.plugin.settings.frontMatterTemplate)
.onChange(async (value) => {
this.plugin.settings.frontMatterTemplate = value;
await this.plugin.saveSettings();
});

text.inputEl.setAttr("rows", 10);
text.inputEl.setAttr("cols", 30);
})
.addExtraButton((button) => {
// add a button to reset template
button
.setIcon("reset")
.setTooltip("Reset front matter template")
.onClick(async () => {
this.plugin.settings.frontMatterTemplate =
DEFAULT_SETTINGS.frontMatterTemplate;
await this.plugin.saveSettings();
this.display();
new Notice("Front matter template reset");
});
});

const help = containerEl.createEl("p");
help.innerHTML = `For more information, please visit the <a href="https://github.com/omnivore-app/obsidian-omnivore/blob/master/README.md">plugin's GitHub page</a> or email us at <a href="mailto:[email protected]">[email protected]</a>.`;
help.innerHTML = `For more information, please visit our <a href="https://github.com/omnivore-app/obsidian-omnivore">GitHub page</a>, email us at <a href="mailto:[email protected]">[email protected]</a> or join our <a href="https://discord.gg/h2z5rppzz9">Discord server</a>.`;

// script to make collapsible sections
const coll = document.getElementsByClassName("omnivore-collapsible");
Expand Down
15 changes: 14 additions & 1 deletion src/settings/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,17 @@ export const FRONT_MATTER_VARIABLES = [
"tags",
"date_saved",
"date_published",
"omnivore_url",
"site_name",
"original_url",
"description",
"note",
"type",
"date_read",
"words_count",
"read_length",
"state",
"date_archived",
];

export const DEFAULT_SETTINGS: OmnivoreSettings = {
Expand All @@ -27,7 +38,8 @@ export const DEFAULT_SETTINGS: OmnivoreSettings = {
isSingleFile: false,
frequency: 0,
intervalId: 0,
frontMatterVariables: FRONT_MATTER_VARIABLES,
frontMatterVariables: [],
frontMatterTemplate: "",
};

export enum Filter {
Expand Down Expand Up @@ -61,4 +73,5 @@ export interface OmnivoreSettings {
frequency: number;
intervalId: number;
frontMatterVariables: string[];
frontMatterTemplate: string;
}
82 changes: 55 additions & 27 deletions src/settings/template.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { truncate } from "lodash";
import Mustache from "mustache";
import { stringifyYaml } from "obsidian";
import { parseYaml, stringifyYaml } from "obsidian";
import { Article, HighlightType, PageType } from "../api";
import {
compareHighlightsInFile,
Expand All @@ -9,6 +9,7 @@ import {
getHighlightLocation,
removeFrontMatterFromContent,
siteNameFromUrl,
snakeToCamelCase,
} from "../util";

type FunctionMap = {
Expand Down Expand Up @@ -163,6 +164,7 @@ export const renderArticleContnet = async (
dateSavedFormat: string,
isSingleFile: boolean,
frontMatterVariables: string[],
frontMatterTemplate: string,
fileAttachment?: string
) => {
// filter out notes and redactions
Expand Down Expand Up @@ -241,34 +243,60 @@ export const renderArticleContnet = async (
...functionMap,
};

const frontMatter: { [id: string]: unknown } = {
let frontMatter: { [id: string]: unknown } = {
id: article.id, // id is required for deduplication
};

for (const item of frontMatterVariables) {
switch (item) {
case "title":
frontMatter[item] = articleView.title;
break;
case "author":
if (articleView.author) {
frontMatter[item] = articleView.author;
}
break;
case "tags":
if (articleView.labels && articleView.labels.length > 0) {
// use label names as tags
frontMatter[item] = articleView.labels.map((l) => l.name);
}
break;
case "date_saved":
frontMatter[item] = dateSaved;
break;
case "date_published":
if (datePublished) {
frontMatter[item] = datePublished;
}
break;
// if the front matter template is set, use it
if (frontMatterTemplate) {
const frontMatterTemplateRendered = Mustache.render(
frontMatterTemplate,
articleView
);
try {
// parse the front matter template as yaml
const frontMatterParsed = parseYaml(frontMatterTemplateRendered);

frontMatter = {
...frontMatterParsed,
...frontMatter,
};
} catch (error) {
// if there's an error parsing the front matter template, log it
console.error("Error parsing front matter template", error);
// and add the error to the front matter
frontMatter = {
...frontMatter,
omnivore_error:
"There was an error parsing the front matter template. See console for details.",
};
}
} else {
// otherwise, use the front matter variables
for (const item of frontMatterVariables) {
// split the item into variable and alias
const aliasedVariables = item.split("::");
const variable = aliasedVariables[0];
// we use snake case for variables in the front matter
const articleVariable = snakeToCamelCase(variable);
// use alias if available, otherwise use variable
const key = aliasedVariables[1] || variable;
if (
variable === "tags" &&
articleView.labels &&
articleView.labels.length > 0
) {
// tags are handled separately
// use label names as tags
frontMatter[key] = articleView.labels.map((l) => l.name);
continue;
}

const value = (articleView as any)[articleVariable];
if (value) {
// if variable is in article, use it
frontMatter[key] = value;
}
}
}

Expand Down Expand Up @@ -298,5 +326,5 @@ export const renderFolderName = (folder: string, folderDate: string) => {
};

export const preParseTemplate = (template: string) => {
Mustache.parse(template);
return Mustache.parse(template);
};
3 changes: 3 additions & 0 deletions src/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -161,3 +161,6 @@ export const removeFrontMatterFromContent = (content: string): string => {

return content.replace(frontMatterRegex, "");
};

export const snakeToCamelCase = (str: string) =>
str.replace(/(_[a-z])/g, (group) => group.toUpperCase().replace("_", ""));

0 comments on commit d93245c

Please sign in to comment.