obsidian-media-db-sync/packages/obsidian/src/settings/Settings.ts
2026-06-21 22:00:13 +02:00

872 lines
27 KiB
TypeScript

import type { App } from 'obsidian';
import { Notice, PluginSettingTab, SecretComponent, SettingGroup } from 'obsidian';
import type MediaDbPlugin from 'packages/obsidian/src/main';
import type { MediaTypeModel } from 'packages/obsidian/src/models/MediaTypeModel';
import type { PropertyMappingModelData } from 'packages/obsidian/src/settings/PropertyMapping';
import { PropertyMapping, PropertyMappingModel, PropertyMappingOption } from 'packages/obsidian/src/settings/PropertyMapping';
import PropertyMappingModelsComponent from 'packages/obsidian/src/settings/PropertyMappingModelsComponent';
import { FileSuggest } from 'packages/obsidian/src/settings/suggesters/FileSuggest';
import { FolderSuggest } from 'packages/obsidian/src/settings/suggesters/FolderSuggest';
import { MediaType } from 'packages/obsidian/src/utils/MediaType';
import { MEDIA_TYPES } from 'packages/obsidian/src/utils/MediaTypeManager';
import { unCamelCase } from 'packages/obsidian/src/utils/Utils';
function createDateFormatDescription(preview: string): DocumentFragment {
return createFragment(frag => {
const container = frag.createDiv();
container.appendText('Your custom date format. Use ');
container.createEl('em', { text: "'YYYY-MM-DD'" });
container.appendText(' for example.');
container.createEl('br');
container.appendText('For more syntax, refer to ');
container.createEl('a', {
href: 'https://momentjs.com/docs/#/displaying/format/',
text: 'format reference',
});
container.appendText('.');
container.createEl('br');
container.appendText('Your current syntax looks like this: ');
container.createEl('em', { text: preview });
});
}
function createPropertyMappingsDescription(): DocumentFragment {
return createFragment(frag => {
const container = frag.createDiv();
container.createEl('p', {
text: 'Here you can customize how metadata fields are mapped to property names in the front matter of the created notes.',
});
container.createEl('p', {
text: 'You can choose to keep the original name, rename the property, or remove it entirely.',
});
const paragraph = container.createEl('p');
paragraph.createEl('strong', {
text: 'Remember to save your changes using the save button for each individual category.',
});
});
}
// MARK: Settings
export interface MediaDbPluginSettings {
OMDbKeyId: string;
TMDBKeyId: string;
//MobyGamesKeyId: string;
//GiantBombKeyId: string;
IGDBClientId: string;
IGDBClientSecret: string;
RAWGAPIKeyId: string;
ComicVineKeyId: string;
BoardgameGeekKeyId: string;
LegacyApiKeys: readonly ['OMDbKey', 'TMDBKey', 'MobyGamesKey', 'GiantBombKey', 'ComicVineKey', 'BoardgameGeekKey'];
sfwFilter: boolean;
templates: boolean;
customDateFormat: string;
openNoteInNewTab: boolean;
useDefaultFrontMatter: boolean;
enableTemplaterIntegration: boolean;
imageDownload: boolean;
imageFolder: string;
BoardgameGeekAPI_disabledMediaTypes: MediaType[];
ComicVineAPI_disabledMediaTypes: MediaType[];
//GiantBombAPI_disabledMediaTypes: MediaType[];
IGDBAPI_disabledMediaTypes: MediaType[];
RAWGAPI_disabledMediaTypes: MediaType[];
MALAPI_disabledMediaTypes: MediaType[];
MALAPIManga_disabledMediaTypes: MediaType[];
//MobyGamesAPI_disabledMediaTypes: MediaType[];
MusicBrainzAPI_disabledMediaTypes: MediaType[];
OMDbAPI_disabledMediaTypes: MediaType[];
OpenLibraryAPI_disabledMediaTypes: MediaType[];
SteamAPI_disabledMediaTypes: MediaType[];
TMDBMovieAPI_disabledMediaTypes: MediaType[];
TMDBSeasonAPI_disabledMediaTypes: MediaType[];
TMDBSeriesAPI_disabledMediaTypes: MediaType[];
VNDBAPI_disabledMediaTypes: MediaType[];
WikipediaAPI_disabledMediaTypes: MediaType[];
movieTemplate: string;
seriesTemplate: string;
seasonTemplate: string;
mangaTemplate: string;
gameTemplate: string;
wikiTemplate: string;
musicReleaseTemplate: string;
boardgameTemplate: string;
bookTemplate: string;
movieFileNameTemplate: string;
seriesFileNameTemplate: string;
seasonFileNameTemplate: string;
mangaFileNameTemplate: string;
gameFileNameTemplate: string;
wikiFileNameTemplate: string;
musicReleaseFileNameTemplate: string;
boardgameFileNameTemplate: string;
bookFileNameTemplate: string;
movieFolder: string;
seriesFolder: string;
seasonFolder: string;
mangaFolder: string;
gameFolder: string;
wikiFolder: string;
musicReleaseFolder: string;
boardgameFolder: string;
bookFolder: string;
propertyMappingModels: PropertyMappingModelData[];
// DEPRECATED: Use propertyMappingModels instead
moviePropertyConversionRules: string;
seriesPropertyConversionRules: string;
seasonPropertyConversionRules: string;
mangaPropertyConversionRules: string;
gamePropertyConversionRules: string;
wikiPropertyConversionRules: string;
musicReleasePropertyConversionRules: string;
boardgamePropertyConversionRules: string;
bookPropertyConversionRules: string;
}
/**
* Helper class to get/set settings for a specific media type.
*/
class MediaTypeMappedSettings {
mediaType: MediaType;
constructor(mediaType: MediaType) {
this.mediaType = mediaType;
}
getTemplate(settings: MediaDbPluginSettings): string {
switch (this.mediaType) {
case MediaType.Movie:
return settings.movieTemplate;
case MediaType.Series:
return settings.seriesTemplate;
case MediaType.Season:
return settings.seasonTemplate;
case MediaType.ComicManga:
return settings.mangaTemplate;
case MediaType.Game:
return settings.gameTemplate;
case MediaType.Wiki:
return settings.wikiTemplate;
case MediaType.MusicRelease:
return settings.musicReleaseTemplate;
case MediaType.BoardGame:
return settings.boardgameTemplate;
case MediaType.Book:
return settings.bookTemplate;
}
}
setTemplate(settings: MediaDbPluginSettings, template: string): void {
switch (this.mediaType) {
case MediaType.Movie:
settings.movieTemplate = template;
break;
case MediaType.Series:
settings.seriesTemplate = template;
break;
case MediaType.Season:
settings.seasonTemplate = template;
break;
case MediaType.ComicManga:
settings.mangaTemplate = template;
break;
case MediaType.Game:
settings.gameTemplate = template;
break;
case MediaType.Wiki:
settings.wikiTemplate = template;
break;
case MediaType.MusicRelease:
settings.musicReleaseTemplate = template;
break;
case MediaType.BoardGame:
settings.boardgameTemplate = template;
break;
case MediaType.Book:
settings.bookTemplate = template;
break;
}
}
getFileNameTemplate(settings: MediaDbPluginSettings): string {
switch (this.mediaType) {
case MediaType.Movie:
return settings.movieFileNameTemplate;
case MediaType.Series:
return settings.seriesFileNameTemplate;
case MediaType.Season:
return settings.seasonFileNameTemplate;
case MediaType.ComicManga:
return settings.mangaFileNameTemplate;
case MediaType.Game:
return settings.gameFileNameTemplate;
case MediaType.Wiki:
return settings.wikiFileNameTemplate;
case MediaType.MusicRelease:
return settings.musicReleaseFileNameTemplate;
case MediaType.BoardGame:
return settings.boardgameFileNameTemplate;
case MediaType.Book:
return settings.bookFileNameTemplate;
}
}
setFileNameTemplate(settings: MediaDbPluginSettings, template: string): void {
switch (this.mediaType) {
case MediaType.Movie:
settings.movieFileNameTemplate = template;
break;
case MediaType.Series:
settings.seriesFileNameTemplate = template;
break;
case MediaType.Season:
settings.seasonFileNameTemplate = template;
break;
case MediaType.ComicManga:
settings.mangaFileNameTemplate = template;
break;
case MediaType.Game:
settings.gameFileNameTemplate = template;
break;
case MediaType.Wiki:
settings.wikiFileNameTemplate = template;
break;
case MediaType.MusicRelease:
settings.musicReleaseFileNameTemplate = template;
break;
case MediaType.BoardGame:
settings.boardgameFileNameTemplate = template;
break;
case MediaType.Book:
settings.bookFileNameTemplate = template;
break;
}
}
getFolder(settings: MediaDbPluginSettings): string {
switch (this.mediaType) {
case MediaType.Movie:
return settings.movieFolder;
case MediaType.Series:
return settings.seriesFolder;
case MediaType.Season:
return settings.seasonFolder;
case MediaType.ComicManga:
return settings.mangaFolder;
case MediaType.Game:
return settings.gameFolder;
case MediaType.Wiki:
return settings.wikiFolder;
case MediaType.MusicRelease:
return settings.musicReleaseFolder;
case MediaType.BoardGame:
return settings.boardgameFolder;
case MediaType.Book:
return settings.bookFolder;
}
}
setFolder(settings: MediaDbPluginSettings, folder: string): void {
switch (this.mediaType) {
case MediaType.Movie:
settings.movieFolder = folder;
break;
case MediaType.Series:
settings.seriesFolder = folder;
break;
case MediaType.Season:
settings.seasonFolder = folder;
break;
case MediaType.ComicManga:
settings.mangaFolder = folder;
break;
case MediaType.Game:
settings.gameFolder = folder;
break;
case MediaType.Wiki:
settings.wikiFolder = folder;
break;
case MediaType.MusicRelease:
settings.musicReleaseFolder = folder;
break;
case MediaType.BoardGame:
settings.boardgameFolder = folder;
break;
case MediaType.Book:
settings.bookFolder = folder;
break;
}
}
}
// MARK: Defaults
const DEFAULT_SETTINGS: MediaDbPluginSettings = {
OMDbKeyId: '',
TMDBKeyId: '',
//MobyGamesKeyId: '',
//GiantBombKeyId: '',
IGDBClientId: '',
IGDBClientSecret: '',
RAWGAPIKeyId: '',
ComicVineKeyId: '',
BoardgameGeekKeyId: '',
LegacyApiKeys: ['OMDbKey', 'TMDBKey', 'MobyGamesKey', 'GiantBombKey', 'ComicVineKey', 'BoardgameGeekKey'],
sfwFilter: true,
templates: true,
customDateFormat: 'L',
openNoteInNewTab: true,
useDefaultFrontMatter: true,
enableTemplaterIntegration: false,
imageDownload: false,
imageFolder: 'Media DB/images',
BoardgameGeekAPI_disabledMediaTypes: [],
ComicVineAPI_disabledMediaTypes: [],
//GiantBombAPI_disabledMediaTypes: [],
IGDBAPI_disabledMediaTypes: [],
RAWGAPI_disabledMediaTypes: [],
MALAPI_disabledMediaTypes: [],
MALAPIManga_disabledMediaTypes: [],
//MobyGamesAPI_disabledMediaTypes: [],
MusicBrainzAPI_disabledMediaTypes: [],
OMDbAPI_disabledMediaTypes: [],
OpenLibraryAPI_disabledMediaTypes: [],
SteamAPI_disabledMediaTypes: [],
TMDBMovieAPI_disabledMediaTypes: [],
TMDBSeasonAPI_disabledMediaTypes: [],
TMDBSeriesAPI_disabledMediaTypes: [],
VNDBAPI_disabledMediaTypes: [],
WikipediaAPI_disabledMediaTypes: [],
movieTemplate: '',
seriesTemplate: '',
seasonTemplate: '',
mangaTemplate: '',
gameTemplate: '',
wikiTemplate: '',
musicReleaseTemplate: '',
boardgameTemplate: '',
bookTemplate: '',
movieFileNameTemplate: '{{ title }} ({{ year }})',
seriesFileNameTemplate: '{{ title }} ({{ year }})',
seasonFileNameTemplate: '{{ title }} ({{ year }})',
mangaFileNameTemplate: '{{ title }} ({{ year }})',
gameFileNameTemplate: '{{ title }} ({{ year }})',
wikiFileNameTemplate: '{{ title }}',
musicReleaseFileNameTemplate: '{{ title }} (by {{ ENUM:artists }} - {{ year }})',
boardgameFileNameTemplate: '{{ title }} ({{ year }})',
bookFileNameTemplate: '{{ title }} ({{ year }})',
movieFolder: 'Media DB/movies',
seriesFolder: 'Media DB/series',
seasonFolder: 'Media DB/series',
mangaFolder: 'Media DB/comics',
gameFolder: 'Media DB/games',
wikiFolder: 'Media DB/wiki',
musicReleaseFolder: 'Media DB/music',
boardgameFolder: 'Media DB/boardgames',
bookFolder: 'Media DB/books',
propertyMappingModels: [],
// DEPRECATED
moviePropertyConversionRules: '',
seriesPropertyConversionRules: '',
seasonPropertyConversionRules: '',
mangaPropertyConversionRules: '',
gamePropertyConversionRules: '',
wikiPropertyConversionRules: '',
musicReleasePropertyConversionRules: '',
boardgamePropertyConversionRules: '',
bookPropertyConversionRules: '',
};
export const lockedPropertyMappings: string[] = ['type', 'id', 'dataSource'];
export function getDefaultSettings(plugin: MediaDbPlugin): MediaDbPluginSettings {
const defaultSettings = DEFAULT_SETTINGS;
// construct property mapping defaults
const propertyMappingModels: PropertyMappingModelData[] = [];
for (const mediaType of MEDIA_TYPES) {
const model: MediaTypeModel = plugin.mediaTypeManager.createMediaTypeModelFromMediaType({}, mediaType);
const metadataObj = model.toMetaDataObject();
const propertyMappingModel: PropertyMappingModel = new PropertyMappingModel(mediaType);
for (const key of Object.keys(metadataObj)) {
propertyMappingModel.properties.push(
new PropertyMapping(
key,
'',
PropertyMappingOption.Default,
lockedPropertyMappings.includes(key),
false, // wikilink default
),
);
}
// Convert to plain data for serialization
propertyMappingModels.push(propertyMappingModel.toJSON());
}
defaultSettings.propertyMappingModels = propertyMappingModels;
return defaultSettings;
}
// MARK: Settings Tab
export class MediaDbSettingTab extends PluginSettingTab {
plugin: MediaDbPlugin;
private propertyMappingModelsComponent?: PropertyMappingModelsComponent;
constructor(app: App, plugin: MediaDbPlugin) {
super(app, plugin);
this.plugin = plugin;
}
override hide(): void {
this.propertyMappingModelsComponent?.unload();
this.propertyMappingModelsComponent = undefined;
super.hide();
}
display(): void {
const { containerEl } = this;
if (this.propertyMappingModelsComponent) {
this.propertyMappingModelsComponent.unload();
this.propertyMappingModelsComponent = undefined;
}
containerEl.empty();
const mediaTypeSettings = MEDIA_TYPES.map(mt => new MediaTypeMappedSettings(mt));
// MARK: General settings
const generalGroup = new SettingGroup(containerEl);
generalGroup.addSetting(
setting =>
void setting
.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;
void this.plugin.saveSettings();
});
}),
);
generalGroup.addSetting(
setting =>
void setting
.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;
void this.plugin.saveSettings();
});
}),
);
generalGroup.addSetting(
setting =>
void setting
.setName('Date format')
.setDesc(createDateFormatDescription(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;
const previewEl = activeDocument.getElementById('media-db-dateformat-preview');
if (previewEl) {
previewEl.textContent = this.plugin.dateFormatter.getPreview(newDateFormat); // update preview
}
void this.plugin.saveSettings();
});
}),
);
generalGroup.addSetting(
setting =>
void setting
.setName('Open note in new tab')
.setDesc('Open the newly created note in a new tab.')
.addToggle(cb => {
cb.setValue(this.plugin.settings.openNoteInNewTab).onChange(data => {
this.plugin.settings.openNoteInNewTab = data;
void this.plugin.saveSettings();
});
}),
);
generalGroup.addSetting(
setting =>
void setting
.setName('Use default front matter')
.setDesc('Whether 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;
void this.plugin.saveSettings();
// Redraw settings to display/remove the property mappings
this.display();
});
}),
);
generalGroup.addSetting(
setting =>
void setting
.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;
void this.plugin.saveSettings();
});
}),
);
generalGroup.addSetting(
setting =>
void setting
.setName('Download images')
.setDesc('Downloads images for new notes in the folder below')
.addToggle(cb => {
cb.setValue(this.plugin.settings.imageDownload).onChange(data => {
this.plugin.settings.imageDownload = data;
void this.plugin.saveSettings();
});
}),
);
generalGroup.addSetting(
setting =>
void setting
.setName('Image folder')
.setDesc('Where downloaded images should be stored.')
.addSearch(cb => {
const suggester = new FolderSuggest(this.app, cb.inputEl);
suggester.onSelect(folder => {
cb.setValue(folder.path);
this.plugin.settings.imageFolder = folder.path;
void this.plugin.saveSettings();
suggester.close();
});
cb.setPlaceholder(DEFAULT_SETTINGS.imageFolder)
.setValue(this.plugin.settings.imageFolder)
.onChange(data => {
this.plugin.settings.imageFolder = data;
void this.plugin.saveSettings();
});
}),
);
// MARK: API keys
const apiKeyGroup = new SettingGroup(containerEl);
apiKeyGroup.setHeading('API Keys');
apiKeyGroup.addSetting(
setting =>
void setting
.setName('OMDb API key')
.setDesc('API key for "www.omdbapi.com".')
.addComponent(el => {
const component = new SecretComponent(this.app, el);
component.setValue(this.plugin.settings.OMDbKeyId).onChange(data => {
this.plugin.settings.OMDbKeyId = data;
void this.plugin.saveSettings();
});
return component;
}),
);
apiKeyGroup.addSetting(
setting =>
void setting
.setName('TMDB API key')
.setDesc('API Read Access Token for "https://www.themoviedb.org".')
.addComponent(el => {
const component = new SecretComponent(this.app, el);
component.setValue(this.plugin.settings.TMDBKeyId).onChange(data => {
this.plugin.settings.TMDBKeyId = data;
void this.plugin.saveSettings();
});
return component;
}),
);
// apiKeyGroup.addSetting(
// setting =>
// void setting
// .setName('Moby Games key')
// .setDesc('API key for "www.mobygames.com".')
// .addComponent(el => {
// const component = new SecretComponent(this.app, el);
// component.setValue(this.plugin.settings.MobyGamesKeyId).onChange(data => {
// this.plugin.settings.MobyGamesKeyId = data;
// void this.plugin.saveSettings();
// });
// return component;
// }),
// );
// apiKeyGroup.addSetting(
// setting =>
// void setting
// .setName('Giant Bomb Key')
// .setDesc('API key for "www.giantbomb.com".')
// .addComponent(el => {
// const component = new SecretComponent(this.app, el);
// component.setValue(this.plugin.settings.GiantBombKeyId).onChange(data => {
// this.plugin.settings.GiantBombKeyId = data;
// void this.plugin.saveSettings();
// });
// return component;
// }),
// );
apiKeyGroup.addSetting(
setting =>
void setting
.setName('IGDB Client ID')
.setDesc('Client ID for IGDB API (Required for Twitch OAuth).')
.addComponent(el => {
const component = new SecretComponent(this.app, el);
component.setValue(this.plugin.settings.IGDBClientId).onChange(data => {
this.plugin.settings.IGDBClientId = data;
void this.plugin.saveSettings();
});
return component;
}),
);
apiKeyGroup.addSetting(
setting =>
void setting
.setName('IGDB Client Secret')
.setDesc('Client Secret for IGDB API.')
.addComponent(el => {
const component = new SecretComponent(this.app, el);
component.setValue(this.plugin.settings.IGDBClientSecret).onChange(data => {
this.plugin.settings.IGDBClientSecret = data;
void this.plugin.saveSettings();
});
return component;
}),
);
apiKeyGroup.addSetting(
setting =>
void setting
.setName('RAWG API Key')
.setDesc('API key for "rawg.io".')
.addComponent(el => {
const component = new SecretComponent(this.app, el);
component.setValue(this.plugin.settings.RAWGAPIKeyId).onChange(data => {
this.plugin.settings.RAWGAPIKeyId = data;
void this.plugin.saveSettings();
});
return component;
}),
);
apiKeyGroup.addSetting(
setting =>
void setting
.setName('Comic Vine Key')
.setDesc('API key for "www.comicvine.gamespot.com".')
.addComponent(el => {
const component = new SecretComponent(this.app, el);
component.setValue(this.plugin.settings.ComicVineKeyId).onChange(data => {
this.plugin.settings.ComicVineKeyId = data;
void this.plugin.saveSettings();
});
return component;
}),
);
apiKeyGroup.addSetting(
setting =>
void setting
.setName('Boardgame Geek Key')
.setDesc('API key for "www.boardgamegeek.com".')
.addComponent(el => {
const component = new SecretComponent(this.app, el);
component.setValue(this.plugin.settings.BoardgameGeekKeyId).onChange(data => {
this.plugin.settings.BoardgameGeekKeyId = data;
void this.plugin.saveSettings();
});
return component;
}),
);
// MARK: Media type settings
// Create a map to store APIs for each media type
const mediaTypeApiMap = new Map<MediaType, string[]>();
// Populate the map with APIs for each media type dynamically
for (const api of this.plugin.apiManager.apis) {
for (const mediaType of api.types) {
if (!mediaTypeApiMap.has(mediaType)) {
mediaTypeApiMap.set(mediaType, []);
}
mediaTypeApiMap.get(mediaType)!.push(api.apiName);
}
}
for (const mediaTypeSetting of mediaTypeSettings) {
const mediaTypeGroup = new SettingGroup(containerEl);
const mediaType = mediaTypeSetting.mediaType;
const mediaTypeName = unCamelCase(mediaTypeSetting.mediaType);
const mediaTypeNameLower = mediaTypeName.toLowerCase();
mediaTypeGroup.setHeading(`${mediaTypeName} settings`);
// Folder
mediaTypeGroup.addSetting(
setting =>
void setting
.setName(`Import Folder`)
.setDesc(`Where newly imported ${mediaTypeNameLower} should be placed.`)
.addSearch(cb => {
const suggester = new FolderSuggest(this.app, cb.inputEl);
suggester.onSelect(folder => {
cb.setValue(folder.path);
mediaTypeSetting.setFolder(this.plugin.settings, folder.path);
void this.plugin.saveSettings();
suggester.close();
});
cb.setPlaceholder(mediaTypeSetting.getFolder(DEFAULT_SETTINGS))
.setValue(mediaTypeSetting.getFolder(this.plugin.settings))
.onChange(data => {
mediaTypeSetting.setFolder(this.plugin.settings, data);
void this.plugin.saveSettings();
});
}),
);
// Template
mediaTypeGroup.addSetting(
setting =>
void setting
.setName(`Template`)
.setDesc(`Template file to be used when creating a new note for a ${mediaTypeNameLower}.`)
.addSearch(cb => {
const suggester = new FileSuggest(this.app, cb.inputEl);
suggester.onSelect(file => {
cb.setValue(file.path);
mediaTypeSetting.setTemplate(this.plugin.settings, file.path);
void this.plugin.saveSettings();
suggester.close();
});
cb.setPlaceholder(`Example: ${mediaTypeNameLower}Template.md`)
.setValue(mediaTypeSetting.getTemplate(this.plugin.settings))
.onChange(data => {
mediaTypeSetting.setTemplate(this.plugin.settings, data);
void this.plugin.saveSettings();
});
}),
);
// File name template
mediaTypeGroup.addSetting(
setting =>
void setting
.setName(`File name template`)
.setDesc(`Template for the file name used when creating a new note for a ${mediaTypeNameLower}.`)
.addText(cb => {
cb.setPlaceholder(`Example: ${mediaTypeSetting.getFileNameTemplate(DEFAULT_SETTINGS)}`)
.setValue(mediaTypeSetting.getFileNameTemplate(this.plugin.settings))
.onChange(data => {
mediaTypeSetting.setFileNameTemplate(this.plugin.settings, data);
void this.plugin.saveSettings();
});
}),
);
// APIs
const apis = mediaTypeApiMap.get(mediaType) ?? [];
if (apis.length > 1) {
for (const apiName of apis) {
const api = this.plugin.apiManager.apis.find(api => api.apiName === apiName);
if (api) {
const disabledMediaTypes = api.getDisabledMediaTypes();
mediaTypeGroup.addSetting(
setting =>
void setting
.setName(apiName)
.setDesc(`Use ${apiName} API for ${unCamelCase(mediaType)}.`)
.addToggle(cb => {
cb.setValue(!disabledMediaTypes.includes(mediaType)).onChange(data => {
if (data) {
const index = disabledMediaTypes.indexOf(mediaType);
if (index != -1) {
disabledMediaTypes.splice(index, 1);
}
} else {
disabledMediaTypes.push(mediaType);
}
void this.plugin.saveSettings();
});
}),
);
}
}
}
}
// MARK: Property mappings
if (this.plugin.settings.useDefaultFrontMatter) {
const mappingGroup = new SettingGroup(containerEl);
mappingGroup.setHeading('Property mappings');
mappingGroup.addSetting(setting => {
setting.setName('Property mappings explanation').setDesc(createPropertyMappingsDescription());
const propertyMappingsEl = setting.descEl.createDiv();
this.propertyMappingModelsComponent = new PropertyMappingModelsComponent(propertyMappingsEl, {
models: structuredClone(this.plugin.settings.propertyMappingModels),
save: (model: PropertyMappingModelData): void => {
// Update the matching model in settings (stored as plain data)
const index = this.plugin.settings.propertyMappingModels.findIndex(m => m.type === model.type);
if (index !== -1) {
this.plugin.settings.propertyMappingModels[index] = model;
}
new Notice(`MDB: Property mappings for ${model.type} saved successfully.`);
void this.plugin.saveSettings();
},
});
this.propertyMappingModelsComponent.load();
});
}
}
}