Skip to content

Commit 89b5b0f

Browse files
committed
feat: add setting to disable default front matter. support templater.
1 parent 06946c7 commit 89b5b0f

File tree

3 files changed

+157
-33
lines changed

3 files changed

+157
-33
lines changed

src/main.ts

Lines changed: 76 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,15 @@ import { MarkdownView, Notice, parseYaml, Plugin, stringifyYaml, TFile, TFolder
22
import { getDefaultSettings, MediaDbPluginSettings, MediaDbSettingTab } from './settings/Settings';
33
import { APIManager } from './api/APIManager';
44
import { MediaTypeModel } from './models/MediaTypeModel';
5-
import { CreateNoteOptions, dateTimeToString, markdownTable, replaceIllegalFileNameCharactersInString, unCamelCase } from './utils/Utils';
5+
import {
6+
CreateNoteOptions,
7+
dateTimeToString,
8+
markdownTable,
9+
replaceIllegalFileNameCharactersInString,
10+
unCamelCase,
11+
executeInlineScriptsTemplates,
12+
useTemplaterPluginInFile,
13+
} from './utils/Utils';
614
import { OMDbAPI } from './api/apis/OMDbAPI';
715
import { MALAPI } from './api/apis/MALAPI';
816
import { MALAPIManga } from './api/apis/MALAPIManga';
@@ -63,7 +71,8 @@ export default class MediaDbPlugin extends Plugin {
6371
this.app.workspace.on('file-menu', (menu, file) => {
6472
if (file instanceof TFolder) {
6573
menu.addItem(item => {
66-
item.setTitle('Import folder as Media DB entries')
74+
item
75+
.setTitle('Import folder as Media DB entries')
6776
.setIcon('database')
6877
.onClick(() => this.createEntriesFromFolder(file));
6978
});
@@ -286,7 +295,9 @@ export default class MediaDbPlugin extends Plugin {
286295
options.folder = await this.mediaTypeManager.getFolder(mediaTypeModel, this.app);
287296
}
288297

289-
await this.createNote(this.mediaTypeManager.getFileName(mediaTypeModel), fileContent, options);
298+
const targetFile = await this.createNote(this.mediaTypeManager.getFileName(mediaTypeModel), fileContent, options);
299+
300+
await useTemplaterPluginInFile(this.app, targetFile);
290301
} catch (e) {
291302
console.warn(e);
292303
new Notice(e.toString());
@@ -299,15 +310,67 @@ export default class MediaDbPlugin extends Plugin {
299310
}
300311

301312
async generateMediaDbNoteContents(mediaTypeModel: MediaTypeModel, options: CreateNoteOptions): Promise<string> {
302-
let fileMetadata = this.modelPropertyMapper.convertObject(mediaTypeModel.toMetaDataObject());
303-
let fileContent = '';
304-
const template = options.attachTemplate ? await this.mediaTypeManager.getTemplate(mediaTypeModel, this.app) : '';
313+
if (this.settings.useDefaultFrontMatter) {
314+
let fileMetadata = this.modelPropertyMapper.convertObject(mediaTypeModel.toMetaDataObject());
315+
let fileContent = '';
316+
const template = options.attachTemplate ? await this.mediaTypeManager.getTemplate(mediaTypeModel, this.app) : '';
317+
318+
({ fileMetadata, fileContent } = await this.attachFile(fileMetadata, fileContent, options.attachFile));
319+
({ fileMetadata, fileContent } = await this.attachTemplate(fileMetadata, fileContent, template));
320+
321+
fileContent = `---\n${this.settings.useCustomYamlStringifier ? YAMLConverter.toYaml(fileMetadata) : stringifyYaml(fileMetadata)}---\n` + fileContent;
322+
return fileContent;
323+
} else {
324+
let template = await this.mediaTypeManager.getTemplate(mediaTypeModel, this.app);
325+
const parts = template.split('---');
326+
327+
if (parts.length < 3) {
328+
throw new Error('Cannot find YAML front matter for template.');
329+
}
330+
331+
let frontMatter = parseYaml(parts[1]);
332+
let fileContent: string = parts[2];
333+
334+
// Updating a previous file
335+
if (options.attachFile) {
336+
const previousMetadata = this.app.metadataCache.getFileCache(options.attachFile).frontmatter;
337+
338+
// Use contents (below front matter) from previous file
339+
fileContent = await this.app.vault.read(options.attachFile);
340+
const regExp = new RegExp(this.frontMatterRexExpPattern);
341+
fileContent = fileContent.replace(regExp, '');
342+
fileContent = fileContent.startsWith('\n') ? fileContent.substring(1) : fileContent;
343+
344+
// Update updated front matter with entries from the old front matter, if it isn't defined in the new front matter
345+
Object.keys(previousMetadata).forEach(key => {
346+
const value = previousMetadata[key];
347+
348+
if (!frontMatter[key] && value) {
349+
frontMatter[key] = value;
350+
}
351+
});
352+
}
353+
354+
// Ensure that id, type, and dataSource are defined
355+
if (!frontMatter.id) {
356+
frontMatter.id = mediaTypeModel.id;
357+
}
305358

306-
({ fileMetadata, fileContent } = await this.attachFile(fileMetadata, fileContent, options.attachFile));
307-
({ fileMetadata, fileContent } = await this.attachTemplate(fileMetadata, fileContent, template));
359+
if (!frontMatter.type) {
360+
frontMatter.type = mediaTypeModel.type;
361+
}
308362

309-
fileContent = `---\n${this.settings.useCustomYamlStringifier ? YAMLConverter.toYaml(fileMetadata) : stringifyYaml(fileMetadata)}---\n` + fileContent;
310-
return fileContent;
363+
if (!frontMatter.dataSource) {
364+
frontMatter.dataSource = mediaTypeModel.dataSource;
365+
}
366+
367+
// Only support stringifyYaml for templater plugin
368+
fileContent = `---\n${stringifyYaml(frontMatter)}---\n${fileContent}`;
369+
370+
fileContent = executeInlineScriptsTemplates(mediaTypeModel, fileContent);
371+
372+
return fileContent;
373+
}
311374
}
312375

313376
async attachFile(fileMetadata: any, fileContent: string, fileToAttach?: TFile): Promise<{ fileMetadata: any; fileContent: string }> {
@@ -386,7 +449,7 @@ export default class MediaDbPlugin extends Plugin {
386449
* @param fileContent
387450
* @param options
388451
*/
389-
async createNote(fileName: string, fileContent: string, options: CreateNoteOptions): Promise<void> {
452+
async createNote(fileName: string, fileContent: string, options: CreateNoteOptions): Promise<TFile> {
390453
// find and possibly create the folder set in settings or passed in folder
391454
const folder = options.folder ?? this.app.vault.getAbstractFileByPath('/');
392455

@@ -412,6 +475,8 @@ export default class MediaDbPlugin extends Plugin {
412475
}
413476
await activeLeaf.openFile(targetFile, { state: { mode: 'source' } });
414477
}
478+
479+
return targetFile;
415480
}
416481

417482
/**

src/settings/Settings.ts

Lines changed: 37 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ export interface MediaDbPluginSettings {
1616
templates: boolean;
1717
customDateFormat: string;
1818
openNoteInNewTab: boolean;
19+
useDefaultFrontMatter: boolean;
1920

2021
movieTemplate: string;
2122
seriesTemplate: string;
@@ -63,6 +64,7 @@ const DEFAULT_SETTINGS: MediaDbPluginSettings = {
6364
templates: true,
6465
customDateFormat: 'L',
6566
openNoteInNewTab: true,
67+
useDefaultFrontMatter: true,
6668

6769
movieTemplate: '',
6870
seriesTemplate: '',
@@ -218,6 +220,18 @@ export class MediaDbSettingTab extends PluginSettingTab {
218220
});
219221
});
220222

223+
new Setting(containerEl)
224+
.setName('Use default front matter')
225+
.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.')
226+
.addToggle(cb => {
227+
cb.setValue(this.plugin.settings.useDefaultFrontMatter).onChange(data => {
228+
this.plugin.settings.useDefaultFrontMatter = data;
229+
this.plugin.saveSettings();
230+
// Redraw settings to display/remove the property mappings
231+
this.display();
232+
});
233+
});
234+
221235
containerEl.createEl('h3', { text: 'New File Location' });
222236
// region new file location
223237
new Setting(containerEl)
@@ -531,11 +545,11 @@ export class MediaDbSettingTab extends PluginSettingTab {
531545
// endregion
532546

533547
// region Property Mappings
548+
if (this.plugin.settings.useDefaultFrontMatter) {
549+
containerEl.createEl('h3', { text: 'Property Mappings' });
534550

535-
containerEl.createEl('h3', { text: 'Property Mappings' });
536-
537-
const propertyMappingExplanation = containerEl.createEl('div');
538-
propertyMappingExplanation.innerHTML = `
551+
const propertyMappingExplanation = containerEl.createEl('div');
552+
propertyMappingExplanation.innerHTML = `
539553
<p>Allow you to remap the metadata fields of newly created media db entries.</p>
540554
<p>
541555
The different options are:
@@ -549,27 +563,28 @@ export class MediaDbSettingTab extends PluginSettingTab {
549563
Don't forget to save your changes using the save button for each individual category.
550564
</p>`;
551565

552-
new PropertyMappingModelsComponent({
553-
target: this.containerEl,
554-
props: {
555-
models: this.plugin.settings.propertyMappingModels.map(x => x.copy()),
556-
save: (model: PropertyMappingModel): void => {
557-
const propertyMappingModels: PropertyMappingModel[] = [];
558-
559-
for (const model2 of this.plugin.settings.propertyMappingModels) {
560-
if (model2.type === model.type) {
561-
propertyMappingModels.push(model);
562-
} else {
563-
propertyMappingModels.push(model2);
566+
new PropertyMappingModelsComponent({
567+
target: this.containerEl,
568+
props: {
569+
models: this.plugin.settings.propertyMappingModels.map(x => x.copy()),
570+
save: (model: PropertyMappingModel): void => {
571+
const propertyMappingModels: PropertyMappingModel[] = [];
572+
573+
for (const model2 of this.plugin.settings.propertyMappingModels) {
574+
if (model2.type === model.type) {
575+
propertyMappingModels.push(model);
576+
} else {
577+
propertyMappingModels.push(model2);
578+
}
564579
}
565-
}
566580

567-
this.plugin.settings.propertyMappingModels = propertyMappingModels;
568-
new Notice(`MDB: Property Mappings for ${model.type} saved successfully.`);
569-
this.plugin.saveSettings();
581+
this.plugin.settings.propertyMappingModels = propertyMappingModels;
582+
new Notice(`MDB: Property Mappings for ${model.type} saved successfully.`);
583+
this.plugin.saveSettings();
584+
},
570585
},
571-
},
572-
});
586+
});
587+
}
573588

574589
// endregion
575590
}

src/utils/Utils.ts

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,3 +202,47 @@ export function unCamelCase(str: string): string {
202202
})
203203
);
204204
}
205+
206+
// Copied from https://github.com/anpigon/obsidian-book-search-plugin
207+
// Licensed under the MIT license. Copyright (c) 2020 Jake Runzer
208+
export function getFunctionConstructor(): typeof Function {
209+
try {
210+
return new Function('return (function(){}).constructor')();
211+
} catch (err) {
212+
console.warn(err);
213+
if (err instanceof SyntaxError) {
214+
throw Error('Bad template syntax');
215+
} else {
216+
throw err;
217+
}
218+
}
219+
}
220+
221+
// Modified from https://github.com/anpigon/obsidian-book-search-plugin
222+
// Licensed under the MIT license. Copyright (c) 2020 Jake Runzer
223+
export function executeInlineScriptsTemplates(media: MediaTypeModel, text: string) {
224+
const commandRegex = /<%(?:=)(.+)%>/g;
225+
const ctor = getFunctionConstructor();
226+
const matchedList = [...text.matchAll(commandRegex)];
227+
return matchedList.reduce((result, [matched, script]) => {
228+
try {
229+
const outputs = new ctor(
230+
['const [media] = arguments', `const output = ${script}`, 'if(typeof output === "string") return output', 'return JSON.stringify(output)'].join(';'),
231+
)(media);
232+
return result.replace(matched, outputs);
233+
} catch (err) {
234+
console.warn(err);
235+
}
236+
return result;
237+
}, text);
238+
}
239+
240+
// Copied from https://github.com/anpigon/obsidian-book-search-plugin
241+
// Licensed under the MIT license. Copyright (c) 2020 Jake Runzer
242+
export async function useTemplaterPluginInFile(app: App, file: TFile) {
243+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
244+
const templater = (app as any).plugins.plugins['templater-obsidian'];
245+
if (templater && !templater?.settings['trigger_on_file_creation']) {
246+
await templater.templater.overwrite_file_commands(file);
247+
}
248+
}

0 commit comments

Comments
 (0)