big changes; we have a good TS config now
This commit is contained in:
parent
cbbaf54b33
commit
4497991344
54 changed files with 750 additions and 671 deletions
|
|
@ -1,2 +0,0 @@
|
|||
npm node_modules
|
||||
build
|
||||
20
.eslintrc
20
.eslintrc
|
|
@ -1,20 +0,0 @@
|
|||
{
|
||||
"root": true,
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"env": { "node": true },
|
||||
"plugins": ["@typescript-eslint", "only-warn"],
|
||||
"extends": ["eslint:recommended", "plugin:@typescript-eslint/eslint-recommended", "plugin:@typescript-eslint/recommended"],
|
||||
"parserOptions": {
|
||||
"sourceType": "module"
|
||||
},
|
||||
"rules": {
|
||||
"no-unused-vars": "off",
|
||||
"@typescript-eslint/no-unused-vars": ["error", { "args": "none" }],
|
||||
"@typescript-eslint/ban-ts-comment": "off",
|
||||
"no-prototype-builtins": "off",
|
||||
"@typescript-eslint/no-empty-function": "off",
|
||||
"@typescript-eslint/no-inferrable-types": "off",
|
||||
"@typescript-eslint/no-explicit-any": "off",
|
||||
"@typescript-eslint/explicit-function-return-type": ["warn"]
|
||||
}
|
||||
}
|
||||
|
|
@ -112,7 +112,7 @@ Now you select the result you want and the plugin will cast it's magic and creat
|
|||
### Currently supported APIs:
|
||||
|
||||
| Name | Description | Supported formats | Authentification | Rate limiting | SFW filter support |
|
||||
| ---------------------------------------------------- | ------------------------------------------------------------------------------------------------- | ----------------------------------------------------- | ---------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------ |
|
||||
| ---------------------------------------------------- | ------------------------------------------------------------------------------------------------- | ----------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------ |
|
||||
| [Jikan](https://jikan.moe/) | Jikan is an API that uses [My Anime List](https://myanimelist.net) and offers metadata for anime. | series, movies, specials, OVAs, manga, manwha, novels | No | 60 per minute and 3 per second | Yes |
|
||||
| [OMDb](https://www.omdbapi.com/) | OMDb is an API that offers metadata for movie, series and games. | series, movies, games | Yes, you can get a free key here [here](https://www.omdbapi.com/apikey.aspx) | 1000 per day | No |
|
||||
| [MusicBrainz](https://musicbrainz.org/) | MusicBrainz is an API that offers information about music releases. | music releases | No | 50 per second | No |
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import builtins from 'builtin-modules';
|
||||
import esbuild from 'esbuild';
|
||||
import esbuildSvelte from 'esbuild-svelte';
|
||||
import sveltePreprocess from 'svelte-preprocess';
|
||||
import { sveltePreprocess } from 'svelte-preprocess';
|
||||
import { getBuildBanner } from 'build/buildBanner';
|
||||
|
||||
const banner = getBuildBanner('Release Build', version => version);
|
||||
|
|
@ -41,7 +41,7 @@ const build = await esbuild.build({
|
|||
},
|
||||
plugins: [
|
||||
esbuildSvelte({
|
||||
compilerOptions: { css: 'injected', dev: false, sveltePath: 'svelte' },
|
||||
compilerOptions: { css: 'injected', dev: false },
|
||||
preprocess: sveltePreprocess(),
|
||||
filterWarnings: warning => {
|
||||
// we don't want warnings from node modules that we can do nothing about
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import esbuild from 'esbuild';
|
||||
import copy from 'esbuild-plugin-copy-watch';
|
||||
import esbuildSvelte from 'esbuild-svelte';
|
||||
import sveltePreprocess from 'svelte-preprocess';
|
||||
import { sveltePreprocess } from 'svelte-preprocess';
|
||||
import manifest from '../../manifest.json' assert { type: 'json' };
|
||||
import { getBuildBanner } from 'build/buildBanner';
|
||||
|
||||
|
|
@ -52,7 +52,7 @@ const context = await esbuild.context({
|
|||
],
|
||||
}),
|
||||
esbuildSvelte({
|
||||
compilerOptions: { css: 'injected', dev: true, sveltePath: 'svelte' },
|
||||
compilerOptions: { css: 'injected', dev: true },
|
||||
preprocess: sveltePreprocess(),
|
||||
filterWarnings: warning => {
|
||||
// we don't want warnings from node modules that we can do nothing about
|
||||
|
|
|
|||
BIN
bun.lockb
BIN
bun.lockb
Binary file not shown.
54
eslint.config.mjs
Normal file
54
eslint.config.mjs
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
// @ts-check
|
||||
|
||||
import eslint from '@eslint/js';
|
||||
import tseslint from 'typescript-eslint';
|
||||
import only_warn from 'eslint-plugin-only-warn';
|
||||
import * as plugin_import from 'eslint-plugin-import';
|
||||
|
||||
export default tseslint.config(
|
||||
{
|
||||
ignores: ['npm/', 'node_modules/', 'exampleVault/', 'automation/', 'main.js', '*.svelte'],
|
||||
},
|
||||
{
|
||||
files: ['src/**/*.ts'],
|
||||
extends: [eslint.configs.recommended, ...tseslint.configs.recommended, ...tseslint.configs.recommendedTypeChecked, ...tseslint.configs.stylisticTypeChecked],
|
||||
languageOptions: {
|
||||
parser: tseslint.parser,
|
||||
parserOptions: {
|
||||
project: true,
|
||||
},
|
||||
},
|
||||
plugins: {
|
||||
// @ts-ignore
|
||||
'only-warn': only_warn,
|
||||
import: plugin_import,
|
||||
},
|
||||
rules: {
|
||||
'@typescript-eslint/no-explicit-any': ['warn'],
|
||||
|
||||
'@typescript-eslint/no-unused-vars': [
|
||||
'error',
|
||||
{ argsIgnorePattern: '^_', destructuredArrayIgnorePattern: '^_', varsIgnorePattern: '^_', caughtErrorsIgnorePattern: '^_' },
|
||||
],
|
||||
'@typescript-eslint/consistent-type-imports': ['error', { prefer: 'type-imports', fixStyle: 'separate-type-imports' }],
|
||||
|
||||
'import/consistent-type-specifier-style': ['error', 'prefer-top-level'],
|
||||
'import/order': [
|
||||
'error',
|
||||
{
|
||||
'newlines-between': 'never',
|
||||
alphabetize: { order: 'asc', orderImportKind: 'asc', caseInsensitive: true },
|
||||
},
|
||||
],
|
||||
|
||||
'@typescript-eslint/no-confusing-void-expression': ['error', { ignoreArrowShorthand: true }],
|
||||
'@typescript-eslint/restrict-template-expressions': 'off',
|
||||
|
||||
'@typescript-eslint/ban-ts-comment': 'off',
|
||||
'@typescript-eslint/no-empty-function': 'off',
|
||||
'@typescript-eslint/no-inferrable-types': 'off',
|
||||
'@typescript-eslint/explicit-function-return-type': ['warn'],
|
||||
'@typescript-eslint/require-await': 'off',
|
||||
},
|
||||
},
|
||||
);
|
||||
39
package.json
39
package.json
|
|
@ -14,8 +14,8 @@
|
|||
"lint": "eslint --max-warnings=0 src/**",
|
||||
"lint:fix": "eslint --max-warnings=0 --fix src/**",
|
||||
"svelte-check": "svelte-check --compiler-warnings \"unused-export-let:ignore\"",
|
||||
"check": "bun run format:check && bun run tsc && bun run lint && bun run test",
|
||||
"check:fix": "bun run format && bun run tsc && bun run lint:fix && bun run test",
|
||||
"check": "bun run format:check && bun run tsc && bun run test",
|
||||
"check:fix": "bun run format && bun run tsc && bun run test",
|
||||
"release": "bun run automation/release.ts",
|
||||
"stats": "bun run automation/stats.ts"
|
||||
},
|
||||
|
|
@ -25,27 +25,24 @@
|
|||
"devDependencies": {
|
||||
"@popperjs/core": "^2.11.8",
|
||||
"@lemons_dev/parsinom": "^0.0.12",
|
||||
"@happy-dom/global-registrator": "^14.3.6",
|
||||
"@tsconfig/svelte": "^5.0.3",
|
||||
"@types/bun": "^1.0.10",
|
||||
"@typescript-eslint/eslint-plugin": "^7.3.1",
|
||||
"@typescript-eslint/parser": "^7.3.1",
|
||||
"builtin-modules": "^3.3.0",
|
||||
"esbuild": "^0.20.2",
|
||||
"esbuild-plugin-copy-watch": "^2.1.0",
|
||||
"esbuild-svelte": "^0.8.0",
|
||||
"eslint": "^8.57.0",
|
||||
"eslint-plugin-import": "^2.29.1",
|
||||
"eslint-plugin-isaacscript": "^3.12.2",
|
||||
"@happy-dom/global-registrator": "^14.12.3",
|
||||
"@types/bun": "^1.1.16",
|
||||
"builtin-modules": "^4.0.0",
|
||||
"esbuild": "^0.24.2",
|
||||
"esbuild-plugin-copy-watch": "^2.3.1",
|
||||
"esbuild-svelte": "^0.8.2",
|
||||
"eslint": "^9.18.0",
|
||||
"eslint-plugin-import": "^2.31.0",
|
||||
"eslint-plugin-only-warn": "^1.1.0",
|
||||
"obsidian": "latest",
|
||||
"prettier": "^3.2.5",
|
||||
"prettier-plugin-svelte": "^3.2.2",
|
||||
"prettier": "^3.4.2",
|
||||
"prettier-plugin-svelte": "^3.3.3",
|
||||
"string-argv": "^0.3.2",
|
||||
"svelte": "^4.2.12",
|
||||
"svelte-check": "^3.6.8",
|
||||
"svelte-preprocess": "^5.1.3",
|
||||
"tslib": "^2.6.2",
|
||||
"typescript": "^5.4.3"
|
||||
"svelte": "^5.17.5",
|
||||
"svelte-check": "^4.1.4",
|
||||
"svelte-preprocess": "^6.0.3",
|
||||
"tslib": "^2.8.1",
|
||||
"typescript": "^5.7.3",
|
||||
"typescript-eslint": "^8.20.0"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import { APIModel } from './APIModel';
|
||||
import { MediaTypeModel } from '../models/MediaTypeModel';
|
||||
import { Notice } from 'obsidian';
|
||||
import type { MediaTypeModel } from '../models/MediaTypeModel';
|
||||
import type { APIModel } from './APIModel';
|
||||
|
||||
export class APIManager {
|
||||
apis: APIModel[];
|
||||
|
|
@ -23,7 +24,10 @@ export class APIManager {
|
|||
try {
|
||||
return await api.searchByTitle(query);
|
||||
} catch (e) {
|
||||
new Notice(`Error querying ${api.apiName}: ${e}`);
|
||||
console.warn(e);
|
||||
|
||||
return [];
|
||||
}
|
||||
});
|
||||
|
||||
|
|
@ -35,7 +39,7 @@ export class APIManager {
|
|||
*
|
||||
* @param item
|
||||
*/
|
||||
async queryDetailedInfo(item: MediaTypeModel): Promise<MediaTypeModel> {
|
||||
async queryDetailedInfo(item: MediaTypeModel): Promise<MediaTypeModel | undefined> {
|
||||
return await this.queryDetailedInfoById(item.id, item.dataSource);
|
||||
}
|
||||
|
||||
|
|
@ -45,22 +49,31 @@ export class APIManager {
|
|||
* @param id
|
||||
* @param apiName
|
||||
*/
|
||||
async queryDetailedInfoById(id: string, apiName: string): Promise<MediaTypeModel> {
|
||||
async queryDetailedInfoById(id: string, apiName: string): Promise<MediaTypeModel | undefined> {
|
||||
for (const api of this.apis) {
|
||||
if (api.apiName === apiName) {
|
||||
try {
|
||||
return api.getById(id);
|
||||
} catch (e) {
|
||||
new Notice(`Error querying ${api.apiName}: ${e}`);
|
||||
console.warn(e);
|
||||
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
getApiByName(name: string): APIModel {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
getApiByName(name: string): APIModel | undefined {
|
||||
for (const api of this.apis) {
|
||||
if (api.apiName === name) {
|
||||
return api;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
return undefined;
|
||||
}
|
||||
|
||||
registerAPI(api: APIModel): void {
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
import { MediaTypeModel } from '../models/MediaTypeModel';
|
||||
import { MediaType } from '../utils/MediaType';
|
||||
import MediaDbPlugin from '../main';
|
||||
import type MediaDbPlugin from '../main';
|
||||
import type { MediaTypeModel } from '../models/MediaTypeModel';
|
||||
import type { MediaType } from '../utils/MediaType';
|
||||
|
||||
export abstract class APIModel {
|
||||
apiName: string;
|
||||
apiUrl: string;
|
||||
apiDescription: string;
|
||||
types: MediaType[];
|
||||
plugin: MediaDbPlugin;
|
||||
apiName!: string;
|
||||
apiUrl!: string;
|
||||
apiDescription!: string;
|
||||
types!: MediaType[];
|
||||
plugin!: MediaDbPlugin;
|
||||
|
||||
/**
|
||||
* This function should query the api and return a list of matches. The matches should be caped at 20.
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
import { APIModel } from '../APIModel';
|
||||
import { MediaTypeModel } from '../../models/MediaTypeModel';
|
||||
import MediaDbPlugin from '../../main';
|
||||
import { BoardGameModel } from 'src/models/BoardGameModel';
|
||||
import { requestUrl } from 'obsidian';
|
||||
import { BoardGameModel } from 'src/models/BoardGameModel';
|
||||
import type MediaDbPlugin from '../../main';
|
||||
import type { MediaTypeModel } from '../../models/MediaTypeModel';
|
||||
import { MediaType } from '../../utils/MediaType';
|
||||
import { APIModel } from '../APIModel';
|
||||
|
||||
export class BoardGameGeekAPI extends APIModel {
|
||||
plugin: MediaDbPlugin;
|
||||
|
|
@ -38,8 +38,8 @@ export class BoardGameGeekAPI extends APIModel {
|
|||
const ret: MediaTypeModel[] = [];
|
||||
|
||||
for (const boardgame of Array.from(response.querySelectorAll('boardgame'))) {
|
||||
const id = boardgame.attributes.getNamedItem('objectid')!.value;
|
||||
const title = boardgame.querySelector('name[primary=true]')?.textContent ?? boardgame.querySelector('name')!.textContent!;
|
||||
const id = boardgame.attributes.getNamedItem('objectid')?.value;
|
||||
const title = boardgame.querySelector('name[primary=true]')?.textContent ?? boardgame.querySelector('name')?.textContent ?? undefined;
|
||||
const year = boardgame.querySelector('yearpublished')?.textContent ?? '';
|
||||
|
||||
ret.push(
|
||||
|
|
@ -49,7 +49,7 @@ export class BoardGameGeekAPI extends APIModel {
|
|||
title,
|
||||
englishTitle: title,
|
||||
year,
|
||||
} as BoardGameModel),
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -72,21 +72,29 @@ export class BoardGameGeekAPI extends APIModel {
|
|||
const response = new window.DOMParser().parseFromString(data, 'text/xml');
|
||||
// console.debug(response);
|
||||
|
||||
const boardgame = response.querySelector('boardgame')!;
|
||||
const title = boardgame.querySelector('name[primary=true]')!.textContent!;
|
||||
const boardgame = response.querySelector('boardgame');
|
||||
if (!boardgame) {
|
||||
throw Error(`MDB | Received invalid data from ${this.apiName}.`);
|
||||
}
|
||||
|
||||
const title = boardgame.querySelector('name[primary=true]')?.textContent;
|
||||
const year = boardgame.querySelector('yearpublished')?.textContent ?? '';
|
||||
const image = boardgame.querySelector('image')?.textContent ?? undefined;
|
||||
const onlineRating = Number.parseFloat(boardgame.querySelector('statistics ratings average')?.textContent ?? '0');
|
||||
const genres = Array.from(boardgame.querySelectorAll('boardgamecategory')).map(n => n!.textContent!);
|
||||
const genres = Array.from(boardgame.querySelectorAll('boardgamecategory'))
|
||||
.map(n => n.textContent)
|
||||
.filter(n => n !== null);
|
||||
const complexityRating = Number.parseFloat(boardgame.querySelector('averageweight')?.textContent ?? '0');
|
||||
const minPlayers = Number.parseFloat(boardgame.querySelector('minplayers')?.textContent ?? '0');
|
||||
const maxPlayers = Number.parseFloat(boardgame.querySelector('maxplayers')?.textContent ?? '0');
|
||||
const playtime = (boardgame.querySelector('playingtime')?.textContent ?? 'unknown') + ' minutes';
|
||||
const publishers = Array.from(boardgame.querySelectorAll('boardgamepublisher')).map(n => n!.textContent!);
|
||||
const publishers = Array.from(boardgame.querySelectorAll('boardgamepublisher'))
|
||||
.map(n => n.textContent)
|
||||
.filter(n => n !== null);
|
||||
|
||||
return new BoardGameModel({
|
||||
title: title,
|
||||
englishTitle: title,
|
||||
title: title ?? undefined,
|
||||
englishTitle: title ?? undefined,
|
||||
year: year === '0' ? '' : year,
|
||||
dataSource: this.apiName,
|
||||
url: `https://boardgamegeek.com/boardgame/${id}`,
|
||||
|
|
@ -107,6 +115,6 @@ export class BoardGameGeekAPI extends APIModel {
|
|||
played: false,
|
||||
personalRating: 0,
|
||||
},
|
||||
} as BoardGameModel);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
import { APIModel } from '../APIModel';
|
||||
import { MediaTypeModel } from '../../models/MediaTypeModel';
|
||||
import MediaDbPlugin from '../../main';
|
||||
import { GameModel } from '../../models/GameModel';
|
||||
import { requestUrl } from 'obsidian';
|
||||
import type MediaDbPlugin from '../../main';
|
||||
import { GameModel } from '../../models/GameModel';
|
||||
import type { MediaTypeModel } from '../../models/MediaTypeModel';
|
||||
import { MediaType } from '../../utils/MediaType';
|
||||
import { APIModel } from '../APIModel';
|
||||
|
||||
export class GiantBombAPI extends APIModel {
|
||||
plugin: MediaDbPlugin;
|
||||
|
|
@ -54,7 +54,7 @@ export class GiantBombAPI extends APIModel {
|
|||
year: new Date(result.original_release_date).getFullYear().toString(),
|
||||
dataSource: this.apiName,
|
||||
id: result.guid,
|
||||
} as GameModel),
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -104,6 +104,6 @@ export class GiantBombAPI extends APIModel {
|
|||
|
||||
personalRating: 0,
|
||||
},
|
||||
} as GameModel);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
import { APIModel } from '../APIModel';
|
||||
import { MediaTypeModel } from '../../models/MediaTypeModel';
|
||||
import type MediaDbPlugin from '../../main';
|
||||
import type { MediaTypeModel } from '../../models/MediaTypeModel';
|
||||
import { MovieModel } from '../../models/MovieModel';
|
||||
import MediaDbPlugin from '../../main';
|
||||
import { SeriesModel } from '../../models/SeriesModel';
|
||||
import { MediaType } from '../../utils/MediaType';
|
||||
import { APIModel } from '../APIModel';
|
||||
|
||||
export class MALAPI extends APIModel {
|
||||
plugin: MediaDbPlugin;
|
||||
|
|
@ -52,7 +52,7 @@ export class MALAPI extends APIModel {
|
|||
year: result.year ?? result.aired?.prop?.from?.year ?? '',
|
||||
dataSource: this.apiName,
|
||||
id: result.mal_id,
|
||||
} as MovieModel),
|
||||
}),
|
||||
);
|
||||
}
|
||||
if (type === 'movie' || type === 'special') {
|
||||
|
|
@ -64,7 +64,7 @@ export class MALAPI extends APIModel {
|
|||
year: result.year ?? result.aired?.prop?.from?.year ?? '',
|
||||
dataSource: this.apiName,
|
||||
id: result.mal_id,
|
||||
} as MovieModel),
|
||||
}),
|
||||
);
|
||||
} else if (type === 'series' || type === 'ova') {
|
||||
ret.push(
|
||||
|
|
@ -75,7 +75,7 @@ export class MALAPI extends APIModel {
|
|||
year: result.year ?? result.aired?.prop?.from?.year ?? '',
|
||||
dataSource: this.apiName,
|
||||
id: result.mal_id,
|
||||
} as SeriesModel),
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -127,7 +127,7 @@ export class MALAPI extends APIModel {
|
|||
lastWatched: '',
|
||||
personalRating: 0,
|
||||
},
|
||||
} as MovieModel);
|
||||
});
|
||||
}
|
||||
|
||||
if (type === 'movie' || type === 'special') {
|
||||
|
|
@ -159,7 +159,7 @@ export class MALAPI extends APIModel {
|
|||
lastWatched: '',
|
||||
personalRating: 0,
|
||||
},
|
||||
} as MovieModel);
|
||||
});
|
||||
} else if (type === 'series' || type === 'ova') {
|
||||
return new SeriesModel({
|
||||
subType: type,
|
||||
|
|
@ -190,9 +190,9 @@ export class MALAPI extends APIModel {
|
|||
lastWatched: '',
|
||||
personalRating: 0,
|
||||
},
|
||||
} as SeriesModel);
|
||||
});
|
||||
}
|
||||
|
||||
return;
|
||||
throw new Error(`MDB | Unknown media type for id ${id}`);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import { APIModel } from '../APIModel';
|
||||
import { MediaTypeModel } from '../../models/MediaTypeModel';
|
||||
import MediaDbPlugin from '../../main';
|
||||
import type MediaDbPlugin from '../../main';
|
||||
import { MangaModel } from '../../models/MangaModel';
|
||||
import type { MediaTypeModel } from '../../models/MediaTypeModel';
|
||||
import { MediaType } from '../../utils/MediaType';
|
||||
import { APIModel } from '../APIModel';
|
||||
|
||||
export class MALAPIManga extends APIModel {
|
||||
plugin: MediaDbPlugin;
|
||||
|
|
@ -73,7 +73,7 @@ export class MALAPIManga extends APIModel {
|
|||
lastWatched: '',
|
||||
personalRating: 0,
|
||||
},
|
||||
} as MangaModel),
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -123,6 +123,6 @@ export class MALAPIManga extends APIModel {
|
|||
lastWatched: '',
|
||||
personalRating: 0,
|
||||
},
|
||||
} as MangaModel);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
import { APIModel } from '../APIModel';
|
||||
import { Notice } from 'obsidian';
|
||||
import { MediaTypeModel } from '../../models/MediaTypeModel';
|
||||
import MediaDbPlugin from '../../main';
|
||||
import { GameModel } from '../../models/GameModel';
|
||||
import { requestUrl } from 'obsidian';
|
||||
import type MediaDbPlugin from '../../main';
|
||||
import { GameModel } from '../../models/GameModel';
|
||||
import type { MediaTypeModel } from '../../models/MediaTypeModel';
|
||||
import { MediaType } from '../../utils/MediaType';
|
||||
import { APIModel } from '../APIModel';
|
||||
|
||||
export class MobyGamesAPI extends APIModel {
|
||||
plugin: MediaDbPlugin;
|
||||
|
|
@ -23,9 +23,7 @@ export class MobyGamesAPI extends APIModel {
|
|||
console.log(`MDB | api "${this.apiName}" queried by Title`);
|
||||
|
||||
if (!this.plugin.settings.MobyGamesKey) {
|
||||
console.error(new Error(`MDB | API key for ${this.apiName} missing.`));
|
||||
new Notice(`MediaDB | API key for ${this.apiName} missing.`);
|
||||
return [];
|
||||
throw new Error(`MDB | API key for ${this.apiName} missing.`);
|
||||
}
|
||||
|
||||
const searchUrl = `${this.apiUrl}/games?title=${encodeURIComponent(title)}&api_key=${this.plugin.settings.MobyGamesKey}`;
|
||||
|
|
@ -68,7 +66,6 @@ export class MobyGamesAPI extends APIModel {
|
|||
console.log(`MDB | api "${this.apiName}" queried by ID`);
|
||||
|
||||
if (!this.plugin.settings.MobyGamesKey) {
|
||||
new Notice(`MediaDB | API key for ${this.apiName} missing.`);
|
||||
throw Error(`MDB | API key for ${this.apiName} missing.`);
|
||||
}
|
||||
|
||||
|
|
@ -79,7 +76,6 @@ export class MobyGamesAPI extends APIModel {
|
|||
console.debug(fetchData);
|
||||
|
||||
if (fetchData.status !== 200) {
|
||||
new Notice(`MDB | Received status code ${fetchData.status} from ${this.apiName}.`);
|
||||
throw Error(`MDB | Received status code ${fetchData.status} from ${this.apiName}.`);
|
||||
}
|
||||
|
||||
|
|
@ -109,6 +105,6 @@ export class MobyGamesAPI extends APIModel {
|
|||
|
||||
personalRating: 0,
|
||||
},
|
||||
} as GameModel);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
import { APIModel } from '../APIModel';
|
||||
import { MediaTypeModel } from '../../models/MediaTypeModel';
|
||||
import MediaDbPlugin from '../../main';
|
||||
import { requestUrl } from 'obsidian';
|
||||
import type MediaDbPlugin from '../../main';
|
||||
import type { MediaTypeModel } from '../../models/MediaTypeModel';
|
||||
import { MusicReleaseModel } from '../../models/MusicReleaseModel';
|
||||
import { contactEmail, mediaDbVersion, pluginName } from '../../utils/Utils';
|
||||
import { MediaType } from '../../utils/MediaType';
|
||||
import { contactEmail, mediaDbVersion, pluginName } from '../../utils/Utils';
|
||||
import { APIModel } from '../APIModel';
|
||||
|
||||
export class MusicBrainzAPI extends APIModel {
|
||||
plugin: MediaDbPlugin;
|
||||
|
|
@ -55,7 +55,7 @@ export class MusicBrainzAPI extends APIModel {
|
|||
|
||||
artists: result['artist-credit'].map((a: any) => a.name),
|
||||
subType: result['primary-type'],
|
||||
} as MusicReleaseModel),
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -97,6 +97,6 @@ export class MusicBrainzAPI extends APIModel {
|
|||
userData: {
|
||||
personalRating: 0,
|
||||
},
|
||||
} as MusicReleaseModel);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
import { APIModel } from '../APIModel';
|
||||
import { Notice } from 'obsidian';
|
||||
import { MediaTypeModel } from '../../models/MediaTypeModel';
|
||||
import { MovieModel } from '../../models/MovieModel';
|
||||
import MediaDbPlugin from '../../main';
|
||||
import { SeriesModel } from '../../models/SeriesModel';
|
||||
import type MediaDbPlugin from '../../main';
|
||||
import { GameModel } from '../../models/GameModel';
|
||||
import type { MediaTypeModel } from '../../models/MediaTypeModel';
|
||||
import { MovieModel } from '../../models/MovieModel';
|
||||
import { SeriesModel } from '../../models/SeriesModel';
|
||||
import { MediaType } from '../../utils/MediaType';
|
||||
import { APIModel } from '../APIModel';
|
||||
|
||||
export class OMDbAPI extends APIModel {
|
||||
plugin: MediaDbPlugin;
|
||||
|
|
@ -30,9 +30,7 @@ export class OMDbAPI extends APIModel {
|
|||
console.log(`MDB | api "${this.apiName}" queried by Title`);
|
||||
|
||||
if (!this.plugin.settings.OMDbKey) {
|
||||
console.error(new Error(`MDB | API key for ${this.apiName} missing.`));
|
||||
new Notice(`MediaDB | API key for ${this.apiName} missing.`);
|
||||
return [];
|
||||
throw new Error(`MDB | API key for ${this.apiName} missing.`);
|
||||
}
|
||||
|
||||
const searchUrl = `https://www.omdbapi.com/?s=${encodeURIComponent(title)}&apikey=${this.plugin.settings.OMDbKey}`;
|
||||
|
|
@ -76,7 +74,7 @@ export class OMDbAPI extends APIModel {
|
|||
year: result.Year,
|
||||
dataSource: this.apiName,
|
||||
id: result.imdbID,
|
||||
} as MovieModel),
|
||||
}),
|
||||
);
|
||||
} else if (type === 'series') {
|
||||
ret.push(
|
||||
|
|
@ -87,7 +85,7 @@ export class OMDbAPI extends APIModel {
|
|||
year: result.Year,
|
||||
dataSource: this.apiName,
|
||||
id: result.imdbID,
|
||||
} as SeriesModel),
|
||||
}),
|
||||
);
|
||||
} else if (type === 'game') {
|
||||
ret.push(
|
||||
|
|
@ -98,7 +96,7 @@ export class OMDbAPI extends APIModel {
|
|||
year: result.Year,
|
||||
dataSource: this.apiName,
|
||||
id: result.imdbID,
|
||||
} as GameModel),
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -110,7 +108,6 @@ export class OMDbAPI extends APIModel {
|
|||
console.log(`MDB | api "${this.apiName}" queried by ID`);
|
||||
|
||||
if (!this.plugin.settings.OMDbKey) {
|
||||
new Notice(`MediaDB | API key for ${this.apiName} missing.`);
|
||||
throw Error(`MDB | API key for ${this.apiName} missing.`);
|
||||
}
|
||||
|
||||
|
|
@ -118,11 +115,9 @@ export class OMDbAPI extends APIModel {
|
|||
const fetchData = await fetch(searchUrl);
|
||||
|
||||
if (fetchData.status === 401) {
|
||||
new Notice(`MDB | Authentication for ${this.apiName} failed. Check the API key.`);
|
||||
throw Error(`MDB | Authentication for ${this.apiName} failed. Check the API key.`);
|
||||
}
|
||||
if (fetchData.status !== 200) {
|
||||
new Notice(`MDB | Received status code ${fetchData.status} from ${this.apiName}.`);
|
||||
throw Error(`MDB | Received status code ${fetchData.status} from ${this.apiName}.`);
|
||||
}
|
||||
|
||||
|
|
@ -130,7 +125,6 @@ export class OMDbAPI extends APIModel {
|
|||
// console.debug(result);
|
||||
|
||||
if (result.Response === 'False') {
|
||||
new Notice(`MDB | Received error from ${this.apiName}: ${result.Error}`);
|
||||
throw Error(`MDB | Received error from ${this.apiName}: ${result.Error}`);
|
||||
}
|
||||
|
||||
|
|
@ -168,7 +162,7 @@ export class OMDbAPI extends APIModel {
|
|||
lastWatched: '',
|
||||
personalRating: 0,
|
||||
},
|
||||
} as MovieModel);
|
||||
});
|
||||
} else if (type === 'series') {
|
||||
return new SeriesModel({
|
||||
type: type,
|
||||
|
|
@ -200,7 +194,7 @@ export class OMDbAPI extends APIModel {
|
|||
lastWatched: '',
|
||||
personalRating: 0,
|
||||
},
|
||||
} as SeriesModel);
|
||||
});
|
||||
} else if (type === 'game') {
|
||||
return new GameModel({
|
||||
type: type,
|
||||
|
|
@ -224,9 +218,9 @@ export class OMDbAPI extends APIModel {
|
|||
played: false,
|
||||
personalRating: 0,
|
||||
},
|
||||
} as GameModel);
|
||||
});
|
||||
}
|
||||
|
||||
return;
|
||||
throw new Error(`MDB | Unknown media type for id ${id}`);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
import { APIModel } from '../APIModel';
|
||||
import { MediaTypeModel } from '../../models/MediaTypeModel';
|
||||
import MediaDbPlugin from '../../main';
|
||||
import { BookModel } from 'src/models/BookModel';
|
||||
import type MediaDbPlugin from '../../main';
|
||||
import type { MediaTypeModel } from '../../models/MediaTypeModel';
|
||||
import { MediaType } from '../../utils/MediaType';
|
||||
import { APIModel } from '../APIModel';
|
||||
|
||||
export class OpenLibraryAPI extends APIModel {
|
||||
plugin: MediaDbPlugin;
|
||||
|
|
@ -42,7 +42,7 @@ export class OpenLibraryAPI extends APIModel {
|
|||
dataSource: this.apiName,
|
||||
id: result.key,
|
||||
author: result.author_name ?? 'unknown',
|
||||
} as BookModel),
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -87,6 +87,6 @@ export class OpenLibraryAPI extends APIModel {
|
|||
lastRead: '',
|
||||
personalRating: 0,
|
||||
},
|
||||
} as BookModel);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
import { APIModel } from '../APIModel';
|
||||
import { MediaTypeModel } from '../../models/MediaTypeModel';
|
||||
import MediaDbPlugin from '../../main';
|
||||
import { GameModel } from '../../models/GameModel';
|
||||
import { requestUrl } from 'obsidian';
|
||||
import type MediaDbPlugin from '../../main';
|
||||
import { GameModel } from '../../models/GameModel';
|
||||
import type { MediaTypeModel } from '../../models/MediaTypeModel';
|
||||
import { MediaType } from '../../utils/MediaType';
|
||||
import { APIModel } from '../APIModel';
|
||||
|
||||
export class SteamAPI extends APIModel {
|
||||
plugin: MediaDbPlugin;
|
||||
|
|
@ -49,7 +49,7 @@ export class SteamAPI extends APIModel {
|
|||
year: '',
|
||||
dataSource: this.apiName,
|
||||
id: result.appid,
|
||||
} as GameModel),
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -94,8 +94,8 @@ export class SteamAPI extends APIModel {
|
|||
url: `https://store.steampowered.com/app/${result.steam_appid}`,
|
||||
id: result.steam_appid,
|
||||
|
||||
developers: result['developers'],
|
||||
publishers: result['publishers'],
|
||||
developers: result.developers,
|
||||
publishers: result.publishers,
|
||||
genres: result.genres?.map((x: any) => x.description) ?? [],
|
||||
onlineRating: Number.parseFloat(result.metacritic?.score ?? 0),
|
||||
image: result.header_image ?? '',
|
||||
|
|
@ -107,6 +107,6 @@ export class SteamAPI extends APIModel {
|
|||
played: false,
|
||||
personalRating: 0,
|
||||
},
|
||||
} as GameModel);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import { APIModel } from '../APIModel';
|
||||
import { MediaTypeModel } from '../../models/MediaTypeModel';
|
||||
import MediaDbPlugin from '../../main';
|
||||
import type MediaDbPlugin from '../../main';
|
||||
import type { MediaTypeModel } from '../../models/MediaTypeModel';
|
||||
import { WikiModel } from '../../models/WikiModel';
|
||||
import { MediaType } from '../../utils/MediaType';
|
||||
import { APIModel } from '../APIModel';
|
||||
|
||||
export class WikipediaAPI extends APIModel {
|
||||
plugin: MediaDbPlugin;
|
||||
|
|
@ -42,7 +42,7 @@ export class WikipediaAPI extends APIModel {
|
|||
year: '',
|
||||
dataSource: this.apiName,
|
||||
id: result.pageid,
|
||||
} as WikiModel),
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -73,10 +73,10 @@ export class WikipediaAPI extends APIModel {
|
|||
id: result.pageid,
|
||||
|
||||
wikiUrl: result.fullurl,
|
||||
lastUpdated: this.plugin.dateFormatter.format(result.touched, this.apiDateFormat),
|
||||
lastUpdated: this.plugin.dateFormatter.format(result.touched, this.apiDateFormat) ?? undefined,
|
||||
length: result.length,
|
||||
|
||||
userData: {},
|
||||
} as WikiModel);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
108
src/main.ts
108
src/main.ts
|
|
@ -1,33 +1,28 @@
|
|||
import { MarkdownView, Notice, parseYaml, Plugin, stringifyYaml, TFile, TFolder } from 'obsidian';
|
||||
import { getDefaultSettings, MediaDbPluginSettings, MediaDbSettingTab } from './settings/Settings';
|
||||
import type { MediaType } from 'src/utils/MediaType';
|
||||
import { APIManager } from './api/APIManager';
|
||||
import { MediaTypeModel } from './models/MediaTypeModel';
|
||||
import {
|
||||
CreateNoteOptions,
|
||||
dateTimeToString,
|
||||
markdownTable,
|
||||
replaceIllegalFileNameCharactersInString,
|
||||
unCamelCase,
|
||||
hasTemplaterPlugin,
|
||||
useTemplaterPluginInFile,
|
||||
} from './utils/Utils';
|
||||
import { OMDbAPI } from './api/apis/OMDbAPI';
|
||||
import { BoardGameGeekAPI } from './api/apis/BoardGameGeekAPI';
|
||||
import { GiantBombAPI } from './api/apis/GiantBombAPI';
|
||||
import { MALAPI } from './api/apis/MALAPI';
|
||||
import { MALAPIManga } from './api/apis/MALAPIManga';
|
||||
import { WikipediaAPI } from './api/apis/WikipediaAPI';
|
||||
import { MusicBrainzAPI } from './api/apis/MusicBrainzAPI';
|
||||
import { OMDbAPI } from './api/apis/OMDbAPI';
|
||||
import type { MediaTypeModel } from './models/MediaTypeModel';
|
||||
import type { MediaDbPluginSettings } from './settings/Settings';
|
||||
import { getDefaultSettings, MediaDbSettingTab } from './settings/Settings';
|
||||
import { MEDIA_TYPES, MediaTypeManager } from './utils/MediaTypeManager';
|
||||
import type { SearchModalOptions } from './utils/ModalHelper';
|
||||
import type { CreateNoteOptions } from './utils/Utils';
|
||||
import { dateTimeToString, markdownTable, replaceIllegalFileNameCharactersInString, unCamelCase, hasTemplaterPlugin, useTemplaterPluginInFile } from './utils/Utils';
|
||||
import { WikipediaAPI } from './api/apis/WikipediaAPI';
|
||||
import { SteamAPI } from './api/apis/SteamAPI';
|
||||
import { BoardGameGeekAPI } from './api/apis/BoardGameGeekAPI';
|
||||
import { OpenLibraryAPI } from './api/apis/OpenLibraryAPI';
|
||||
import { MobyGamesAPI } from './api/apis/MobyGamesAPI';
|
||||
import { GiantBombAPI } from './api/apis/GiantBombAPI';
|
||||
import { PropertyMapper } from './settings/PropertyMapper';
|
||||
import { MediaDbFolderImportModal } from './modals/MediaDbFolderImportModal';
|
||||
import { PropertyMapping, PropertyMappingModel } from './settings/PropertyMapping';
|
||||
import { ModalHelper, ModalResultCode, SearchModalOptions } from './utils/ModalHelper';
|
||||
import { ModalHelper, ModalResultCode } from './utils/ModalHelper';
|
||||
import { DateFormatter } from './utils/DateFormatter';
|
||||
import { MediaType } from 'src/utils/MediaType';
|
||||
|
||||
export type Metadata = Record<string, unknown>;
|
||||
|
||||
|
|
@ -38,12 +33,12 @@ export interface MediaTypeModelObj {
|
|||
}
|
||||
|
||||
export default class MediaDbPlugin extends Plugin {
|
||||
settings: MediaDbPluginSettings;
|
||||
apiManager: APIManager;
|
||||
mediaTypeManager: MediaTypeManager;
|
||||
modelPropertyMapper: PropertyMapper;
|
||||
modalHelper: ModalHelper;
|
||||
dateFormatter: DateFormatter;
|
||||
settings!: MediaDbPluginSettings;
|
||||
apiManager!: APIManager;
|
||||
mediaTypeManager!: MediaTypeManager;
|
||||
modelPropertyMapper!: PropertyMapper;
|
||||
modalHelper!: ModalHelper;
|
||||
dateFormatter!: DateFormatter;
|
||||
|
||||
frontMatterRexExpPattern: string = '^(---)\\n[\\s\\S]*?\\n---';
|
||||
|
||||
|
|
@ -165,7 +160,7 @@ export default class MediaDbPlugin extends Plugin {
|
|||
* - maybe custom link syntax
|
||||
*/
|
||||
async createLinkWithSearchModal(): Promise<void> {
|
||||
const apiSearchResults: MediaTypeModel[] = await this.modalHelper.openAdvancedSearchModal({}, async advancedSearchModalData => {
|
||||
const apiSearchResults = await this.modalHelper.openAdvancedSearchModal({}, async advancedSearchModalData => {
|
||||
return await this.apiManager.query(advancedSearchModalData.query, advancedSearchModalData.apis);
|
||||
});
|
||||
|
||||
|
|
@ -173,7 +168,7 @@ export default class MediaDbPlugin extends Plugin {
|
|||
return;
|
||||
}
|
||||
|
||||
const selectResults: MediaTypeModel[] = await this.modalHelper.openSelectModal({ elements: apiSearchResults, multiSelect: false }, async selectModalData => {
|
||||
const selectResults = await this.modalHelper.openSelectModal({ elements: apiSearchResults, multiSelect: false }, async selectModalData => {
|
||||
return await this.queryDetails(selectModalData.selected);
|
||||
});
|
||||
|
||||
|
|
@ -193,7 +188,7 @@ export default class MediaDbPlugin extends Plugin {
|
|||
|
||||
async createEntryWithSearchModal(searchModalOptions?: SearchModalOptions): Promise<void> {
|
||||
let types: string[] = [];
|
||||
let apiSearchResults: MediaTypeModel[] = await this.modalHelper.openSearchModal(searchModalOptions ?? {}, async searchModalData => {
|
||||
let apiSearchResults = 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);
|
||||
try {
|
||||
|
|
@ -214,12 +209,13 @@ export default class MediaDbPlugin extends Plugin {
|
|||
apiSearchResults = apiSearchResults.filter(x => types.contains(x.type));
|
||||
|
||||
let selectResults: MediaTypeModel[];
|
||||
let proceed: boolean;
|
||||
let proceed: boolean = false;
|
||||
|
||||
while (!proceed) {
|
||||
selectResults = await this.modalHelper.openSelectModal({ elements: apiSearchResults }, async selectModalData => {
|
||||
selectResults =
|
||||
(await this.modalHelper.openSelectModal({ elements: apiSearchResults }, async selectModalData => {
|
||||
return await this.queryDetails(selectModalData.selected);
|
||||
});
|
||||
})) ?? [];
|
||||
if (!selectResults) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -229,11 +225,11 @@ export default class MediaDbPlugin extends Plugin {
|
|||
});
|
||||
}
|
||||
|
||||
await this.createMediaDbNotes(selectResults);
|
||||
await this.createMediaDbNotes(selectResults!);
|
||||
}
|
||||
|
||||
async createEntryWithAdvancedSearchModal(): Promise<void> {
|
||||
const apiSearchResults: MediaTypeModel[] = await this.modalHelper.openAdvancedSearchModal({}, async advancedSearchModalData => {
|
||||
const apiSearchResults = await this.modalHelper.openAdvancedSearchModal({}, async advancedSearchModalData => {
|
||||
return await this.apiManager.query(advancedSearchModalData.query, advancedSearchModalData.apis);
|
||||
});
|
||||
|
||||
|
|
@ -243,12 +239,13 @@ export default class MediaDbPlugin extends Plugin {
|
|||
}
|
||||
|
||||
let selectResults: MediaTypeModel[];
|
||||
let proceed: boolean;
|
||||
let proceed: boolean = false;
|
||||
|
||||
while (!proceed) {
|
||||
selectResults = await this.modalHelper.openSelectModal({ elements: apiSearchResults }, async selectModalData => {
|
||||
selectResults =
|
||||
(await this.modalHelper.openSelectModal({ elements: apiSearchResults }, async selectModalData => {
|
||||
return await this.queryDetails(selectModalData.selected);
|
||||
});
|
||||
})) ?? [];
|
||||
if (!selectResults) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -258,12 +255,12 @@ export default class MediaDbPlugin extends Plugin {
|
|||
});
|
||||
}
|
||||
|
||||
await this.createMediaDbNotes(selectResults);
|
||||
await this.createMediaDbNotes(selectResults!);
|
||||
}
|
||||
|
||||
async createEntryWithIdSearchModal(): Promise<void> {
|
||||
let idSearchResult: MediaTypeModel;
|
||||
let proceed: boolean;
|
||||
let idSearchResult: MediaTypeModel | undefined = undefined;
|
||||
let proceed: boolean = false;
|
||||
|
||||
while (!proceed) {
|
||||
idSearchResult = await this.modalHelper.openIdSearchModal({}, async idSearchModalData => {
|
||||
|
|
@ -278,6 +275,9 @@ export default class MediaDbPlugin extends Plugin {
|
|||
});
|
||||
}
|
||||
|
||||
if (!idSearchResult) {
|
||||
return;
|
||||
}
|
||||
await this.createMediaDbNoteFromModel(idSearchResult, { attachTemplate: true, openNote: true });
|
||||
}
|
||||
|
||||
|
|
@ -290,11 +290,9 @@ export default class MediaDbPlugin extends Plugin {
|
|||
async queryDetails(models: MediaTypeModel[]): Promise<MediaTypeModel[]> {
|
||||
const detailModels: MediaTypeModel[] = [];
|
||||
for (const model of models) {
|
||||
try {
|
||||
detailModels.push(await this.apiManager.queryDetailedInfo(model));
|
||||
} catch (e) {
|
||||
console.warn(e);
|
||||
new Notice(e.toString());
|
||||
const res = await this.apiManager.queryDetailedInfo(model);
|
||||
if (res) {
|
||||
detailModels.push(res);
|
||||
}
|
||||
}
|
||||
return detailModels;
|
||||
|
|
@ -319,7 +317,7 @@ export default class MediaDbPlugin extends Plugin {
|
|||
}
|
||||
} catch (e) {
|
||||
console.warn(e);
|
||||
new Notice(e.toString());
|
||||
new Notice(`${e}`);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -383,7 +381,7 @@ export default class MediaDbPlugin extends Plugin {
|
|||
|
||||
// Updating a previous file
|
||||
if (options.attachFile) {
|
||||
const previousMetadata = this.app.metadataCache.getFileCache(options.attachFile).frontmatter;
|
||||
const previousMetadata = this.app.metadataCache.getFileCache(options.attachFile)?.frontmatter ?? {};
|
||||
|
||||
// Use contents (below front matter) from previous file
|
||||
fileContent = await this.app.vault.read(options.attachFile);
|
||||
|
|
@ -443,7 +441,7 @@ export default class MediaDbPlugin extends Plugin {
|
|||
return { fileMetadata: fileMetadata, fileContent: fileContent };
|
||||
}
|
||||
|
||||
async attachTemplate(fileMetadata: Metadata, fileContent: string, template: string): Promise<{ fileMetadata: Metadata; fileContent: string }> {
|
||||
async attachTemplate(fileMetadata: Metadata, fileContent: string, template: string | undefined): Promise<{ fileMetadata: Metadata; fileContent: string }> {
|
||||
if (!template) {
|
||||
return { fileMetadata: fileMetadata, fileContent: fileContent };
|
||||
}
|
||||
|
|
@ -486,7 +484,7 @@ export default class MediaDbPlugin extends Plugin {
|
|||
}
|
||||
|
||||
getMetadataFromFileCache(file: TFile): Metadata {
|
||||
const metadata: Metadata | undefined = this.app.metadataCache.getFileCache(file).frontmatter;
|
||||
const metadata: Metadata | undefined = this.app.metadataCache.getFileCache(file)?.frontmatter;
|
||||
return structuredClone(metadata ?? {});
|
||||
}
|
||||
|
||||
|
|
@ -501,6 +499,10 @@ export default class MediaDbPlugin extends Plugin {
|
|||
// find and possibly create the folder set in settings or passed in folder
|
||||
const folder = options.folder ?? this.app.vault.getAbstractFileByPath('/');
|
||||
|
||||
if (!folder || !(folder instanceof TFolder)) {
|
||||
throw new Error('MDB | invalid folder');
|
||||
}
|
||||
|
||||
fileName = replaceIllegalFileNameCharactersInString(fileName);
|
||||
const filePath = `${folder.path}/${fileName}.md`;
|
||||
|
||||
|
|
@ -519,7 +521,7 @@ export default class MediaDbPlugin extends Plugin {
|
|||
const activeLeaf = this.app.workspace.getUnpinnedLeaf();
|
||||
if (!activeLeaf) {
|
||||
console.warn('MDB | no active leaf, not opening newly created note');
|
||||
return;
|
||||
return targetFile;
|
||||
}
|
||||
await activeLeaf.openFile(targetFile, { state: { mode: 'source' } });
|
||||
}
|
||||
|
|
@ -532,7 +534,7 @@ export default class MediaDbPlugin extends Plugin {
|
|||
* Tries to read the type, id and dataSource of the active note. If successful it will query the api, delete the old note and create a new one.
|
||||
*/
|
||||
async updateActiveNote(onlyMetadata: boolean = false): Promise<void> {
|
||||
const activeFile: TFile = this.app.workspace.getActiveFile();
|
||||
const activeFile = this.app.workspace.getActiveFile() ?? undefined;
|
||||
if (!activeFile) {
|
||||
throw new Error('MDB | there is no active note');
|
||||
}
|
||||
|
|
@ -560,9 +562,9 @@ export default class MediaDbPlugin extends Plugin {
|
|||
// console.debug(newMediaTypeModel);
|
||||
|
||||
if (onlyMetadata) {
|
||||
await this.createMediaDbNoteFromModel(newMediaTypeModel, { attachFile: activeFile, folder: activeFile.parent, openNote: true });
|
||||
await this.createMediaDbNoteFromModel(newMediaTypeModel, { attachFile: activeFile, folder: activeFile.parent ?? undefined, openNote: true });
|
||||
} else {
|
||||
await this.createMediaDbNoteFromModel(newMediaTypeModel, { attachTemplate: true, folder: activeFile.parent, openNote: true });
|
||||
await this.createMediaDbNoteFromModel(newMediaTypeModel, { attachTemplate: true, folder: activeFile.parent ?? undefined, openNote: true });
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -596,7 +598,7 @@ export default class MediaDbPlugin extends Plugin {
|
|||
try {
|
||||
results = await this.apiManager.query(title, [selectedAPI]);
|
||||
} catch (e) {
|
||||
erroredFiles.push({ filePath: file.path, error: e.toString() });
|
||||
erroredFiles.push({ filePath: file.path, error: `${e}` });
|
||||
continue;
|
||||
}
|
||||
if (!results || results.length === 0) {
|
||||
|
|
@ -631,7 +633,7 @@ export default class MediaDbPlugin extends Plugin {
|
|||
}
|
||||
|
||||
const detailedResults = await this.queryDetails(selectModalResult.data.selected);
|
||||
await this.createMediaDbNotes(detailedResults, appendContent ? file : null);
|
||||
await this.createMediaDbNotes(detailedResults, appendContent ? file : undefined);
|
||||
|
||||
selectModal.close();
|
||||
}
|
||||
|
|
@ -661,7 +663,7 @@ export default class MediaDbPlugin extends Plugin {
|
|||
// migrate the settings loaded from the disk to match the structure of the default settings
|
||||
const newPropertyMappings: PropertyMappingModel[] = [];
|
||||
for (const defaultPropertyMappingModel of defaultSettings.propertyMappingModels) {
|
||||
const newPropertyMappingModel: PropertyMappingModel = loadedSettings.propertyMappingModels.find(x => x.type === defaultPropertyMappingModel.type);
|
||||
const newPropertyMappingModel = 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);
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
import { ButtonComponent, Modal, Notice, Setting, TextComponent, ToggleComponent } from 'obsidian';
|
||||
import { MediaTypeModel } from '../models/MediaTypeModel';
|
||||
import MediaDbPlugin from '../main';
|
||||
import { ADVANCED_SEARCH_MODAL_DEFAULT_OPTIONS, AdvancedSearchModalData, AdvancedSearchModalOptions } from '../utils/ModalHelper';
|
||||
import type { ButtonComponent } from 'obsidian';
|
||||
import { Modal, Notice, Setting, TextComponent, ToggleComponent } from 'obsidian';
|
||||
import type MediaDbPlugin from '../main';
|
||||
import type { MediaTypeModel } from '../models/MediaTypeModel';
|
||||
import type { AdvancedSearchModalData, AdvancedSearchModalOptions } from '../utils/ModalHelper';
|
||||
import { ADVANCED_SEARCH_MODAL_DEFAULT_OPTIONS } from '../utils/ModalHelper';
|
||||
|
||||
export class MediaDbAdvancedSearchModal extends Modal {
|
||||
plugin: MediaDbPlugin;
|
||||
|
|
@ -9,9 +11,9 @@ export class MediaDbAdvancedSearchModal extends Modal {
|
|||
query: string;
|
||||
isBusy: boolean;
|
||||
title: string;
|
||||
selectedApis: { name: string; selected: boolean }[];
|
||||
selectedApis: string[];
|
||||
|
||||
searchBtn: ButtonComponent;
|
||||
searchBtn?: ButtonComponent;
|
||||
|
||||
submitCallback?: (res: AdvancedSearchModalData) => void;
|
||||
closeCallback?: (err?: Error) => void;
|
||||
|
|
@ -22,12 +24,9 @@ export class MediaDbAdvancedSearchModal extends Modal {
|
|||
|
||||
this.plugin = plugin;
|
||||
this.selectedApis = [];
|
||||
this.title = advancedSearchModalOptions.modalTitle;
|
||||
this.query = advancedSearchModalOptions.prefilledSearchString;
|
||||
|
||||
for (const api of this.plugin.apiManager.apis) {
|
||||
this.selectedApis.push({ name: api.apiName, selected: advancedSearchModalOptions.preselectedAPIs.contains(api.apiName) });
|
||||
}
|
||||
this.title = advancedSearchModalOptions.modalTitle ?? '';
|
||||
this.query = advancedSearchModalOptions.prefilledSearchString ?? '';
|
||||
this.isBusy = false;
|
||||
}
|
||||
|
||||
setSubmitCallback(submitCallback: (res: AdvancedSearchModalData) => void): void {
|
||||
|
|
@ -44,13 +43,13 @@ export class MediaDbAdvancedSearchModal extends Modal {
|
|||
}
|
||||
}
|
||||
|
||||
async search(): Promise<MediaTypeModel[]> {
|
||||
async search(): Promise<void> {
|
||||
if (!this.query || this.query.length < 3) {
|
||||
new Notice('MDB | Query too short');
|
||||
return;
|
||||
}
|
||||
|
||||
const apis: string[] = this.selectedApis.filter(x => x.selected).map(x => x.name);
|
||||
const apis: string[] = this.selectedApis;
|
||||
|
||||
if (apis.length === 0) {
|
||||
new Notice('MDB | No API selected');
|
||||
|
|
@ -59,10 +58,10 @@ export class MediaDbAdvancedSearchModal extends Modal {
|
|||
|
||||
if (!this.isBusy) {
|
||||
this.isBusy = true;
|
||||
this.searchBtn.setDisabled(false);
|
||||
this.searchBtn.setButtonText('Searching...');
|
||||
this.searchBtn?.setDisabled(false);
|
||||
this.searchBtn?.setButtonText('Searching...');
|
||||
|
||||
this.submitCallback({ query: this.query, apis: apis });
|
||||
this.submitCallback?.({ query: this.query, apis: apis });
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -97,9 +96,13 @@ export class MediaDbAdvancedSearchModal extends Modal {
|
|||
|
||||
const apiToggleComponent = new ToggleComponent(apiToggleComponentWrapper);
|
||||
apiToggleComponent.setTooltip(api.apiName);
|
||||
apiToggleComponent.setValue(this.selectedApis.find(x => x.name === api.apiName).selected);
|
||||
apiToggleComponent.setValue(this.selectedApis.some(x => x === api.apiName));
|
||||
apiToggleComponent.onChange(value => {
|
||||
this.selectedApis.find(x => x.name === api.apiName).selected = value;
|
||||
if (value) {
|
||||
this.selectedApis.push(api.apiName);
|
||||
} else {
|
||||
this.selectedApis = this.selectedApis.filter(x => x !== api.apiName);
|
||||
}
|
||||
});
|
||||
apiToggleComponentWrapper.appendChild(apiToggleComponent.toggleEl);
|
||||
}
|
||||
|
|
@ -124,7 +127,7 @@ export class MediaDbAdvancedSearchModal extends Modal {
|
|||
}
|
||||
|
||||
onClose(): void {
|
||||
this.closeCallback();
|
||||
this.closeCallback?.();
|
||||
const { contentEl } = this;
|
||||
contentEl.empty();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,12 @@
|
|||
import { App, ButtonComponent, DropdownComponent, Modal, Setting, TextComponent, ToggleComponent } from 'obsidian';
|
||||
import MediaDbPlugin from '../main';
|
||||
import type { App, ButtonComponent } from 'obsidian';
|
||||
import { DropdownComponent, Modal, Setting, TextComponent, ToggleComponent } from 'obsidian';
|
||||
import type MediaDbPlugin from '../main';
|
||||
|
||||
export class MediaDbFolderImportModal extends Modal {
|
||||
plugin: MediaDbPlugin;
|
||||
onSubmit: (selectedAPI: string, titleFieldName: string, appendContent: boolean) => void;
|
||||
selectedApi: string;
|
||||
searchBtn: ButtonComponent;
|
||||
searchBtn?: ButtonComponent;
|
||||
titleFieldName: string;
|
||||
appendContent: boolean;
|
||||
|
||||
|
|
@ -14,6 +15,8 @@ export class MediaDbFolderImportModal extends Modal {
|
|||
this.plugin = plugin;
|
||||
this.onSubmit = onSubmit;
|
||||
this.selectedApi = plugin.apiManager.apis[0].apiName;
|
||||
this.titleFieldName = '';
|
||||
this.appendContent = false;
|
||||
}
|
||||
|
||||
submit(): void {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
import { ButtonComponent, DropdownComponent, Modal, Notice, Setting, TextComponent } from 'obsidian';
|
||||
import { MediaTypeModel } from '../models/MediaTypeModel';
|
||||
import MediaDbPlugin from '../main';
|
||||
import { ID_SEARCH_MODAL_DEFAULT_OPTIONS, IdSearchModalData, IdSearchModalOptions } from '../utils/ModalHelper';
|
||||
import type { ButtonComponent } from 'obsidian';
|
||||
import { DropdownComponent, Modal, Notice, Setting, TextComponent } from 'obsidian';
|
||||
import type MediaDbPlugin from '../main';
|
||||
import type { MediaTypeModel } from '../models/MediaTypeModel';
|
||||
import type { IdSearchModalData, IdSearchModalOptions } from '../utils/ModalHelper';
|
||||
import { ID_SEARCH_MODAL_DEFAULT_OPTIONS } from '../utils/ModalHelper';
|
||||
|
||||
export class MediaDbIdSearchModal extends Modal {
|
||||
plugin: MediaDbPlugin;
|
||||
|
|
@ -11,7 +13,7 @@ export class MediaDbIdSearchModal extends Modal {
|
|||
title: string;
|
||||
selectedApi: string;
|
||||
|
||||
searchBtn: ButtonComponent;
|
||||
searchBtn?: ButtonComponent;
|
||||
|
||||
submitCallback?: (res: IdSearchModalData, err?: Error) => void;
|
||||
closeCallback?: (err?: Error) => void;
|
||||
|
|
@ -21,8 +23,10 @@ export class MediaDbIdSearchModal extends Modal {
|
|||
super(plugin.app);
|
||||
|
||||
this.plugin = plugin;
|
||||
this.title = idSearchModalOptions.modalTitle;
|
||||
this.title = idSearchModalOptions.modalTitle ?? '';
|
||||
this.selectedApi = idSearchModalOptions.preselectedAPI || plugin.apiManager.apis[0].apiName;
|
||||
this.query = '';
|
||||
this.isBusy = false;
|
||||
}
|
||||
|
||||
setSubmitCallback(submitCallback: (res: IdSearchModalData, err?: Error) => void): void {
|
||||
|
|
@ -39,7 +43,7 @@ export class MediaDbIdSearchModal extends Modal {
|
|||
}
|
||||
}
|
||||
|
||||
async search(): Promise<MediaTypeModel> {
|
||||
async search(): Promise<void> {
|
||||
if (!this.query) {
|
||||
new Notice('MDB | no Id entered');
|
||||
return;
|
||||
|
|
@ -52,10 +56,10 @@ export class MediaDbIdSearchModal extends Modal {
|
|||
|
||||
if (!this.isBusy) {
|
||||
this.isBusy = true;
|
||||
this.searchBtn.setDisabled(false);
|
||||
this.searchBtn.setButtonText('Searching...');
|
||||
this.searchBtn?.setDisabled(false);
|
||||
this.searchBtn?.setButtonText('Searching...');
|
||||
|
||||
this.submitCallback({ query: this.query, api: this.selectedApi });
|
||||
this.submitCallback?.({ query: this.query, api: this.selectedApi });
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -109,7 +113,7 @@ export class MediaDbIdSearchModal extends Modal {
|
|||
}
|
||||
|
||||
onClose(): void {
|
||||
this.closeCallback();
|
||||
this.closeCallback?.();
|
||||
const { contentEl } = this;
|
||||
contentEl.empty();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,22 +1,19 @@
|
|||
import { ButtonComponent, Component, MarkdownRenderer, Modal, Setting } from 'obsidian';
|
||||
import MediaDbPlugin from 'src/main';
|
||||
import { MediaTypeModel } from 'src/models/MediaTypeModel';
|
||||
import { PREVIEW_MODAL_DEFAULT_OPTIONS, PreviewModalData, PreviewModalOptions } from '../utils/ModalHelper';
|
||||
import { CreateNoteOptions } from '../utils/Utils';
|
||||
import type { ButtonComponent } from 'obsidian';
|
||||
import { Component, MarkdownRenderer, Modal, Setting } from 'obsidian';
|
||||
import type MediaDbPlugin from 'src/main';
|
||||
import type { MediaTypeModel } from 'src/models/MediaTypeModel';
|
||||
import type { PreviewModalData, PreviewModalOptions } from '../utils/ModalHelper';
|
||||
import { PREVIEW_MODAL_DEFAULT_OPTIONS } from '../utils/ModalHelper';
|
||||
|
||||
export class MediaDbPreviewModal extends Modal {
|
||||
plugin: MediaDbPlugin;
|
||||
|
||||
createNoteOptions: CreateNoteOptions;
|
||||
elements: MediaTypeModel[];
|
||||
isBusy: boolean;
|
||||
title: string;
|
||||
cancelButton: ButtonComponent;
|
||||
submitButton: ButtonComponent;
|
||||
markdownComponent: Component;
|
||||
|
||||
submitCallback: (previewModalData: PreviewModalData) => void;
|
||||
closeCallback: (err?: Error) => void;
|
||||
submitCallback?: (previewModalData: PreviewModalData) => void;
|
||||
closeCallback?: (err?: Error) => void;
|
||||
|
||||
constructor(plugin: MediaDbPlugin, previewModalOptions: PreviewModalOptions) {
|
||||
previewModalOptions = Object.assign({}, PREVIEW_MODAL_DEFAULT_OPTIONS, previewModalOptions);
|
||||
|
|
@ -24,8 +21,8 @@ export class MediaDbPreviewModal extends Modal {
|
|||
super(plugin.app);
|
||||
|
||||
this.plugin = plugin;
|
||||
this.title = previewModalOptions.modalTitle;
|
||||
this.elements = previewModalOptions.elements;
|
||||
this.title = previewModalOptions.modalTitle ?? '';
|
||||
this.elements = previewModalOptions.elements ?? [];
|
||||
|
||||
this.markdownComponent = new Component();
|
||||
}
|
||||
|
|
@ -70,14 +67,12 @@ export class MediaDbPreviewModal extends Modal {
|
|||
btn.setButtonText('Cancel');
|
||||
btn.onClick(() => this.close());
|
||||
btn.buttonEl.addClass('media-db-plugin-button');
|
||||
this.cancelButton = btn;
|
||||
});
|
||||
bottomSettingRow.addButton(btn => {
|
||||
btn.setButtonText('Ok');
|
||||
btn.setCta();
|
||||
btn.onClick(() => this.submitCallback({ confirmed: true }));
|
||||
btn.onClick(() => this.submitCallback?.({ confirmed: true }));
|
||||
btn.buttonEl.addClass('media-db-plugin-button');
|
||||
this.submitButton = btn;
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -87,6 +82,6 @@ export class MediaDbPreviewModal extends Modal {
|
|||
|
||||
onClose(): void {
|
||||
this.markdownComponent.unload();
|
||||
this.closeCallback();
|
||||
this.closeCallback?.();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,12 @@
|
|||
import { ButtonComponent, Modal, Notice, Setting, TextComponent, ToggleComponent } from 'obsidian';
|
||||
import { MediaTypeModel } from '../models/MediaTypeModel';
|
||||
import MediaDbPlugin from '../main';
|
||||
import { SEARCH_MODAL_DEFAULT_OPTIONS, SearchModalData, SearchModalOptions } from '../utils/ModalHelper';
|
||||
import type { ButtonComponent } from 'obsidian';
|
||||
import { Modal, Notice, Setting, TextComponent, ToggleComponent } from 'obsidian';
|
||||
import type MediaDbPlugin from '../main';
|
||||
import type { MediaTypeModel } from '../models/MediaTypeModel';
|
||||
import type { MediaType } from '../utils/MediaType';
|
||||
import { MEDIA_TYPES } from '../utils/MediaTypeManager';
|
||||
import type { SearchModalData, SearchModalOptions } from '../utils/ModalHelper';
|
||||
import { SEARCH_MODAL_DEFAULT_OPTIONS } from '../utils/ModalHelper';
|
||||
import { unCamelCase } from '../utils/Utils';
|
||||
import { MediaType } from '../utils/MediaType';
|
||||
|
||||
export class MediaDbSearchModal extends Modal {
|
||||
plugin: MediaDbPlugin;
|
||||
|
|
@ -12,9 +14,9 @@ export class MediaDbSearchModal extends Modal {
|
|||
query: string;
|
||||
isBusy: boolean;
|
||||
title: string;
|
||||
selectedTypes: { name: MediaType; selected: boolean }[];
|
||||
selectedTypes: MediaType[];
|
||||
|
||||
searchBtn: ButtonComponent;
|
||||
searchBtn?: ButtonComponent;
|
||||
|
||||
submitCallback?: (res: SearchModalData) => void;
|
||||
closeCallback?: (err?: Error) => void;
|
||||
|
|
@ -24,13 +26,10 @@ export class MediaDbSearchModal extends Modal {
|
|||
super(plugin.app);
|
||||
|
||||
this.plugin = plugin;
|
||||
this.selectedTypes = [];
|
||||
this.title = searchModalOptions.modalTitle;
|
||||
this.query = searchModalOptions.prefilledSearchString;
|
||||
|
||||
for (const mediaType of MEDIA_TYPES) {
|
||||
this.selectedTypes.push({ name: mediaType, selected: searchModalOptions.preselectedTypes.contains(mediaType) });
|
||||
}
|
||||
this.selectedTypes = [...(searchModalOptions.preselectedTypes ?? [])];
|
||||
this.title = searchModalOptions.modalTitle ?? '';
|
||||
this.query = searchModalOptions.prefilledSearchString ?? '';
|
||||
this.isBusy = false;
|
||||
}
|
||||
|
||||
setSubmitCallback(submitCallback: (res: SearchModalData) => void): void {
|
||||
|
|
@ -47,13 +46,13 @@ export class MediaDbSearchModal extends Modal {
|
|||
}
|
||||
}
|
||||
|
||||
async search(): Promise<MediaTypeModel[]> {
|
||||
async search(): Promise<void> {
|
||||
if (!this.query || this.query.length < 3) {
|
||||
new Notice('MDB | Query too short');
|
||||
return;
|
||||
}
|
||||
|
||||
const types: MediaType[] = this.selectedTypes.filter(x => x.selected).map(x => x.name);
|
||||
const types: MediaType[] = this.selectedTypes;
|
||||
|
||||
if (types.length === 0) {
|
||||
new Notice('MDB | No Type selected');
|
||||
|
|
@ -62,10 +61,10 @@ export class MediaDbSearchModal extends Modal {
|
|||
|
||||
if (!this.isBusy) {
|
||||
this.isBusy = true;
|
||||
this.searchBtn.setDisabled(false);
|
||||
this.searchBtn.setButtonText('Searching...');
|
||||
this.searchBtn?.setDisabled(false);
|
||||
this.searchBtn?.setButtonText('Searching...');
|
||||
|
||||
this.submitCallback({ query: this.query, types: types });
|
||||
this.submitCallback?.({ query: this.query, types: types });
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -76,7 +75,7 @@ export class MediaDbSearchModal extends Modal {
|
|||
|
||||
const placeholder = 'Search by title';
|
||||
const searchComponent = new TextComponent(contentEl);
|
||||
let currentToggle: ToggleComponent = null;
|
||||
let currentToggle: ToggleComponent | undefined = undefined;
|
||||
|
||||
searchComponent.inputEl.style.width = '100%';
|
||||
searchComponent.setPlaceholder(placeholder);
|
||||
|
|
@ -100,7 +99,7 @@ export class MediaDbSearchModal extends Modal {
|
|||
|
||||
const apiToggleComponent = new ToggleComponent(apiToggleComponentWrapper);
|
||||
apiToggleComponent.setTooltip(unCamelCase(mediaType));
|
||||
apiToggleComponent.setValue(this.selectedTypes.find(x => x.name === mediaType).selected);
|
||||
apiToggleComponent.setValue(this.selectedTypes.contains(mediaType));
|
||||
if (apiToggleComponent.getValue()) {
|
||||
currentToggle = apiToggleComponent;
|
||||
}
|
||||
|
|
@ -108,13 +107,13 @@ export class MediaDbSearchModal extends Modal {
|
|||
if (value) {
|
||||
if (currentToggle && currentToggle !== apiToggleComponent) {
|
||||
currentToggle.setValue(false);
|
||||
this.selectedTypes.find(x => x.name === mediaType).selected = false;
|
||||
this.selectedTypes = this.selectedTypes.filter(x => x !== mediaType);
|
||||
}
|
||||
currentToggle = apiToggleComponent;
|
||||
this.selectedTypes.find(x => x.name === mediaType).selected = true;
|
||||
this.selectedTypes.push(mediaType);
|
||||
} else {
|
||||
currentToggle = null;
|
||||
this.selectedTypes.find(x => x.name === mediaType).selected = false;
|
||||
currentToggle = undefined;
|
||||
this.selectedTypes = this.selectedTypes.filter(x => x !== mediaType);
|
||||
}
|
||||
});
|
||||
apiToggleComponentWrapper.appendChild(apiToggleComponent.toggleEl);
|
||||
|
|
@ -140,7 +139,7 @@ export class MediaDbSearchModal extends Modal {
|
|||
}
|
||||
|
||||
onClose(): void {
|
||||
this.closeCallback();
|
||||
this.closeCallback?.();
|
||||
const { contentEl } = this;
|
||||
contentEl.empty();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
import { MediaTypeModel } from '../models/MediaTypeModel';
|
||||
import MediaDbPlugin from '../main';
|
||||
import type MediaDbPlugin from '../main';
|
||||
import type { MediaTypeModel } from '../models/MediaTypeModel';
|
||||
import type { SelectModalData, SelectModalOptions } from '../utils/ModalHelper';
|
||||
import { SELECT_MODAL_OPTIONS_DEFAULT } from '../utils/ModalHelper';
|
||||
import { SelectModal } from './SelectModal';
|
||||
import { SELECT_MODAL_OPTIONS_DEFAULT, SelectModalData, SelectModalOptions } from '../utils/ModalHelper';
|
||||
|
||||
export class MediaDbSearchResultModal extends SelectModal<MediaTypeModel> {
|
||||
plugin: MediaDbPlugin;
|
||||
|
|
@ -9,18 +10,18 @@ export class MediaDbSearchResultModal extends SelectModal<MediaTypeModel> {
|
|||
busy: boolean;
|
||||
sendCallback: boolean;
|
||||
|
||||
submitCallback: (res: SelectModalData) => void;
|
||||
closeCallback: (err?: Error) => void;
|
||||
skipCallback: () => void;
|
||||
submitCallback?: (res: SelectModalData) => void;
|
||||
closeCallback?: (err?: Error) => void;
|
||||
skipCallback?: () => void;
|
||||
|
||||
constructor(plugin: MediaDbPlugin, selectModalOptions: SelectModalOptions) {
|
||||
selectModalOptions = Object.assign({}, SELECT_MODAL_OPTIONS_DEFAULT, selectModalOptions);
|
||||
super(plugin.app, selectModalOptions.elements, selectModalOptions.multiSelect);
|
||||
super(plugin.app, selectModalOptions.elements ?? [], selectModalOptions.multiSelect);
|
||||
this.plugin = plugin;
|
||||
|
||||
this.title = selectModalOptions.modalTitle;
|
||||
this.title = selectModalOptions.modalTitle ?? '';
|
||||
this.description = 'Select one or multiple search results.';
|
||||
this.addSkipButton = selectModalOptions.skipButton;
|
||||
this.addSkipButton = selectModalOptions.skipButton ?? false;
|
||||
|
||||
this.busy = false;
|
||||
|
||||
|
|
@ -50,17 +51,17 @@ export class MediaDbSearchResultModal extends SelectModal<MediaTypeModel> {
|
|||
submit(): void {
|
||||
if (!this.busy) {
|
||||
this.busy = true;
|
||||
this.submitButton.setButtonText('Creating entry...');
|
||||
this.submitCallback({ selected: this.selectModalElements.filter(x => x.isActive()).map(x => x.value) });
|
||||
this.submitButton?.setButtonText('Creating entry...');
|
||||
this.submitCallback?.({ selected: this.selectModalElements.filter(x => x.isActive()).map(x => x.value) });
|
||||
}
|
||||
}
|
||||
|
||||
skip(): void {
|
||||
this.skipButton.setButtonText('Skipping...');
|
||||
this.skipCallback();
|
||||
this.skipButton?.setButtonText('Skipping...');
|
||||
this.skipCallback?.();
|
||||
}
|
||||
|
||||
onClose(): void {
|
||||
this.closeCallback();
|
||||
this.closeCallback?.();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import { App, ButtonComponent, Modal, Setting } from 'obsidian';
|
||||
import { SelectModalElement } from './SelectModalElement';
|
||||
import type { App, ButtonComponent } from 'obsidian';
|
||||
import { Modal, Setting } from 'obsidian';
|
||||
import { mod } from '../utils/Utils';
|
||||
import { SelectModalElement } from './SelectModalElement';
|
||||
|
||||
export abstract class SelectModal<T> extends Modal {
|
||||
allowMultiSelect: boolean;
|
||||
|
|
@ -142,7 +143,7 @@ export abstract class SelectModal<T> extends Modal {
|
|||
}
|
||||
|
||||
// nothing is highlighted
|
||||
this.selectModalElements.last().setHighlighted(true);
|
||||
this.selectModalElements.last()?.setHighlighted(true);
|
||||
}
|
||||
|
||||
highlightDown(): void {
|
||||
|
|
@ -154,20 +155,20 @@ export abstract class SelectModal<T> extends Modal {
|
|||
}
|
||||
|
||||
// nothing is highlighted
|
||||
this.selectModalElements.first().setHighlighted(true);
|
||||
this.selectModalElements.first()?.setHighlighted(true);
|
||||
}
|
||||
|
||||
private getNextSelectModalElement(selectModalElement: SelectModalElement<T>): SelectModalElement<T> {
|
||||
let nextId = selectModalElement.id + 1;
|
||||
nextId = mod(nextId, this.selectModalElements.length);
|
||||
|
||||
return this.selectModalElements.filter(x => x.id === nextId).first();
|
||||
return this.selectModalElements.find(x => x.id === nextId)!;
|
||||
}
|
||||
|
||||
private getPreviousSelectModalElement(selectModalElement: SelectModalElement<T>): SelectModalElement<T> {
|
||||
let nextId = selectModalElement.id - 1;
|
||||
nextId = mod(nextId, this.selectModalElements.length);
|
||||
|
||||
return this.selectModalElements.filter(x => x.id === nextId).first();
|
||||
return this.selectModalElements.find(x => x.id === nextId)!;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { SelectModal } from './SelectModal';
|
||||
import type { SelectModal } from './SelectModal';
|
||||
|
||||
export class SelectModalElement<T> {
|
||||
selectModal: SelectModal<T>;
|
||||
|
|
@ -35,6 +35,8 @@ export class SelectModalElement<T> {
|
|||
this.element.on('mouseleave', '#' + this.getHTMLId(), () => {
|
||||
this.setHighlighted(false);
|
||||
});
|
||||
|
||||
this.highlighted = false;
|
||||
}
|
||||
|
||||
getHTMLId(): string {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
import { MediaTypeModel } from './MediaTypeModel';
|
||||
import { mediaDbTag, migrateObject } from '../utils/Utils';
|
||||
import { MediaType } from '../utils/MediaType';
|
||||
import { mediaDbTag, migrateObject, type ModelToData } from '../utils/Utils';
|
||||
import { MediaTypeModel } from './MediaTypeModel';
|
||||
|
||||
export type BoardGameData = ModelToData<BoardGameModel>;
|
||||
|
||||
export class BoardGameModel extends MediaTypeModel {
|
||||
genres: string[];
|
||||
|
|
@ -19,23 +21,23 @@ export class BoardGameModel extends MediaTypeModel {
|
|||
personalRating: number;
|
||||
};
|
||||
|
||||
constructor(obj: any = {}) {
|
||||
constructor(obj: BoardGameData) {
|
||||
super();
|
||||
|
||||
this.genres = undefined;
|
||||
this.onlineRating = undefined;
|
||||
this.minPlayers = undefined;
|
||||
this.maxPlayers = undefined;
|
||||
this.playtime = undefined;
|
||||
this.publishers = undefined;
|
||||
this.complexityRating = undefined;
|
||||
this.image = undefined;
|
||||
this.genres = [];
|
||||
this.onlineRating = 0;
|
||||
this.complexityRating = 0;
|
||||
this.minPlayers = 0;
|
||||
this.maxPlayers = 0;
|
||||
this.playtime = '';
|
||||
this.publishers = [];
|
||||
this.image = '';
|
||||
|
||||
this.released = undefined;
|
||||
this.released = false;
|
||||
|
||||
this.userData = {
|
||||
played: undefined,
|
||||
personalRating: undefined,
|
||||
played: false,
|
||||
personalRating: 0,
|
||||
};
|
||||
|
||||
migrateObject(this, obj, this);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
import { MediaTypeModel } from './MediaTypeModel';
|
||||
import { mediaDbTag, migrateObject } from '../utils/Utils';
|
||||
import { MediaType } from '../utils/MediaType';
|
||||
import { mediaDbTag, migrateObject, type ModelToData } from '../utils/Utils';
|
||||
import { MediaTypeModel } from './MediaTypeModel';
|
||||
|
||||
export type BookData = ModelToData<BookModel>;
|
||||
|
||||
export class BookModel extends MediaTypeModel {
|
||||
author: string;
|
||||
|
|
@ -8,7 +10,6 @@ export class BookModel extends MediaTypeModel {
|
|||
pages: number;
|
||||
image: string;
|
||||
onlineRating: number;
|
||||
english_title: string;
|
||||
isbn: number;
|
||||
isbn13: number;
|
||||
|
||||
|
|
@ -20,22 +21,23 @@ export class BookModel extends MediaTypeModel {
|
|||
personalRating: number;
|
||||
};
|
||||
|
||||
constructor(obj: any = {}) {
|
||||
constructor(obj: BookData) {
|
||||
super();
|
||||
|
||||
this.author = undefined;
|
||||
this.pages = undefined;
|
||||
this.image = undefined;
|
||||
this.onlineRating = undefined;
|
||||
this.isbn = undefined;
|
||||
this.isbn13 = undefined;
|
||||
this.author = '';
|
||||
this.plot = '';
|
||||
this.pages = 0;
|
||||
this.image = '';
|
||||
this.onlineRating = 0;
|
||||
this.isbn = 0;
|
||||
this.isbn13 = 0;
|
||||
|
||||
this.released = undefined;
|
||||
this.released = false;
|
||||
|
||||
this.userData = {
|
||||
read: undefined,
|
||||
lastRead: undefined,
|
||||
personalRating: undefined,
|
||||
read: false,
|
||||
lastRead: '',
|
||||
personalRating: 0,
|
||||
};
|
||||
|
||||
migrateObject(this, obj, this);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
import { MediaTypeModel } from './MediaTypeModel';
|
||||
import { mediaDbTag, migrateObject } from '../utils/Utils';
|
||||
import { MediaType } from '../utils/MediaType';
|
||||
import { mediaDbTag, migrateObject, type ModelToData } from '../utils/Utils';
|
||||
import { MediaTypeModel } from './MediaTypeModel';
|
||||
|
||||
export type GameData = ModelToData<GameModel>;
|
||||
|
||||
export class GameModel extends MediaTypeModel {
|
||||
developers: string[];
|
||||
|
|
@ -17,19 +19,21 @@ export class GameModel extends MediaTypeModel {
|
|||
personalRating: number;
|
||||
};
|
||||
|
||||
constructor(obj: any = {}) {
|
||||
constructor(obj: GameData) {
|
||||
super();
|
||||
|
||||
this.developers = undefined;
|
||||
this.publishers = undefined;
|
||||
this.genres = undefined;
|
||||
this.onlineRating = undefined;
|
||||
this.image = undefined;
|
||||
this.released = undefined;
|
||||
this.releaseDate = undefined;
|
||||
this.developers = [];
|
||||
this.publishers = [];
|
||||
this.genres = [];
|
||||
this.onlineRating = 0;
|
||||
this.image = '';
|
||||
|
||||
this.released = false;
|
||||
this.releaseDate = '';
|
||||
|
||||
this.userData = {
|
||||
played: undefined,
|
||||
personalRating: undefined,
|
||||
played: false,
|
||||
personalRating: 0,
|
||||
};
|
||||
|
||||
migrateObject(this, obj, this);
|
||||
|
|
|
|||
|
|
@ -1,19 +1,12 @@
|
|||
import { MediaTypeModel } from './MediaTypeModel';
|
||||
import { mediaDbTag, migrateObject } from '../utils/Utils';
|
||||
import { MediaType } from '../utils/MediaType';
|
||||
import { mediaDbTag, migrateObject, type ModelToData } from '../utils/Utils';
|
||||
import { MediaTypeModel } from './MediaTypeModel';
|
||||
|
||||
export type MangaData = ModelToData<MangaModel>;
|
||||
|
||||
export class MangaModel extends MediaTypeModel {
|
||||
type: string;
|
||||
subType: string;
|
||||
title: string;
|
||||
plot: string;
|
||||
englishTitle: string;
|
||||
alternateTitles: string[];
|
||||
year: string;
|
||||
dataSource: string;
|
||||
url: string;
|
||||
id: string;
|
||||
|
||||
genres: string[];
|
||||
authors: string[];
|
||||
chapters: number;
|
||||
|
|
@ -32,27 +25,27 @@ export class MangaModel extends MediaTypeModel {
|
|||
personalRating: number;
|
||||
};
|
||||
|
||||
constructor(obj: any = {}) {
|
||||
constructor(obj: MangaData) {
|
||||
super();
|
||||
|
||||
this.plot = undefined;
|
||||
this.genres = undefined;
|
||||
this.authors = undefined;
|
||||
this.alternateTitles = undefined;
|
||||
this.chapters = undefined;
|
||||
this.volumes = undefined;
|
||||
this.onlineRating = undefined;
|
||||
this.image = undefined;
|
||||
this.plot = '';
|
||||
this.alternateTitles = [];
|
||||
this.genres = [];
|
||||
this.authors = [];
|
||||
this.chapters = 0;
|
||||
this.volumes = 0;
|
||||
this.onlineRating = 0;
|
||||
this.image = '';
|
||||
|
||||
this.released = undefined;
|
||||
this.status = undefined;
|
||||
this.publishedFrom = undefined;
|
||||
this.publishedTo = undefined;
|
||||
this.released = false;
|
||||
this.status = '';
|
||||
this.publishedFrom = '';
|
||||
this.publishedTo = '';
|
||||
|
||||
this.userData = {
|
||||
watched: undefined,
|
||||
lastWatched: undefined,
|
||||
personalRating: undefined,
|
||||
watched: false,
|
||||
lastWatched: '',
|
||||
personalRating: 0,
|
||||
};
|
||||
|
||||
migrateObject(this, obj, this);
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { MediaType } from '../utils/MediaType';
|
||||
import type { MediaType } from '../utils/MediaType';
|
||||
|
||||
export abstract class MediaTypeModel {
|
||||
type: string;
|
||||
|
|
@ -13,14 +13,14 @@ export abstract class MediaTypeModel {
|
|||
userData: object;
|
||||
|
||||
protected 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.type = '';
|
||||
this.subType = '';
|
||||
this.title = '';
|
||||
this.englishTitle = '';
|
||||
this.year = '';
|
||||
this.dataSource = '';
|
||||
this.url = '';
|
||||
this.id = '';
|
||||
this.userData = {};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
import { MediaTypeModel } from './MediaTypeModel';
|
||||
import { mediaDbTag, migrateObject } from '../utils/Utils';
|
||||
import { MediaType } from '../utils/MediaType';
|
||||
import { mediaDbTag, migrateObject, type ModelToData } from '../utils/Utils';
|
||||
import { MediaTypeModel } from './MediaTypeModel';
|
||||
|
||||
export type MovieData = ModelToData<MovieModel>;
|
||||
|
||||
export class MovieModel extends MediaTypeModel {
|
||||
plot: string;
|
||||
|
|
@ -23,27 +25,27 @@ export class MovieModel extends MediaTypeModel {
|
|||
personalRating: number;
|
||||
};
|
||||
|
||||
constructor(obj: any = {}) {
|
||||
constructor(obj: MovieData) {
|
||||
super();
|
||||
|
||||
this.plot = undefined;
|
||||
this.genres = undefined;
|
||||
this.director = undefined;
|
||||
this.writer = undefined;
|
||||
this.studio = undefined;
|
||||
this.duration = undefined;
|
||||
this.onlineRating = undefined;
|
||||
this.actors = undefined;
|
||||
this.image = undefined;
|
||||
this.plot = '';
|
||||
this.genres = [];
|
||||
this.director = [];
|
||||
this.writer = [];
|
||||
this.studio = [];
|
||||
this.duration = '';
|
||||
this.onlineRating = 0;
|
||||
this.actors = [];
|
||||
this.image = '';
|
||||
|
||||
this.released = undefined;
|
||||
this.streamingServices = undefined;
|
||||
this.premiere = undefined;
|
||||
this.released = false;
|
||||
this.streamingServices = [];
|
||||
this.premiere = '';
|
||||
|
||||
this.userData = {
|
||||
watched: undefined,
|
||||
lastWatched: undefined,
|
||||
personalRating: undefined,
|
||||
watched: false,
|
||||
lastWatched: '',
|
||||
personalRating: 0,
|
||||
};
|
||||
|
||||
migrateObject(this, obj, this);
|
||||
|
|
|
|||
|
|
@ -1,35 +1,28 @@
|
|||
import { MediaTypeModel } from './MediaTypeModel';
|
||||
import { mediaDbTag, migrateObject } from '../utils/Utils';
|
||||
import { MediaType } from '../utils/MediaType';
|
||||
import { mediaDbTag, migrateObject, type ModelToData } from '../utils/Utils';
|
||||
import { MediaTypeModel } from './MediaTypeModel';
|
||||
|
||||
export type MusicReleaseData = ModelToData<MusicReleaseModel>;
|
||||
|
||||
export class MusicReleaseModel extends MediaTypeModel {
|
||||
type: string;
|
||||
subType: string;
|
||||
title: string;
|
||||
englishTitle: string;
|
||||
year: string;
|
||||
dataSource: string;
|
||||
url: string;
|
||||
id: string;
|
||||
image: string;
|
||||
|
||||
genres: string[];
|
||||
artists: string[];
|
||||
image: string;
|
||||
rating: number;
|
||||
|
||||
userData: {
|
||||
personalRating: number;
|
||||
};
|
||||
|
||||
constructor(obj: any = {}) {
|
||||
constructor(obj: MusicReleaseData) {
|
||||
super();
|
||||
|
||||
this.genres = undefined;
|
||||
this.artists = undefined;
|
||||
this.image = undefined;
|
||||
this.rating = undefined;
|
||||
this.genres = [];
|
||||
this.artists = [];
|
||||
this.image = '';
|
||||
this.rating = 0;
|
||||
this.userData = {
|
||||
personalRating: undefined,
|
||||
personalRating: 0,
|
||||
};
|
||||
|
||||
migrateObject(this, obj, this);
|
||||
|
|
|
|||
|
|
@ -1,17 +1,10 @@
|
|||
import { MediaTypeModel } from './MediaTypeModel';
|
||||
import { mediaDbTag, migrateObject } from '../utils/Utils';
|
||||
import { MediaType } from '../utils/MediaType';
|
||||
import { mediaDbTag, migrateObject, type ModelToData } from '../utils/Utils';
|
||||
import { MediaTypeModel } from './MediaTypeModel';
|
||||
|
||||
export type SeriesData = ModelToData<SeriesModel>;
|
||||
|
||||
export class SeriesModel extends MediaTypeModel {
|
||||
type: string;
|
||||
subType: string;
|
||||
title: string;
|
||||
englishTitle: string;
|
||||
year: string;
|
||||
dataSource: string;
|
||||
url: string;
|
||||
id: string;
|
||||
|
||||
plot: string;
|
||||
genres: string[];
|
||||
writer: string[];
|
||||
|
|
@ -34,29 +27,29 @@ export class SeriesModel extends MediaTypeModel {
|
|||
personalRating: number;
|
||||
};
|
||||
|
||||
constructor(obj: any = {}) {
|
||||
constructor(obj: SeriesData) {
|
||||
super();
|
||||
|
||||
this.plot = undefined;
|
||||
this.genres = undefined;
|
||||
this.writer = undefined;
|
||||
this.studio = undefined;
|
||||
this.episodes = undefined;
|
||||
this.duration = undefined;
|
||||
this.onlineRating = undefined;
|
||||
this.actors = undefined;
|
||||
this.image = undefined;
|
||||
this.plot = '';
|
||||
this.genres = [];
|
||||
this.writer = [];
|
||||
this.studio = [];
|
||||
this.episodes = 0;
|
||||
this.duration = '';
|
||||
this.onlineRating = 0;
|
||||
this.actors = [];
|
||||
this.image = '';
|
||||
|
||||
this.released = undefined;
|
||||
this.streamingServices = undefined;
|
||||
this.airing = undefined;
|
||||
this.airedFrom = undefined;
|
||||
this.airedTo = undefined;
|
||||
this.released = false;
|
||||
this.streamingServices = [];
|
||||
this.airing = false;
|
||||
this.airedFrom = '';
|
||||
this.airedTo = '';
|
||||
|
||||
this.userData = {
|
||||
watched: undefined,
|
||||
lastWatched: undefined,
|
||||
personalRating: undefined,
|
||||
watched: false,
|
||||
lastWatched: '',
|
||||
personalRating: 0,
|
||||
};
|
||||
|
||||
migrateObject(this, obj, this);
|
||||
|
|
|
|||
|
|
@ -1,17 +1,10 @@
|
|||
import { MediaTypeModel } from './MediaTypeModel';
|
||||
import { mediaDbTag, migrateObject } from '../utils/Utils';
|
||||
import { MediaType } from '../utils/MediaType';
|
||||
import { mediaDbTag, migrateObject, type ModelToData } from '../utils/Utils';
|
||||
import { MediaTypeModel } from './MediaTypeModel';
|
||||
|
||||
export type WikiData = ModelToData<WikiModel>;
|
||||
|
||||
export class WikiModel extends MediaTypeModel {
|
||||
type: string;
|
||||
subType: string;
|
||||
title: string;
|
||||
englishTitle: string;
|
||||
year: string;
|
||||
dataSource: string;
|
||||
url: string;
|
||||
id: string;
|
||||
|
||||
wikiUrl: string;
|
||||
lastUpdated: string;
|
||||
length: number;
|
||||
|
|
@ -19,13 +12,13 @@ export class WikiModel extends MediaTypeModel {
|
|||
|
||||
userData: Record<string, unknown>;
|
||||
|
||||
constructor(obj: any = {}) {
|
||||
constructor(obj: WikiData) {
|
||||
super();
|
||||
|
||||
this.wikiUrl = undefined;
|
||||
this.lastUpdated = undefined;
|
||||
this.length = undefined;
|
||||
this.article = undefined;
|
||||
this.wikiUrl = '';
|
||||
this.lastUpdated = '';
|
||||
this.length = 0;
|
||||
this.article = '';
|
||||
this.userData = {};
|
||||
|
||||
migrateObject(this, obj, this);
|
||||
|
|
|
|||
|
|
@ -4,13 +4,16 @@
|
|||
import { setIcon } from 'obsidian';
|
||||
import { onMount } from 'svelte';
|
||||
|
||||
export let iconName: string = '';
|
||||
export let iconSize: number = 20;
|
||||
interface Props {
|
||||
iconName?: string;
|
||||
}
|
||||
|
||||
let iconEl: HTMLElement;
|
||||
let { iconName = '' }: Props = $props();
|
||||
|
||||
let iconEl: HTMLElement | undefined = $state();
|
||||
|
||||
onMount(() => {
|
||||
setIcon(iconEl, iconName, iconSize);
|
||||
setIcon(iconEl!, iconName);
|
||||
});
|
||||
</script>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import { PropertyMappingOption } from './PropertyMapping';
|
||||
import type MediaDbPlugin from '../main';
|
||||
import { MEDIA_TYPES } from '../utils/MediaTypeManager';
|
||||
import MediaDbPlugin from '../main';
|
||||
import { PropertyMappingOption } from './PropertyMapping';
|
||||
|
||||
export class PropertyMapper {
|
||||
plugin: MediaDbPlugin;
|
||||
|
|
@ -66,7 +66,7 @@ export class PropertyMapper {
|
|||
return obj;
|
||||
}
|
||||
|
||||
const propertyMappings = this.plugin.settings.propertyMappingModels.find(x => x.type === obj.type).properties;
|
||||
const propertyMappings = this.plugin.settings.propertyMappingModels.find(x => x.type === obj.type)?.properties ?? [];
|
||||
|
||||
const originalObj: Record<string, unknown> = {};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import type { MediaType } from '../utils/MediaType';
|
||||
import { containsOnlyLettersAndUnderscores, PropertyMappingNameConflictError, PropertyMappingValidationError } from '../utils/Utils';
|
||||
import { MediaType } from '../utils/MediaType';
|
||||
|
||||
export enum PropertyMappingOption {
|
||||
Default = 'default',
|
||||
|
|
|
|||
|
|
@ -1,18 +1,22 @@
|
|||
<script lang="ts">
|
||||
import { run } from 'svelte/legacy';
|
||||
|
||||
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 };
|
||||
|
||||
$: modelChanged(model);
|
||||
|
||||
function modelChanged(model: PropertyMappingModel) {
|
||||
validationResult = model.validate();
|
||||
interface Props {
|
||||
model: PropertyMappingModel;
|
||||
save: (model: PropertyMappingModel) => void;
|
||||
}
|
||||
|
||||
let { model, save }: Props = $props();
|
||||
|
||||
let validationResult: { res: boolean; err?: Error } | undefined = $state();
|
||||
|
||||
$effect(() => {
|
||||
validationResult = model.validate();
|
||||
});
|
||||
</script>
|
||||
|
||||
<div class="media-db-plugin-property-mappings-model-container">
|
||||
|
|
@ -51,7 +55,7 @@
|
|||
{/if}
|
||||
<button
|
||||
class="media-db-plugin-property-mappings-save-button {validationResult?.res ? 'mod-cta' : 'mod-muted'}"
|
||||
on:click={() => {
|
||||
onclick={() => {
|
||||
if (model.validate().res) save(model);
|
||||
}}
|
||||
>Save
|
||||
|
|
|
|||
|
|
@ -2,8 +2,12 @@
|
|||
import { PropertyMappingModel } from './PropertyMapping';
|
||||
import PropertyMappingModelComponent from './PropertyMappingModelComponent.svelte';
|
||||
|
||||
export let models: PropertyMappingModel[] = [];
|
||||
export let save: (model: PropertyMappingModel) => void;
|
||||
interface Props {
|
||||
models?: PropertyMappingModel[];
|
||||
save: (model: PropertyMappingModel) => void;
|
||||
}
|
||||
|
||||
let { models = [], save }: Props = $props();
|
||||
</script>
|
||||
|
||||
<div class="setting-item" style="display: flex; gap: 10px; flex-direction: column; align-items: stretch;">
|
||||
|
|
|
|||
|
|
@ -1,13 +1,14 @@
|
|||
import { App, Notice, PluginSettingTab, Setting } from 'obsidian';
|
||||
|
||||
import MediaDbPlugin from '../main';
|
||||
import { FolderSuggest } from './suggesters/FolderSuggest';
|
||||
import { FileSuggest } from './suggesters/FileSuggest';
|
||||
import PropertyMappingModelsComponent from './PropertyMappingModelsComponent.svelte';
|
||||
import { PropertyMapping, PropertyMappingModel, PropertyMappingOption } from './PropertyMapping';
|
||||
import type { App } from 'obsidian';
|
||||
import { Notice, PluginSettingTab, Setting } from 'obsidian';
|
||||
import { mount } from 'svelte';
|
||||
import type MediaDbPlugin from '../main';
|
||||
import type { MediaTypeModel } from '../models/MediaTypeModel';
|
||||
import { MEDIA_TYPES } from '../utils/MediaTypeManager';
|
||||
import { MediaTypeModel } from '../models/MediaTypeModel';
|
||||
import { fragWithHTML } from '../utils/Utils';
|
||||
import { PropertyMapping, PropertyMappingModel, PropertyMappingOption } from './PropertyMapping';
|
||||
import PropertyMappingModelsComponent from './PropertyMappingModelsComponent.svelte';
|
||||
import { FileSuggest } from './suggesters/FileSuggest';
|
||||
import { FolderSuggest } from './suggesters/FolderSuggest';
|
||||
|
||||
export interface MediaDbPluginSettings {
|
||||
OMDbKey: string;
|
||||
|
|
@ -254,7 +255,10 @@ export class MediaDbSettingTab extends PluginSettingTab {
|
|||
.onChange(data => {
|
||||
const newDateFormat = data ? data : DEFAULT_SETTINGS.customDateFormat;
|
||||
this.plugin.settings.customDateFormat = newDateFormat;
|
||||
document.getElementById('media-db-dateformat-preview').textContent = this.plugin.dateFormatter.getPreview(newDateFormat); // update preview
|
||||
const previewEl = document.getElementById('media-db-dateformat-preview');
|
||||
if (previewEl) {
|
||||
previewEl.textContent = this.plugin.dateFormatter.getPreview(newDateFormat); // update preview
|
||||
}
|
||||
void this.plugin.saveSettings();
|
||||
});
|
||||
});
|
||||
|
|
@ -689,7 +693,7 @@ export class MediaDbSettingTab extends PluginSettingTab {
|
|||
Don't forget to save your changes using the save button for each individual category.
|
||||
</p>`;
|
||||
|
||||
new PropertyMappingModelsComponent({
|
||||
mount(PropertyMappingModelsComponent, {
|
||||
target: this.containerEl,
|
||||
props: {
|
||||
models: this.plugin.settings.propertyMappingModels.map(x => x.copy()),
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import type { TAbstractFile } from 'obsidian';
|
||||
import { TFile } from 'obsidian';
|
||||
import { TextInputSuggest } from './Suggest';
|
||||
import { TAbstractFile, TFile } from 'obsidian';
|
||||
|
||||
export class FileSuggest extends TextInputSuggest<TFile> {
|
||||
getSuggestions(inputStr: string): TFile[] {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
// Credits go to Liam's Periodic Notes Plugin: https://github.com/liamcain/obsidian-periodic-notes
|
||||
|
||||
import { TAbstractFile, TFolder } from 'obsidian';
|
||||
import type { TAbstractFile } from 'obsidian';
|
||||
import { TFolder } from 'obsidian';
|
||||
import { TextInputSuggest } from './Suggest';
|
||||
|
||||
export class FolderSuggest extends TextInputSuggest<TFolder> {
|
||||
|
|
|
|||
|
|
@ -1,28 +1,34 @@
|
|||
// Credits go to Liam's Periodic Notes Plugin: https://github.com/liamcain/obsidian-periodic-notes
|
||||
|
||||
import { App, ISuggestOwner, Scope } from 'obsidian';
|
||||
import { createPopper, Instance as PopperInstance } from '@popperjs/core';
|
||||
import type { Instance as PopperInstance } from '@popperjs/core';
|
||||
import { createPopper } from '@popperjs/core';
|
||||
import type { App, ISuggestOwner } from 'obsidian';
|
||||
import { Scope } from 'obsidian';
|
||||
import { wrapAround } from 'src/utils/Utils';
|
||||
|
||||
export class Suggest<T> {
|
||||
private owner: ISuggestOwner<T>;
|
||||
private values: T[];
|
||||
private suggestions: HTMLDivElement[];
|
||||
private suggestions: HTMLElement[];
|
||||
private selectedItem: number;
|
||||
private containerEl: HTMLElement;
|
||||
|
||||
constructor(owner: ISuggestOwner<T>, containerEl: HTMLElement, scope: Scope) {
|
||||
this.owner = owner;
|
||||
this.containerEl = containerEl;
|
||||
this.values = [];
|
||||
this.suggestions = [];
|
||||
this.selectedItem = 0;
|
||||
|
||||
containerEl.on('click', '.suggestion-item', this.onSuggestionClick.bind(this));
|
||||
containerEl.on('mousemove', '.suggestion-item', this.onSuggestionMouseover.bind(this));
|
||||
containerEl.on('click', '.suggestion-item', (e, el) => this.onSuggestionClick(e, el));
|
||||
containerEl.on('mousemove', '.suggestion-item', (e, el) => this.onSuggestionMouseover(e, el));
|
||||
|
||||
scope.register([], 'ArrowUp', event => {
|
||||
if (!event.isComposing) {
|
||||
this.setSelectedItem(this.selectedItem - 1, true);
|
||||
return false;
|
||||
}
|
||||
return undefined;
|
||||
});
|
||||
|
||||
scope.register([], 'ArrowDown', event => {
|
||||
|
|
@ -30,6 +36,7 @@ export class Suggest<T> {
|
|||
this.setSelectedItem(this.selectedItem + 1, true);
|
||||
return false;
|
||||
}
|
||||
return undefined;
|
||||
});
|
||||
|
||||
scope.register([], 'Enter', event => {
|
||||
|
|
@ -37,10 +44,11 @@ export class Suggest<T> {
|
|||
this.useSelectedItem(event);
|
||||
return false;
|
||||
}
|
||||
return undefined;
|
||||
});
|
||||
}
|
||||
|
||||
onSuggestionClick(event: MouseEvent, el: HTMLDivElement): void {
|
||||
onSuggestionClick(event: MouseEvent, el: HTMLElement): void {
|
||||
event.preventDefault();
|
||||
|
||||
const item = this.suggestions.indexOf(el);
|
||||
|
|
@ -48,7 +56,7 @@ export class Suggest<T> {
|
|||
this.useSelectedItem(event);
|
||||
}
|
||||
|
||||
onSuggestionMouseover(_event: MouseEvent, el: HTMLDivElement): void {
|
||||
onSuggestionMouseover(_event: MouseEvent, el: HTMLElement): void {
|
||||
const item = this.suggestions.indexOf(el);
|
||||
this.setSelectedItem(item, false);
|
||||
}
|
||||
|
|
@ -95,7 +103,7 @@ export abstract class TextInputSuggest<T> implements ISuggestOwner<T> {
|
|||
protected app: App;
|
||||
protected inputEl: HTMLInputElement;
|
||||
|
||||
private popper: PopperInstance;
|
||||
private popper?: PopperInstance;
|
||||
private scope: Scope;
|
||||
private suggestEl: HTMLElement;
|
||||
private suggest: Suggest<T>;
|
||||
|
|
@ -126,13 +134,13 @@ export abstract class TextInputSuggest<T> implements ISuggestOwner<T> {
|
|||
if (suggestions.length > 0) {
|
||||
this.suggest.setSuggestions(suggestions);
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
this.open((<any>this.app).dom.appContainerEl, this.inputEl);
|
||||
this.open((this.app as any).dom.appContainerEl, this.inputEl);
|
||||
}
|
||||
}
|
||||
|
||||
open(container: HTMLElement, inputEl: HTMLElement): void {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
(<any>this.app).keymap.pushScope(this.scope);
|
||||
(this.app as any).keymap.pushScope(this.scope);
|
||||
|
||||
container.appendChild(this.suggestEl);
|
||||
this.popper = createPopper(inputEl, this.suggestEl, {
|
||||
|
|
@ -162,7 +170,7 @@ export abstract class TextInputSuggest<T> implements ISuggestOwner<T> {
|
|||
|
||||
close(): void {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
(<any>this.app).keymap.popScope(this.scope);
|
||||
(this.app as any).keymap.popScope(this.scope);
|
||||
|
||||
this.suggest.setSuggestions([]);
|
||||
this.popper?.destroy();
|
||||
|
|
|
|||
|
|
@ -1,16 +1,17 @@
|
|||
import { MediaDbPluginSettings } from '../settings/Settings';
|
||||
import { MediaType } from './MediaType';
|
||||
import { MediaTypeModel } from '../models/MediaTypeModel';
|
||||
import { replaceTags } from './Utils';
|
||||
import { App, TAbstractFile, TFile, TFolder } from 'obsidian';
|
||||
import { MovieModel } from '../models/MovieModel';
|
||||
import { SeriesModel } from '../models/SeriesModel';
|
||||
import { MangaModel } from '../models/MangaModel';
|
||||
import { GameModel } from '../models/GameModel';
|
||||
import { WikiModel } from '../models/WikiModel';
|
||||
import { MusicReleaseModel } from '../models/MusicReleaseModel';
|
||||
import type { App, TAbstractFile, TFile } from 'obsidian';
|
||||
import { TFolder } from 'obsidian';
|
||||
import { BoardGameModel } from '../models/BoardGameModel';
|
||||
import { BookModel } from '../models/BookModel';
|
||||
import { GameModel } from '../models/GameModel';
|
||||
import { MangaModel } from '../models/MangaModel';
|
||||
import type { MediaTypeModel } from '../models/MediaTypeModel';
|
||||
import { MovieModel } from '../models/MovieModel';
|
||||
import { MusicReleaseModel } from '../models/MusicReleaseModel';
|
||||
import { SeriesModel } from '../models/SeriesModel';
|
||||
import type { MediaDbPluginSettings } from '../settings/Settings';
|
||||
import { MediaType } from './MediaType';
|
||||
import { replaceTags } from './Utils';
|
||||
import { WikiModel } from '../models/WikiModel';
|
||||
|
||||
export const MEDIA_TYPES: MediaType[] = [
|
||||
MediaType.Movie,
|
||||
|
|
@ -28,7 +29,11 @@ export class MediaTypeManager {
|
|||
mediaTemplateMap: Map<MediaType, string>;
|
||||
mediaFolderMap: Map<MediaType, string>;
|
||||
|
||||
constructor() {}
|
||||
constructor() {
|
||||
this.mediaFileNameTemplateMap = new Map<MediaType, string>();
|
||||
this.mediaTemplateMap = new Map<MediaType, string>();
|
||||
this.mediaFolderMap = new Map<MediaType, string>();
|
||||
}
|
||||
|
||||
updateTemplates(settings: MediaDbPluginSettings): void {
|
||||
this.mediaFileNameTemplateMap = new Map<MediaType, string>();
|
||||
|
|
@ -66,7 +71,7 @@ export class MediaTypeManager {
|
|||
|
||||
getFileName(mediaTypeModel: MediaTypeModel): string {
|
||||
// Ignore undefined tags since some search APIs do not return all properties in the model and produce clean file names even if errors occur
|
||||
return replaceTags(this.mediaFileNameTemplateMap.get(mediaTypeModel.getMediaType()), mediaTypeModel, true);
|
||||
return replaceTags(this.mediaFileNameTemplateMap.get(mediaTypeModel.getMediaType())!, mediaTypeModel, true);
|
||||
}
|
||||
|
||||
async getTemplate(mediaTypeModel: MediaTypeModel, app: App): Promise<string> {
|
||||
|
|
@ -76,7 +81,7 @@ export class MediaTypeManager {
|
|||
return '';
|
||||
}
|
||||
|
||||
let templateFile = app.vault.getAbstractFileByPath(templateFilePath);
|
||||
let templateFile = app.vault.getAbstractFileByPath(templateFilePath) ?? undefined;
|
||||
|
||||
// WARNING: This was previously selected by filename, but that could lead to collisions and unwanted effects.
|
||||
// This now falls back to the previous method if no file is found
|
||||
|
|
@ -107,7 +112,7 @@ export class MediaTypeManager {
|
|||
if (!(await app.vault.adapter.exists(folderPath))) {
|
||||
await app.vault.createFolder(folderPath);
|
||||
}
|
||||
const folder: TAbstractFile = app.vault.getAbstractFileByPath(folderPath);
|
||||
const folder = app.vault.getAbstractFileByPath(folderPath);
|
||||
|
||||
if (!(folder instanceof TFolder)) {
|
||||
throw Error(`Expected ${folder} to be instance of TFolder`);
|
||||
|
|
@ -141,6 +146,6 @@ export class MediaTypeManager {
|
|||
return new BookModel(obj);
|
||||
}
|
||||
|
||||
return undefined;
|
||||
throw new Error(`Unknown media type: ${mediaType}`);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
import { Notice } from 'obsidian';
|
||||
import { MediaDbPreviewModal } from 'src/modals/MediaDbPreviewModal';
|
||||
import type MediaDbPlugin from '../main';
|
||||
import { MediaDbAdvancedSearchModal } from '../modals/MediaDbAdvancedSearchModal';
|
||||
import { MediaDbIdSearchModal } from '../modals/MediaDbIdSearchModal';
|
||||
import { MediaTypeModel } from '../models/MediaTypeModel';
|
||||
import { MediaDbSearchResultModal } from '../modals/MediaDbSearchResultModal';
|
||||
import { Notice } from 'obsidian';
|
||||
import MediaDbPlugin from '../main';
|
||||
import { MediaDbPreviewModal } from 'src/modals/MediaDbPreviewModal';
|
||||
import { MediaDbSearchModal } from '../modals/MediaDbSearchModal';
|
||||
import { MediaType } from './MediaType';
|
||||
import { MediaDbSearchResultModal } from '../modals/MediaDbSearchResultModal';
|
||||
import type { MediaTypeModel } from '../models/MediaTypeModel';
|
||||
import type { MediaType } from './MediaType';
|
||||
|
||||
export enum ModalResultCode {
|
||||
SUCCESS = 'SUCCESS',
|
||||
|
|
@ -15,60 +15,59 @@ export enum ModalResultCode {
|
|||
ERROR = 'ERROR',
|
||||
}
|
||||
|
||||
type ModalResult<T> =
|
||||
| {
|
||||
code: ModalResultCode.CLOSE;
|
||||
}
|
||||
| {
|
||||
code: ModalResultCode.ERROR;
|
||||
error: Error;
|
||||
}
|
||||
| {
|
||||
code: ModalResultCode.SUCCESS;
|
||||
data: T;
|
||||
};
|
||||
|
||||
type SkippableModalResult<T> =
|
||||
| ModalResult<T>
|
||||
| {
|
||||
code: ModalResultCode.SKIP;
|
||||
};
|
||||
|
||||
/**
|
||||
* Object containing the data {@link ModalHelper.createSearchModal} returns.
|
||||
* On {@link ModalResultCode.SUCCESS} this contains {@link SearchModalData}.
|
||||
* On {@link ModalResultCode.ERROR} this contains a reference to that error.
|
||||
*/
|
||||
export interface SearchModalResult {
|
||||
code: ModalResultCode.SUCCESS | ModalResultCode.CLOSE | ModalResultCode.ERROR;
|
||||
data?: SearchModalData;
|
||||
error?: Error;
|
||||
}
|
||||
export type SearchModalResult = ModalResult<SearchModalData>;
|
||||
|
||||
/**
|
||||
* Object containing the data {@link ModalHelper.createAdvancedSearchModal} returns.
|
||||
* On {@link ModalResultCode.SUCCESS} this contains {@link AdvancedSearchModalData}.
|
||||
* On {@link ModalResultCode.ERROR} this contains a reference to that error.
|
||||
*/
|
||||
export interface AdvancedSearchModalResult {
|
||||
code: ModalResultCode.SUCCESS | ModalResultCode.CLOSE | ModalResultCode.ERROR;
|
||||
data?: AdvancedSearchModalData;
|
||||
error?: Error;
|
||||
}
|
||||
export type AdvancedSearchModalResult = ModalResult<AdvancedSearchModalData>;
|
||||
|
||||
/**
|
||||
* Object containing the data {@link ModalHelper.createIdSearchModal} returns.
|
||||
* On {@link ModalResultCode.SUCCESS} this contains {@link IdSearchModalData}.
|
||||
* On {@link ModalResultCode.ERROR} this contains a reference to that error.
|
||||
*/
|
||||
export interface IdSearchModalResult {
|
||||
code: ModalResultCode.SUCCESS | ModalResultCode.CLOSE | ModalResultCode.ERROR;
|
||||
data?: IdSearchModalData;
|
||||
error?: Error;
|
||||
}
|
||||
export type IdSearchModalResult = ModalResult<IdSearchModalData>;
|
||||
|
||||
/**
|
||||
* Object containing the data {@link ModalHelper.createSelectModal} returns.
|
||||
* On {@link ModalResultCode.SUCCESS} this contains {@link SelectModalData}.
|
||||
* On {@link ModalResultCode.ERROR} this contains a reference to that error.
|
||||
*/
|
||||
export interface SelectModalResult {
|
||||
code: ModalResultCode.SUCCESS | ModalResultCode.CLOSE | ModalResultCode.SKIP | ModalResultCode.ERROR;
|
||||
data?: SelectModalData;
|
||||
error?: Error;
|
||||
}
|
||||
export type SelectModalResult = SkippableModalResult<SelectModalData>;
|
||||
|
||||
/**
|
||||
* Object containing the data {@link ModalHelper.createPreviewModal} returns.
|
||||
* On {@link ModalResultCode.SUCCESS} this contains {@link PreviewModalData}.
|
||||
* On {@link ModalResultCode.ERROR} this contains a reference to that error.
|
||||
*/
|
||||
export interface PreviewModalResult {
|
||||
code: ModalResultCode.SUCCESS | ModalResultCode.CLOSE | ModalResultCode.ERROR;
|
||||
data?: PreviewModalData;
|
||||
error?: Error;
|
||||
}
|
||||
export type PreviewModalResult = ModalResult<PreviewModalData>;
|
||||
|
||||
/**
|
||||
* The data the search modal returns.
|
||||
|
|
@ -248,7 +247,10 @@ export class ModalHelper {
|
|||
* @param submitCallback the callback that gets executed after the modal has been submitted, but after it has been closed
|
||||
* @returns the user input or nothing and a reference to the modal.
|
||||
*/
|
||||
async openSearchModal(searchModalOptions: SearchModalOptions, submitCallback: (searchModalData: SearchModalData) => Promise<MediaTypeModel[]>): Promise<MediaTypeModel[]> {
|
||||
async openSearchModal(
|
||||
searchModalOptions: SearchModalOptions,
|
||||
submitCallback: (searchModalData: SearchModalData) => Promise<MediaTypeModel[]>,
|
||||
): Promise<MediaTypeModel[] | undefined> {
|
||||
const { searchModalResult, searchModal } = await this.createSearchModal(searchModalOptions);
|
||||
console.debug(`MDB | searchModal closed with code ${searchModalResult.code}`);
|
||||
|
||||
|
|
@ -271,7 +273,7 @@ export class ModalHelper {
|
|||
return callbackRes;
|
||||
} catch (e) {
|
||||
console.warn(e);
|
||||
new Notice(e.toString());
|
||||
new Notice(`${e}`);
|
||||
searchModal.close();
|
||||
return undefined;
|
||||
}
|
||||
|
|
@ -314,7 +316,7 @@ export class ModalHelper {
|
|||
async openAdvancedSearchModal(
|
||||
advancedSearchModalOptions: AdvancedSearchModalOptions,
|
||||
submitCallback: (advancedSearchModalData: AdvancedSearchModalData) => Promise<MediaTypeModel[]>,
|
||||
): Promise<MediaTypeModel[]> {
|
||||
): Promise<MediaTypeModel[] | undefined> {
|
||||
const { advancedSearchModalResult, advancedSearchModal } = await this.createAdvancedSearchModal(advancedSearchModalOptions);
|
||||
console.debug(`MDB | advencedSearchModal closed with code ${advancedSearchModalResult.code}`);
|
||||
|
||||
|
|
@ -337,7 +339,7 @@ export class ModalHelper {
|
|||
return callbackRes;
|
||||
} catch (e) {
|
||||
console.warn(e);
|
||||
new Notice(e.toString());
|
||||
new Notice(`${e}`);
|
||||
advancedSearchModal.close();
|
||||
return undefined;
|
||||
}
|
||||
|
|
@ -377,8 +379,8 @@ export class ModalHelper {
|
|||
*/
|
||||
async openIdSearchModal(
|
||||
idSearchModalOptions: IdSearchModalOptions,
|
||||
submitCallback: (idSearchModalData: IdSearchModalData) => Promise<MediaTypeModel>,
|
||||
): Promise<MediaTypeModel> {
|
||||
submitCallback: (idSearchModalData: IdSearchModalData) => Promise<MediaTypeModel | undefined>,
|
||||
): Promise<MediaTypeModel | undefined> {
|
||||
const { idSearchModalResult, idSearchModal } = await this.createIdSearchModal(idSearchModalOptions);
|
||||
console.debug(`MDB | idSearchModal closed with code ${idSearchModalResult.code}`);
|
||||
|
||||
|
|
@ -396,12 +398,12 @@ export class ModalHelper {
|
|||
}
|
||||
|
||||
try {
|
||||
const callbackRes: MediaTypeModel = await submitCallback(idSearchModalResult.data);
|
||||
const callbackRes = await submitCallback(idSearchModalResult.data);
|
||||
idSearchModal.close();
|
||||
return callbackRes;
|
||||
} catch (e) {
|
||||
console.warn(e);
|
||||
new Notice(e.toString());
|
||||
new Notice(`${e}`);
|
||||
idSearchModal.close();
|
||||
return undefined;
|
||||
}
|
||||
|
|
@ -440,7 +442,10 @@ export class ModalHelper {
|
|||
* @param submitCallback the callback that gets executed after the modal has been submitted, but before it has been closed
|
||||
* @returns the user input or nothing and a reference to the modal.
|
||||
*/
|
||||
async openSelectModal(selectModalOptions: SelectModalOptions, submitCallback: (selectModalData: SelectModalData) => Promise<MediaTypeModel[]>): Promise<MediaTypeModel[]> {
|
||||
async openSelectModal(
|
||||
selectModalOptions: SelectModalOptions,
|
||||
submitCallback: (selectModalData: SelectModalData) => Promise<MediaTypeModel[]>,
|
||||
): Promise<MediaTypeModel[] | undefined> {
|
||||
const { selectModalResult, selectModal } = await this.createSelectModal(selectModalOptions);
|
||||
console.debug(`MDB | selectModal closed with code ${selectModalResult.code}`);
|
||||
|
||||
|
|
@ -468,7 +473,7 @@ export class ModalHelper {
|
|||
return callbackRes;
|
||||
} catch (e) {
|
||||
console.warn(e);
|
||||
new Notice(e.toString());
|
||||
new Notice(`${e}`);
|
||||
selectModal.close();
|
||||
return;
|
||||
}
|
||||
|
|
@ -500,12 +505,12 @@ export class ModalHelper {
|
|||
console.warn(previewModalResult.error);
|
||||
new Notice(previewModalResult.error.toString());
|
||||
previewModal.close();
|
||||
return undefined;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (previewModalResult.code === ModalResultCode.CLOSE) {
|
||||
// modal is already being closed
|
||||
return undefined;
|
||||
return true;
|
||||
}
|
||||
|
||||
try {
|
||||
|
|
@ -514,9 +519,9 @@ export class ModalHelper {
|
|||
return callbackRes;
|
||||
} catch (e) {
|
||||
console.warn(e);
|
||||
new Notice(e.toString());
|
||||
new Notice(`${e}`);
|
||||
previewModal.close();
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { MediaTypeModel } from '../models/MediaTypeModel';
|
||||
import { TFile, TFolder, App } from 'obsidian';
|
||||
import type { TFile, TFolder, App } from 'obsidian';
|
||||
import type { MediaTypeModel } from '../models/MediaTypeModel';
|
||||
|
||||
export const pluginName: string = 'obsidian-media-db-plugin';
|
||||
export const contactEmail: string = 'm.projects.code@gmail.com';
|
||||
|
|
@ -82,7 +82,7 @@ function replaceTag(match: string, mediaTypeModel: MediaTypeModel, ignoreUndefin
|
|||
return '{{ INVALID TEMPLATE TAG }}';
|
||||
}
|
||||
|
||||
function traverseMetaData(path: Array<string>, mediaTypeModel: MediaTypeModel): any {
|
||||
function traverseMetaData(path: string[], mediaTypeModel: MediaTypeModel): any {
|
||||
let o: any = mediaTypeModel;
|
||||
|
||||
for (const part of path) {
|
||||
|
|
@ -226,7 +226,11 @@ export function hasTemplaterPlugin(app: App): boolean {
|
|||
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']) {
|
||||
if (templater && !templater?.settings.trigger_on_file_creation) {
|
||||
await templater.templater.overwrite_file_commands(file);
|
||||
}
|
||||
}
|
||||
|
||||
export type ModelToData<T> = {
|
||||
[K in keyof T as T[K] extends Function ? never : K]?: T[K];
|
||||
};
|
||||
|
|
|
|||
|
|
@ -2,14 +2,22 @@
|
|||
"compilerOptions": {
|
||||
"baseUrl": ".",
|
||||
"module": "ESNext",
|
||||
"target": "ES6",
|
||||
"target": "ESNext",
|
||||
"allowJs": true,
|
||||
"checkJs": true,
|
||||
"noImplicitAny": true,
|
||||
"strict": true,
|
||||
"strictNullChecks": true,
|
||||
"noImplicitReturns": true,
|
||||
"moduleResolution": "node",
|
||||
"importHelpers": true,
|
||||
"isolatedModules": true,
|
||||
"skipLibCheck": true,
|
||||
"verbatimModuleSyntax": true,
|
||||
"resolveJsonModule": true,
|
||||
"moduleDetection": "force",
|
||||
"sourceMap": true,
|
||||
"lib": ["DOM", "ESNext"],
|
||||
"types": ["svelte"],
|
||||
"allowSyntheticDefaultImports": true
|
||||
},
|
||||
"include": ["src/**/*.ts", "tests/**/*.ts"]
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue