more changes for #48, the UI now works \o/
This commit is contained in:
parent
e00c5ce2c2
commit
14719efa22
17 changed files with 381 additions and 165 deletions
55
src/main.ts
55
src/main.ts
|
|
@ -1,5 +1,5 @@
|
||||||
import {Notice, parseYaml, Plugin, stringifyYaml, TFile, TFolder} from 'obsidian';
|
import {Notice, parseYaml, Plugin, stringifyYaml, TFile, TFolder} from 'obsidian';
|
||||||
import {DEFAULT_SETTINGS, MediaDbPluginSettings, MediaDbSettingTab} from './settings/Settings';
|
import {getDefaultSettings, MediaDbPluginSettings, MediaDbSettingTab} from './settings/Settings';
|
||||||
import {APIManager} from './api/APIManager';
|
import {APIManager} from './api/APIManager';
|
||||||
import {MediaTypeModel} from './models/MediaTypeModel';
|
import {MediaTypeModel} from './models/MediaTypeModel';
|
||||||
import {dateTimeToString, debugLog, markdownTable, replaceIllegalFileNameCharactersInString, UserCancelError, UserSkipError} from './utils/Utils';
|
import {dateTimeToString, debugLog, markdownTable, replaceIllegalFileNameCharactersInString, UserCancelError, UserSkipError} from './utils/Utils';
|
||||||
|
|
@ -16,6 +16,7 @@ import {BoardGameGeekAPI} from './api/apis/BoardGameGeekAPI';
|
||||||
import {PropertyMapper} from './settings/PropertyMapper';
|
import {PropertyMapper} from './settings/PropertyMapper';
|
||||||
import {YAMLConverter} from './utils/YAMLConverter';
|
import {YAMLConverter} from './utils/YAMLConverter';
|
||||||
import {MediaDbFolderImportModal} from './modals/MediaDbFolderImportModal';
|
import {MediaDbFolderImportModal} from './modals/MediaDbFolderImportModal';
|
||||||
|
import {PropertyMapping, PropertyMappingModel} from './settings/PropertyMapping';
|
||||||
|
|
||||||
export default class MediaDbPlugin extends Plugin {
|
export default class MediaDbPlugin extends Plugin {
|
||||||
settings: MediaDbPluginSettings;
|
settings: MediaDbPluginSettings;
|
||||||
|
|
@ -26,14 +27,6 @@ export default class MediaDbPlugin extends Plugin {
|
||||||
frontMatterRexExpPattern: string = '^(---)\\n[\\s\\S]*?\\n---';
|
frontMatterRexExpPattern: string = '^(---)\\n[\\s\\S]*?\\n---';
|
||||||
|
|
||||||
async onload() {
|
async onload() {
|
||||||
await this.loadSettings();
|
|
||||||
// register the settings tab
|
|
||||||
this.addSettingTab(new MediaDbSettingTab(this.app, this));
|
|
||||||
|
|
||||||
// TESTING
|
|
||||||
this.settings.propertyMappings = DEFAULT_SETTINGS.propertyMappings;
|
|
||||||
|
|
||||||
|
|
||||||
this.apiManager = new APIManager();
|
this.apiManager = new APIManager();
|
||||||
// register APIs
|
// register APIs
|
||||||
this.apiManager.registerAPI(new OMDbAPI(this));
|
this.apiManager.registerAPI(new OMDbAPI(this));
|
||||||
|
|
@ -44,9 +37,18 @@ export default class MediaDbPlugin extends Plugin {
|
||||||
this.apiManager.registerAPI(new BoardGameGeekAPI(this));
|
this.apiManager.registerAPI(new BoardGameGeekAPI(this));
|
||||||
// this.apiManager.registerAPI(new LocGovAPI(this)); // TODO: parse data
|
// this.apiManager.registerAPI(new LocGovAPI(this)); // TODO: parse data
|
||||||
|
|
||||||
this.mediaTypeManager = new MediaTypeManager(this.settings);
|
this.mediaTypeManager = new MediaTypeManager();
|
||||||
this.modelPropertyMapper = new PropertyMapper(this);
|
this.modelPropertyMapper = new PropertyMapper(this);
|
||||||
|
|
||||||
|
await this.loadSettings();
|
||||||
|
// register the settings tab
|
||||||
|
this.addSettingTab(new MediaDbSettingTab(this.app, this));
|
||||||
|
|
||||||
|
// TESTING
|
||||||
|
// this.settings.propertyMappingModels = getDefaultSettings(this).propertyMappingModels;
|
||||||
|
|
||||||
|
this.mediaTypeManager.updateTemplates(this.settings);
|
||||||
|
|
||||||
|
|
||||||
// add icon to the left ribbon
|
// add icon to the left ribbon
|
||||||
const ribbonIconEl = this.addRibbonIcon('database', 'Add new Media DB entry', (evt: MouseEvent) =>
|
const ribbonIconEl = this.addRibbonIcon('database', 'Add new Media DB entry', (evt: MouseEvent) =>
|
||||||
|
|
@ -491,8 +493,37 @@ export default class MediaDbPlugin extends Plugin {
|
||||||
}
|
}
|
||||||
|
|
||||||
async loadSettings() {
|
async loadSettings() {
|
||||||
console.log(DEFAULT_SETTINGS);
|
// console.log(DEFAULT_SETTINGS);
|
||||||
this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData());
|
const diskSettings: MediaDbPluginSettings = await this.loadData();
|
||||||
|
const defaultSettings: MediaDbPluginSettings = getDefaultSettings(this);
|
||||||
|
const loadedSettings: MediaDbPluginSettings = Object.assign({}, defaultSettings, diskSettings);
|
||||||
|
|
||||||
|
// migrate the settings loaded from the disk to match the structure of the default settings
|
||||||
|
let newPropertyMappings: PropertyMappingModel[] = [];
|
||||||
|
for (const defaultPropertyMappingModel of defaultSettings.propertyMappingModels) {
|
||||||
|
let newPropertyMappingModel: PropertyMappingModel = loadedSettings.propertyMappingModels.find(x => x.type === defaultPropertyMappingModel.type);
|
||||||
|
if (newPropertyMappingModel === undefined) { // if the propertyMappingModel exists in the default settings but not the loaded settings, add it
|
||||||
|
newPropertyMappings.push(defaultPropertyMappingModel);
|
||||||
|
} else { // if the propertyMappingModel also exists in the loaded settings, add it from there
|
||||||
|
let newProperties: PropertyMapping[] = [];
|
||||||
|
|
||||||
|
for (const defaultProperty of defaultPropertyMappingModel.properties) {
|
||||||
|
let newProperty = newPropertyMappingModel.properties.find(x => x.property === defaultProperty.property);
|
||||||
|
if (newProperty === undefined) {
|
||||||
|
newProperties.push(defaultProperty);
|
||||||
|
} else {
|
||||||
|
newProperties.push(newProperty);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
newPropertyMappingModel.properties = newProperties;
|
||||||
|
|
||||||
|
newPropertyMappings.push(newPropertyMappingModel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
loadedSettings.propertyMappingModels = newPropertyMappings;
|
||||||
|
|
||||||
|
this.settings = loadedSettings;
|
||||||
}
|
}
|
||||||
|
|
||||||
async saveSettings() {
|
async saveSettings() {
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,15 @@ export class BoardGameModel extends MediaTypeModel {
|
||||||
constructor(obj: any = {}) {
|
constructor(obj: any = {}) {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
|
this.genres = undefined;
|
||||||
|
this.onlineRating = undefined;
|
||||||
|
this.image = undefined;
|
||||||
|
this.released = undefined;
|
||||||
|
this.userData = {
|
||||||
|
played: undefined,
|
||||||
|
personalRating: undefined,
|
||||||
|
};
|
||||||
|
|
||||||
Object.assign(this, obj);
|
Object.assign(this, obj);
|
||||||
|
|
||||||
this.type = this.getMediaType();
|
this.type = this.getMediaType();
|
||||||
|
|
|
||||||
|
|
@ -4,15 +4,6 @@ import {MediaType} from '../utils/MediaType';
|
||||||
|
|
||||||
|
|
||||||
export class GameModel extends MediaTypeModel {
|
export class GameModel extends MediaTypeModel {
|
||||||
type: string;
|
|
||||||
subType: string;
|
|
||||||
title: string;
|
|
||||||
englishTitle: string;
|
|
||||||
year: string;
|
|
||||||
dataSource: string;
|
|
||||||
url: string;
|
|
||||||
id: string;
|
|
||||||
|
|
||||||
genres: string[];
|
genres: string[];
|
||||||
onlineRating: number;
|
onlineRating: number;
|
||||||
image: string;
|
image: string;
|
||||||
|
|
@ -29,6 +20,16 @@ export class GameModel extends MediaTypeModel {
|
||||||
constructor(obj: any = {}) {
|
constructor(obj: any = {}) {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
|
this.genres = undefined;
|
||||||
|
this.onlineRating = undefined;
|
||||||
|
this.image = undefined;
|
||||||
|
this.released = undefined;
|
||||||
|
this.releaseDate = undefined;
|
||||||
|
this.userData = {
|
||||||
|
played: undefined,
|
||||||
|
personalRating: undefined,
|
||||||
|
};
|
||||||
|
|
||||||
Object.assign(this, obj);
|
Object.assign(this, obj);
|
||||||
|
|
||||||
this.type = this.getMediaType();
|
this.type = this.getMediaType();
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,19 @@ export abstract class MediaTypeModel {
|
||||||
|
|
||||||
userData: object;
|
userData: object;
|
||||||
|
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.type = undefined;
|
||||||
|
this.subType = undefined;
|
||||||
|
this.title = undefined;
|
||||||
|
this.englishTitle = undefined;
|
||||||
|
this.year = undefined;
|
||||||
|
this.dataSource = undefined;
|
||||||
|
this.url = undefined;
|
||||||
|
this.id = undefined;
|
||||||
|
this.userData = {};
|
||||||
|
}
|
||||||
|
|
||||||
abstract getMediaType(): MediaType;
|
abstract getMediaType(): MediaType;
|
||||||
|
|
||||||
//a string that contains enough info to disambiguate from similar media
|
//a string that contains enough info to disambiguate from similar media
|
||||||
|
|
@ -24,7 +37,7 @@ export abstract class MediaTypeModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
getWithOutUserData(): object {
|
getWithOutUserData(): object {
|
||||||
const copy = JSON.parse(JSON.stringify(this));
|
const copy = Object.assign({}, this);
|
||||||
delete copy.userData;
|
delete copy.userData;
|
||||||
return copy;
|
return copy;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,15 +4,6 @@ import {MediaType} from '../utils/MediaType';
|
||||||
|
|
||||||
|
|
||||||
export class MovieModel extends MediaTypeModel {
|
export class MovieModel extends MediaTypeModel {
|
||||||
type: string;
|
|
||||||
subType: string;
|
|
||||||
title: string;
|
|
||||||
englishTitle: string;
|
|
||||||
year: string;
|
|
||||||
dataSource: string;
|
|
||||||
url: string;
|
|
||||||
id: string;
|
|
||||||
|
|
||||||
genres: string[];
|
genres: string[];
|
||||||
producer: string;
|
producer: string;
|
||||||
duration: string;
|
duration: string;
|
||||||
|
|
@ -31,6 +22,19 @@ export class MovieModel extends MediaTypeModel {
|
||||||
constructor(obj: any = {}) {
|
constructor(obj: any = {}) {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
|
this.genres = undefined;
|
||||||
|
this.producer = undefined;
|
||||||
|
this.duration = undefined;
|
||||||
|
this.onlineRating = undefined;
|
||||||
|
this.image = undefined;
|
||||||
|
this.released = undefined;
|
||||||
|
this.premiere = undefined;
|
||||||
|
this.userData = {
|
||||||
|
watched: undefined,
|
||||||
|
lastWatched: undefined,
|
||||||
|
personalRating: undefined,
|
||||||
|
};
|
||||||
|
|
||||||
Object.assign(this, obj);
|
Object.assign(this, obj);
|
||||||
|
|
||||||
this.type = this.getMediaType();
|
this.type = this.getMediaType();
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,13 @@ export class MusicReleaseModel extends MediaTypeModel {
|
||||||
constructor(obj: any = {}) {
|
constructor(obj: any = {}) {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
|
this.genres = undefined;
|
||||||
|
this.artists = undefined;
|
||||||
|
this.rating = undefined;
|
||||||
|
this.userData = {
|
||||||
|
personalRating: undefined,
|
||||||
|
};
|
||||||
|
|
||||||
Object.assign(this, obj);
|
Object.assign(this, obj);
|
||||||
|
|
||||||
this.type = this.getMediaType();
|
this.type = this.getMediaType();
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,22 @@ export class SeriesModel extends MediaTypeModel {
|
||||||
constructor(obj: any = {}) {
|
constructor(obj: any = {}) {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
|
this.genres = undefined;
|
||||||
|
this.studios = undefined;
|
||||||
|
this.episodes = undefined;
|
||||||
|
this.duration = undefined;
|
||||||
|
this.onlineRating = undefined;
|
||||||
|
this.image = undefined;
|
||||||
|
this.released = undefined;
|
||||||
|
this.airing = undefined;
|
||||||
|
this.airedFrom = undefined;
|
||||||
|
this.airedTo = undefined;
|
||||||
|
this.userData = {
|
||||||
|
watched: undefined,
|
||||||
|
lastWatched: undefined,
|
||||||
|
personalRating: undefined,
|
||||||
|
};
|
||||||
|
|
||||||
Object.assign(this, obj);
|
Object.assign(this, obj);
|
||||||
|
|
||||||
this.type = this.getMediaType();
|
this.type = this.getMediaType();
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,12 @@ export class WikiModel extends MediaTypeModel {
|
||||||
constructor(obj: any = {}) {
|
constructor(obj: any = {}) {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
|
this.wikiUrl = undefined;
|
||||||
|
this.lastUpdated = undefined;
|
||||||
|
this.length = undefined;
|
||||||
|
this.article = undefined;
|
||||||
|
this.userData = {};
|
||||||
|
|
||||||
Object.assign(this, obj);
|
Object.assign(this, obj);
|
||||||
|
|
||||||
this.type = this.getMediaType();
|
this.type = this.getMediaType();
|
||||||
|
|
@ -37,7 +43,7 @@ export class WikiModel extends MediaTypeModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
override getWithOutUserData(): object {
|
override getWithOutUserData(): object {
|
||||||
const copy = JSON.parse(JSON.stringify(this));
|
const copy = Object.assign({}, this);
|
||||||
delete copy.userData;
|
delete copy.userData;
|
||||||
delete copy.article;
|
delete copy.article;
|
||||||
return copy;
|
return copy;
|
||||||
|
|
|
||||||
36
src/settings/Icon.svelte
Normal file
36
src/settings/Icon.svelte
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
<!--adapted from @joethei's code: https://github.com/joethei/obsidian-rss/blob/master/src/view/IconComponent.svelte-->
|
||||||
|
<!--adapted from @javalent's code: https://discord.com/channels/686053708261228577/840286264964022302/902949764209987654-->
|
||||||
|
<script lang="ts">
|
||||||
|
import {setIcon} from 'obsidian';
|
||||||
|
import {onMount} from 'svelte';
|
||||||
|
|
||||||
|
export let iconName: string = '';
|
||||||
|
export let iconSize: number = 20;
|
||||||
|
|
||||||
|
let iconEl: HTMLElement;
|
||||||
|
|
||||||
|
onMount(() => {
|
||||||
|
setIcon(iconEl, iconName, iconSize);
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.icon-wrapper {
|
||||||
|
display: inline-block;
|
||||||
|
position: relative;
|
||||||
|
width: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
position: absolute;
|
||||||
|
height: 20px;
|
||||||
|
width: 20px;
|
||||||
|
top: calc(50% - 10px);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
{#if iconName.length > 0}
|
||||||
|
<div class="icon-wrapper">
|
||||||
|
<div bind:this={iconEl} class="icon"></div>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
|
@ -1,74 +0,0 @@
|
||||||
<script lang="ts">
|
|
||||||
import {capitalizeFirstLetter} from '../utils/Utils';
|
|
||||||
import {PropertyMappingModel, PropertyMappingOption, propertyMappingOptions} from './PropertyMapping';
|
|
||||||
|
|
||||||
export let models: PropertyMappingModel[] = [];
|
|
||||||
|
|
||||||
export let save: (models: PropertyMappingModel[]) => void;
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
.media-db-plugin-property-mappings-container {
|
|
||||||
margin: 10px 0;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.media-db-plugin-property-mapping-element {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
gap: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.media-db-plugin-property-mapping-element-property-name-wrapper {
|
|
||||||
min-width: 160px;
|
|
||||||
background: var(--background-modifier-form-field);
|
|
||||||
padding: 2px 5px;
|
|
||||||
border-radius: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.media-db-plugin-property-mapping-element-property-name {
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<div class="setting-item" style="display: block;">
|
|
||||||
{ #each models as model }
|
|
||||||
<div class="setting-item-name">{capitalizeFirstLetter(model.type)}</div>
|
|
||||||
<div class="media-db-plugin-property-mappings-container">
|
|
||||||
{ #each model.properties as property }
|
|
||||||
<div class="media-db-plugin-property-mapping-element">
|
|
||||||
<div class="media-db-plugin-property-mapping-element-property-name-wrapper">
|
|
||||||
<pre
|
|
||||||
class="media-db-plugin-property-mapping-element-property-name"><code>{property.property}</code></pre>
|
|
||||||
</div>
|
|
||||||
{#if property.locked}
|
|
||||||
<div class="media-db-plugin-property-binding-text">
|
|
||||||
property can not be remapped
|
|
||||||
</div>
|
|
||||||
{:else}
|
|
||||||
<select bind:value={property.mapping}>
|
|
||||||
{#each propertyMappingOptions as remappingOption}
|
|
||||||
<option value={remappingOption}>
|
|
||||||
{remappingOption}
|
|
||||||
</option>
|
|
||||||
{/each}
|
|
||||||
</select>
|
|
||||||
|
|
||||||
{#if property.mapping === PropertyMappingOption.Map}
|
|
||||||
<div class="media-db-plugin-property-mapping-text">
|
|
||||||
->
|
|
||||||
</div>
|
|
||||||
<div class="media-db-plugin-property-binding-to">
|
|
||||||
<input type="text" spellcheck="false" bind:value="{property.newProperty}">
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
||||||
{/if}
|
|
||||||
</div>
|
|
||||||
{ /each }
|
|
||||||
</div>
|
|
||||||
{ /each }
|
|
||||||
|
|
||||||
<pre>{JSON.stringify(models, null, 4)}</pre>
|
|
||||||
</div>
|
|
||||||
|
|
@ -26,7 +26,7 @@ export class PropertyMapper {
|
||||||
}
|
}
|
||||||
|
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
const propertyMappings = this.plugin.settings.propertyMappings.find(x => x.type === obj.type).properties;
|
const propertyMappings = this.plugin.settings.propertyMappingModels.find(x => x.type === obj.type).properties;
|
||||||
|
|
||||||
const newObj: object = {};
|
const newObj: object = {};
|
||||||
|
|
||||||
|
|
@ -38,7 +38,7 @@ export class PropertyMapper {
|
||||||
newObj[propertyMapping.newProperty] = value;
|
newObj[propertyMapping.newProperty] = value;
|
||||||
} else if (propertyMapping.mapping === PropertyMappingOption.Remove) {
|
} else if (propertyMapping.mapping === PropertyMappingOption.Remove) {
|
||||||
|
|
||||||
} else if (propertyMapping.mapping === PropertyMappingOption.None) {
|
} else if (propertyMapping.mapping === PropertyMappingOption.Default) {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
newObj[key] = value;
|
newObj[key] = value;
|
||||||
}
|
}
|
||||||
|
|
@ -67,7 +67,7 @@ export class PropertyMapper {
|
||||||
}
|
}
|
||||||
|
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
const propertyMappings = this.plugin.settings.propertyMappings.find(x => x.type === obj.type).properties;
|
const propertyMappings = this.plugin.settings.propertyMappingModels.find(x => x.type === obj.type).properties;
|
||||||
|
|
||||||
const originalObj: object = {};
|
const originalObj: object = {};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,12 +2,12 @@ import {containsOnlyLettersAndUnderscores} from '../utils/Utils';
|
||||||
import {MediaType} from '../utils/MediaType';
|
import {MediaType} from '../utils/MediaType';
|
||||||
|
|
||||||
export enum PropertyMappingOption {
|
export enum PropertyMappingOption {
|
||||||
None = 'none',
|
Default = 'default',
|
||||||
Map = 'remap',
|
Map = 'remap',
|
||||||
Remove = 'remove',
|
Remove = 'remove',
|
||||||
}
|
}
|
||||||
|
|
||||||
export const propertyMappingOptions = [PropertyMappingOption.None, PropertyMappingOption.Map, PropertyMappingOption.Remove];
|
export const propertyMappingOptions = [PropertyMappingOption.Default, PropertyMappingOption.Map, PropertyMappingOption.Remove];
|
||||||
|
|
||||||
export interface PropertyMappingModel {
|
export interface PropertyMappingModel {
|
||||||
type: MediaType,
|
type: MediaType,
|
||||||
|
|
@ -62,7 +62,7 @@ export class PropertyMapping {
|
||||||
}
|
}
|
||||||
|
|
||||||
toString(): string {
|
toString(): string {
|
||||||
if (this.mapping === PropertyMappingOption.None) {
|
if (this.mapping === PropertyMappingOption.Default) {
|
||||||
return this.property;
|
return this.property;
|
||||||
} else if (this.mapping === PropertyMappingOption.Map) {
|
} else if (this.mapping === PropertyMappingOption.Map) {
|
||||||
return `${this.property} -> ${this.newProperty}`;
|
return `${this.property} -> ${this.newProperty}`;
|
||||||
|
|
|
||||||
106
src/settings/PropertyMappingModelsComponent.svelte
Normal file
106
src/settings/PropertyMappingModelsComponent.svelte
Normal file
|
|
@ -0,0 +1,106 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import {capitalizeFirstLetter} from '../utils/Utils';
|
||||||
|
import {PropertyMappingModel, PropertyMappingOption, propertyMappingOptions} from './PropertyMapping';
|
||||||
|
import Icon from './Icon.svelte';
|
||||||
|
|
||||||
|
export let models: PropertyMappingModel[] = [];
|
||||||
|
|
||||||
|
export let save: (model: PropertyMappingModel) => void;
|
||||||
|
|
||||||
|
// TODO: validate all the mappings before saving.
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.media-db-plugin-property-mappings-model-container {
|
||||||
|
border: 1px solid var(--background-modifier-border);
|
||||||
|
border-radius: 5px;
|
||||||
|
padding: 10px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.media-db-plugin-property-mappings-container {
|
||||||
|
margin: 10px 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.media-db-plugin-property-mapping-element {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.media-db-plugin-property-mapping-element-property-name-wrapper {
|
||||||
|
min-width: 160px;
|
||||||
|
background: var(--background-modifier-form-field);
|
||||||
|
padding: 2px 5px;
|
||||||
|
border-radius: 5px;
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.media-db-plugin-property-mapping-element-property-name {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.media-db-plugin-property-mappings-save-button {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.media-db-plugin-property-binding-to {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<div class="setting-item" style="display: flex; gap: 10px; flex-direction: column; align-items: stretch;">
|
||||||
|
{ #each models as model }
|
||||||
|
<div class="media-db-plugin-property-mappings-model-container">
|
||||||
|
<div class="setting-item-name">{capitalizeFirstLetter(model.type)}</div>
|
||||||
|
<div class="media-db-plugin-property-mappings-container">
|
||||||
|
{ #each model.properties as property }
|
||||||
|
<div class="media-db-plugin-property-mapping-element">
|
||||||
|
<div class="media-db-plugin-property-mapping-element-property-name-wrapper">
|
||||||
|
<pre
|
||||||
|
class="media-db-plugin-property-mapping-element-property-name"><code>{property.property}</code></pre>
|
||||||
|
</div>
|
||||||
|
{#if property.locked}
|
||||||
|
<div class="media-db-plugin-property-binding-text">
|
||||||
|
property can not be remapped
|
||||||
|
</div>
|
||||||
|
{:else}
|
||||||
|
<select class="dropdown" bind:value={property.mapping}>
|
||||||
|
{#each propertyMappingOptions as remappingOption}
|
||||||
|
<option value={remappingOption}>
|
||||||
|
{remappingOption}
|
||||||
|
</option>
|
||||||
|
{/each}
|
||||||
|
</select>
|
||||||
|
|
||||||
|
{#if property.mapping === PropertyMappingOption.Map}
|
||||||
|
<Icon iconName="arrow-right"/>
|
||||||
|
<div class="media-db-plugin-property-binding-to">
|
||||||
|
<input type="text" spellcheck="false" bind:value="{property.newProperty}">
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
{/if}
|
||||||
|
</div>
|
||||||
|
{ /each }
|
||||||
|
</div>
|
||||||
|
<button class="mod-cta media-db-plugin-property-mappings-save-button" on:click={() => save(model)}>Save
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
{ /each }
|
||||||
|
|
||||||
|
<pre>{JSON.stringify(models, null, 4)}</pre>
|
||||||
|
|
||||||
|
<!--
|
||||||
|
{ #each ICON_LIST as icon }
|
||||||
|
<p>
|
||||||
|
{icon} <Icon iconName="{icon}"/>
|
||||||
|
</p>
|
||||||
|
{/each}
|
||||||
|
-->
|
||||||
|
</div>
|
||||||
|
|
@ -1,11 +1,12 @@
|
||||||
import {App, PluginSettingTab, Setting} from 'obsidian';
|
import {App, Notice, PluginSettingTab, Setting} from 'obsidian';
|
||||||
|
|
||||||
import MediaDbPlugin from '../main';
|
import MediaDbPlugin from '../main';
|
||||||
import {FolderSuggest} from './suggesters/FolderSuggest';
|
import {FolderSuggest} from './suggesters/FolderSuggest';
|
||||||
import {FileSuggest} from './suggesters/FileSuggest';
|
import {FileSuggest} from './suggesters/FileSuggest';
|
||||||
import PropertyBindingsComponent from './PropertyBindingsComponent.svelte';
|
import PropertyMappingModelsComponent from './PropertyMappingModelsComponent.svelte';
|
||||||
import {PropertyMapping, PropertyMappingModel, PropertyMappingOption} from './PropertyMapping';
|
import {PropertyMapping, PropertyMappingModel, PropertyMappingOption} from './PropertyMapping';
|
||||||
import {MediaType} from '../utils/MediaType';
|
import {MEDIA_TYPES} from '../utils/MediaTypeManager';
|
||||||
|
import {MediaTypeModel} from '../models/MediaTypeModel';
|
||||||
|
|
||||||
|
|
||||||
export interface MediaDbPluginSettings {
|
export interface MediaDbPluginSettings {
|
||||||
|
|
@ -37,7 +38,7 @@ export interface MediaDbPluginSettings {
|
||||||
musicReleasePropertyConversionRules: string,
|
musicReleasePropertyConversionRules: string,
|
||||||
boardgamePropertyConversionRules: string,
|
boardgamePropertyConversionRules: string,
|
||||||
|
|
||||||
propertyMappings: PropertyMappingModel[],
|
propertyMappingModels: PropertyMappingModel[],
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -69,62 +70,96 @@ export const DEFAULT_SETTINGS: MediaDbPluginSettings = {
|
||||||
musicReleasePropertyConversionRules: '',
|
musicReleasePropertyConversionRules: '',
|
||||||
boardgamePropertyConversionRules: '',
|
boardgamePropertyConversionRules: '',
|
||||||
|
|
||||||
propertyMappings: [
|
propertyMappingModels: [
|
||||||
|
/*
|
||||||
{
|
{
|
||||||
type: MediaType.Movie,
|
type: MediaType.Movie,
|
||||||
properties: [
|
properties: [
|
||||||
new PropertyMapping('type', '', PropertyMappingOption.None, true),
|
new PropertyMapping('type', '', PropertyMappingOption.Default, true),
|
||||||
new PropertyMapping('subType', '', PropertyMappingOption.None),
|
new PropertyMapping('subType', '', PropertyMappingOption.Default),
|
||||||
new PropertyMapping('title', '', PropertyMappingOption.None),
|
new PropertyMapping('title', '', PropertyMappingOption.Default),
|
||||||
new PropertyMapping('englishTitle', '', PropertyMappingOption.None),
|
new PropertyMapping('englishTitle', '', PropertyMappingOption.Default),
|
||||||
new PropertyMapping('year', '', PropertyMappingOption.None),
|
new PropertyMapping('year', '', PropertyMappingOption.Default),
|
||||||
new PropertyMapping('dataSource', '', PropertyMappingOption.None, true),
|
new PropertyMapping('dataSource', '', PropertyMappingOption.Default, true),
|
||||||
new PropertyMapping('url', '', PropertyMappingOption.None),
|
new PropertyMapping('url', '', PropertyMappingOption.Default),
|
||||||
new PropertyMapping('id', '', PropertyMappingOption.None, true),
|
new PropertyMapping('id', '', PropertyMappingOption.Default, true),
|
||||||
|
|
||||||
new PropertyMapping('genres', '', PropertyMappingOption.None),
|
new PropertyMapping('genres', '', PropertyMappingOption.Default),
|
||||||
new PropertyMapping('producer', '', PropertyMappingOption.None),
|
new PropertyMapping('producer', '', PropertyMappingOption.Default),
|
||||||
new PropertyMapping('duration', '', PropertyMappingOption.None),
|
new PropertyMapping('duration', '', PropertyMappingOption.Default),
|
||||||
new PropertyMapping('onlineRating', '', PropertyMappingOption.None),
|
new PropertyMapping('onlineRating', '', PropertyMappingOption.Default),
|
||||||
new PropertyMapping('image', '', PropertyMappingOption.None),
|
new PropertyMapping('image', '', PropertyMappingOption.Default),
|
||||||
new PropertyMapping('released', '', PropertyMappingOption.None),
|
new PropertyMapping('released', '', PropertyMappingOption.Default),
|
||||||
new PropertyMapping('premiere', '', PropertyMappingOption.None),
|
new PropertyMapping('premiere', '', PropertyMappingOption.Default),
|
||||||
new PropertyMapping('watched', '', PropertyMappingOption.None),
|
new PropertyMapping('watched', '', PropertyMappingOption.Default),
|
||||||
new PropertyMapping('lastWatched', '', PropertyMappingOption.None),
|
new PropertyMapping('lastWatched', '', PropertyMappingOption.Default),
|
||||||
new PropertyMapping('personalRating', '', PropertyMappingOption.None),
|
new PropertyMapping('personalRating', '', PropertyMappingOption.Default),
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: MediaType.Series,
|
type: MediaType.Series,
|
||||||
properties: [
|
properties: [
|
||||||
new PropertyMapping('type', '', PropertyMappingOption.None, true),
|
new PropertyMapping('type', '', PropertyMappingOption.Default, true),
|
||||||
new PropertyMapping('subType', '', PropertyMappingOption.None),
|
new PropertyMapping('subType', '', PropertyMappingOption.Default),
|
||||||
new PropertyMapping('title', '', PropertyMappingOption.None),
|
new PropertyMapping('title', '', PropertyMappingOption.Default),
|
||||||
new PropertyMapping('englishTitle', '', PropertyMappingOption.None),
|
new PropertyMapping('englishTitle', '', PropertyMappingOption.Default),
|
||||||
new PropertyMapping('year', '', PropertyMappingOption.None),
|
new PropertyMapping('year', '', PropertyMappingOption.Default),
|
||||||
new PropertyMapping('dataSource', '', PropertyMappingOption.None, true),
|
new PropertyMapping('dataSource', '', PropertyMappingOption.Default, true),
|
||||||
new PropertyMapping('url', '', PropertyMappingOption.None),
|
new PropertyMapping('url', '', PropertyMappingOption.Default),
|
||||||
new PropertyMapping('id', '', PropertyMappingOption.None, true),
|
new PropertyMapping('id', '', PropertyMappingOption.Default, true),
|
||||||
|
|
||||||
new PropertyMapping('genres', '', PropertyMappingOption.None),
|
new PropertyMapping('genres', '', PropertyMappingOption.Default),
|
||||||
new PropertyMapping('studios', '', PropertyMappingOption.None),
|
new PropertyMapping('studios', '', PropertyMappingOption.Default),
|
||||||
new PropertyMapping('episodes', '', PropertyMappingOption.None),
|
new PropertyMapping('episodes', '', PropertyMappingOption.Default),
|
||||||
new PropertyMapping('duration', '', PropertyMappingOption.None),
|
new PropertyMapping('duration', '', PropertyMappingOption.Default),
|
||||||
new PropertyMapping('onlineRating', '', PropertyMappingOption.None),
|
new PropertyMapping('onlineRating', '', PropertyMappingOption.Default),
|
||||||
new PropertyMapping('image', '', PropertyMappingOption.None),
|
new PropertyMapping('image', '', PropertyMappingOption.Default),
|
||||||
new PropertyMapping('released', '', PropertyMappingOption.None),
|
new PropertyMapping('released', '', PropertyMappingOption.Default),
|
||||||
new PropertyMapping('airing', '', PropertyMappingOption.None),
|
new PropertyMapping('airing', '', PropertyMappingOption.Default),
|
||||||
new PropertyMapping('airedFrom', '', PropertyMappingOption.None),
|
new PropertyMapping('airedFrom', '', PropertyMappingOption.Default),
|
||||||
new PropertyMapping('airedTo', '', PropertyMappingOption.None),
|
new PropertyMapping('airedTo', '', PropertyMappingOption.Default),
|
||||||
new PropertyMapping('watched', '', PropertyMappingOption.None),
|
new PropertyMapping('watched', '', PropertyMappingOption.Default),
|
||||||
new PropertyMapping('lastWatched', '', PropertyMappingOption.None),
|
new PropertyMapping('lastWatched', '', PropertyMappingOption.Default),
|
||||||
new PropertyMapping('personalRating', '', PropertyMappingOption.None),
|
new PropertyMapping('personalRating', '', PropertyMappingOption.Default),
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|
||||||
|
*/
|
||||||
],
|
],
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const lockedPropertyMappings: string[] = ['type', 'id', 'dataSource'];
|
||||||
|
|
||||||
|
export function getDefaultSettings(plugin: MediaDbPlugin): MediaDbPluginSettings {
|
||||||
|
let 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 = {
|
||||||
|
type: mediaType,
|
||||||
|
properties: [],
|
||||||
|
};
|
||||||
|
|
||||||
|
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 {
|
export class MediaDbSettingTab extends PluginSettingTab {
|
||||||
plugin: MediaDbPlugin;
|
plugin: MediaDbPlugin;
|
||||||
|
|
||||||
|
|
@ -433,14 +468,38 @@ export class MediaDbSettingTab extends PluginSettingTab {
|
||||||
*/
|
*/
|
||||||
// endregion
|
// endregion
|
||||||
|
|
||||||
console.log(this.plugin.settings.propertyMappings);
|
console.log(this.plugin.settings.propertyMappingModels);
|
||||||
|
// console.log(getDefaultSettings(this.plugin));
|
||||||
|
|
||||||
new PropertyBindingsComponent({
|
let propertyMappingExplanation = containerEl.createEl('div');
|
||||||
|
propertyMappingExplanation.innerHTML = `<p>Allow you to remap the metadata fields of newly created media db entries.</p>
|
||||||
|
<p>
|
||||||
|
The different options are:
|
||||||
|
<lu>
|
||||||
|
<li>"default": does no remapping and keeps the metadata field as it is</li>
|
||||||
|
<li>"remap": renames the metadata field to what ever you specify</li>
|
||||||
|
<li>"remove": removes the metadata field entirely</li>
|
||||||
|
</lu>
|
||||||
|
</p>`;
|
||||||
|
|
||||||
|
|
||||||
|
new PropertyMappingModelsComponent({
|
||||||
target: this.containerEl,
|
target: this.containerEl,
|
||||||
props: {
|
props: {
|
||||||
models: this.plugin.settings.propertyMappings,
|
models: JSON.parse(JSON.stringify(this.plugin.settings.propertyMappingModels)),
|
||||||
save: (models: PropertyMappingModel[]) => {
|
save: (model: PropertyMappingModel) => {
|
||||||
this.plugin.settings.propertyMappings = models;
|
let 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();
|
this.plugin.saveSettings();
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -80,7 +80,7 @@ export class Suggest<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
setSelectedItem(selectedIndex: number, scrollIntoView: boolean) {
|
setSelectedItem(selectedIndex: number, scrollIntoView: boolean) {
|
||||||
const normalizedIndex = wrapAround(selectedIndex, this.suggestions.length);
|
const normalizedIndex = this.suggestions.length > 0 ? wrapAround(selectedIndex, this.suggestions.length) : 0;
|
||||||
const prevSelectedSuggestion = this.suggestions[this.selectedItem];
|
const prevSelectedSuggestion = this.suggestions[this.selectedItem];
|
||||||
const selectedSuggestion = this.suggestions[normalizedIndex];
|
const selectedSuggestion = this.suggestions[normalizedIndex];
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,14 +10,13 @@ import {WikiModel} from '../models/WikiModel';
|
||||||
import {MusicReleaseModel} from '../models/MusicReleaseModel';
|
import {MusicReleaseModel} from '../models/MusicReleaseModel';
|
||||||
import {BoardGameModel} from '../models/BoardGameModel';
|
import {BoardGameModel} from '../models/BoardGameModel';
|
||||||
|
|
||||||
export const MEDIA_TYPES = [MediaType.Movie, MediaType.Series, MediaType.Game, MediaType.Wiki, MediaType.MusicRelease, MediaType.BoardGame];
|
export const MEDIA_TYPES: MediaType[] = [MediaType.Movie, MediaType.Series, MediaType.Game, MediaType.Wiki, MediaType.MusicRelease, MediaType.BoardGame];
|
||||||
|
|
||||||
export class MediaTypeManager {
|
export class MediaTypeManager {
|
||||||
mediaFileNameTemplateMap: Map<MediaType, string>;
|
mediaFileNameTemplateMap: Map<MediaType, string>;
|
||||||
mediaTemplateMap: Map<MediaType, string>;
|
mediaTemplateMap: Map<MediaType, string>;
|
||||||
|
|
||||||
constructor(settings: MediaDbPluginSettings) {
|
constructor() {
|
||||||
this.updateTemplates(settings);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
updateTemplates(settings: MediaDbPluginSettings) {
|
updateTemplates(settings: MediaDbPluginSettings) {
|
||||||
|
|
|
||||||
File diff suppressed because one or more lines are too long
Loading…
Add table
Add a link
Reference in a new issue