fix some issues; migrate to bun'
This commit is contained in:
parent
cf3d5c6d6f
commit
54293ac3a1
56 changed files with 1360 additions and 764 deletions
|
|
@ -21,8 +21,12 @@ export class APIManager {
|
|||
|
||||
for (const api of this.apis) {
|
||||
if (apisToQuery.contains(api.apiName)) {
|
||||
const apiRes = await api.searchByTitle(query);
|
||||
res = res.concat(apiRes);
|
||||
try {
|
||||
const apiRes = await api.searchByTitle(query);
|
||||
res = res.concat(apiRes);
|
||||
} catch (e) {
|
||||
console.warn(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
import { MediaTypeModel } from '../models/MediaTypeModel';
|
||||
import { MediaType } from '../utils/MediaType';
|
||||
import { MediaDbPluginSettings } from 'src/settings/Settings';
|
||||
import MediaDbPlugin from '../main';
|
||||
|
||||
export abstract class APIModel {
|
||||
|
|
@ -20,7 +19,10 @@ export abstract class APIModel {
|
|||
abstract getById(id: string): Promise<MediaTypeModel>;
|
||||
|
||||
hasType(type: MediaType): boolean {
|
||||
if (this.types.contains(type) && (Boolean((this.plugin.settings.apiToggle as any)?.[this.apiName]?.[type] as MediaDbPluginSettings) === true || (this.plugin.settings.apiToggle as any)?.[this.apiName]?.[type] as MediaDbPluginSettings === undefined)) {
|
||||
if (
|
||||
this.types.contains(type) &&
|
||||
(Boolean((this.plugin.settings.apiToggle as any)?.[this.apiName]?.[type]) === true || (this.plugin.settings.apiToggle as any)?.[this.apiName]?.[type] === undefined)
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,64 +0,0 @@
|
|||
import { APIModel } from '../APIModel';
|
||||
import { MediaTypeModel } from '../../models/MediaTypeModel';
|
||||
import MediaDbPlugin from '../../main';
|
||||
|
||||
// WIP
|
||||
export class LocGovAPI extends APIModel {
|
||||
plugin: MediaDbPlugin;
|
||||
typeMappings: Map<string, string>;
|
||||
|
||||
constructor(plugin: MediaDbPlugin) {
|
||||
super();
|
||||
|
||||
this.plugin = plugin;
|
||||
this.apiName = 'loc.gov API';
|
||||
this.apiDescription = 'A free API for the Library of Congress collections.';
|
||||
this.apiUrl = 'https://libraryofcongress.github.io/data-exploration/index.html';
|
||||
this.types = [];
|
||||
this.typeMappings = new Map<string, string>();
|
||||
// this.typeMappings.set('movie', 'movie');
|
||||
}
|
||||
|
||||
async searchByTitle(title: string): Promise<MediaTypeModel[]> {
|
||||
console.log(`MDB | api "${this.apiName}" queried by Title`);
|
||||
|
||||
const searchUrl = `https://www.loc.gov/search/?q=${encodeURIComponent(title)}&fo=json&c=20`;
|
||||
const fetchData = await fetch(searchUrl);
|
||||
console.debug(fetchData);
|
||||
|
||||
if (fetchData.status !== 200) {
|
||||
throw Error(`MDB | Received status code ${fetchData.status} from an API.`);
|
||||
}
|
||||
|
||||
const data = await fetchData.json();
|
||||
console.debug(data);
|
||||
let ret: MediaTypeModel[] = [];
|
||||
|
||||
throw new Error('MDB | Under construction, API implementation not finished');
|
||||
|
||||
// return ret;
|
||||
}
|
||||
|
||||
async getById(id: string): Promise<MediaTypeModel> {
|
||||
console.log(`MDB | api "${this.apiName}" queried by ID`);
|
||||
|
||||
const searchUrl = `https://www.loc.gov/item/${encodeURIComponent(id)}/?fo=json`;
|
||||
const fetchData = await fetch(searchUrl);
|
||||
if (fetchData.status !== 200) {
|
||||
throw Error(`MDB | Received status code ${fetchData.status} from an API.`);
|
||||
}
|
||||
|
||||
const data = await fetchData.json();
|
||||
console.debug(data);
|
||||
const result = data.data;
|
||||
|
||||
const type = this.typeMappings.get(result.type.toLowerCase());
|
||||
if (type === undefined) {
|
||||
throw Error(`${result.type.toLowerCase()} is an unsupported type.`);
|
||||
}
|
||||
|
||||
throw new Error('MDB | Under construction, API implementation not finished');
|
||||
|
||||
// return;
|
||||
}
|
||||
}
|
||||
|
|
@ -41,7 +41,13 @@ export class SteamAPI extends APIModel {
|
|||
const filteredData = [];
|
||||
|
||||
for (const app of data.applist.apps) {
|
||||
if (app.name.toLowerCase().includes(title.toLowerCase())) {
|
||||
if (
|
||||
app.name
|
||||
.normalize('NFD')
|
||||
.replace(/\p{Diacritic}/gu, '')
|
||||
.toLowerCase()
|
||||
.includes(title.toLowerCase())
|
||||
) {
|
||||
filteredData.push(app);
|
||||
}
|
||||
if (filteredData.length > 20) {
|
||||
|
|
|
|||
105
src/main.ts
105
src/main.ts
|
|
@ -22,11 +22,19 @@ import { BoardGameGeekAPI } from './api/apis/BoardGameGeekAPI';
|
|||
import { OpenLibraryAPI } from './api/apis/OpenLibraryAPI';
|
||||
import { MobyGamesAPI } from './api/apis/MobyGamesAPI';
|
||||
import { PropertyMapper } from './settings/PropertyMapper';
|
||||
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';
|
||||
import { MediaType } from 'src/utils/MediaType';
|
||||
|
||||
export type Metadata = Record<string, unknown>;
|
||||
|
||||
export interface MediaTypeModelObj {
|
||||
id: string;
|
||||
type: MediaType;
|
||||
dataSource: string;
|
||||
}
|
||||
|
||||
export default class MediaDbPlugin extends Plugin {
|
||||
settings: MediaDbPluginSettings;
|
||||
|
|
@ -186,7 +194,12 @@ export default class MediaDbPlugin extends Plugin {
|
|||
let apiSearchResults: MediaTypeModel[] = await this.modalHelper.openSearchModal(searchModalOptions ?? {}, async searchModalData => {
|
||||
types = searchModalData.types;
|
||||
const apis = this.apiManager.apis.filter(x => x.hasTypeOverlap(searchModalData.types)).map(x => x.apiName);
|
||||
return await this.apiManager.query(searchModalData.query, apis);
|
||||
try {
|
||||
return await this.apiManager.query(searchModalData.query, apis);
|
||||
} catch (e) {
|
||||
console.warn(e);
|
||||
return [];
|
||||
}
|
||||
});
|
||||
|
||||
if (!apiSearchResults) {
|
||||
|
|
@ -309,21 +322,40 @@ export default class MediaDbPlugin extends Plugin {
|
|||
|
||||
generateMediaDbNoteFrontmatterPreview(mediaTypeModel: MediaTypeModel): string {
|
||||
const fileMetadata = this.modelPropertyMapper.convertObject(mediaTypeModel.toMetaDataObject());
|
||||
return this.settings.useCustomYamlStringifier ? YAMLConverter.toYaml(fileMetadata) : stringifyYaml(fileMetadata);
|
||||
return stringifyYaml(fileMetadata);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the content of a note from a media model and some options.
|
||||
*
|
||||
* @param mediaTypeModel
|
||||
* @param options
|
||||
*/
|
||||
async generateMediaDbNoteContents(mediaTypeModel: MediaTypeModel, options: CreateNoteOptions): Promise<string> {
|
||||
let template = await this.mediaTypeManager.getTemplate(mediaTypeModel, this.app);
|
||||
const template = await this.mediaTypeManager.getTemplate(mediaTypeModel, this.app);
|
||||
|
||||
if (this.settings.useDefaultFrontMatter || !template) {
|
||||
return this.generateContentWithDefaultFrontMatter(mediaTypeModel, options, template);
|
||||
} else {
|
||||
return this.generateContentWithCustomFrontMatter(mediaTypeModel, options, template);
|
||||
}
|
||||
return this.generateContentWithDefaultFrontMatter(mediaTypeModel, options, template);
|
||||
|
||||
// if (this.settings.useDefaultFrontMatter || !template) {
|
||||
// return this.generateContentWithDefaultFrontMatter(mediaTypeModel, options, template);
|
||||
// } else {
|
||||
// return this.generateContentWithCustomFrontMatter(mediaTypeModel, options, template);
|
||||
// }
|
||||
}
|
||||
|
||||
async generateContentWithDefaultFrontMatter(mediaTypeModel: MediaTypeModel, options: CreateNoteOptions, template?: string): Promise<string> {
|
||||
let fileMetadata = this.modelPropertyMapper.convertObject(mediaTypeModel.toMetaDataObject());
|
||||
let fileMetadata: Record<string, unknown>;
|
||||
|
||||
if (this.settings.useDefaultFrontMatter) {
|
||||
fileMetadata = this.modelPropertyMapper.convertObject(mediaTypeModel.toMetaDataObject());
|
||||
} else {
|
||||
fileMetadata = {
|
||||
id: mediaTypeModel.id,
|
||||
type: mediaTypeModel.type,
|
||||
dataSource: mediaTypeModel.dataSource,
|
||||
};
|
||||
}
|
||||
|
||||
let fileContent = '';
|
||||
template = options.attachTemplate ? template : '';
|
||||
|
||||
|
|
@ -331,27 +363,20 @@ export default class MediaDbPlugin extends Plugin {
|
|||
({ fileMetadata, fileContent } = await this.attachTemplate(fileMetadata, fileContent, template));
|
||||
|
||||
if (this.settings.enableTemplaterIntegration && hasTemplaterPlugin(this.app)) {
|
||||
// Only support stringifyYaml for templater plugin
|
||||
// Include the media variable in all templater commands by using a top level JavaScript execution command.
|
||||
fileContent = `---\n<%* const media = ${JSON.stringify(mediaTypeModel)} %>\n${stringifyYaml(fileMetadata)}---\n${fileContent}`;
|
||||
} else {
|
||||
fileContent = `---\n${this.settings.useCustomYamlStringifier ? YAMLConverter.toYaml(fileMetadata) : stringifyYaml(fileMetadata)}---\n` + fileContent;
|
||||
fileContent = `---\n${stringifyYaml(fileMetadata)}---\n${fileContent}`;
|
||||
}
|
||||
|
||||
return fileContent;
|
||||
}
|
||||
|
||||
async generateContentWithCustomFrontMatter(mediaTypeModel: MediaTypeModel, options: CreateNoteOptions, template: string): Promise<string> {
|
||||
const frontMatterRegex = /^---*\n([\s\S]*?)\n---\h*/;
|
||||
const regExp = new RegExp(this.frontMatterRexExpPattern);
|
||||
|
||||
const match = template.match(frontMatterRegex);
|
||||
|
||||
if (!match || match.length !== 2) {
|
||||
throw new Error('Cannot find YAML front matter for template.');
|
||||
}
|
||||
|
||||
let frontMatter = parseYaml(match[1]);
|
||||
let fileContent: string = template.replace(frontMatterRegex, '');
|
||||
const frontMatter = this.getMetaDataFromFileContent(template);
|
||||
let fileContent: string = template.replace(regExp, '');
|
||||
|
||||
// Updating a previous file
|
||||
if (options.attachFile) {
|
||||
|
|
@ -359,7 +384,7 @@ export default class MediaDbPlugin extends Plugin {
|
|||
|
||||
// Use contents (below front matter) from previous file
|
||||
fileContent = await this.app.vault.read(options.attachFile);
|
||||
const regExp = new RegExp(this.frontMatterRexExpPattern);
|
||||
|
||||
fileContent = fileContent.replace(regExp, '');
|
||||
fileContent = fileContent.startsWith('\n') ? fileContent.substring(1) : fileContent;
|
||||
|
||||
|
|
@ -391,18 +416,19 @@ export default class MediaDbPlugin extends Plugin {
|
|||
// Include the media variable in all templater commands by using a top level JavaScript execution command.
|
||||
fileContent = `---\n<%* const media = ${JSON.stringify(mediaTypeModel)} %>\n${stringifyYaml(frontMatter)}---\n${fileContent}`;
|
||||
} else {
|
||||
fileContent = `---\n${this.settings.useCustomYamlStringifier ? YAMLConverter.toYaml(frontMatter) : stringifyYaml(frontMatter)}---\n` + fileContent;
|
||||
fileContent = `---\n${stringifyYaml(frontMatter)}---\n${fileContent}`;
|
||||
}
|
||||
|
||||
return fileContent;
|
||||
}
|
||||
|
||||
async attachFile(fileMetadata: any, fileContent: string, fileToAttach?: TFile): Promise<{ fileMetadata: any; fileContent: string }> {
|
||||
async attachFile(fileMetadata: Metadata, fileContent: string, fileToAttach?: TFile): Promise<{ fileMetadata: Metadata; fileContent: string }> {
|
||||
if (!fileToAttach) {
|
||||
return { fileMetadata: fileMetadata, fileContent: fileContent };
|
||||
}
|
||||
|
||||
const attachFileMetadata: any = this.getMetadataFromFileCache(fileToAttach);
|
||||
// TODO: better object merging
|
||||
fileMetadata = Object.assign(attachFileMetadata, fileMetadata);
|
||||
|
||||
let attachFileContent: string = await this.app.vault.read(fileToAttach);
|
||||
|
|
@ -414,12 +440,13 @@ export default class MediaDbPlugin extends Plugin {
|
|||
return { fileMetadata: fileMetadata, fileContent: fileContent };
|
||||
}
|
||||
|
||||
async attachTemplate(fileMetadata: any, fileContent: string, template: string): Promise<{ fileMetadata: any; fileContent: string }> {
|
||||
async attachTemplate(fileMetadata: Metadata, fileContent: string, template: string): Promise<{ fileMetadata: Metadata; fileContent: string }> {
|
||||
if (!template) {
|
||||
return { fileMetadata: fileMetadata, fileContent: fileContent };
|
||||
}
|
||||
|
||||
const templateMetadata: any = this.getMetaDataFromFileContent(template);
|
||||
const templateMetadata: Metadata = this.getMetaDataFromFileContent(template);
|
||||
// TODO: better object merging
|
||||
fileMetadata = Object.assign(templateMetadata, fileMetadata);
|
||||
|
||||
const regExp = new RegExp(this.frontMatterRexExpPattern);
|
||||
|
|
@ -429,8 +456,8 @@ export default class MediaDbPlugin extends Plugin {
|
|||
return { fileMetadata: fileMetadata, fileContent: fileContent };
|
||||
}
|
||||
|
||||
getMetaDataFromFileContent(fileContent: string): any {
|
||||
let metadata: any;
|
||||
getMetaDataFromFileContent(fileContent: string): Metadata {
|
||||
let metadata: Metadata;
|
||||
|
||||
const regExp = new RegExp(this.frontMatterRexExpPattern);
|
||||
const frontMatterRegExpResult = regExp.exec(fileContent);
|
||||
|
|
@ -455,15 +482,9 @@ export default class MediaDbPlugin extends Plugin {
|
|||
return metadata;
|
||||
}
|
||||
|
||||
getMetadataFromFileCache(file: TFile): any {
|
||||
let metadata: any = this.app.metadataCache.getFileCache(file).frontmatter;
|
||||
if (metadata) {
|
||||
metadata = Object.assign({}, metadata); // copy
|
||||
delete metadata.position;
|
||||
} else {
|
||||
metadata = {};
|
||||
}
|
||||
return metadata;
|
||||
getMetadataFromFileCache(file: TFile): Metadata {
|
||||
const metadata: Metadata | undefined = this.app.metadataCache.getFileCache(file).frontmatter;
|
||||
return structuredClone(metadata ?? {});
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -513,7 +534,7 @@ export default class MediaDbPlugin extends Plugin {
|
|||
throw new Error('MDB | there is no active note');
|
||||
}
|
||||
|
||||
let metadata: any = this.getMetadataFromFileCache(activeFile);
|
||||
let metadata = this.getMetadataFromFileCache(activeFile);
|
||||
metadata = this.modelPropertyMapper.convertObjectBack(metadata);
|
||||
|
||||
console.debug(`MDB | read metadata`, metadata);
|
||||
|
|
@ -522,10 +543,12 @@ export default class MediaDbPlugin extends Plugin {
|
|||
throw new Error('MDB | active note is not a Media DB entry or is missing metadata');
|
||||
}
|
||||
|
||||
const oldMediaTypeModel = this.mediaTypeManager.createMediaTypeModelFromMediaType(metadata, metadata.type);
|
||||
const validOldMetadata: MediaTypeModelObj = metadata as unknown as MediaTypeModelObj;
|
||||
|
||||
const oldMediaTypeModel = this.mediaTypeManager.createMediaTypeModelFromMediaType(validOldMetadata, validOldMetadata.type);
|
||||
// console.debug(oldMediaTypeModel);
|
||||
|
||||
let newMediaTypeModel = await this.apiManager.queryDetailedInfoById(metadata.id, metadata.dataSource);
|
||||
let newMediaTypeModel = await this.apiManager.queryDetailedInfoById(validOldMetadata.id, validOldMetadata.dataSource);
|
||||
if (!newMediaTypeModel) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -533,8 +556,6 @@ export default class MediaDbPlugin extends Plugin {
|
|||
newMediaTypeModel = Object.assign(oldMediaTypeModel, newMediaTypeModel.getWithOutUserData());
|
||||
// console.debug(newMediaTypeModel);
|
||||
|
||||
// deletion not happening anymore why is this log statement still here
|
||||
console.debug('MDB | deleting old entry');
|
||||
if (onlyMetadata) {
|
||||
await this.createMediaDbNoteFromModel(newMediaTypeModel, { attachFile: activeFile, folder: activeFile.parent, openNote: true });
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -31,12 +31,12 @@ export abstract class MediaTypeModel {
|
|||
|
||||
abstract getTags(): string[];
|
||||
|
||||
toMetaDataObject(): object {
|
||||
toMetaDataObject(): Record<string, unknown> {
|
||||
return { ...this.getWithOutUserData(), ...this.userData, tags: this.getTags().join('/') };
|
||||
}
|
||||
|
||||
getWithOutUserData(): object {
|
||||
const copy = Object.assign({}, this);
|
||||
getWithOutUserData(): Record<string, unknown> {
|
||||
const copy = structuredClone(this) as Record<string, unknown>;
|
||||
delete copy.userData;
|
||||
return copy;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ export class WikiModel extends MediaTypeModel {
|
|||
length: number;
|
||||
article: string;
|
||||
|
||||
userData: {};
|
||||
userData: Record<string, unknown>;
|
||||
|
||||
constructor(obj: any = {}) {
|
||||
super();
|
||||
|
|
@ -45,8 +45,8 @@ export class WikiModel extends MediaTypeModel {
|
|||
return MediaType.Wiki;
|
||||
}
|
||||
|
||||
override getWithOutUserData(): object {
|
||||
const copy = Object.assign({}, this);
|
||||
override getWithOutUserData(): Record<string, unknown> {
|
||||
const copy = structuredClone(this) as Record<string, unknown>;
|
||||
delete copy.userData;
|
||||
delete copy.article;
|
||||
return copy;
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
<!--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';
|
||||
import { setIcon } from 'obsidian';
|
||||
import { onMount } from 'svelte';
|
||||
|
||||
export let iconName: string = '';
|
||||
export let iconSize: number = 20;
|
||||
|
|
@ -14,23 +14,23 @@
|
|||
});
|
||||
</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}
|
||||
|
||||
<style>
|
||||
.icon-wrapper {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
width: 20px;
|
||||
}
|
||||
|
||||
.icon {
|
||||
position: absolute;
|
||||
height: 20px;
|
||||
width: 20px;
|
||||
top: calc(50% - 10px);
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -15,15 +15,13 @@ export class PropertyMapper {
|
|||
*
|
||||
* @param obj
|
||||
*/
|
||||
convertObject(obj: object): object {
|
||||
convertObject(obj: Record<string, unknown>): Record<string, unknown> {
|
||||
if (!obj.hasOwnProperty('type')) {
|
||||
return obj;
|
||||
}
|
||||
|
||||
// @ts-ignore
|
||||
// console.log(obj.type);
|
||||
|
||||
// @ts-ignore
|
||||
if (MEDIA_TYPES.filter(x => x.toString() == obj.type).length < 1) {
|
||||
return obj;
|
||||
}
|
||||
|
|
@ -31,7 +29,7 @@ export class PropertyMapper {
|
|||
// @ts-ignore
|
||||
const propertyMappings = this.plugin.settings.propertyMappingModels.find(x => x.type === obj.type).properties;
|
||||
|
||||
const newObj: object = {};
|
||||
const newObj: Record<string, unknown> = {};
|
||||
|
||||
for (const [key, value] of Object.entries(obj)) {
|
||||
for (const propertyMapping of propertyMappings) {
|
||||
|
|
@ -59,20 +57,18 @@ export class PropertyMapper {
|
|||
*
|
||||
* @param obj
|
||||
*/
|
||||
convertObjectBack(obj: object): object {
|
||||
convertObjectBack(obj: Record<string, unknown>): Record<string, unknown> {
|
||||
if (!obj.hasOwnProperty('type')) {
|
||||
return obj;
|
||||
}
|
||||
|
||||
// @ts-ignore
|
||||
if (MEDIA_TYPES.contains(obj.type)) {
|
||||
if (MEDIA_TYPES.contains(obj.type as any)) {
|
||||
return obj;
|
||||
}
|
||||
|
||||
// @ts-ignore
|
||||
const propertyMappings = this.plugin.settings.propertyMappingModels.find(x => x.type === obj.type).properties;
|
||||
|
||||
const originalObj: object = {};
|
||||
const originalObj: Record<string, unknown> = {};
|
||||
|
||||
objLoop: for (const [key, value] of Object.entries(obj)) {
|
||||
// first try if it is a normal property
|
||||
|
|
|
|||
|
|
@ -68,7 +68,7 @@ export class PropertyMappingModel {
|
|||
};
|
||||
}
|
||||
|
||||
getMappedProperties() {
|
||||
getMappedProperties(): PropertyMapping[] {
|
||||
return this.properties.filter(x => x.mapping === PropertyMappingOption.Map);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
<script lang="ts">
|
||||
import {PropertyMappingModel, PropertyMappingOption, propertyMappingOptions} from './PropertyMapping';
|
||||
import {capitalizeFirstLetter} from '../utils/Utils';
|
||||
import { PropertyMappingModel, PropertyMappingOption, propertyMappingOptions } from './PropertyMapping';
|
||||
import { capitalizeFirstLetter } from '../utils/Utils';
|
||||
import Icon from './Icon.svelte';
|
||||
|
||||
export let model: PropertyMappingModel;
|
||||
export let save: (model: PropertyMappingModel) => void;
|
||||
|
||||
let validationResult: { res: boolean, err?: Error };
|
||||
let validationResult: { res: boolean; err?: Error };
|
||||
|
||||
$: modelChanged(model);
|
||||
|
||||
|
|
@ -15,23 +15,17 @@
|
|||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
</style>
|
||||
|
||||
<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 }
|
||||
{#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 }
|
||||
{#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}>
|
||||
|
|
@ -40,23 +34,29 @@
|
|||
{/each}
|
||||
</select>
|
||||
|
||||
{ #if property.mapping === PropertyMappingOption.Map }
|
||||
<Icon iconName="arrow-right"/>
|
||||
{#if property.mapping === PropertyMappingOption.Map}
|
||||
<Icon iconName="arrow-right" />
|
||||
<div class="media-db-plugin-property-mapping-to">
|
||||
<input type="text" spellcheck="false" bind:value="{property.newProperty}">
|
||||
<input type="text" spellcheck="false" bind:value={property.newProperty} />
|
||||
</div>
|
||||
{ /if }
|
||||
{ /if }
|
||||
{/if}
|
||||
{/if}
|
||||
</div>
|
||||
{ /each }
|
||||
{/each}
|
||||
</div>
|
||||
{ #if !validationResult?.res }
|
||||
{#if !validationResult?.res}
|
||||
<div class="media-db-plugin-property-mapping-validation">
|
||||
{validationResult?.err?.message}
|
||||
</div>
|
||||
{ /if }
|
||||
{/if}
|
||||
<button
|
||||
class="media-db-plugin-property-mappings-save-button {validationResult?.res ? 'mod-cta' : 'mod-muted'}"
|
||||
on:click={() => { if(model.validate().res) save(model) }}>Save
|
||||
on:click={() => {
|
||||
if (model.validate().res) save(model);
|
||||
}}
|
||||
>Save
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -1,19 +1,15 @@
|
|||
<script lang="ts">
|
||||
import {PropertyMappingModel} from './PropertyMapping';
|
||||
import { PropertyMappingModel } from './PropertyMapping';
|
||||
import PropertyMappingModelComponent from './PropertyMappingModelComponent.svelte';
|
||||
|
||||
export let models: PropertyMappingModel[] = [];
|
||||
export let save: (model: PropertyMappingModel) => void;
|
||||
</script>
|
||||
|
||||
<style>
|
||||
|
||||
</style>
|
||||
|
||||
<div class="setting-item" style="display: flex; gap: 10px; flex-direction: column; align-items: stretch;">
|
||||
{ #each models as model }
|
||||
<PropertyMappingModelComponent model={model} save={save}></PropertyMappingModelComponent>
|
||||
{ /each }
|
||||
{#each models as model}
|
||||
<PropertyMappingModelComponent {model} {save}></PropertyMappingModelComponent>
|
||||
{/each}
|
||||
|
||||
<!--
|
||||
<pre>{JSON.stringify(models, null, 4)}</pre>
|
||||
|
|
@ -25,3 +21,6 @@
|
|||
{/each}
|
||||
-->
|
||||
</div>
|
||||
|
||||
<style>
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@ export interface MediaDbPluginSettings {
|
|||
OMDbKey: string;
|
||||
MobyGamesKey: string;
|
||||
sfwFilter: boolean;
|
||||
useCustomYamlStringifier: boolean;
|
||||
templates: boolean;
|
||||
customDateFormat: string;
|
||||
openNoteInNewTab: boolean;
|
||||
|
|
@ -24,18 +23,18 @@ export interface MediaDbPluginSettings {
|
|||
movie: boolean;
|
||||
series: boolean;
|
||||
game: boolean;
|
||||
},
|
||||
};
|
||||
MALAPI: {
|
||||
movie: boolean;
|
||||
series: boolean;
|
||||
},
|
||||
};
|
||||
SteamAPI: {
|
||||
game: boolean;
|
||||
},
|
||||
};
|
||||
MobyGamesAPI: {
|
||||
game: boolean;
|
||||
}
|
||||
},
|
||||
};
|
||||
};
|
||||
movieTemplate: string;
|
||||
seriesTemplate: string;
|
||||
mangaTemplate: string;
|
||||
|
|
@ -79,7 +78,6 @@ const DEFAULT_SETTINGS: MediaDbPluginSettings = {
|
|||
OMDbKey: '',
|
||||
MobyGamesKey: '',
|
||||
sfwFilter: true,
|
||||
useCustomYamlStringifier: true,
|
||||
templates: true,
|
||||
customDateFormat: 'L',
|
||||
openNoteInNewTab: true,
|
||||
|
|
@ -100,7 +98,7 @@ const DEFAULT_SETTINGS: MediaDbPluginSettings = {
|
|||
},
|
||||
MobyGamesAPI: {
|
||||
game: true,
|
||||
}
|
||||
},
|
||||
},
|
||||
movieTemplate: '',
|
||||
seriesTemplate: '',
|
||||
|
|
@ -190,7 +188,7 @@ export class MediaDbSettingTab extends PluginSettingTab {
|
|||
.setValue(this.plugin.settings.OMDbKey)
|
||||
.onChange(data => {
|
||||
this.plugin.settings.OMDbKey = data;
|
||||
this.plugin.saveSettings();
|
||||
void this.plugin.saveSettings();
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -202,7 +200,7 @@ export class MediaDbSettingTab extends PluginSettingTab {
|
|||
.setValue(this.plugin.settings.MobyGamesKey)
|
||||
.onChange(data => {
|
||||
this.plugin.settings.MobyGamesKey = data;
|
||||
this.plugin.saveSettings();
|
||||
void this.plugin.saveSettings();
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -212,17 +210,7 @@ export class MediaDbSettingTab extends PluginSettingTab {
|
|||
.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();
|
||||
void this.plugin.saveSettings();
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -232,7 +220,7 @@ export class MediaDbSettingTab extends PluginSettingTab {
|
|||
.addToggle(cb => {
|
||||
cb.setValue(this.plugin.settings.templates).onChange(data => {
|
||||
this.plugin.settings.templates = data;
|
||||
this.plugin.saveSettings();
|
||||
void this.plugin.saveSettings();
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -241,10 +229,10 @@ export class MediaDbSettingTab extends PluginSettingTab {
|
|||
.setDesc(
|
||||
fragWithHTML(
|
||||
"Your custom date format. Use <em>'YYYY-MM-DD'</em> for example.<br>" +
|
||||
"For more syntax, refer to <a href='https://momentjs.com/docs/#/displaying/format/'>format reference</a>.<br>" +
|
||||
"Your current syntax looks like this: <b><a id='media-db-dateformat-preview' style='pointer-events: none; cursor: default; text-decoration: none;'>" +
|
||||
this.plugin.dateFormatter.getPreview() +
|
||||
'</a></b>',
|
||||
"For more syntax, refer to <a href='https://momentjs.com/docs/#/displaying/format/'>format reference</a>.<br>" +
|
||||
"Your current syntax looks like this: <b><a id='media-db-dateformat-preview' style='pointer-events: none; cursor: default; text-decoration: none;'>" +
|
||||
this.plugin.dateFormatter.getPreview() +
|
||||
'</a></b>',
|
||||
),
|
||||
)
|
||||
.addText(cb => {
|
||||
|
|
@ -254,7 +242,7 @@ export class MediaDbSettingTab extends PluginSettingTab {
|
|||
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();
|
||||
void this.plugin.saveSettings();
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -264,17 +252,17 @@ export class MediaDbSettingTab extends PluginSettingTab {
|
|||
.addToggle(cb => {
|
||||
cb.setValue(this.plugin.settings.openNoteInNewTab).onChange(data => {
|
||||
this.plugin.settings.openNoteInNewTab = data;
|
||||
this.plugin.saveSettings();
|
||||
void this.plugin.saveSettings();
|
||||
});
|
||||
});
|
||||
|
||||
new Setting(containerEl)
|
||||
.setName('Use default front matter')
|
||||
.setDesc('Wheter to use the default front matter. If disabled, the front matter from the template will be used. Same as mapping everything to remove.')
|
||||
.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;
|
||||
this.plugin.saveSettings();
|
||||
void this.plugin.saveSettings();
|
||||
// Redraw settings to display/remove the property mappings
|
||||
this.display();
|
||||
});
|
||||
|
|
@ -288,11 +276,10 @@ export class MediaDbSettingTab extends PluginSettingTab {
|
|||
.addToggle(cb => {
|
||||
cb.setValue(this.plugin.settings.enableTemplaterIntegration).onChange(data => {
|
||||
this.plugin.settings.enableTemplaterIntegration = data;
|
||||
this.plugin.saveSettings();
|
||||
void this.plugin.saveSettings();
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
containerEl.createEl('h3', { text: 'APIs Per Media Type' });
|
||||
containerEl.createEl('h5', { text: 'Movies' });
|
||||
new Setting(containerEl)
|
||||
|
|
@ -301,7 +288,7 @@ export class MediaDbSettingTab extends PluginSettingTab {
|
|||
.addToggle(cb => {
|
||||
cb.setValue(this.plugin.settings.apiToggle.OMDbAPI.movie).onChange(data => {
|
||||
this.plugin.settings.apiToggle.OMDbAPI.movie = data;
|
||||
this.plugin.saveSettings();
|
||||
void this.plugin.saveSettings();
|
||||
});
|
||||
});
|
||||
new Setting(containerEl)
|
||||
|
|
@ -310,7 +297,7 @@ export class MediaDbSettingTab extends PluginSettingTab {
|
|||
.addToggle(cb => {
|
||||
cb.setValue(this.plugin.settings.apiToggle.MALAPI.movie).onChange(data => {
|
||||
this.plugin.settings.apiToggle.MALAPI.movie = data;
|
||||
this.plugin.saveSettings();
|
||||
void this.plugin.saveSettings();
|
||||
});
|
||||
});
|
||||
containerEl.createEl('h5', { text: 'Series' });
|
||||
|
|
@ -320,7 +307,7 @@ export class MediaDbSettingTab extends PluginSettingTab {
|
|||
.addToggle(cb => {
|
||||
cb.setValue(this.plugin.settings.apiToggle.OMDbAPI.series).onChange(data => {
|
||||
this.plugin.settings.apiToggle.OMDbAPI.series = data;
|
||||
this.plugin.saveSettings();
|
||||
void this.plugin.saveSettings();
|
||||
});
|
||||
});
|
||||
new Setting(containerEl)
|
||||
|
|
@ -329,7 +316,7 @@ export class MediaDbSettingTab extends PluginSettingTab {
|
|||
.addToggle(cb => {
|
||||
cb.setValue(this.plugin.settings.apiToggle.MALAPI.series).onChange(data => {
|
||||
this.plugin.settings.apiToggle.MALAPI.series = data;
|
||||
this.plugin.saveSettings();
|
||||
void this.plugin.saveSettings();
|
||||
});
|
||||
});
|
||||
containerEl.createEl('h5', { text: 'Games' });
|
||||
|
|
@ -339,7 +326,7 @@ export class MediaDbSettingTab extends PluginSettingTab {
|
|||
.addToggle(cb => {
|
||||
cb.setValue(this.plugin.settings.apiToggle.OMDbAPI.game).onChange(data => {
|
||||
this.plugin.settings.apiToggle.OMDbAPI.game = data;
|
||||
this.plugin.saveSettings();
|
||||
void this.plugin.saveSettings();
|
||||
});
|
||||
});
|
||||
new Setting(containerEl)
|
||||
|
|
@ -348,7 +335,7 @@ export class MediaDbSettingTab extends PluginSettingTab {
|
|||
.addToggle(cb => {
|
||||
cb.setValue(this.plugin.settings.apiToggle.SteamAPI.game).onChange(data => {
|
||||
this.plugin.settings.apiToggle.SteamAPI.game = data;
|
||||
this.plugin.saveSettings();
|
||||
void this.plugin.saveSettings();
|
||||
});
|
||||
});
|
||||
new Setting(containerEl)
|
||||
|
|
@ -357,7 +344,7 @@ export class MediaDbSettingTab extends PluginSettingTab {
|
|||
.addToggle(cb => {
|
||||
cb.setValue(this.plugin.settings.apiToggle.MobyGamesAPI.game).onChange(data => {
|
||||
this.plugin.settings.apiToggle.MobyGamesAPI.game = data;
|
||||
this.plugin.saveSettings();
|
||||
void this.plugin.saveSettings();
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -372,7 +359,7 @@ export class MediaDbSettingTab extends PluginSettingTab {
|
|||
.setValue(this.plugin.settings.movieFolder)
|
||||
.onChange(data => {
|
||||
this.plugin.settings.movieFolder = data;
|
||||
this.plugin.saveSettings();
|
||||
void this.plugin.saveSettings();
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -385,7 +372,7 @@ export class MediaDbSettingTab extends PluginSettingTab {
|
|||
.setValue(this.plugin.settings.seriesFolder)
|
||||
.onChange(data => {
|
||||
this.plugin.settings.seriesFolder = data;
|
||||
this.plugin.saveSettings();
|
||||
void this.plugin.saveSettings();
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -398,7 +385,7 @@ export class MediaDbSettingTab extends PluginSettingTab {
|
|||
.setValue(this.plugin.settings.mangaFolder)
|
||||
.onChange(data => {
|
||||
this.plugin.settings.mangaFolder = data;
|
||||
this.plugin.saveSettings();
|
||||
void this.plugin.saveSettings();
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -411,7 +398,7 @@ export class MediaDbSettingTab extends PluginSettingTab {
|
|||
.setValue(this.plugin.settings.gameFolder)
|
||||
.onChange(data => {
|
||||
this.plugin.settings.gameFolder = data;
|
||||
this.plugin.saveSettings();
|
||||
void this.plugin.saveSettings();
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -424,7 +411,7 @@ export class MediaDbSettingTab extends PluginSettingTab {
|
|||
.setValue(this.plugin.settings.wikiFolder)
|
||||
.onChange(data => {
|
||||
this.plugin.settings.wikiFolder = data;
|
||||
this.plugin.saveSettings();
|
||||
void this.plugin.saveSettings();
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -437,7 +424,7 @@ export class MediaDbSettingTab extends PluginSettingTab {
|
|||
.setValue(this.plugin.settings.musicReleaseFolder)
|
||||
.onChange(data => {
|
||||
this.plugin.settings.musicReleaseFolder = data;
|
||||
this.plugin.saveSettings();
|
||||
void this.plugin.saveSettings();
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -450,7 +437,7 @@ export class MediaDbSettingTab extends PluginSettingTab {
|
|||
.setValue(this.plugin.settings.boardgameFolder)
|
||||
.onChange(data => {
|
||||
this.plugin.settings.boardgameFolder = data;
|
||||
this.plugin.saveSettings();
|
||||
void this.plugin.saveSettings();
|
||||
});
|
||||
});
|
||||
new Setting(containerEl)
|
||||
|
|
@ -462,7 +449,7 @@ export class MediaDbSettingTab extends PluginSettingTab {
|
|||
.setValue(this.plugin.settings.bookFolder)
|
||||
.onChange(data => {
|
||||
this.plugin.settings.bookFolder = data;
|
||||
this.plugin.saveSettings();
|
||||
void this.plugin.saveSettings();
|
||||
});
|
||||
});
|
||||
// endregion
|
||||
|
|
@ -478,7 +465,7 @@ export class MediaDbSettingTab extends PluginSettingTab {
|
|||
.setValue(this.plugin.settings.movieTemplate)
|
||||
.onChange(data => {
|
||||
this.plugin.settings.movieTemplate = data;
|
||||
this.plugin.saveSettings();
|
||||
void this.plugin.saveSettings();
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -491,7 +478,7 @@ export class MediaDbSettingTab extends PluginSettingTab {
|
|||
.setValue(this.plugin.settings.seriesTemplate)
|
||||
.onChange(data => {
|
||||
this.plugin.settings.seriesTemplate = data;
|
||||
this.plugin.saveSettings();
|
||||
void this.plugin.saveSettings();
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -504,7 +491,7 @@ export class MediaDbSettingTab extends PluginSettingTab {
|
|||
.setValue(this.plugin.settings.mangaTemplate)
|
||||
.onChange(data => {
|
||||
this.plugin.settings.mangaTemplate = data;
|
||||
this.plugin.saveSettings();
|
||||
void this.plugin.saveSettings();
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -517,7 +504,7 @@ export class MediaDbSettingTab extends PluginSettingTab {
|
|||
.setValue(this.plugin.settings.gameTemplate)
|
||||
.onChange(data => {
|
||||
this.plugin.settings.gameTemplate = data;
|
||||
this.plugin.saveSettings();
|
||||
void this.plugin.saveSettings();
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -530,7 +517,7 @@ export class MediaDbSettingTab extends PluginSettingTab {
|
|||
.setValue(this.plugin.settings.wikiTemplate)
|
||||
.onChange(data => {
|
||||
this.plugin.settings.wikiTemplate = data;
|
||||
this.plugin.saveSettings();
|
||||
void this.plugin.saveSettings();
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -543,7 +530,7 @@ export class MediaDbSettingTab extends PluginSettingTab {
|
|||
.setValue(this.plugin.settings.musicReleaseTemplate)
|
||||
.onChange(data => {
|
||||
this.plugin.settings.musicReleaseTemplate = data;
|
||||
this.plugin.saveSettings();
|
||||
void this.plugin.saveSettings();
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -556,7 +543,7 @@ export class MediaDbSettingTab extends PluginSettingTab {
|
|||
.setValue(this.plugin.settings.boardgameTemplate)
|
||||
.onChange(data => {
|
||||
this.plugin.settings.boardgameTemplate = data;
|
||||
this.plugin.saveSettings();
|
||||
void this.plugin.saveSettings();
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -569,7 +556,7 @@ export class MediaDbSettingTab extends PluginSettingTab {
|
|||
.setValue(this.plugin.settings.bookTemplate)
|
||||
.onChange(data => {
|
||||
this.plugin.settings.bookTemplate = data;
|
||||
this.plugin.saveSettings();
|
||||
void this.plugin.saveSettings();
|
||||
});
|
||||
});
|
||||
// endregion
|
||||
|
|
@ -584,7 +571,7 @@ export class MediaDbSettingTab extends PluginSettingTab {
|
|||
.setValue(this.plugin.settings.movieFileNameTemplate)
|
||||
.onChange(data => {
|
||||
this.plugin.settings.movieFileNameTemplate = data;
|
||||
this.plugin.saveSettings();
|
||||
void this.plugin.saveSettings();
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -596,7 +583,7 @@ export class MediaDbSettingTab extends PluginSettingTab {
|
|||
.setValue(this.plugin.settings.seriesFileNameTemplate)
|
||||
.onChange(data => {
|
||||
this.plugin.settings.seriesFileNameTemplate = data;
|
||||
this.plugin.saveSettings();
|
||||
void this.plugin.saveSettings();
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -608,7 +595,7 @@ export class MediaDbSettingTab extends PluginSettingTab {
|
|||
.setValue(this.plugin.settings.mangaFileNameTemplate)
|
||||
.onChange(data => {
|
||||
this.plugin.settings.mangaFileNameTemplate = data;
|
||||
this.plugin.saveSettings();
|
||||
void this.plugin.saveSettings();
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -620,7 +607,7 @@ export class MediaDbSettingTab extends PluginSettingTab {
|
|||
.setValue(this.plugin.settings.gameFileNameTemplate)
|
||||
.onChange(data => {
|
||||
this.plugin.settings.gameFileNameTemplate = data;
|
||||
this.plugin.saveSettings();
|
||||
void this.plugin.saveSettings();
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -632,7 +619,7 @@ export class MediaDbSettingTab extends PluginSettingTab {
|
|||
.setValue(this.plugin.settings.wikiFileNameTemplate)
|
||||
.onChange(data => {
|
||||
this.plugin.settings.wikiFileNameTemplate = data;
|
||||
this.plugin.saveSettings();
|
||||
void this.plugin.saveSettings();
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -644,7 +631,7 @@ export class MediaDbSettingTab extends PluginSettingTab {
|
|||
.setValue(this.plugin.settings.musicReleaseFileNameTemplate)
|
||||
.onChange(data => {
|
||||
this.plugin.settings.musicReleaseFileNameTemplate = data;
|
||||
this.plugin.saveSettings();
|
||||
void this.plugin.saveSettings();
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -656,7 +643,7 @@ export class MediaDbSettingTab extends PluginSettingTab {
|
|||
.setValue(this.plugin.settings.boardgameFileNameTemplate)
|
||||
.onChange(data => {
|
||||
this.plugin.settings.boardgameFileNameTemplate = data;
|
||||
this.plugin.saveSettings();
|
||||
void this.plugin.saveSettings();
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -668,7 +655,7 @@ export class MediaDbSettingTab extends PluginSettingTab {
|
|||
.setValue(this.plugin.settings.bookFileNameTemplate)
|
||||
.onChange(data => {
|
||||
this.plugin.settings.bookFileNameTemplate = data;
|
||||
this.plugin.saveSettings();
|
||||
void this.plugin.saveSettings();
|
||||
});
|
||||
});
|
||||
// endregion
|
||||
|
|
@ -709,7 +696,7 @@ export class MediaDbSettingTab extends PluginSettingTab {
|
|||
|
||||
this.plugin.settings.propertyMappingModels = propertyMappingModels;
|
||||
new Notice(`MDB: Property Mappings for ${model.type} saved successfully.`);
|
||||
this.plugin.saveSettings();
|
||||
void this.plugin.saveSettings();
|
||||
},
|
||||
},
|
||||
});
|
||||
|
|
|
|||
|
|
@ -165,7 +165,7 @@ export abstract class TextInputSuggest<T> implements ISuggestOwner<T> {
|
|||
(<any>this.app).keymap.popScope(this.scope);
|
||||
|
||||
this.suggest.setSuggestions([]);
|
||||
this.popper.destroy();
|
||||
this.popper?.destroy();
|
||||
this.suggestEl.detach();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,104 +0,0 @@
|
|||
import fetchMock, { enableFetchMocks } from 'jest-fetch-mock';
|
||||
import { MediaDbPluginSettings } from 'src/settings/Settings';
|
||||
import { LocGovAPI } from '../api/apis/LocGovAPI';
|
||||
import { MALAPI } from '../api/apis/MALAPI';
|
||||
import { MusicBrainzAPI } from '../api/apis/MusicBrainzAPI';
|
||||
import { OMDbAPI } from '../api/apis/OMDbAPI';
|
||||
import { SteamAPI } from '../api/apis/SteamAPI';
|
||||
import { WikipediaAPI } from '../api/apis/WikipediaAPI';
|
||||
import MediaDbPlugin from '../main';
|
||||
import { setMALResponseMock, setMusicBrainzResponseMock, setOMDbResponseMock, setSteamResponseMock, setWikipediaResponseMock } from './mockHelpers';
|
||||
import MALMockMovie from './ResponseMocks/MALMockMovie.json';
|
||||
import MusicBrainzResponseMock from './ResponseMocks/MusicBrainzMockResponse.json';
|
||||
import OMDBMockMovie from './ResponseMocks/OMDBMockResponse.json';
|
||||
import SteamAPIResponseMock from './ResponseMocks/SteamAPIMockResponse.json';
|
||||
import WikipediaMockResponse from './ResponseMocks/WikipediaMockResponse.json';
|
||||
|
||||
enableFetchMocks();
|
||||
export let apiMock: OMDbAPI | MALAPI | LocGovAPI | MusicBrainzAPI | SteamAPI | WikipediaAPI;
|
||||
|
||||
describe.each([{ name: OMDbAPI }, { name: MALAPI }, { name: LocGovAPI }, { name: MusicBrainzAPI }, { name: SteamAPI }, { name: WikipediaAPI }])(
|
||||
'$name.name',
|
||||
({ name: parameterizedApi }) => {
|
||||
beforeAll(() => {
|
||||
let settingsMock: MediaDbPluginSettings = {} as MediaDbPluginSettings;
|
||||
let pluginMock = {} as MediaDbPlugin;
|
||||
pluginMock.settings = settingsMock;
|
||||
// TODO: add fake API key?
|
||||
apiMock = new parameterizedApi(pluginMock);
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fetchMock.resetMocks();
|
||||
});
|
||||
|
||||
test('searchByTitle behavior when API returns garbage data', async () => {
|
||||
const garbageResponse = JSON.stringify({
|
||||
data: 'string',
|
||||
});
|
||||
fetchMock.mockResponseOnce(garbageResponse);
|
||||
await expect(apiMock.searchByTitle('sample')).resolves.toEqual([]);
|
||||
// }
|
||||
expect(fetch).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
test('searchByTitle behavior when requestUrl/fetch returns 401', async () => {
|
||||
let sampleResponse = {
|
||||
data: 'string',
|
||||
};
|
||||
fetchMock.mockResponse(JSON.stringify(sampleResponse), { status: 401 });
|
||||
// TODO: Check API name and fix message
|
||||
// TODO: Externalize string
|
||||
await expect(apiMock.searchByTitle('sample')).rejects.toThrow(`MDB | Received status code ${401} from an API.`);
|
||||
expect(fetchMock).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
test('searchByTitle behavior when requestUrl/fetch returns 403', async () => {
|
||||
let sampleResponse = {
|
||||
data: 'string',
|
||||
};
|
||||
fetchMock.mockResponse(JSON.stringify(sampleResponse), { status: 403 });
|
||||
// TODO: Check API name and fix message
|
||||
// TODO: Externalize string/import?
|
||||
await expect(apiMock.searchByTitle('sample')).rejects.toThrow(`MDB | Received status code ${403} from an API.`);
|
||||
expect(fetchMock).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
test('searchByTitle behavior when requestUrl/fetch returns 200', async () => {
|
||||
let sampleResponse;
|
||||
let ret;
|
||||
switch (parameterizedApi) {
|
||||
case OMDbAPI:
|
||||
ret = setOMDbResponseMock();
|
||||
sampleResponse = OMDBMockMovie;
|
||||
break;
|
||||
case WikipediaAPI:
|
||||
ret = setWikipediaResponseMock();
|
||||
sampleResponse = WikipediaMockResponse;
|
||||
break;
|
||||
case MALAPI:
|
||||
// TODO: MAL needs more tests for different types of content
|
||||
ret = setMALResponseMock();
|
||||
sampleResponse = MALMockMovie;
|
||||
case LocGovAPI:
|
||||
// TODO: Add soon
|
||||
break;
|
||||
case SteamAPI:
|
||||
sampleResponse = SteamAPIResponseMock;
|
||||
ret = setSteamResponseMock();
|
||||
break;
|
||||
case MusicBrainzAPI:
|
||||
sampleResponse = MusicBrainzResponseMock;
|
||||
ret = setMusicBrainzResponseMock();
|
||||
break;
|
||||
default:
|
||||
throw Error();
|
||||
}
|
||||
fetchMock.mockResponse(JSON.stringify(sampleResponse), { status: 200 });
|
||||
// TODO: Check API name and fix message
|
||||
// TODO: Externalize string
|
||||
await expect(apiMock.searchByTitle('Hooking Season Playtest')).resolves.toEqual(ret);
|
||||
expect(fetchMock).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
},
|
||||
);
|
||||
|
|
@ -1,30 +0,0 @@
|
|||
{
|
||||
"data": [
|
||||
{
|
||||
"mal_id": 2890,
|
||||
"url": "https://myanimelist.net/anime/2890/Gake_no_Ue_no_Ponyo",
|
||||
"title": "Gake no Ue no Ponyo",
|
||||
"title_english": "Ponyo",
|
||||
"type": "Movie",
|
||||
"source": "Original",
|
||||
"episodes": 1,
|
||||
"aired": {
|
||||
"from": "2008-07-19T00:00:00+00:00",
|
||||
"to": null,
|
||||
"prop": {
|
||||
"from": {
|
||||
"day": 19,
|
||||
"month": 7,
|
||||
"year": 2008
|
||||
},
|
||||
"to": {
|
||||
"day": null,
|
||||
"month": null,
|
||||
"year": null
|
||||
}
|
||||
},
|
||||
"string": "Jul 19, 2008"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -1,25 +0,0 @@
|
|||
{
|
||||
"release-groups": [
|
||||
{
|
||||
"id": "9cf08bf9-1948-4087-abe1-783210ea1fae",
|
||||
"primary-type-id": "f529b476-6e62-324f-b0aa-1f3e33d313fc",
|
||||
"title": "Halo Halo",
|
||||
"first-release-date": "2013-07-08",
|
||||
"primary-type": "Album",
|
||||
"artist-credit": [
|
||||
{
|
||||
"name": "Halo Halo",
|
||||
"artist": {
|
||||
"name": "Halo Halo"
|
||||
}
|
||||
}
|
||||
],
|
||||
"releases": [
|
||||
{
|
||||
"id": "58dd1d57-2201-472e-9e36-5d497dcedb6f",
|
||||
"title": "Halo Halo"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
{
|
||||
"Search": [
|
||||
{
|
||||
"Title": "Guardians of the Galaxy",
|
||||
"Year": "2014",
|
||||
"imdbID": "tt2015381",
|
||||
"Type": "movie",
|
||||
"Poster": "https://m.media-amazon.com/images/M/MV5BMTAwMjU5OTgxNjZeQTJeQWpwZ15BbWU4MDUxNDYxODEx._V1_SX300.jpg"
|
||||
}
|
||||
],
|
||||
"totalResults": "1",
|
||||
"Response": "True"
|
||||
}
|
||||
|
|
@ -1,14 +0,0 @@
|
|||
{
|
||||
"applist": {
|
||||
"apps": [
|
||||
{
|
||||
"appid": 2076590,
|
||||
"name": "Hooking Season Playtest"
|
||||
},
|
||||
{
|
||||
"appid": 2076600,
|
||||
"name": "MonsterTamer"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
@ -1,20 +0,0 @@
|
|||
{
|
||||
"query": {
|
||||
"searchinfo": {
|
||||
"totalhits": 1199001,
|
||||
"suggestion": "book",
|
||||
"suggestionsnippet": "book"
|
||||
},
|
||||
"search": [
|
||||
{
|
||||
"ns": 0,
|
||||
"title": "Book",
|
||||
"pageid": 3778,
|
||||
"size": 68829,
|
||||
"wordcount": 8821,
|
||||
"snippet": "called <span class=\"searchmatch\">books</span> or chapters or parts, are parts. The intellectual content in a physical book need not be a composition, nor even be called a book. <span class=\"searchmatch\">Books</span> can",
|
||||
"timestamp": "2022-08-19T19:13:56Z"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
@ -1,25 +0,0 @@
|
|||
import { APIModel } from '../api/APIModel';
|
||||
import { MediaTypeModel } from '../models/MediaTypeModel';
|
||||
import MediaDbPlugin from '../main';
|
||||
|
||||
export class TestAPI extends APIModel {
|
||||
plugin: MediaDbPlugin;
|
||||
|
||||
constructor(plugin: MediaDbPlugin) {
|
||||
super();
|
||||
|
||||
this.plugin = plugin;
|
||||
this.apiName = 'TestAPI';
|
||||
this.apiDescription = 'A test API for automated testing.';
|
||||
this.apiUrl = '';
|
||||
this.types = [];
|
||||
}
|
||||
|
||||
async getById(id: string): Promise<MediaTypeModel> {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
async searchByTitle(title: string): Promise<MediaTypeModel[]> {
|
||||
return [] as MediaTypeModel[];
|
||||
}
|
||||
}
|
||||
|
|
@ -1,95 +0,0 @@
|
|||
import { GameModel } from '../models/GameModel';
|
||||
import { MovieModel } from '../models/MovieModel';
|
||||
import { MusicReleaseModel } from '../models/MusicReleaseModel';
|
||||
import { WikiModel } from '../models/WikiModel';
|
||||
import { MediaType } from '../utils/MediaType';
|
||||
import { apiMock } from './ParameterizedAPI.test';
|
||||
import MALMockMovie from './ResponseMocks/MALMockMovie.json';
|
||||
import MusicBrainzResponseMock from './ResponseMocks/MusicBrainzMockResponse.json';
|
||||
import OMDBMockMovie from './ResponseMocks/OMDBMockResponse.json';
|
||||
import SteamAPIResponseMock from './ResponseMocks/SteamAPIMockResponse.json';
|
||||
import WikipediaMockResponse from './ResponseMocks/WikipediaMockResponse.json';
|
||||
|
||||
export function setWikipediaResponseMock() {
|
||||
let ret = [];
|
||||
let wikiresponse = WikipediaMockResponse.query.search[0];
|
||||
ret.push(
|
||||
new WikiModel({
|
||||
type: 'wiki',
|
||||
title: wikiresponse.title,
|
||||
englishTitle: wikiresponse.title,
|
||||
year: '',
|
||||
dataSource: apiMock.apiName,
|
||||
id: wikiresponse.pageid,
|
||||
}),
|
||||
);
|
||||
return ret;
|
||||
}
|
||||
|
||||
export function setOMDbResponseMock() {
|
||||
let ret = [];
|
||||
let omdbresponse = OMDBMockMovie.Search[0];
|
||||
ret.push(
|
||||
new MovieModel({
|
||||
type: 'wiki',
|
||||
title: omdbresponse.Title,
|
||||
englishTitle: omdbresponse.Title,
|
||||
year: omdbresponse.Year,
|
||||
dataSource: apiMock.apiName,
|
||||
id: omdbresponse.imdbID,
|
||||
}),
|
||||
);
|
||||
return ret;
|
||||
}
|
||||
|
||||
export function setMALResponseMock() {
|
||||
let ret = [];
|
||||
let result = MALMockMovie.data[0];
|
||||
ret.push(
|
||||
new MovieModel({
|
||||
type: result.type,
|
||||
title: result.title,
|
||||
englishTitle: result.title_english,
|
||||
year: result.aired.prop.from.year,
|
||||
dataSource: apiMock.apiName,
|
||||
id: result.mal_id,
|
||||
}),
|
||||
);
|
||||
return ret;
|
||||
}
|
||||
|
||||
export function setSteamResponseMock() {
|
||||
let ret = [];
|
||||
let steamResponse = SteamAPIResponseMock.applist.apps[0];
|
||||
ret.push(
|
||||
new GameModel({
|
||||
type: MediaType.Game,
|
||||
title: steamResponse.name,
|
||||
englishTitle: steamResponse.name,
|
||||
year: '',
|
||||
dataSource: apiMock.apiName,
|
||||
id: steamResponse.appid,
|
||||
}),
|
||||
);
|
||||
return ret;
|
||||
}
|
||||
|
||||
export function setMusicBrainzResponseMock() {
|
||||
let ret = [];
|
||||
let result = MusicBrainzResponseMock['release-groups'][0];
|
||||
ret.push(
|
||||
new MusicReleaseModel({
|
||||
type: 'musicRelease',
|
||||
title: result.title,
|
||||
englishTitle: result.title,
|
||||
year: new Date(result['first-release-date']).getFullYear().toString(),
|
||||
dataSource: apiMock.apiName,
|
||||
url: '',
|
||||
id: result.id,
|
||||
|
||||
artists: result['artist-credit'].map((a: any) => a.name),
|
||||
subType: result['primary-type'],
|
||||
} as MusicReleaseModel),
|
||||
);
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -1,29 +0,0 @@
|
|||
import { containsOnlyLettersAndUnderscores, replaceIllegalFileNameCharactersInString, wrapAround } from '../utils/Utils';
|
||||
|
||||
test('If wrapAround wraps correctly', () => {
|
||||
expect(wrapAround(100, 5)).toBe(0);
|
||||
expect(wrapAround(100, 7)).toBe(2);
|
||||
});
|
||||
|
||||
test('If wrapAround errors out when dividing by zero', () => {
|
||||
expect(wrapAround(100, 0)).toThrow();
|
||||
});
|
||||
|
||||
test('If wrapAround errors out when size is negative', () => {
|
||||
expect(wrapAround(100, -5)).toThrow();
|
||||
});
|
||||
|
||||
test('Letter and underscore string validity', () => {
|
||||
expect(containsOnlyLettersAndUnderscores('asdkfj_')).toBe(true);
|
||||
expect(containsOnlyLettersAndUnderscores('asdkfj0')).toBe(false);
|
||||
});
|
||||
|
||||
// since this is used to check if a string is a valid name for an object property, unicode characters shouldn't be allowed, thus the name of the function is misleading
|
||||
test('Letter and underscore unicode char test', () => {
|
||||
expect(containsOnlyLettersAndUnderscores('asdkaÈj')).toBe(true);
|
||||
expect(containsOnlyLettersAndUnderscores('asdkaÈj0')).toBe(false);
|
||||
});
|
||||
|
||||
test('Valid filename test', () => {
|
||||
expect(replaceIllegalFileNameCharactersInString('what?is\\this:')).toBe('whatisthis -');
|
||||
});
|
||||
|
|
@ -28,7 +28,7 @@ export class MediaTypeManager {
|
|||
mediaTemplateMap: Map<MediaType, string>;
|
||||
mediaFolderMap: Map<MediaType, string>;
|
||||
|
||||
constructor() { }
|
||||
constructor() {}
|
||||
|
||||
updateTemplates(settings: MediaDbPluginSettings): void {
|
||||
this.mediaFileNameTemplateMap = new Map<MediaType, string>();
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ import { MediaDbSearchResultModal } from '../modals/MediaDbSearchResultModal';
|
|||
import { Notice } from 'obsidian';
|
||||
import MediaDbPlugin from '../main';
|
||||
import { MediaDbPreviewModal } from 'src/modals/MediaDbPreviewModal';
|
||||
import { CreateNoteOptions } from './Utils';
|
||||
import { MediaDbSearchModal } from '../modals/MediaDbSearchModal';
|
||||
import { MediaType } from './MediaType';
|
||||
|
||||
|
|
|
|||
|
|
@ -145,7 +145,9 @@ export function markdownTable(content: string[][]): string {
|
|||
return table;
|
||||
}
|
||||
|
||||
export const fragWithHTML = (html: string) => createFragment(frag => (frag.createDiv().innerHTML = html));
|
||||
export function fragWithHTML(html: string): DocumentFragment {
|
||||
return createFragment(frag => (frag.createDiv().innerHTML = html));
|
||||
}
|
||||
|
||||
export function dateToString(date: Date): string {
|
||||
return `${date.getMonth() + 1}-${date.getDate()}-${date.getFullYear()}`;
|
||||
|
|
@ -207,13 +209,13 @@ export function unCamelCase(str: string): string {
|
|||
// space before last upper in a sequence followed by lower
|
||||
.replace(/\b([A-Z]+)([A-Z])([a-z])/, '$1 $2$3')
|
||||
// uppercase the first character
|
||||
.replace(/^./, function(str) {
|
||||
.replace(/^./, function (str) {
|
||||
return str.toUpperCase();
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
export function hasTemplaterPlugin(app: App) {
|
||||
export function hasTemplaterPlugin(app: App): boolean {
|
||||
const templater = (app as any).plugins.plugins['templater-obsidian'];
|
||||
|
||||
return !!templater;
|
||||
|
|
@ -221,7 +223,7 @@ export function hasTemplaterPlugin(app: App) {
|
|||
|
||||
// Copied from https://github.com/anpigon/obsidian-book-search-plugin
|
||||
// Licensed under the MIT license. Copyright (c) 2020 Jake Runzer
|
||||
export async function useTemplaterPluginInFile(app: App, file: TFile) {
|
||||
export async function useTemplaterPluginInFile(app: App, file: TFile): Promise<void> {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const templater = (app as any).plugins.plugins['templater-obsidian'];
|
||||
if (templater && !templater?.settings['trigger_on_file_creation']) {
|
||||
|
|
|
|||
|
|
@ -1,43 +0,0 @@
|
|||
export class YAMLConverter {
|
||||
static toYaml(obj: any): string {
|
||||
let output = '';
|
||||
|
||||
for (const [key, value] of Object.entries(obj)) {
|
||||
output += `${key}: ${YAMLConverter.toYamlString(value, 0)}\n`;
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
private static toYamlString(value: any, indentation: number): string {
|
||||
if (value == null) {
|
||||
return 'null';
|
||||
}
|
||||
|
||||
if (typeof value === 'boolean') {
|
||||
return value ? 'true' : 'false';
|
||||
} else if (typeof value === 'number') {
|
||||
return value.toString();
|
||||
} else if (typeof value === 'string') {
|
||||
return '"' + value.replace('"', '\\"') + '"';
|
||||
} else if (typeof value === 'object') {
|
||||
let output = '';
|
||||
|
||||
if (Array.isArray(value)) {
|
||||
for (const valueElement of value) {
|
||||
output += `\n${YAMLConverter.calculateSpacing(indentation)} - ${YAMLConverter.toYamlString(valueElement, indentation + 1)}`;
|
||||
}
|
||||
} else {
|
||||
for (const [objKey, objValue] of Object.entries(value)) {
|
||||
output += `\n${YAMLConverter.calculateSpacing(indentation)} ${objKey}: ${YAMLConverter.toYamlString(objValue, indentation + 1)}`;
|
||||
}
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
}
|
||||
|
||||
private static calculateSpacing(indentation: number): string {
|
||||
return ' '.repeat(indentation * 4);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue