From 06946c73daca831a726ae47bc91103de3afbbbca Mon Sep 17 00:00:00 2001 From: Kelvin John Falk Szolnoky Date: Thu, 28 Dec 2023 11:54:29 +0100 Subject: [PATCH 1/9] fix: use file path instead of filename for finding templates --- src/settings/suggesters/FileSuggest.ts | 4 ++-- src/utils/MediaTypeManager.ts | 24 +++++++++++++++--------- 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/src/settings/suggesters/FileSuggest.ts b/src/settings/suggesters/FileSuggest.ts index 8da7802..49275ab 100644 --- a/src/settings/suggesters/FileSuggest.ts +++ b/src/settings/suggesters/FileSuggest.ts @@ -17,11 +17,11 @@ export class FileSuggest extends TextInputSuggest { } renderSuggestion(file: TFile, el: HTMLElement): void { - el.setText(file.name); + el.setText(file.path); } selectSuggestion(file: TFile): void { - this.inputEl.value = file.name; + this.inputEl.value = file.path; this.inputEl.trigger('input'); this.close(); } diff --git a/src/utils/MediaTypeManager.ts b/src/utils/MediaTypeManager.ts index d94c1ec..e72e539 100644 --- a/src/utils/MediaTypeManager.ts +++ b/src/utils/MediaTypeManager.ts @@ -69,22 +69,28 @@ export class MediaTypeManager { } async getTemplate(mediaTypeModel: MediaTypeModel, app: App): Promise { - const templateFileName = this.mediaTemplateMap.get(mediaTypeModel.getMediaType()); + const templateFilePath = this.mediaTemplateMap.get(mediaTypeModel.getMediaType()); - if (!templateFileName) { + if (!templateFilePath) { return ''; } - const templateFile: TFile = app.vault - .getFiles() - .filter((f: TFile) => f.name === templateFileName) - .first(); + let templateFile = app.vault.getAbstractFileByPath(templateFilePath); - if (!templateFile) { - return ''; + // WARNING: This was previously selected by filename, but that could lead to collisions and unwanted effects. + // This now falls back to the previous method if no file is found + if (!templateFile || templateFile instanceof TFolder) { + templateFile = app.vault + .getFiles() + .filter((f: TFile) => f.name === templateFilePath) + .first(); + + if (!templateFile) { + return ''; + } } - const template = await app.vault.cachedRead(templateFile); + const template = await app.vault.cachedRead(templateFile as TFile); // console.log(template); return replaceTags(template, mediaTypeModel); } From 89b5b0f16b9db50ba784be13b545697eb1645d50 Mon Sep 17 00:00:00 2001 From: Kelvin John Falk Szolnoky Date: Thu, 28 Dec 2023 17:37:54 +0100 Subject: [PATCH 2/9] feat: add setting to disable default front matter. support templater. --- src/main.ts | 87 +++++++++++++++++++++++++++++++++++----- src/settings/Settings.ts | 57 ++++++++++++++++---------- src/utils/Utils.ts | 44 ++++++++++++++++++++ 3 files changed, 156 insertions(+), 32 deletions(-) diff --git a/src/main.ts b/src/main.ts index 6f85109..8aa54af 100644 --- a/src/main.ts +++ b/src/main.ts @@ -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 { - 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 { + async createNote(fileName: string, fileContent: string, options: CreateNoteOptions): Promise { // 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; } /** diff --git a/src/settings/Settings.ts b/src/settings/Settings.ts index 80f473e..7063308 100644 --- a/src/settings/Settings.ts +++ b/src/settings/Settings.ts @@ -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 = `

Allow you to remap the metadata fields of newly created media db entries.

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.

`; - 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 } diff --git a/src/utils/Utils.ts b/src/utils/Utils.ts index 4aebac1..3b7aa17 100644 --- a/src/utils/Utils.ts +++ b/src/utils/Utils.ts @@ -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); + } +} From 40cde2b09ab2a721726fd07623a122dfad583b9b Mon Sep 17 00:00:00 2001 From: Kelvin John Falk Szolnoky Date: Thu, 28 Dec 2023 17:49:33 +0100 Subject: [PATCH 3/9] fix: fallback to default front matter if no template is found --- src/main.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/main.ts b/src/main.ts index 8aa54af..a8f9187 100644 --- a/src/main.ts +++ b/src/main.ts @@ -310,10 +310,12 @@ export default class MediaDbPlugin extends Plugin { } async generateMediaDbNoteContents(mediaTypeModel: MediaTypeModel, options: CreateNoteOptions): Promise { - if (this.settings.useDefaultFrontMatter) { + let template = await this.mediaTypeManager.getTemplate(mediaTypeModel, this.app); + + if (this.settings.useDefaultFrontMatter || !template) { let fileMetadata = this.modelPropertyMapper.convertObject(mediaTypeModel.toMetaDataObject()); let fileContent = ''; - const template = options.attachTemplate ? await this.mediaTypeManager.getTemplate(mediaTypeModel, this.app) : ''; + template = options.attachTemplate ? template : ''; ({ fileMetadata, fileContent } = await this.attachFile(fileMetadata, fileContent, options.attachFile)); ({ fileMetadata, fileContent } = await this.attachTemplate(fileMetadata, fileContent, template)); @@ -321,7 +323,6 @@ export default class MediaDbPlugin extends Plugin { 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) { From d499071d238865df51c598a7942e32bf59f18f9b Mon Sep 17 00:00:00 2001 From: Kelvin John Falk Szolnoky Date: Mon, 22 Jan 2024 22:38:04 +0100 Subject: [PATCH 4/9] fix: add regex to find front matter --- src/main.ts | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/main.ts b/src/main.ts index a8f9187..94d4272 100644 --- a/src/main.ts +++ b/src/main.ts @@ -323,14 +323,16 @@ export default class MediaDbPlugin extends Plugin { fileContent = `---\n${this.settings.useCustomYamlStringifier ? YAMLConverter.toYaml(fileMetadata) : stringifyYaml(fileMetadata)}---\n` + fileContent; return fileContent; } else { - const parts = template.split('---'); + const frontMatterRegex = /^---*\n([\s\S]*?)\n---\h*/; - if (parts.length < 3) { + const match = template.match(frontMatterRegex); + + if (!match || match.length !== 2) { throw new Error('Cannot find YAML front matter for template.'); } - let frontMatter = parseYaml(parts[1]); - let fileContent: string = parts[2]; + let frontMatter = parseYaml(match[1]); + let fileContent: string = template.replace(frontMatterRegex, ''); // Updating a previous file if (options.attachFile) { From f4fcc3df88438fde44d78e2ea9360c0cfbd50a77 Mon Sep 17 00:00:00 2001 From: Kelvin John Falk Szolnoky Date: Mon, 22 Jan 2024 22:47:22 +0100 Subject: [PATCH 5/9] refactor: abstract front matter generating functions --- src/main.ts | 126 ++++++++++++++++++++++++++++------------------------ 1 file changed, 67 insertions(+), 59 deletions(-) diff --git a/src/main.ts b/src/main.ts index 94d4272..bf4fbc0 100644 --- a/src/main.ts +++ b/src/main.ts @@ -313,69 +313,77 @@ export default class MediaDbPlugin extends Plugin { let template = await this.mediaTypeManager.getTemplate(mediaTypeModel, this.app); if (this.settings.useDefaultFrontMatter || !template) { - let fileMetadata = this.modelPropertyMapper.convertObject(mediaTypeModel.toMetaDataObject()); - let fileContent = ''; - template = options.attachTemplate ? 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; + return this.generateContentWithDefaultFrontMatter(mediaTypeModel, options, template); } else { - const frontMatterRegex = /^---*\n([\s\S]*?)\n---\h*/; - - const match = template.match(frontMatterRegex); - - if (!match || match.length !== 2) { - throw new Error('Cannot find YAML front matter for template.'); - } - - let frontMatter = parseYaml(match[1]); - let fileContent: string = template.replace(frontMatterRegex, ''); - - // 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; + return this.generateContentWithCustomFrontMatter(mediaTypeModel, options, template); } } + async generateContentWithDefaultFrontMatter(mediaTypeModel: MediaTypeModel, options: CreateNoteOptions, template?: string): Promise { + let fileMetadata = this.modelPropertyMapper.convertObject(mediaTypeModel.toMetaDataObject()); + let fileContent = ''; + template = options.attachTemplate ? 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; + } + + async generateContentWithCustomFrontMatter(mediaTypeModel: MediaTypeModel, options: CreateNoteOptions, template: string): Promise { + const frontMatterRegex = /^---*\n([\s\S]*?)\n---\h*/; + + const match = template.match(frontMatterRegex); + + if (!match || match.length !== 2) { + throw new Error('Cannot find YAML front matter for template.'); + } + + let frontMatter = parseYaml(match[1]); + let fileContent: string = template.replace(frontMatterRegex, ''); + + // 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 }> { if (!fileToAttach) { return { fileMetadata: fileMetadata, fileContent: fileContent }; From 3369a4c6cc30cdd72b5afe8f251506eb5f58a023 Mon Sep 17 00:00:00 2001 From: Kelvin John Falk Szolnoky Date: Tue, 23 Jan 2024 00:00:37 +0100 Subject: [PATCH 6/9] feat: rely on templater for code execution --- src/main.ts | 13 ++++++++----- src/utils/Utils.ts | 36 ++++-------------------------------- 2 files changed, 12 insertions(+), 37 deletions(-) diff --git a/src/main.ts b/src/main.ts index bf4fbc0..cc1ba26 100644 --- a/src/main.ts +++ b/src/main.ts @@ -8,7 +8,7 @@ import { markdownTable, replaceIllegalFileNameCharactersInString, unCamelCase, - executeInlineScriptsTemplates, + hasTemplaterPlugin, useTemplaterPluginInFile, } from './utils/Utils'; import { OMDbAPI } from './api/apis/OMDbAPI'; @@ -376,10 +376,13 @@ export default class MediaDbPlugin extends Plugin { frontMatter.dataSource = mediaTypeModel.dataSource; } - // Only support stringifyYaml for templater plugin - fileContent = `---\n${stringifyYaml(frontMatter)}---\n${fileContent}`; - - fileContent = executeInlineScriptsTemplates(mediaTypeModel, fileContent); + if (hasTemplaterPlugin(this.app)) { + // Only support stringifyYaml for templater plugin + // Include the media variable in all templater commands by using a top level JavaScript execution command. + fileContent = `---\n<%* const media = ${JSON.stringify(mediaTypeModel)} %>\n${stringifyYaml(frontMatter)}---\n${fileContent}`; + } else { + fileContent = `---\n${this.settings.useCustomYamlStringifier ? YAMLConverter.toYaml(frontMatter) : stringifyYaml(frontMatter)}---\n` + fileContent; + } return fileContent; } diff --git a/src/utils/Utils.ts b/src/utils/Utils.ts index 3b7aa17..7cc95fc 100644 --- a/src/utils/Utils.ts +++ b/src/utils/Utils.ts @@ -1,5 +1,5 @@ import { MediaTypeModel } from '../models/MediaTypeModel'; -import { TFile, TFolder } from 'obsidian'; +import { TFile, TFolder, App } from 'obsidian'; export const pluginName: string = 'obsidian-media-db-plugin'; export const contactEmail: string = 'm.projects.code@gmail.com'; @@ -203,38 +203,10 @@ 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; - } - } -} +export function hasTemplaterPlugin(app: App) { + const templater = app.plugins.plugins['templater-obsidian']; -// 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); + return !!templater; } // Copied from https://github.com/anpigon/obsidian-book-search-plugin From 65540b516928d38e4e1d430be8db58fe99737b39 Mon Sep 17 00:00:00 2001 From: Kelvin John Falk Szolnoky Date: Wed, 24 Jan 2024 21:49:14 +0100 Subject: [PATCH 7/9] feat: restrict templater integration behind a setting --- src/main.ts | 6 ++++-- src/settings/Settings.ts | 14 ++++++++++++++ 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/src/main.ts b/src/main.ts index cc1ba26..899495b 100644 --- a/src/main.ts +++ b/src/main.ts @@ -297,7 +297,9 @@ export default class MediaDbPlugin extends Plugin { const targetFile = await this.createNote(this.mediaTypeManager.getFileName(mediaTypeModel), fileContent, options); - await useTemplaterPluginInFile(this.app, targetFile); + if (this.settings.enableTemplaterIntegration) { + await useTemplaterPluginInFile(this.app, targetFile); + } } catch (e) { console.warn(e); new Notice(e.toString()); @@ -376,7 +378,7 @@ export default class MediaDbPlugin extends Plugin { frontMatter.dataSource = mediaTypeModel.dataSource; } - if (hasTemplaterPlugin(this.app)) { + if (this.settings.enableTemplaterIntegration && hasTemplaterPlugin(this.app)) { // Only support stringifyYaml for templater plugin // Include the media variable in all templater commands by using a top level JavaScript execution command. fileContent = `---\n<%* const media = ${JSON.stringify(mediaTypeModel)} %>\n${stringifyYaml(frontMatter)}---\n${fileContent}`; diff --git a/src/settings/Settings.ts b/src/settings/Settings.ts index 7063308..c65078d 100644 --- a/src/settings/Settings.ts +++ b/src/settings/Settings.ts @@ -17,6 +17,7 @@ export interface MediaDbPluginSettings { customDateFormat: string; openNoteInNewTab: boolean; useDefaultFrontMatter: boolean; + enableTemplaterIntegration: boolean; movieTemplate: string; seriesTemplate: string; @@ -65,6 +66,7 @@ const DEFAULT_SETTINGS: MediaDbPluginSettings = { customDateFormat: 'L', openNoteInNewTab: true, useDefaultFrontMatter: true, + enableTemplaterIntegration: false, movieTemplate: '', seriesTemplate: '', @@ -232,6 +234,18 @@ export class MediaDbSettingTab extends PluginSettingTab { }); }); + new Setting(containerEl) + .setName('Enable Templater integration') + .setDesc( + 'Enable integration with the templater plugin, this also needs templater to be installed. Warning: Templater allows you to execute arbitrary JavaScript code and system commands.', + ) + .addToggle(cb => { + cb.setValue(this.plugin.settings.enableTemplaterIntegration).onChange(data => { + this.plugin.settings.enableTemplaterIntegration = data; + this.plugin.saveSettings(); + }); + }); + containerEl.createEl('h3', { text: 'New File Location' }); // region new file location new Setting(containerEl) From 0c9d7c54c203923206fbbe2d2a7000b3b9d2be3e Mon Sep 17 00:00:00 2001 From: Kelvin John Falk Szolnoky Date: Wed, 24 Jan 2024 22:35:25 +0100 Subject: [PATCH 8/9] feat: add support for templater when using default front matter --- src/main.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/main.ts b/src/main.ts index 899495b..fc7ee25 100644 --- a/src/main.ts +++ b/src/main.ts @@ -329,7 +329,14 @@ export default class MediaDbPlugin extends Plugin { ({ 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; + if (this.settings.enableTemplaterIntegration && hasTemplaterPlugin(this.app)) { + // Only support stringifyYaml for templater plugin + // Include the media variable in all templater commands by using a top level JavaScript execution command. + fileContent = `---\n<%* const media = ${JSON.stringify(mediaTypeModel)} %>\n${stringifyYaml(fileMetadata)}---\n${fileContent}`; + } else { + fileContent = `---\n${this.settings.useCustomYamlStringifier ? YAMLConverter.toYaml(fileMetadata) : stringifyYaml(fileMetadata)}---\n` + fileContent; + } + return fileContent; } From 8a9448b1415bb2101cc1370963dab10551c09e64 Mon Sep 17 00:00:00 2001 From: Kelvin John Falk Szolnoky Date: Wed, 24 Jan 2024 23:16:40 +0100 Subject: [PATCH 9/9] fix: app missing plugins type --- src/utils/Utils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils/Utils.ts b/src/utils/Utils.ts index 7cc95fc..ac01139 100644 --- a/src/utils/Utils.ts +++ b/src/utils/Utils.ts @@ -204,7 +204,7 @@ export function unCamelCase(str: string): string { } export function hasTemplaterPlugin(app: App) { - const templater = app.plugins.plugins['templater-obsidian']; + const templater = (app as any).plugins.plugins['templater-obsidian']; return !!templater; }