feat: add setting to disable default front matter. support templater.

This commit is contained in:
Kelvin John Falk Szolnoky 2023-12-28 17:37:54 +01:00
parent 06946c73da
commit 89b5b0f16b
No known key found for this signature in database
GPG key ID: 02BA666D8C0E7E1B
3 changed files with 156 additions and 32 deletions

View file

@ -2,7 +2,15 @@ import { MarkdownView, Notice, parseYaml, Plugin, stringifyYaml, TFile, TFolder
import { getDefaultSettings, MediaDbPluginSettings, MediaDbSettingTab } from './settings/Settings';
import { APIManager } from './api/APIManager';
import { MediaTypeModel } from './models/MediaTypeModel';
import { CreateNoteOptions, dateTimeToString, markdownTable, replaceIllegalFileNameCharactersInString, unCamelCase } from './utils/Utils';
import {
CreateNoteOptions,
dateTimeToString,
markdownTable,
replaceIllegalFileNameCharactersInString,
unCamelCase,
executeInlineScriptsTemplates,
useTemplaterPluginInFile,
} from './utils/Utils';
import { OMDbAPI } from './api/apis/OMDbAPI';
import { MALAPI } from './api/apis/MALAPI';
import { MALAPIManga } from './api/apis/MALAPIManga';
@ -63,7 +71,8 @@ export default class MediaDbPlugin extends Plugin {
this.app.workspace.on('file-menu', (menu, file) => {
if (file instanceof TFolder) {
menu.addItem(item => {
item.setTitle('Import folder as Media DB entries')
item
.setTitle('Import folder as Media DB entries')
.setIcon('database')
.onClick(() => this.createEntriesFromFolder(file));
});
@ -286,7 +295,9 @@ export default class MediaDbPlugin extends Plugin {
options.folder = await this.mediaTypeManager.getFolder(mediaTypeModel, this.app);
}
await this.createNote(this.mediaTypeManager.getFileName(mediaTypeModel), fileContent, options);
const targetFile = await this.createNote(this.mediaTypeManager.getFileName(mediaTypeModel), fileContent, options);
await useTemplaterPluginInFile(this.app, targetFile);
} catch (e) {
console.warn(e);
new Notice(e.toString());
@ -299,15 +310,67 @@ export default class MediaDbPlugin extends Plugin {
}
async generateMediaDbNoteContents(mediaTypeModel: MediaTypeModel, options: CreateNoteOptions): Promise<string> {
let fileMetadata = this.modelPropertyMapper.convertObject(mediaTypeModel.toMetaDataObject());
let fileContent = '';
const template = options.attachTemplate ? await this.mediaTypeManager.getTemplate(mediaTypeModel, this.app) : '';
if (this.settings.useDefaultFrontMatter) {
let fileMetadata = this.modelPropertyMapper.convertObject(mediaTypeModel.toMetaDataObject());
let fileContent = '';
const template = options.attachTemplate ? await this.mediaTypeManager.getTemplate(mediaTypeModel, this.app) : '';
({ fileMetadata, fileContent } = await this.attachFile(fileMetadata, fileContent, options.attachFile));
({ fileMetadata, fileContent } = await this.attachTemplate(fileMetadata, fileContent, template));
({ fileMetadata, fileContent } = await this.attachFile(fileMetadata, fileContent, options.attachFile));
({ fileMetadata, fileContent } = await this.attachTemplate(fileMetadata, fileContent, template));
fileContent = `---\n${this.settings.useCustomYamlStringifier ? YAMLConverter.toYaml(fileMetadata) : stringifyYaml(fileMetadata)}---\n` + fileContent;
return fileContent;
fileContent = `---\n${this.settings.useCustomYamlStringifier ? YAMLConverter.toYaml(fileMetadata) : stringifyYaml(fileMetadata)}---\n` + fileContent;
return fileContent;
} else {
let template = await this.mediaTypeManager.getTemplate(mediaTypeModel, this.app);
const parts = template.split('---');
if (parts.length < 3) {
throw new Error('Cannot find YAML front matter for template.');
}
let frontMatter = parseYaml(parts[1]);
let fileContent: string = parts[2];
// Updating a previous file
if (options.attachFile) {
const previousMetadata = this.app.metadataCache.getFileCache(options.attachFile).frontmatter;
// Use contents (below front matter) from previous file
fileContent = await this.app.vault.read(options.attachFile);
const regExp = new RegExp(this.frontMatterRexExpPattern);
fileContent = fileContent.replace(regExp, '');
fileContent = fileContent.startsWith('\n') ? fileContent.substring(1) : fileContent;
// Update updated front matter with entries from the old front matter, if it isn't defined in the new front matter
Object.keys(previousMetadata).forEach(key => {
const value = previousMetadata[key];
if (!frontMatter[key] && value) {
frontMatter[key] = value;
}
});
}
// Ensure that id, type, and dataSource are defined
if (!frontMatter.id) {
frontMatter.id = mediaTypeModel.id;
}
if (!frontMatter.type) {
frontMatter.type = mediaTypeModel.type;
}
if (!frontMatter.dataSource) {
frontMatter.dataSource = mediaTypeModel.dataSource;
}
// Only support stringifyYaml for templater plugin
fileContent = `---\n${stringifyYaml(frontMatter)}---\n${fileContent}`;
fileContent = executeInlineScriptsTemplates(mediaTypeModel, fileContent);
return fileContent;
}
}
async attachFile(fileMetadata: any, fileContent: string, fileToAttach?: TFile): Promise<{ fileMetadata: any; fileContent: string }> {
@ -386,7 +449,7 @@ export default class MediaDbPlugin extends Plugin {
* @param fileContent
* @param options
*/
async createNote(fileName: string, fileContent: string, options: CreateNoteOptions): Promise<void> {
async createNote(fileName: string, fileContent: string, options: CreateNoteOptions): Promise<TFile> {
// find and possibly create the folder set in settings or passed in folder
const folder = options.folder ?? this.app.vault.getAbstractFileByPath('/');
@ -412,6 +475,8 @@ export default class MediaDbPlugin extends Plugin {
}
await activeLeaf.openFile(targetFile, { state: { mode: 'source' } });
}
return targetFile;
}
/**

View file

@ -16,6 +16,7 @@ export interface MediaDbPluginSettings {
templates: boolean;
customDateFormat: string;
openNoteInNewTab: boolean;
useDefaultFrontMatter: boolean;
movieTemplate: string;
seriesTemplate: string;
@ -63,6 +64,7 @@ const DEFAULT_SETTINGS: MediaDbPluginSettings = {
templates: true,
customDateFormat: 'L',
openNoteInNewTab: true,
useDefaultFrontMatter: true,
movieTemplate: '',
seriesTemplate: '',
@ -218,6 +220,18 @@ export class MediaDbSettingTab extends PluginSettingTab {
});
});
new Setting(containerEl)
.setName('Use default front matter')
.setDesc('Wheter to use the default front matter. If disabled, the front matter from the template will be used. Same as mapping everything to remove.')
.addToggle(cb => {
cb.setValue(this.plugin.settings.useDefaultFrontMatter).onChange(data => {
this.plugin.settings.useDefaultFrontMatter = data;
this.plugin.saveSettings();
// Redraw settings to display/remove the property mappings
this.display();
});
});
containerEl.createEl('h3', { text: 'New File Location' });
// region new file location
new Setting(containerEl)
@ -531,11 +545,11 @@ export class MediaDbSettingTab extends PluginSettingTab {
// endregion
// region Property Mappings
if (this.plugin.settings.useDefaultFrontMatter) {
containerEl.createEl('h3', { text: 'Property Mappings' });
containerEl.createEl('h3', { text: 'Property Mappings' });
const propertyMappingExplanation = containerEl.createEl('div');
propertyMappingExplanation.innerHTML = `
const propertyMappingExplanation = containerEl.createEl('div');
propertyMappingExplanation.innerHTML = `
<p>Allow you to remap the metadata fields of newly created media db entries.</p>
<p>
The different options are:
@ -549,27 +563,28 @@ export class MediaDbSettingTab extends PluginSettingTab {
Don't forget to save your changes using the save button for each individual category.
</p>`;
new PropertyMappingModelsComponent({
target: this.containerEl,
props: {
models: this.plugin.settings.propertyMappingModels.map(x => x.copy()),
save: (model: PropertyMappingModel): void => {
const propertyMappingModels: PropertyMappingModel[] = [];
new PropertyMappingModelsComponent({
target: this.containerEl,
props: {
models: this.plugin.settings.propertyMappingModels.map(x => x.copy()),
save: (model: PropertyMappingModel): void => {
const propertyMappingModels: PropertyMappingModel[] = [];
for (const model2 of this.plugin.settings.propertyMappingModels) {
if (model2.type === model.type) {
propertyMappingModels.push(model);
} else {
propertyMappingModels.push(model2);
for (const model2 of this.plugin.settings.propertyMappingModels) {
if (model2.type === model.type) {
propertyMappingModels.push(model);
} else {
propertyMappingModels.push(model2);
}
}
}
this.plugin.settings.propertyMappingModels = propertyMappingModels;
new Notice(`MDB: Property Mappings for ${model.type} saved successfully.`);
this.plugin.saveSettings();
this.plugin.settings.propertyMappingModels = propertyMappingModels;
new Notice(`MDB: Property Mappings for ${model.type} saved successfully.`);
this.plugin.saveSettings();
},
},
},
});
});
}
// endregion
}

View file

@ -202,3 +202,47 @@ export function unCamelCase(str: string): string {
})
);
}
// Copied from https://github.com/anpigon/obsidian-book-search-plugin
// Licensed under the MIT license. Copyright (c) 2020 Jake Runzer
export function getFunctionConstructor(): typeof Function {
try {
return new Function('return (function(){}).constructor')();
} catch (err) {
console.warn(err);
if (err instanceof SyntaxError) {
throw Error('Bad template syntax');
} else {
throw err;
}
}
}
// Modified from https://github.com/anpigon/obsidian-book-search-plugin
// Licensed under the MIT license. Copyright (c) 2020 Jake Runzer
export function executeInlineScriptsTemplates(media: MediaTypeModel, text: string) {
const commandRegex = /<%(?:=)(.+)%>/g;
const ctor = getFunctionConstructor();
const matchedList = [...text.matchAll(commandRegex)];
return matchedList.reduce((result, [matched, script]) => {
try {
const outputs = new ctor(
['const [media] = arguments', `const output = ${script}`, 'if(typeof output === "string") return output', 'return JSON.stringify(output)'].join(';'),
)(media);
return result.replace(matched, outputs);
} catch (err) {
console.warn(err);
}
return result;
}, text);
}
// Copied from https://github.com/anpigon/obsidian-book-search-plugin
// Licensed under the MIT license. Copyright (c) 2020 Jake Runzer
export async function useTemplaterPluginInFile(app: App, file: TFile) {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const templater = (app as any).plugins.plugins['templater-obsidian'];
if (templater && !templater?.settings['trigger_on_file_creation']) {
await templater.templater.overwrite_file_commands(file);
}
}