diff --git a/src/api/apis/MALAPI.ts b/src/api/apis/MALAPI.ts index a728316..50566cc 100644 --- a/src/api/apis/MALAPI.ts +++ b/src/api/apis/MALAPI.ts @@ -8,6 +8,7 @@ import { MediaType } from '../../utils/MediaType'; export class MALAPI extends APIModel { plugin: MediaDbPlugin; typeMappings: Map; + apiDateFormat: string = 'YYYY-MM-DDTHH:mm:ssZ'; // ISO constructor(plugin: MediaDbPlugin) { super(); @@ -115,7 +116,7 @@ export class MALAPI extends APIModel { image: result.images?.jpg?.image_url ?? '', released: true, - premiere: new Date(result.aired?.from).toLocaleDateString() ?? 'unknown', + premiere: this.plugin.dateFormatter.format(result.aired?.from, this.apiDateFormat) ?? 'unknown', streamingServices: result.streaming?.map((x: any) => x.name) ?? [], userData: { @@ -146,7 +147,7 @@ export class MALAPI extends APIModel { image: result.images?.jpg?.image_url ?? '', released: true, - premiere: new Date(result.aired?.from).toLocaleDateString() ?? 'unknown', + premiere: this.plugin.dateFormatter.format(result.aired?.from, this.apiDateFormat) ?? 'unknown', streamingServices: result.streaming?.map((x: any) => x.name) ?? [], userData: { @@ -176,8 +177,8 @@ export class MALAPI extends APIModel { image: result.images?.jpg?.image_url ?? '', released: true, - airedFrom: new Date(result.aired?.from).toLocaleDateString() ?? 'unknown', - airedTo: new Date(result.aired?.to).toLocaleDateString() ?? 'unknown', + airedFrom: this.plugin.dateFormatter.format(result.aired?.from, this.apiDateFormat) ?? 'unknown', + airedTo: this.plugin.dateFormatter.format(result.aired?.to, this.apiDateFormat) ?? 'unknown', airing: result.airing, userData: { diff --git a/src/api/apis/OMDbAPI.ts b/src/api/apis/OMDbAPI.ts index 9876291..ad3fb45 100644 --- a/src/api/apis/OMDbAPI.ts +++ b/src/api/apis/OMDbAPI.ts @@ -9,6 +9,7 @@ import { MediaType } from '../../utils/MediaType'; export class OMDbAPI extends APIModel { plugin: MediaDbPlugin; typeMappings: Map; + apiDateFormat: string = 'DD MMM YYYY'; constructor(plugin: MediaDbPlugin) { super(); @@ -142,7 +143,7 @@ export class OMDbAPI extends APIModel { released: true, streamingServices: [], - premiere: new Date(result.Released).toLocaleDateString() ?? 'unknown', + premiere: this.plugin.dateFormatter.format(result.Released, this.apiDateFormat) ?? 'unknown', userData: { watched: false, @@ -173,7 +174,7 @@ export class OMDbAPI extends APIModel { released: true, streamingServices: [], airing: false, - airedFrom: new Date(result.Released).toLocaleDateString() ?? 'unknown', + airedFrom: this.plugin.dateFormatter.format(result.Released, this.apiDateFormat) ?? 'unknown', airedTo: 'unknown', userData: { @@ -199,7 +200,7 @@ export class OMDbAPI extends APIModel { image: result.Poster ?? '', released: true, - releaseDate: new Date(result.Released).toLocaleDateString() ?? 'unknown', + releaseDate: this.plugin.dateFormatter.format(result.Released, this.apiDateFormat) ?? 'unknown', userData: { played: false, diff --git a/src/api/apis/SteamAPI.ts b/src/api/apis/SteamAPI.ts index ae36d3a..fda9dcb 100644 --- a/src/api/apis/SteamAPI.ts +++ b/src/api/apis/SteamAPI.ts @@ -8,6 +8,7 @@ import { MediaType } from '../../utils/MediaType'; export class SteamAPI extends APIModel { plugin: MediaDbPlugin; typeMappings: Map; + apiDateFormat: string = 'DD MMM, YYYY'; constructor(plugin: MediaDbPlugin) { super(); @@ -109,7 +110,7 @@ export class SteamAPI extends APIModel { image: result.header_image ?? '', released: !result.release_date?.comming_soon, - releaseDate: new Date(result.release_date?.date).toLocaleDateString() ?? 'unknown', + releaseDate: this.plugin.dateFormatter.format(result.release_date?.date, this.apiDateFormat) ?? 'unknown', userData: { played: false, diff --git a/src/api/apis/WikipediaAPI.ts b/src/api/apis/WikipediaAPI.ts index 5193bb4..72571d8 100644 --- a/src/api/apis/WikipediaAPI.ts +++ b/src/api/apis/WikipediaAPI.ts @@ -6,6 +6,7 @@ import { MediaType } from '../../utils/MediaType'; export class WikipediaAPI extends APIModel { plugin: MediaDbPlugin; + apiDateFormat: string = 'YYYY-MM-DDTHH:mm:ssZ'; // ISO constructor(plugin: MediaDbPlugin) { super(); @@ -72,7 +73,7 @@ export class WikipediaAPI extends APIModel { id: result.pageid, wikiUrl: result.fullurl, - lastUpdated: new Date(result.touched).toLocaleDateString() ?? 'unknown', + lastUpdated: this.plugin.dateFormatter.format(result.touched, this.apiDateFormat), length: result.length, userData: {}, diff --git a/src/main.ts b/src/main.ts index 76abff4..a62e99c 100644 --- a/src/main.ts +++ b/src/main.ts @@ -15,6 +15,7 @@ import { YAMLConverter } from './utils/YAMLConverter'; import { MediaDbFolderImportModal } from './modals/MediaDbFolderImportModal'; import { PropertyMapping, PropertyMappingModel } from './settings/PropertyMapping'; import { ModalHelper, ModalResultCode, SearchModalOptions } from './utils/ModalHelper'; +import { DateFormatter } from './utils/DateFormatter'; export default class MediaDbPlugin extends Plugin { settings: MediaDbPluginSettings; @@ -22,6 +23,7 @@ export default class MediaDbPlugin extends Plugin { mediaTypeManager: MediaTypeManager; modelPropertyMapper: PropertyMapper; modalHelper: ModalHelper; + dateFormatter: DateFormatter; frontMatterRexExpPattern: string = '^(---)\\n[\\s\\S]*?\\n---'; @@ -39,6 +41,7 @@ export default class MediaDbPlugin extends Plugin { this.mediaTypeManager = new MediaTypeManager(); this.modelPropertyMapper = new PropertyMapper(this); this.modalHelper = new ModalHelper(this); + this.dateFormatter = new DateFormatter(); await this.loadSettings(); // register the settings tab @@ -46,6 +49,7 @@ export default class MediaDbPlugin extends Plugin { this.mediaTypeManager.updateTemplates(this.settings); this.mediaTypeManager.updateFolders(this.settings); + this.dateFormatter.setFormat(this.settings.customDateFormat); // add icon to the left ribbon const ribbonIconEl = this.addRibbonIcon('database', 'Add new Media DB entry', () => this.createEntryWithAdvancedSearchModal()); @@ -563,6 +567,7 @@ export default class MediaDbPlugin extends Plugin { async saveSettings(): Promise { this.mediaTypeManager.updateTemplates(this.settings); this.mediaTypeManager.updateFolders(this.settings); + this.dateFormatter.setFormat(this.settings.customDateFormat); await this.saveData(this.settings); } diff --git a/src/settings/Settings.ts b/src/settings/Settings.ts index 53ff9c5..9c4b43d 100644 --- a/src/settings/Settings.ts +++ b/src/settings/Settings.ts @@ -1,448 +1,468 @@ -import { App, Notice, PluginSettingTab, Setting } from 'obsidian'; - -import MediaDbPlugin from '../main'; -import { FolderSuggest } from './suggesters/FolderSuggest'; -import { FileSuggest } from './suggesters/FileSuggest'; -import PropertyMappingModelsComponent from './PropertyMappingModelsComponent.svelte'; -import { PropertyMapping, PropertyMappingModel, PropertyMappingOption } from './PropertyMapping'; -import { MEDIA_TYPES } from '../utils/MediaTypeManager'; -import { MediaTypeModel } from '../models/MediaTypeModel'; - -export interface MediaDbPluginSettings { - OMDbKey: string; - sfwFilter: boolean; - useCustomYamlStringifier: boolean; - templates: boolean; - - movieTemplate: string; - seriesTemplate: string; - gameTemplate: string; - wikiTemplate: string; - musicReleaseTemplate: string; - boardgameTemplate: string; - - movieFileNameTemplate: string; - seriesFileNameTemplate: string; - gameFileNameTemplate: string; - wikiFileNameTemplate: string; - musicReleaseFileNameTemplate: string; - boardgameFileNameTemplate: string; - - moviePropertyConversionRules: string; - seriesPropertyConversionRules: string; - gamePropertyConversionRules: string; - wikiPropertyConversionRules: string; - musicReleasePropertyConversionRules: string; - boardgamePropertyConversionRules: string; - - movieFolder: string; - seriesFolder: string; - gameFolder: string; - wikiFolder: string; - musicReleaseFolder: string; - boardgameFolder: string; - - propertyMappingModels: PropertyMappingModel[]; -} - -const DEFAULT_SETTINGS: MediaDbPluginSettings = { - OMDbKey: '', - sfwFilter: true, - useCustomYamlStringifier: true, - templates: true, - - movieTemplate: '', - seriesTemplate: '', - gameTemplate: '', - wikiTemplate: '', - musicReleaseTemplate: '', - boardgameTemplate: '', - - movieFileNameTemplate: '{{ title }} ({{ year }})', - seriesFileNameTemplate: '{{ title }} ({{ year }})', - gameFileNameTemplate: '{{ title }} ({{ year }})', - wikiFileNameTemplate: '{{ title }}', - musicReleaseFileNameTemplate: '{{ title }} (by {{ ENUM:artists }} - {{ year }})', - boardgameFileNameTemplate: '{{ title }} ({{ year }})', - - moviePropertyConversionRules: '', - seriesPropertyConversionRules: '', - gamePropertyConversionRules: '', - wikiPropertyConversionRules: '', - musicReleasePropertyConversionRules: '', - boardgamePropertyConversionRules: '', - - movieFolder: 'Media DB/movies', - seriesFolder: 'Media DB/series', - gameFolder: 'Media DB/games', - wikiFolder: 'Media DB/wiki', - musicReleaseFolder: 'Media DB/music', - boardgameFolder: 'Media DB/boardgames', - - propertyMappingModels: [], -}; - -export const lockedPropertyMappings: string[] = ['type', 'id', 'dataSource']; - -export function getDefaultSettings(plugin: MediaDbPlugin): MediaDbPluginSettings { - const defaultSettings = DEFAULT_SETTINGS; - - // construct property mapping defaults - const propertyMappingModels: PropertyMappingModel[] = []; - for (const mediaType of MEDIA_TYPES) { - const model: MediaTypeModel = plugin.mediaTypeManager.createMediaTypeModelFromMediaType({}, mediaType); - const metadataObj = model.toMetaDataObject(); - // console.log(metadataObj); - // console.log(model); - - const propertyMappingModel: PropertyMappingModel = new PropertyMappingModel(mediaType); - - for (const key of Object.keys(metadataObj)) { - propertyMappingModel.properties.push(new PropertyMapping(key, '', PropertyMappingOption.Default, lockedPropertyMappings.contains(key))); - } - - propertyMappingModels.push(propertyMappingModel); - } - - defaultSettings.propertyMappingModels = propertyMappingModels; - return defaultSettings; -} - -export class MediaDbSettingTab extends PluginSettingTab { - plugin: MediaDbPlugin; - - constructor(app: App, plugin: MediaDbPlugin) { - super(app, plugin); - this.plugin = plugin; - } - - display(): void { - const { containerEl } = this; - - containerEl.empty(); - - containerEl.createEl('h2', { text: 'Media DB Plugin Settings' }); - - new Setting(containerEl) - .setName('OMDb API key') - .setDesc('API key for "www.omdbapi.com".') - .addText(cb => { - cb.setPlaceholder('API key') - .setValue(this.plugin.settings.OMDbKey) - .onChange(data => { - this.plugin.settings.OMDbKey = data; - this.plugin.saveSettings(); - }); - }); - - new Setting(containerEl) - .setName('SFW filter') - .setDesc('Only shows SFW results for APIs that offer filtering.') - .addToggle(cb => { - cb.setValue(this.plugin.settings.sfwFilter).onChange(data => { - this.plugin.settings.sfwFilter = data; - this.plugin.saveSettings(); - }); - }); - - new Setting(containerEl) - .setName('YAML formatter') - .setDesc('Add optional quotation marks around strings in the metadata block.') - .addToggle(cb => { - cb.setValue(this.plugin.settings.useCustomYamlStringifier).onChange(data => { - this.plugin.settings.useCustomYamlStringifier = data; - this.plugin.saveSettings(); - }); - }); - - new Setting(containerEl) - .setName('Resolve {{ tags }} in templates') - .setDesc('Whether to resolve {{ tags }} in templates. The spaces inside the curly braces are important.') - .addToggle(cb => { - cb.setValue(this.plugin.settings.templates).onChange(data => { - this.plugin.settings.templates = data; - this.plugin.saveSettings(); - }); - }); - - containerEl.createEl('h3', { text: 'New File Location' }); - // region new file location - new Setting(containerEl) - .setName('Movie Folder') - .setDesc('Where newly imported movies should be places.') - .addSearch(cb => { - new FolderSuggest(this.app, cb.inputEl); - cb.setPlaceholder(DEFAULT_SETTINGS.movieFolder) - .setValue(this.plugin.settings.movieFolder) - .onChange(data => { - this.plugin.settings.movieFolder = data; - this.plugin.saveSettings(); - }); - }); - - new Setting(containerEl) - .setName('Series Folder') - .setDesc('Where newly imported series should be places.') - .addSearch(cb => { - new FolderSuggest(this.app, cb.inputEl); - cb.setPlaceholder(DEFAULT_SETTINGS.seriesFolder) - .setValue(this.plugin.settings.seriesFolder) - .onChange(data => { - this.plugin.settings.seriesFolder = data; - this.plugin.saveSettings(); - }); - }); - - new Setting(containerEl) - .setName('Game Folder') - .setDesc('Where newly imported games should be places.') - .addSearch(cb => { - new FolderSuggest(this.app, cb.inputEl); - cb.setPlaceholder(DEFAULT_SETTINGS.gameFolder) - .setValue(this.plugin.settings.gameFolder) - .onChange(data => { - this.plugin.settings.gameFolder = data; - this.plugin.saveSettings(); - }); - }); - - new Setting(containerEl) - .setName('Wiki Folder') - .setDesc('Where newly imported wiki articles should be places.') - .addSearch(cb => { - new FolderSuggest(this.app, cb.inputEl); - cb.setPlaceholder(DEFAULT_SETTINGS.wikiFolder) - .setValue(this.plugin.settings.wikiFolder) - .onChange(data => { - this.plugin.settings.wikiFolder = data; - this.plugin.saveSettings(); - }); - }); - - new Setting(containerEl) - .setName('Music Folder') - .setDesc('Where newly imported music should be places.') - .addSearch(cb => { - new FolderSuggest(this.app, cb.inputEl); - cb.setPlaceholder(DEFAULT_SETTINGS.musicReleaseFolder) - .setValue(this.plugin.settings.musicReleaseFolder) - .onChange(data => { - this.plugin.settings.musicReleaseFolder = data; - this.plugin.saveSettings(); - }); - }); - - new Setting(containerEl) - .setName('Board Game Folder') - .setDesc('Where newly imported board games should be places.') - .addSearch(cb => { - new FolderSuggest(this.app, cb.inputEl); - cb.setPlaceholder(DEFAULT_SETTINGS.boardgameFolder) - .setValue(this.plugin.settings.boardgameFolder) - .onChange(data => { - this.plugin.settings.boardgameFolder = data; - this.plugin.saveSettings(); - }); - }); - // endregion - - containerEl.createEl('h3', { text: 'Template Settings' }); - // region templates - new Setting(containerEl) - .setName('Movie template') - .setDesc('Template file to be used when creating a new note for a movie.') - .addSearch(cb => { - new FileSuggest(this.app, cb.inputEl); - cb.setPlaceholder('Example: movieTemplate.md') - .setValue(this.plugin.settings.movieTemplate) - .onChange(data => { - this.plugin.settings.movieTemplate = data; - this.plugin.saveSettings(); - }); - }); - - new Setting(containerEl) - .setName('Series template') - .setDesc('Template file to be used when creating a new note for a series.') - .addSearch(cb => { - new FileSuggest(this.app, cb.inputEl); - cb.setPlaceholder('Example: seriesTemplate.md') - .setValue(this.plugin.settings.seriesTemplate) - .onChange(data => { - this.plugin.settings.seriesTemplate = data; - this.plugin.saveSettings(); - }); - }); - - new Setting(containerEl) - .setName('Game template') - .setDesc('Template file to be used when creating a new note for a game.') - .addSearch(cb => { - new FileSuggest(this.app, cb.inputEl); - cb.setPlaceholder('Example: gameTemplate.md') - .setValue(this.plugin.settings.gameTemplate) - .onChange(data => { - this.plugin.settings.gameTemplate = data; - this.plugin.saveSettings(); - }); - }); - - new Setting(containerEl) - .setName('Wiki template') - .setDesc('Template file to be used when creating a new note for a wiki entry.') - .addSearch(cb => { - new FileSuggest(this.app, cb.inputEl); - cb.setPlaceholder('Example: wikiTemplate.md') - .setValue(this.plugin.settings.wikiTemplate) - .onChange(data => { - this.plugin.settings.wikiTemplate = data; - this.plugin.saveSettings(); - }); - }); - - new Setting(containerEl) - .setName('Music Release template') - .setDesc('Template file to be used when creating a new note for a music release.') - .addSearch(cb => { - new FileSuggest(this.app, cb.inputEl); - cb.setPlaceholder('Example: musicReleaseTemplate.md') - .setValue(this.plugin.settings.musicReleaseTemplate) - .onChange(data => { - this.plugin.settings.musicReleaseTemplate = data; - this.plugin.saveSettings(); - }); - }); - - new Setting(containerEl) - .setName('Board Game template') - .setDesc('Template file to be used when creating a new note for a boardgame.') - .addSearch(cb => { - new FileSuggest(this.app, cb.inputEl); - cb.setPlaceholder('Example: boardgameTemplate.md') - .setValue(this.plugin.settings.boardgameTemplate) - .onChange(data => { - this.plugin.settings.boardgameTemplate = data; - this.plugin.saveSettings(); - }); - }); - // endregion - - containerEl.createEl('h3', { text: 'File Name Settings' }); - // region file name templates - new Setting(containerEl) - .setName('Movie file name template') - .setDesc('Template for the file name used when creating a new note for a movie.') - .addText(cb => { - cb.setPlaceholder(`Example: ${DEFAULT_SETTINGS.movieFileNameTemplate}`) - .setValue(this.plugin.settings.movieFileNameTemplate) - .onChange(data => { - this.plugin.settings.movieFileNameTemplate = data; - this.plugin.saveSettings(); - }); - }); - - new Setting(containerEl) - .setName('Series file name template') - .setDesc('Template for the file name used when creating a new note for a series.') - .addText(cb => { - cb.setPlaceholder(`Example: ${DEFAULT_SETTINGS.seriesFileNameTemplate}`) - .setValue(this.plugin.settings.seriesFileNameTemplate) - .onChange(data => { - this.plugin.settings.seriesFileNameTemplate = data; - this.plugin.saveSettings(); - }); - }); - - new Setting(containerEl) - .setName('Game file name template') - .setDesc('Template for the file name used when creating a new note for a game.') - .addText(cb => { - cb.setPlaceholder(`Example: ${DEFAULT_SETTINGS.gameFileNameTemplate}`) - .setValue(this.plugin.settings.gameFileNameTemplate) - .onChange(data => { - this.plugin.settings.gameFileNameTemplate = data; - this.plugin.saveSettings(); - }); - }); - - new Setting(containerEl) - .setName('Wiki file name template') - .setDesc('Template for the file name used when creating a new note for a wiki entry.') - .addText(cb => { - cb.setPlaceholder(`Example: ${DEFAULT_SETTINGS.wikiFileNameTemplate}`) - .setValue(this.plugin.settings.wikiFileNameTemplate) - .onChange(data => { - this.plugin.settings.wikiFileNameTemplate = data; - this.plugin.saveSettings(); - }); - }); - - 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.') - .addText(cb => { - cb.setPlaceholder(`Example: ${DEFAULT_SETTINGS.musicReleaseFileNameTemplate}`) - .setValue(this.plugin.settings.musicReleaseFileNameTemplate) - .onChange(data => { - this.plugin.settings.musicReleaseFileNameTemplate = data; - this.plugin.saveSettings(); - }); - }); - - new Setting(containerEl) - .setName('Board Game file name template') - .setDesc('Template for the file name used when creating a new note for a boardgame.') - .addText(cb => { - cb.setPlaceholder(`Example: ${DEFAULT_SETTINGS.boardgameFileNameTemplate}`) - .setValue(this.plugin.settings.boardgameFileNameTemplate) - .onChange(data => { - this.plugin.settings.boardgameFileNameTemplate = data; - this.plugin.saveSettings(); - }); - }); - // endregion - - // region Property Mappings - - containerEl.createEl('h3', { text: 'Property Mappings' }); - - const propertyMappingExplanation = containerEl.createEl('div'); - propertyMappingExplanation.innerHTML = ` -

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

-

- The different options are: - -

  • "default": does no remapping and keeps the metadata field as it is
  • -
  • "remap": renames the metadata field to what ever you specify
  • -
  • "remove": removes the metadata field entirely
  • - -

    -

    - 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[] = []; - - 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(); - }, - }, - }); - - // endregion - } -} +import { App, Notice, PluginSettingTab, Setting } from 'obsidian'; + +import MediaDbPlugin from '../main'; +import { FolderSuggest } from './suggesters/FolderSuggest'; +import { FileSuggest } from './suggesters/FileSuggest'; +import PropertyMappingModelsComponent from './PropertyMappingModelsComponent.svelte'; +import { PropertyMapping, PropertyMappingModel, PropertyMappingOption } from './PropertyMapping'; +import { MEDIA_TYPES } from '../utils/MediaTypeManager'; +import { MediaTypeModel } from '../models/MediaTypeModel'; +import { fragWithHTML } from '../utils/Utils'; + +export interface MediaDbPluginSettings { + OMDbKey: string; + sfwFilter: boolean; + useCustomYamlStringifier: boolean; + templates: boolean; + customDateFormat: string; + + movieTemplate: string; + seriesTemplate: string; + gameTemplate: string; + wikiTemplate: string; + musicReleaseTemplate: string; + boardgameTemplate: string; + + movieFileNameTemplate: string; + seriesFileNameTemplate: string; + gameFileNameTemplate: string; + wikiFileNameTemplate: string; + musicReleaseFileNameTemplate: string; + boardgameFileNameTemplate: string; + + moviePropertyConversionRules: string; + seriesPropertyConversionRules: string; + gamePropertyConversionRules: string; + wikiPropertyConversionRules: string; + musicReleasePropertyConversionRules: string; + boardgamePropertyConversionRules: string; + + movieFolder: string; + seriesFolder: string; + gameFolder: string; + wikiFolder: string; + musicReleaseFolder: string; + boardgameFolder: string; + + propertyMappingModels: PropertyMappingModel[]; +} + +const DEFAULT_SETTINGS: MediaDbPluginSettings = { + OMDbKey: '', + sfwFilter: true, + useCustomYamlStringifier: true, + templates: true, + customDateFormat: 'L', + + movieTemplate: '', + seriesTemplate: '', + gameTemplate: '', + wikiTemplate: '', + musicReleaseTemplate: '', + boardgameTemplate: '', + + movieFileNameTemplate: '{{ title }} ({{ year }})', + seriesFileNameTemplate: '{{ title }} ({{ year }})', + gameFileNameTemplate: '{{ title }} ({{ year }})', + wikiFileNameTemplate: '{{ title }}', + musicReleaseFileNameTemplate: '{{ title }} (by {{ ENUM:artists }} - {{ year }})', + boardgameFileNameTemplate: '{{ title }} ({{ year }})', + + moviePropertyConversionRules: '', + seriesPropertyConversionRules: '', + gamePropertyConversionRules: '', + wikiPropertyConversionRules: '', + musicReleasePropertyConversionRules: '', + boardgamePropertyConversionRules: '', + + movieFolder: 'Media DB/movies', + seriesFolder: 'Media DB/series', + gameFolder: 'Media DB/games', + wikiFolder: 'Media DB/wiki', + musicReleaseFolder: 'Media DB/music', + boardgameFolder: 'Media DB/boardgames', + + propertyMappingModels: [], +}; + +export const lockedPropertyMappings: string[] = ['type', 'id', 'dataSource']; + +export function getDefaultSettings(plugin: MediaDbPlugin): MediaDbPluginSettings { + const defaultSettings = DEFAULT_SETTINGS; + + // construct property mapping defaults + const propertyMappingModels: PropertyMappingModel[] = []; + for (const mediaType of MEDIA_TYPES) { + const model: MediaTypeModel = plugin.mediaTypeManager.createMediaTypeModelFromMediaType({}, mediaType); + const metadataObj = model.toMetaDataObject(); + // console.log(metadataObj); + // console.log(model); + + const propertyMappingModel: PropertyMappingModel = new PropertyMappingModel(mediaType); + + for (const key of Object.keys(metadataObj)) { + propertyMappingModel.properties.push(new PropertyMapping(key, '', PropertyMappingOption.Default, lockedPropertyMappings.contains(key))); + } + + propertyMappingModels.push(propertyMappingModel); + } + + defaultSettings.propertyMappingModels = propertyMappingModels; + return defaultSettings; +} + +export class MediaDbSettingTab extends PluginSettingTab { + plugin: MediaDbPlugin; + + constructor(app: App, plugin: MediaDbPlugin) { + super(app, plugin); + this.plugin = plugin; + } + + display(): void { + const { containerEl } = this; + + containerEl.empty(); + + containerEl.createEl('h2', { text: 'Media DB Plugin Settings' }); + + new Setting(containerEl) + .setName('OMDb API key') + .setDesc('API key for "www.omdbapi.com".') + .addText(cb => { + cb.setPlaceholder('API key') + .setValue(this.plugin.settings.OMDbKey) + .onChange(data => { + this.plugin.settings.OMDbKey = data; + this.plugin.saveSettings(); + }); + }); + + new Setting(containerEl) + .setName('SFW filter') + .setDesc('Only shows SFW results for APIs that offer filtering.') + .addToggle(cb => { + cb.setValue(this.plugin.settings.sfwFilter).onChange(data => { + this.plugin.settings.sfwFilter = data; + this.plugin.saveSettings(); + }); + }); + + new Setting(containerEl) + .setName('YAML formatter') + .setDesc('Add optional quotation marks around strings in the metadata block.') + .addToggle(cb => { + cb.setValue(this.plugin.settings.useCustomYamlStringifier).onChange(data => { + this.plugin.settings.useCustomYamlStringifier = data; + this.plugin.saveSettings(); + }); + }); + + new Setting(containerEl) + .setName('Resolve {{ tags }} in templates') + .setDesc('Whether to resolve {{ tags }} in templates. The spaces inside the curly braces are important.') + .addToggle(cb => { + cb.setValue(this.plugin.settings.templates).onChange(data => { + this.plugin.settings.templates = data; + this.plugin.saveSettings(); + }); + }); + + new Setting(containerEl) + .setName('Date format') + .setDesc(fragWithHTML("Your custom date format. Use \'YYYY-MM-DD\' for example.
    " + + "For more syntax, refer to format reference.
    " + + "Your current syntax looks like this: " + + this.plugin.dateFormatter.getPreview() + "")) + .addText(cb => { + cb.setPlaceholder(DEFAULT_SETTINGS.customDateFormat) + .setValue(this.plugin.settings.customDateFormat === DEFAULT_SETTINGS.customDateFormat ? '' : this.plugin.settings.customDateFormat) + .onChange(data => { + const newDateFormat = data ? data : DEFAULT_SETTINGS.customDateFormat; + this.plugin.settings.customDateFormat = newDateFormat; + document.getElementById('media-db-dateformat-preview').textContent = this.plugin.dateFormatter.getPreview(newDateFormat); // update preview + this.plugin.saveSettings(); + }); + }); + + containerEl.createEl('h3', { text: 'New File Location' }); + // region new file location + new Setting(containerEl) + .setName('Movie Folder') + .setDesc('Where newly imported movies should be places.') + .addSearch(cb => { + new FolderSuggest(this.app, cb.inputEl); + cb.setPlaceholder(DEFAULT_SETTINGS.movieFolder) + .setValue(this.plugin.settings.movieFolder) + .onChange(data => { + this.plugin.settings.movieFolder = data; + this.plugin.saveSettings(); + }); + }); + + new Setting(containerEl) + .setName('Series Folder') + .setDesc('Where newly imported series should be places.') + .addSearch(cb => { + new FolderSuggest(this.app, cb.inputEl); + cb.setPlaceholder(DEFAULT_SETTINGS.seriesFolder) + .setValue(this.plugin.settings.seriesFolder) + .onChange(data => { + this.plugin.settings.seriesFolder = data; + this.plugin.saveSettings(); + }); + }); + + new Setting(containerEl) + .setName('Game Folder') + .setDesc('Where newly imported games should be places.') + .addSearch(cb => { + new FolderSuggest(this.app, cb.inputEl); + cb.setPlaceholder(DEFAULT_SETTINGS.gameFolder) + .setValue(this.plugin.settings.gameFolder) + .onChange(data => { + this.plugin.settings.gameFolder = data; + this.plugin.saveSettings(); + }); + }); + + new Setting(containerEl) + .setName('Wiki Folder') + .setDesc('Where newly imported wiki articles should be places.') + .addSearch(cb => { + new FolderSuggest(this.app, cb.inputEl); + cb.setPlaceholder(DEFAULT_SETTINGS.wikiFolder) + .setValue(this.plugin.settings.wikiFolder) + .onChange(data => { + this.plugin.settings.wikiFolder = data; + this.plugin.saveSettings(); + }); + }); + + new Setting(containerEl) + .setName('Music Folder') + .setDesc('Where newly imported music should be places.') + .addSearch(cb => { + new FolderSuggest(this.app, cb.inputEl); + cb.setPlaceholder(DEFAULT_SETTINGS.musicReleaseFolder) + .setValue(this.plugin.settings.musicReleaseFolder) + .onChange(data => { + this.plugin.settings.musicReleaseFolder = data; + this.plugin.saveSettings(); + }); + }); + + new Setting(containerEl) + .setName('Board Game Folder') + .setDesc('Where newly imported board games should be places.') + .addSearch(cb => { + new FolderSuggest(this.app, cb.inputEl); + cb.setPlaceholder(DEFAULT_SETTINGS.boardgameFolder) + .setValue(this.plugin.settings.boardgameFolder) + .onChange(data => { + this.plugin.settings.boardgameFolder = data; + this.plugin.saveSettings(); + }); + }); + // endregion + + containerEl.createEl('h3', { text: 'Template Settings' }); + // region templates + new Setting(containerEl) + .setName('Movie template') + .setDesc('Template file to be used when creating a new note for a movie.') + .addSearch(cb => { + new FileSuggest(this.app, cb.inputEl); + cb.setPlaceholder('Example: movieTemplate.md') + .setValue(this.plugin.settings.movieTemplate) + .onChange(data => { + this.plugin.settings.movieTemplate = data; + this.plugin.saveSettings(); + }); + }); + + new Setting(containerEl) + .setName('Series template') + .setDesc('Template file to be used when creating a new note for a series.') + .addSearch(cb => { + new FileSuggest(this.app, cb.inputEl); + cb.setPlaceholder('Example: seriesTemplate.md') + .setValue(this.plugin.settings.seriesTemplate) + .onChange(data => { + this.plugin.settings.seriesTemplate = data; + this.plugin.saveSettings(); + }); + }); + + new Setting(containerEl) + .setName('Game template') + .setDesc('Template file to be used when creating a new note for a game.') + .addSearch(cb => { + new FileSuggest(this.app, cb.inputEl); + cb.setPlaceholder('Example: gameTemplate.md') + .setValue(this.plugin.settings.gameTemplate) + .onChange(data => { + this.plugin.settings.gameTemplate = data; + this.plugin.saveSettings(); + }); + }); + + new Setting(containerEl) + .setName('Wiki template') + .setDesc('Template file to be used when creating a new note for a wiki entry.') + .addSearch(cb => { + new FileSuggest(this.app, cb.inputEl); + cb.setPlaceholder('Example: wikiTemplate.md') + .setValue(this.plugin.settings.wikiTemplate) + .onChange(data => { + this.plugin.settings.wikiTemplate = data; + this.plugin.saveSettings(); + }); + }); + + new Setting(containerEl) + .setName('Music Release template') + .setDesc('Template file to be used when creating a new note for a music release.') + .addSearch(cb => { + new FileSuggest(this.app, cb.inputEl); + cb.setPlaceholder('Example: musicReleaseTemplate.md') + .setValue(this.plugin.settings.musicReleaseTemplate) + .onChange(data => { + this.plugin.settings.musicReleaseTemplate = data; + this.plugin.saveSettings(); + }); + }); + + new Setting(containerEl) + .setName('Board Game template') + .setDesc('Template file to be used when creating a new note for a boardgame.') + .addSearch(cb => { + new FileSuggest(this.app, cb.inputEl); + cb.setPlaceholder('Example: boardgameTemplate.md') + .setValue(this.plugin.settings.boardgameTemplate) + .onChange(data => { + this.plugin.settings.boardgameTemplate = data; + this.plugin.saveSettings(); + }); + }); + // endregion + + containerEl.createEl('h3', { text: 'File Name Settings' }); + // region file name templates + new Setting(containerEl) + .setName('Movie file name template') + .setDesc('Template for the file name used when creating a new note for a movie.') + .addText(cb => { + cb.setPlaceholder(`Example: ${DEFAULT_SETTINGS.movieFileNameTemplate}`) + .setValue(this.plugin.settings.movieFileNameTemplate) + .onChange(data => { + this.plugin.settings.movieFileNameTemplate = data; + this.plugin.saveSettings(); + }); + }); + + new Setting(containerEl) + .setName('Series file name template') + .setDesc('Template for the file name used when creating a new note for a series.') + .addText(cb => { + cb.setPlaceholder(`Example: ${DEFAULT_SETTINGS.seriesFileNameTemplate}`) + .setValue(this.plugin.settings.seriesFileNameTemplate) + .onChange(data => { + this.plugin.settings.seriesFileNameTemplate = data; + this.plugin.saveSettings(); + }); + }); + + new Setting(containerEl) + .setName('Game file name template') + .setDesc('Template for the file name used when creating a new note for a game.') + .addText(cb => { + cb.setPlaceholder(`Example: ${DEFAULT_SETTINGS.gameFileNameTemplate}`) + .setValue(this.plugin.settings.gameFileNameTemplate) + .onChange(data => { + this.plugin.settings.gameFileNameTemplate = data; + this.plugin.saveSettings(); + }); + }); + + new Setting(containerEl) + .setName('Wiki file name template') + .setDesc('Template for the file name used when creating a new note for a wiki entry.') + .addText(cb => { + cb.setPlaceholder(`Example: ${DEFAULT_SETTINGS.wikiFileNameTemplate}`) + .setValue(this.plugin.settings.wikiFileNameTemplate) + .onChange(data => { + this.plugin.settings.wikiFileNameTemplate = data; + this.plugin.saveSettings(); + }); + }); + + 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.') + .addText(cb => { + cb.setPlaceholder(`Example: ${DEFAULT_SETTINGS.musicReleaseFileNameTemplate}`) + .setValue(this.plugin.settings.musicReleaseFileNameTemplate) + .onChange(data => { + this.plugin.settings.musicReleaseFileNameTemplate = data; + this.plugin.saveSettings(); + }); + }); + + new Setting(containerEl) + .setName('Board Game file name template') + .setDesc('Template for the file name used when creating a new note for a boardgame.') + .addText(cb => { + cb.setPlaceholder(`Example: ${DEFAULT_SETTINGS.boardgameFileNameTemplate}`) + .setValue(this.plugin.settings.boardgameFileNameTemplate) + .onChange(data => { + this.plugin.settings.boardgameFileNameTemplate = data; + this.plugin.saveSettings(); + }); + }); + // endregion + + // region Property Mappings + + containerEl.createEl('h3', { text: 'Property Mappings' }); + + const propertyMappingExplanation = containerEl.createEl('div'); + propertyMappingExplanation.innerHTML = ` +

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

    +

    + The different options are: + +

  • "default": does no remapping and keeps the metadata field as it is
  • +
  • "remap": renames the metadata field to what ever you specify
  • +
  • "remove": removes the metadata field entirely
  • + +

    +

    + 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[] = []; + + 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(); + }, + }, + }); + + // endregion + } +} diff --git a/src/utils/DateFormatter.ts b/src/utils/DateFormatter.ts new file mode 100644 index 0000000..6f85656 --- /dev/null +++ b/src/utils/DateFormatter.ts @@ -0,0 +1,71 @@ +// obsidian already uses moment, so no need to package it twice! +// import { moment } from 'obsidian'; // doesn't work for release build +// obsidian uses a namespace-style import for moment, which ES6 doesn't allow anymore +const obsidian = require('obsidian'); +const moment = obsidian.moment; + +export class DateFormatter { + toFormat: string; + locale: string; + + constructor() { + this.toFormat = 'YYYY-MM-DD'; + // get locale of this machine (e.g. en, en-gb, de, fr, etc.) + this.locale = new Intl.DateTimeFormat().resolvedOptions().locale; + } + + setFormat(format: string): void { + this.toFormat = format; + } + + getPreview(format?: string): string { + const today = moment(); + + if (!format) { + format = this.toFormat; + } + + return today.locale(this.locale).format(format); + } + + /** + * Tries to format a given date string with the currently set date format. + * You can set a date format by calling `setFormat()`. + * + * @param dateString the date string to be formatted + * @param dateFormat the current format of `dateString`. When this is `null` and the actual format of the + * given date string is not `C2822` or `ISO` format, this function will try to guess the format by using the native `Date` module. + * @param locale the locale of `dateString`. This is needed when `dateString` includes a month or day name and its locale format differs + * from the locale of this machine. + * @returns formatted date string or null if `dateString` is not a valid date + */ + format(dateString: string, dateFormat?: string, locale: string = 'en'): string | null { + if (!dateString) { + return null; + } + + let date: moment.Moment; + + if (!dateFormat) { + // reading date formats other then C2822 or ISO with moment is deprecated + // see https://momentjs.com/docs/#/parsing/string/ + if (this.hasMomentFormat(dateString)) { + // expect C2822 or ISO format + date = moment(dateString); + } else { + // try to read date string with native Date + date = moment(new Date(dateString)); + } + } else { + date = moment(dateString, dateFormat, locale); + } + + // format date (if it is valid) + return date.isValid() ? date.locale(this.locale).format(this.toFormat) : null; + } + + private hasMomentFormat(dateString: string): boolean { + const date = moment(dateString, true); // strict mode + return date.isValid(); + } +} diff --git a/src/utils/Utils.ts b/src/utils/Utils.ts index 2d2fb71..4aebac1 100644 --- a/src/utils/Utils.ts +++ b/src/utils/Utils.ts @@ -135,6 +135,8 @@ export function markdownTable(content: string[][]): string { return table; } +export const fragWithHTML = (html: string) => createFragment(frag => (frag.createDiv().innerHTML = html)); + export function dateToString(date: Date): string { return `${date.getMonth() + 1}-${date.getDate()}-${date.getFullYear()}`; }