From 78ee146b71551c6e9f5cbe9ceed0b23a7eb58e79 Mon Sep 17 00:00:00 2001 From: mProjectsCode Date: Tue, 7 Jun 2022 10:38:51 +0200 Subject: [PATCH] Meta data field customization #19 --- src/api/apis/SteamAPI.ts | 5 +- src/main.ts | 16 ++- src/models/MediaTypeModel.ts | 4 +- src/models/WikiModel.ts | 8 ++ src/settings/ModelPropertyConversionRule.ts | 27 +++++ src/settings/ModelPropertyMapper.ts | 109 ++++++++++++++++++++ src/settings/Settings.ts | 85 ++++++++++++++- src/utils/Utils.ts | 4 + 8 files changed, 247 insertions(+), 11 deletions(-) create mode 100644 src/settings/ModelPropertyConversionRule.ts create mode 100644 src/settings/ModelPropertyMapper.ts diff --git a/src/api/apis/SteamAPI.ts b/src/api/apis/SteamAPI.ts index c523609..ef8f21d 100644 --- a/src/api/apis/SteamAPI.ts +++ b/src/api/apis/SteamAPI.ts @@ -81,7 +81,10 @@ export class SteamAPI extends APIModel { let result; for (const [key, value] of Object.entries(await fetchData.json)) { - if (key == id) { + // console.log(typeof key, key) + // console.log(typeof id, id) + // after some testing I found out that id is somehow a number despite that it's defined as string... + if (key === String(id)) { result = value.data; } } diff --git a/src/main.ts b/src/main.ts index b72add6..4c427ce 100644 --- a/src/main.ts +++ b/src/main.ts @@ -12,11 +12,14 @@ import {WikipediaAPI} from './api/apis/WikipediaAPI'; import {MusicBrainzAPI} from './api/apis/MusicBrainzAPI'; import {MediaTypeManager} from './utils/MediaTypeManager'; import {SteamAPI} from './api/apis/SteamAPI'; +import {ModelPropertyMapper} from './settings/ModelPropertyMapper'; +import {YAMLConverter} from './utils/YAMLConverter'; export default class MediaDbPlugin extends Plugin { settings: MediaDbPluginSettings; apiManager: APIManager; mediaTypeManager: MediaTypeManager; + modelPropertyMapper: ModelPropertyMapper; async onload() { await this.loadSettings(); @@ -68,6 +71,7 @@ export default class MediaDbPlugin extends Plugin { // this.apiManager.registerAPI(new LocGovAPI(this)); // TODO: parse data this.mediaTypeManager = new MediaTypeManager(this.settings); + this.modelPropertyMapper = new ModelPropertyMapper(this.settings); } async createMediaDbNote(modal: () => Promise): Promise { @@ -87,7 +91,7 @@ export default class MediaDbPlugin extends Plugin { console.log('MDB | Creating new note...'); // console.log(mediaTypeModel); - let fileContent = `---\n${mediaTypeModel.toMetaData()}---\n`; + let fileContent = `---\n${YAMLConverter.toYaml(this.modelPropertyMapper.convertObject(mediaTypeModel.toMetaDataObject()))}---\n`; if (this.settings.templates) { fileContent += await this.mediaTypeManager.getContent(mediaTypeModel, this.app); @@ -144,13 +148,17 @@ export default class MediaDbPlugin extends Plugin { throw new Error('MDB | there is no active note'); } - let metadata: FrontMatterCache = this.app.metadataCache.getFileCache(activeFile).frontmatter; + let metadata: any = this.app.metadataCache.getFileCache(activeFile).frontmatter; + delete metadata.position; // remove unnecessary data from the FrontMatterCache + metadata = this.modelPropertyMapper.convertObjectBack(metadata); + + console.log(metadata) if (!metadata?.type || !metadata?.dataSource || !metadata?.id) { throw new Error('MDB | active note is not a Media DB entry or is missing metadata'); } - delete metadata.position; // remove unnecessary data from the FrontMatterCache + let oldMediaTypeModel = this.mediaTypeManager.createMediaTypeModelFromMediaType(metadata, metadata.type); let newMediaTypeModel = await this.apiManager.queryDetailedInfoById(metadata.id, metadata.dataSource); @@ -171,6 +179,8 @@ export default class MediaDbPlugin extends Plugin { async saveSettings() { this.mediaTypeManager.updateTemplates(this.settings); + this.modelPropertyMapper.updateConversionRules(this.settings); + await this.saveData(this.settings); } } diff --git a/src/models/MediaTypeModel.ts b/src/models/MediaTypeModel.ts index 9c52813..d8fbd4a 100644 --- a/src/models/MediaTypeModel.ts +++ b/src/models/MediaTypeModel.ts @@ -17,8 +17,8 @@ export abstract class MediaTypeModel { abstract getTags(): string[]; - toMetaData(): string { - return YAMLConverter.toYaml({...this.getWithOutUserData(), ...this.userData, tags: '#' + this.getTags().join('/')}); + toMetaDataObject(): object { + return {...this.getWithOutUserData(), ...this.userData, tags: '#' + this.getTags().join('/')}; } getWithOutUserData(): object { diff --git a/src/models/WikiModel.ts b/src/models/WikiModel.ts index 6c067e9..64b2ab5 100644 --- a/src/models/WikiModel.ts +++ b/src/models/WikiModel.ts @@ -16,6 +16,7 @@ export class WikiModel extends MediaTypeModel { wikiUrl: string; lastUpdated: string; length: number; + article: string; userData: {}; @@ -35,4 +36,11 @@ export class WikiModel extends MediaTypeModel { return MediaType.Wiki; } + override getWithOutUserData(): object { + const copy = JSON.parse(JSON.stringify(this)); + delete copy.userData; + delete copy.article; + return copy; + } + } diff --git a/src/settings/ModelPropertyConversionRule.ts b/src/settings/ModelPropertyConversionRule.ts new file mode 100644 index 0000000..d749918 --- /dev/null +++ b/src/settings/ModelPropertyConversionRule.ts @@ -0,0 +1,27 @@ +import {containsOnlyLettersAndUnderscores} from '../utils/Utils'; + +export class ModelPropertyConversionRule { + property: string; + newProperty: string; + + constructor(conversionRule: string) { + const conversionRuleParts = conversionRule.split('->'); + if (conversionRuleParts.length !== 2) { + throw Error(`Conversion rule "${conversionRule}" may only have exactly one "->"`); + } + + let property = conversionRuleParts[0].trim(); + let newProperty = conversionRuleParts[1].trim(); + + if (!property || !containsOnlyLettersAndUnderscores(property)) { + throw Error(`Error in conversion rule "${conversionRule}": property may not be empty and only contain letters and underscores.`); + } + + if (!newProperty || !containsOnlyLettersAndUnderscores(newProperty)) { + throw Error(`Error in conversion rule "${conversionRule}": new property may not be empty and only contain letters and underscores.`); + } + + this.property = property; + this.newProperty = newProperty; + } +} diff --git a/src/settings/ModelPropertyMapper.ts b/src/settings/ModelPropertyMapper.ts new file mode 100644 index 0000000..a97ed44 --- /dev/null +++ b/src/settings/ModelPropertyMapper.ts @@ -0,0 +1,109 @@ +import {MediaType} from '../utils/MediaType'; +import {MediaDbPluginSettings} from './Settings'; +import {ModelPropertyConversionRule} from './ModelPropertyConversionRule'; + +export class ModelPropertyMapper { + conversionRulesMap: Map; + + constructor(settings: MediaDbPluginSettings) { + this.updateConversionRules(settings); + } + + updateConversionRules(settings: MediaDbPluginSettings) { + this.conversionRulesMap = new Map(); + this.conversionRulesMap.set(MediaType.Movie, settings.moviePropertyConversionRules); + this.conversionRulesMap.set(MediaType.Series, settings.seriesPropertyConversionRules); + this.conversionRulesMap.set(MediaType.Game, settings.gamePropertyConversionRules); + this.conversionRulesMap.set(MediaType.Wiki, settings.wikiPropertyConversionRules); + this.conversionRulesMap.set(MediaType.MusicRelease, settings.musicReleasePropertyConversionRules); + } + + convertObject(obj: object): object { + if (!obj.hasOwnProperty('type')) { + return obj; + } + + // @ts-ignore + const conversionRulesString: string = this.conversionRulesMap.get(obj['type']); + if (!conversionRulesString) { + return obj; + } + + const conversionRules: ModelPropertyConversionRule[] = [] + for (const conversionRuleString of conversionRulesString.split('\n')) { + if (conversionRuleString) { + conversionRules.push(new ModelPropertyConversionRule(conversionRuleString)); + } + } + + const newObj: object = {}; + + + for (const [key, value] of Object.entries(obj)) { + if (key === 'type') { + // @ts-ignore + newObj[key] = value; + continue; + } + + let hasConversionRule = false; + for (const conversionRule of conversionRules) { + if (conversionRule.property === key) { + hasConversionRule = true; + // @ts-ignore + newObj[conversionRule.newProperty] = value; + } + } + if (!hasConversionRule) { + // @ts-ignore + newObj[key] = value; + } + } + + return newObj; + } + + convertObjectBack(obj: object): object { + if (!obj.hasOwnProperty('type')) { + return obj; + } + + // @ts-ignore + const conversionRulesString: string = this.conversionRulesMap.get(obj['type']); + if (!conversionRulesString) { + return obj; + } + + const conversionRules: ModelPropertyConversionRule[] = [] + for (const conversionRuleString of conversionRulesString.split('\n')) { + if (conversionRuleString) { + conversionRules.push(new ModelPropertyConversionRule(conversionRuleString)); + } + } + + const originalObj: object = {}; + + for (const [key, value] of Object.entries(obj)) { + if (key === 'type') { + // @ts-ignore + originalObj[key] = value; + continue; + } + + let hasConversionRule = false; + for (const conversionRule of conversionRules) { + if (conversionRule.newProperty === key) { + hasConversionRule = true; + // @ts-ignore + originalObj[conversionRule.property] = value; + } + } + if (!hasConversionRule) { + // @ts-ignore + originalObj[key] = value; + } + } + + return originalObj; + } +} diff --git a/src/settings/Settings.ts b/src/settings/Settings.ts index 4fb9e95..f526dbe 100644 --- a/src/settings/Settings.ts +++ b/src/settings/Settings.ts @@ -22,6 +22,12 @@ export interface MediaDbPluginSettings { wikiFileNameTemplate: string, musicReleaseFileNameTemplate: string, + moviePropertyConversionRules: string, + seriesPropertyConversionRules: string, + gamePropertyConversionRules: string, + wikiPropertyConversionRules: string, + musicReleasePropertyConversionRules: string, + templates: boolean, } @@ -42,6 +48,12 @@ export const DEFAULT_SETTINGS: MediaDbPluginSettings = { wikiFileNameTemplate: '{{ title }}', musicReleaseFileNameTemplate: '{{ title }} (by {{ ENUM:artists }} - {{ year }})', + moviePropertyConversionRules: '', + seriesPropertyConversionRules: '', + gamePropertyConversionRules: '', + wikiPropertyConversionRules: '', + musicReleasePropertyConversionRules: '', + templates: true, }; @@ -181,7 +193,7 @@ export class MediaDbSettingTab extends PluginSettingTab { new Setting(containerEl) .setName('Movie file name template') .setDesc('Template for the file name used when creating a new note for a movie.') - .addSearch(cb => { + .addText(cb => { cb.setPlaceholder(`Example: ${DEFAULT_SETTINGS.movieFileNameTemplate}`) .setValue(this.plugin.settings.movieFileNameTemplate) .onChange(data => { @@ -193,7 +205,7 @@ export class MediaDbSettingTab extends PluginSettingTab { new Setting(containerEl) .setName('Series file name template') .setDesc('Template for the file name used when creating a new note for a series.') - .addSearch(cb => { + .addText(cb => { cb.setPlaceholder(`Example: ${DEFAULT_SETTINGS.seriesFileNameTemplate}`) .setValue(this.plugin.settings.seriesFileNameTemplate) .onChange(data => { @@ -205,7 +217,7 @@ export class MediaDbSettingTab extends PluginSettingTab { new Setting(containerEl) .setName('Game file name template') .setDesc('Template for the file name used when creating a new note for a game.') - .addSearch(cb => { + .addText(cb => { cb.setPlaceholder(`Example: ${DEFAULT_SETTINGS.gameFileNameTemplate}`) .setValue(this.plugin.settings.gameFileNameTemplate) .onChange(data => { @@ -217,7 +229,7 @@ export class MediaDbSettingTab extends PluginSettingTab { new Setting(containerEl) .setName('Wiki file name template') .setDesc('Template for the file name used when creating a new note for a wiki entry.') - .addSearch(cb => { + .addText(cb => { cb.setPlaceholder(`Example: ${DEFAULT_SETTINGS.wikiFileNameTemplate}`) .setValue(this.plugin.settings.wikiFileNameTemplate) .onChange(data => { @@ -229,7 +241,7 @@ export class MediaDbSettingTab extends PluginSettingTab { new Setting(containerEl) .setName('Music Release file name template') .setDesc('Template for the file name used when creating a new note for a music release.') - .addSearch(cb => { + .addText(cb => { cb.setPlaceholder(`Example: ${DEFAULT_SETTINGS.musicReleaseFileNameTemplate}`) .setValue(this.plugin.settings.musicReleaseFileNameTemplate) .onChange(data => { @@ -239,6 +251,69 @@ export class MediaDbSettingTab extends PluginSettingTab { }); // endregion + containerEl.createEl('h3', {text: 'Property Mappings'}); + // region Property Mappings + new Setting(containerEl) + .setName('Movie model property mappings') + .setDesc('Mappings for the property names of a movie.') + .addTextArea(cb => { + cb.setPlaceholder(`Example: \ntitle -> name\nyear -> releaseYear`) + .setValue(this.plugin.settings.moviePropertyConversionRules) + .onChange(data => { + this.plugin.settings.moviePropertyConversionRules = data; + this.plugin.saveSettings(); + }); + }); + + new Setting(containerEl) + .setName('Series model property mappings') + .setDesc('Mappings for the property names of a series.') + .addTextArea(cb => { + cb.setPlaceholder(`Example: \ntitle -> name\nyear -> releaseYear`) + .setValue(this.plugin.settings.seriesPropertyConversionRules) + .onChange(data => { + this.plugin.settings.seriesPropertyConversionRules = data; + this.plugin.saveSettings(); + }); + }); + + new Setting(containerEl) + .setName('Game model property mappings') + .setDesc('Mappings for the property names of a game.') + .addTextArea(cb => { + cb.setPlaceholder(`Example: \ntitle -> name\nyear -> releaseYear`) + .setValue(this.plugin.settings.gamePropertyConversionRules) + .onChange(data => { + this.plugin.settings.gamePropertyConversionRules = data; + this.plugin.saveSettings(); + }); + }); + + new Setting(containerEl) + .setName('Wiki model property mappings') + .setDesc('Mappings for the property names of a wiki entry.') + .addTextArea(cb => { + cb.setPlaceholder(`Example: \ntitle -> name\nyear -> releaseYear`) + .setValue(this.plugin.settings.wikiPropertyConversionRules) + .onChange(data => { + this.plugin.settings.wikiPropertyConversionRules = data; + this.plugin.saveSettings(); + }); + }); + + new Setting(containerEl) + .setName('Music Release model property mappings') + .setDesc('Mappings for the property names of a music release.') + .addTextArea(cb => { + cb.setPlaceholder(`Example: \ntitle -> name\nyear -> releaseYear`) + .setValue(this.plugin.settings.musicReleasePropertyConversionRules) + .onChange(data => { + this.plugin.settings.musicReleasePropertyConversionRules = data; + this.plugin.saveSettings(); + }); + }); + // endregion + } } diff --git a/src/utils/Utils.ts b/src/utils/Utils.ts index 25fb06e..24c74cc 100644 --- a/src/utils/Utils.ts +++ b/src/utils/Utils.ts @@ -17,6 +17,10 @@ export function debugLog(o: any): void { } } +export function containsOnlyLettersAndUnderscores(str: string): boolean { + return /^[a-zA-Z_]+$/.test(str); +} + export function replaceIllegalFileNameCharactersInString(string: string): string { return string.replace(/[\\,#%&{}/*<>$"@.?]*/g, '').replace(/:+/g, ' -'); }