update deps; make apis more type safe
This commit is contained in:
parent
9518ede41c
commit
292dcf5b49
46 changed files with 26911 additions and 550 deletions
17
automation/fetchSchemas.ts
Normal file
17
automation/fetchSchemas.ts
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
import { $ } from 'utils/shellUtils';
|
||||||
|
|
||||||
|
async function fetchSchema() {
|
||||||
|
// https://docs.api.jikan.moe/
|
||||||
|
await $('bun openapi-typescript https://raw.githubusercontent.com/jikan-me/jikan-rest/master/storage/api-docs/api-docs.json -o ./src/api/schemas/MALAPI.ts');
|
||||||
|
|
||||||
|
// https://www.giantbomb.com/forums/api-developers-3017/giant-bomb-openapi-specification-1901269/
|
||||||
|
await $('bun openapi-typescript ./src/api/schemas/GiantBomb.json -o ./src/api/schemas/GiantBomb.ts');
|
||||||
|
|
||||||
|
// https://www.omdbapi.com/swagger.json
|
||||||
|
await $('bun openapi-typescript ./src/api/schemas/OMDb.json -o ./src/api/schemas/OMDb.ts');
|
||||||
|
|
||||||
|
// https://github.com/internetarchive/openlibrary-api/blob/main/swagger.yaml
|
||||||
|
await $('bun openapi-typescript ./src/api/schemas/OpenLibrary.json -o ./src/api/schemas/OpenLibrary.ts');
|
||||||
|
}
|
||||||
|
|
||||||
|
await fetchSchema();
|
||||||
BIN
bun.lockb
BIN
bun.lockb
Binary file not shown.
|
|
@ -7,7 +7,7 @@ import * as plugin_import from 'eslint-plugin-import';
|
||||||
|
|
||||||
export default tseslint.config(
|
export default tseslint.config(
|
||||||
{
|
{
|
||||||
ignores: ['npm/', 'node_modules/', 'exampleVault/', 'automation/', 'main.js', '*.svelte'],
|
ignores: ['npm/', 'node_modules/', 'exampleVault/', 'automation/', 'main.js', '*.svelte', 'src/api/schemas/'],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
files: ['src/**/*.ts'],
|
files: ['src/**/*.ts'],
|
||||||
|
|
|
||||||
34
package.json
34
package.json
|
|
@ -14,8 +14,8 @@
|
||||||
"lint": "eslint --max-warnings=0 src/**",
|
"lint": "eslint --max-warnings=0 src/**",
|
||||||
"lint:fix": "eslint --max-warnings=0 --fix src/**",
|
"lint:fix": "eslint --max-warnings=0 --fix src/**",
|
||||||
"svelte-check": "svelte-check --compiler-warnings \"unused-export-let:ignore\"",
|
"svelte-check": "svelte-check --compiler-warnings \"unused-export-let:ignore\"",
|
||||||
"check": "bun run format:check && bun run tsc && bun run test",
|
"check": "bun run format:check && bun run tsc && bun run lint && bun run svelte-check",
|
||||||
"check:fix": "bun run format && bun run tsc && bun run test",
|
"check:fix": "bun run format && bun run tsc && bun run lint:fix && bun run svelte-check",
|
||||||
"release": "bun run automation/release.ts",
|
"release": "bun run automation/release.ts",
|
||||||
"stats": "bun run automation/stats.ts"
|
"stats": "bun run automation/stats.ts"
|
||||||
},
|
},
|
||||||
|
|
@ -23,26 +23,28 @@
|
||||||
"author": "Moritz Jung",
|
"author": "Moritz Jung",
|
||||||
"license": "GPL-3.0",
|
"license": "GPL-3.0",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@popperjs/core": "^2.11.8",
|
"@happy-dom/global-registrator": "^18.0.1",
|
||||||
"@lemons_dev/parsinom": "^0.0.12",
|
"@lemons_dev/parsinom": "^0.0.12",
|
||||||
"@happy-dom/global-registrator": "^14.12.3",
|
"@popperjs/core": "^2.11.8",
|
||||||
"@types/bun": "^1.1.16",
|
"@types/bun": "^1.2.19",
|
||||||
"builtin-modules": "^4.0.0",
|
"builtin-modules": "^5.0.0",
|
||||||
"esbuild": "^0.24.2",
|
"esbuild": "^0.25.8",
|
||||||
"esbuild-plugin-copy-watch": "^2.3.1",
|
"esbuild-plugin-copy-watch": "^2.3.1",
|
||||||
"esbuild-svelte": "^0.8.2",
|
"esbuild-svelte": "^0.9.3",
|
||||||
"eslint": "^9.18.0",
|
"eslint": "^9.32.0",
|
||||||
"eslint-plugin-import": "^2.31.0",
|
"eslint-plugin-import": "^2.32.0",
|
||||||
"eslint-plugin-only-warn": "^1.1.0",
|
"eslint-plugin-only-warn": "^1.1.0",
|
||||||
"obsidian": "latest",
|
"obsidian": "latest",
|
||||||
"prettier": "^3.4.2",
|
"openapi-fetch": "^0.14.0",
|
||||||
"prettier-plugin-svelte": "^3.3.3",
|
"openapi-typescript": "^7.8.0",
|
||||||
|
"prettier": "^3.6.2",
|
||||||
|
"prettier-plugin-svelte": "^3.4.0",
|
||||||
"string-argv": "^0.3.2",
|
"string-argv": "^0.3.2",
|
||||||
"svelte": "^5.17.5",
|
"svelte": "^5.38.0",
|
||||||
"svelte-check": "^4.1.4",
|
"svelte-check": "^4.3.1",
|
||||||
"svelte-preprocess": "^6.0.3",
|
"svelte-preprocess": "^6.0.3",
|
||||||
"tslib": "^2.8.1",
|
"tslib": "^2.8.1",
|
||||||
"typescript": "^5.7.3",
|
"typescript": "^5.9.2",
|
||||||
"typescript-eslint": "^8.20.0"
|
"typescript-eslint": "^8.39.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,8 @@ import type { MediaTypeModel } from '../../models/MediaTypeModel';
|
||||||
import { MediaType } from '../../utils/MediaType';
|
import { MediaType } from '../../utils/MediaType';
|
||||||
import { APIModel } from '../APIModel';
|
import { APIModel } from '../APIModel';
|
||||||
|
|
||||||
|
// sadly no open api schema available
|
||||||
|
|
||||||
export class BoardGameGeekAPI extends APIModel {
|
export class BoardGameGeekAPI extends APIModel {
|
||||||
plugin: MediaDbPlugin;
|
plugin: MediaDbPlugin;
|
||||||
|
|
||||||
|
|
@ -118,6 +120,6 @@ export class BoardGameGeekAPI extends APIModel {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
getDisabledMediaTypes(): MediaType[] {
|
getDisabledMediaTypes(): MediaType[] {
|
||||||
return this.plugin.settings.BoardgameGeekAPI_disabledMediaTypes as MediaType[];
|
return this.plugin.settings.BoardgameGeekAPI_disabledMediaTypes;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
|
/* eslint-disable @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access */
|
||||||
|
|
||||||
import { requestUrl } from 'obsidian';
|
import { requestUrl } from 'obsidian';
|
||||||
import { ComicMangaModel } from 'src/models/ComicMangaModel';
|
import { ComicMangaModel } from 'src/models/ComicMangaModel';
|
||||||
import type MediaDbPlugin from '../../main';
|
import type MediaDbPlugin from '../../main';
|
||||||
|
|
@ -5,6 +7,8 @@ import type { MediaTypeModel } from '../../models/MediaTypeModel';
|
||||||
import { MediaType } from '../../utils/MediaType';
|
import { MediaType } from '../../utils/MediaType';
|
||||||
import { APIModel } from '../APIModel';
|
import { APIModel } from '../APIModel';
|
||||||
|
|
||||||
|
// sadly no open api schema available
|
||||||
|
|
||||||
export class ComicVineAPI extends APIModel {
|
export class ComicVineAPI extends APIModel {
|
||||||
plugin: MediaDbPlugin;
|
plugin: MediaDbPlugin;
|
||||||
|
|
||||||
|
|
@ -41,7 +45,7 @@ export class ComicVineAPI extends APIModel {
|
||||||
year: result.start_year,
|
year: result.start_year,
|
||||||
dataSource: this.apiName,
|
dataSource: this.apiName,
|
||||||
id: `4050-${result.id}`,
|
id: `4050-${result.id}`,
|
||||||
publishers: result.publisher?.name ?? [],
|
publishers: result.publisher?.name,
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -64,28 +68,32 @@ export class ComicVineAPI extends APIModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
const data = await fetchData.json;
|
const data = await fetchData.json;
|
||||||
// console.debug(data);
|
|
||||||
const result = data.results;
|
const result = data.results;
|
||||||
|
|
||||||
|
const authors = result.people as
|
||||||
|
| {
|
||||||
|
name: string;
|
||||||
|
}[]
|
||||||
|
| undefined;
|
||||||
|
|
||||||
return new ComicMangaModel({
|
return new ComicMangaModel({
|
||||||
type: MediaType.ComicManga,
|
type: MediaType.ComicManga,
|
||||||
title: result.name,
|
title: result.name,
|
||||||
englishTitle: result.name,
|
englishTitle: result.name,
|
||||||
alternateTitles: result.aliases,
|
alternateTitles: result.aliases,
|
||||||
plot: result.deck,
|
plot: result.deck,
|
||||||
year: result.start_year ?? '',
|
year: result.start_year,
|
||||||
dataSource: this.apiName,
|
dataSource: this.apiName,
|
||||||
url: result.site_detail_url,
|
url: result.site_detail_url,
|
||||||
id: `4050-${result.id}`,
|
id: `4050-${result.id}`,
|
||||||
|
|
||||||
authors: result.people?.map((x: any) => x.name) ?? [],
|
authors: authors?.map(x => x.name),
|
||||||
chapters: result.count_of_issues,
|
chapters: result.count_of_issues,
|
||||||
image: result.image?.original_url ?? '',
|
image: result.image?.original_url,
|
||||||
|
|
||||||
released: true,
|
released: true,
|
||||||
publishers: result.publisher?.name ?? [],
|
publishers: result.publisher?.name,
|
||||||
publishedFrom: result.start_year ?? 'unknown',
|
publishedFrom: result.start_year,
|
||||||
publishedTo: 'unknown',
|
|
||||||
status: result.status,
|
status: result.status,
|
||||||
|
|
||||||
userData: {
|
userData: {
|
||||||
|
|
@ -96,6 +104,6 @@ export class ComicVineAPI extends APIModel {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
getDisabledMediaTypes(): MediaType[] {
|
getDisabledMediaTypes(): MediaType[] {
|
||||||
return this.plugin.settings.ComicVineAPI_disabledMediaTypes as MediaType[];
|
return this.plugin.settings.ComicVineAPI_disabledMediaTypes;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,11 @@
|
||||||
import { requestUrl } from 'obsidian';
|
import createClient from 'openapi-fetch';
|
||||||
|
import { obsidianFetch } from 'src/utils/Utils';
|
||||||
import type MediaDbPlugin from '../../main';
|
import type MediaDbPlugin from '../../main';
|
||||||
import { GameModel } from '../../models/GameModel';
|
import { GameModel } from '../../models/GameModel';
|
||||||
import type { MediaTypeModel } from '../../models/MediaTypeModel';
|
import type { MediaTypeModel } from '../../models/MediaTypeModel';
|
||||||
import { MediaType } from '../../utils/MediaType';
|
import { MediaType } from '../../utils/MediaType';
|
||||||
import { APIModel } from '../APIModel';
|
import { APIModel } from '../APIModel';
|
||||||
|
import type { paths } from '../schemas/GiantBomb';
|
||||||
|
|
||||||
export class GiantBombAPI extends APIModel {
|
export class GiantBombAPI extends APIModel {
|
||||||
plugin: MediaDbPlugin;
|
plugin: MediaDbPlugin;
|
||||||
|
|
@ -18,6 +20,7 @@ export class GiantBombAPI extends APIModel {
|
||||||
this.apiUrl = 'https://www.giantbomb.com/api';
|
this.apiUrl = 'https://www.giantbomb.com/api';
|
||||||
this.types = [MediaType.Game];
|
this.types = [MediaType.Game];
|
||||||
}
|
}
|
||||||
|
|
||||||
async searchByTitle(title: string): Promise<MediaTypeModel[]> {
|
async searchByTitle(title: string): Promise<MediaTypeModel[]> {
|
||||||
console.log(`MDB | api "${this.apiName}" queried by Title`);
|
console.log(`MDB | api "${this.apiName}" queried by Title`);
|
||||||
|
|
||||||
|
|
@ -25,35 +28,42 @@ export class GiantBombAPI extends APIModel {
|
||||||
throw Error(`MDB | API key for ${this.apiName} missing.`);
|
throw Error(`MDB | API key for ${this.apiName} missing.`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const searchUrl = `${this.apiUrl}/games?api_key=${this.plugin.settings.GiantBombKey}&filter=name:${encodeURIComponent(title)}&format=json`;
|
const client = createClient<paths>({ baseUrl: 'https://www.giantbomb.com/api/' });
|
||||||
const fetchData = await requestUrl({
|
const response = await client.GET('/games', {
|
||||||
url: searchUrl,
|
params: {
|
||||||
|
query: {
|
||||||
|
api_key: this.plugin.settings.GiantBombKey,
|
||||||
|
filter: `name:${encodeURIComponent(title)}`,
|
||||||
|
format: 'json',
|
||||||
|
limit: 20,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
fetch: obsidianFetch,
|
||||||
});
|
});
|
||||||
|
|
||||||
// console.debug(fetchData);
|
if (response.response.status === 401) {
|
||||||
|
|
||||||
if (fetchData.status === 401) {
|
|
||||||
throw Error(`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 === 429) {
|
if (response.response.status === 429) {
|
||||||
throw Error(`MDB | Too many requests for ${this.apiName}, you've exceeded your API quota.`);
|
throw Error(`MDB | Too many requests for ${this.apiName}, you've exceeded your API quota.`);
|
||||||
}
|
}
|
||||||
if (fetchData.status !== 200) {
|
if (response.response.status !== 200) {
|
||||||
throw Error(`MDB | Received status code ${fetchData.status} from ${this.apiName}.`);
|
throw Error(`MDB | Received status code ${response.response.status} from ${this.apiName}.`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const data = await fetchData.json;
|
const data = response.data?.results;
|
||||||
// console.debug(data);
|
|
||||||
const ret: MediaTypeModel[] = [];
|
const ret: MediaTypeModel[] = [];
|
||||||
for (const result of data.results) {
|
for (const result of data ?? []) {
|
||||||
|
const year = result.original_release_date ? new Date(result.original_release_date).getFullYear().toString() : undefined;
|
||||||
|
|
||||||
ret.push(
|
ret.push(
|
||||||
new GameModel({
|
new GameModel({
|
||||||
type: MediaType.Game,
|
|
||||||
title: result.name,
|
title: result.name,
|
||||||
englishTitle: result.name,
|
englishTitle: result.name,
|
||||||
year: new Date(result.original_release_date).getFullYear().toString(),
|
year: year,
|
||||||
dataSource: this.apiName,
|
dataSource: this.apiName,
|
||||||
id: result.guid,
|
id: result.guid?.toString(),
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -68,36 +78,79 @@ export class GiantBombAPI extends APIModel {
|
||||||
throw Error(`MDB | API key for ${this.apiName} missing.`);
|
throw Error(`MDB | API key for ${this.apiName} missing.`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const searchUrl = `${this.apiUrl}/game/${encodeURIComponent(id)}/?api_key=${this.plugin.settings.GiantBombKey}&format=json`;
|
const client = createClient<paths>({ baseUrl: 'https://www.giantbomb.com/api/' });
|
||||||
const fetchData = await requestUrl({
|
const response = await client.GET('/game/{guid}', {
|
||||||
url: searchUrl,
|
params: {
|
||||||
|
path: {
|
||||||
|
guid: id,
|
||||||
|
},
|
||||||
|
query: {
|
||||||
|
api_key: this.plugin.settings.GiantBombKey,
|
||||||
|
format: 'json',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
fetch: obsidianFetch,
|
||||||
});
|
});
|
||||||
console.debug(fetchData);
|
|
||||||
|
|
||||||
if (fetchData.status !== 200) {
|
if (response.response.status === 401) {
|
||||||
throw Error(`MDB | Received status code ${fetchData.status} from ${this.apiName}.`);
|
throw Error(`MDB | Authentication for ${this.apiName} failed. Check the API key.`);
|
||||||
|
}
|
||||||
|
if (response.response.status === 429) {
|
||||||
|
throw Error(`MDB | Too many requests for ${this.apiName}, you've exceeded your API quota.`);
|
||||||
|
}
|
||||||
|
if (response.response.status !== 200) {
|
||||||
|
throw Error(`MDB | Received status code ${response.response.status} from ${this.apiName}.`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const data = await fetchData.json;
|
const result = response.data?.results;
|
||||||
// console.debug(data);
|
|
||||||
const result = data.results;
|
if (!result) {
|
||||||
|
throw Error(`MDB | No results found for ID ${id} in ${this.apiName}.`);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(result);
|
||||||
|
|
||||||
|
// sadly the only OpenAPI definition I could find doesn't have the right types
|
||||||
|
const year = result.original_release_date ? new Date(result.original_release_date).getFullYear().toString() : undefined;
|
||||||
|
const developers = result.developers as
|
||||||
|
| {
|
||||||
|
name: string;
|
||||||
|
}[]
|
||||||
|
| undefined;
|
||||||
|
const publishers = result.publishers as
|
||||||
|
| {
|
||||||
|
name: string;
|
||||||
|
}[]
|
||||||
|
| undefined;
|
||||||
|
const genres = result.genres as
|
||||||
|
| {
|
||||||
|
name: string;
|
||||||
|
}[]
|
||||||
|
| undefined;
|
||||||
|
const image = result.image as
|
||||||
|
| {
|
||||||
|
small_url: string;
|
||||||
|
medium_url: string;
|
||||||
|
super_url: string;
|
||||||
|
}
|
||||||
|
| undefined;
|
||||||
|
|
||||||
return new GameModel({
|
return new GameModel({
|
||||||
type: MediaType.Game,
|
type: MediaType.Game,
|
||||||
title: result.name,
|
title: result.name,
|
||||||
englishTitle: result.name,
|
englishTitle: result.name,
|
||||||
year: new Date(result.original_release_date).getFullYear().toString(),
|
year: year,
|
||||||
dataSource: this.apiName,
|
dataSource: this.apiName,
|
||||||
url: result.site_detail_url,
|
url: result.site_detail_url,
|
||||||
id: result.guid,
|
id: result.guid?.toString(),
|
||||||
developers: result.developers?.map((x: any) => x.name) ?? [],
|
developers: developers?.map(x => x.name),
|
||||||
publishers: result.publishers?.map((x: any) => x.name) ?? [],
|
publishers: publishers?.map(x => x.name),
|
||||||
genres: result.genres?.map((x: any) => x.name) ?? [],
|
genres: genres?.map(x => x.name),
|
||||||
onlineRating: 0,
|
onlineRating: 0,
|
||||||
image: result.image?.super_url ?? '',
|
image: image?.super_url,
|
||||||
|
|
||||||
released: true,
|
released: true,
|
||||||
releaseDate: result.original_release_date ?? 'unknown',
|
releaseDate: result.original_release_date,
|
||||||
|
|
||||||
userData: {
|
userData: {
|
||||||
played: false,
|
played: false,
|
||||||
|
|
@ -107,6 +160,6 @@ export class GiantBombAPI extends APIModel {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
getDisabledMediaTypes(): MediaType[] {
|
getDisabledMediaTypes(): MediaType[] {
|
||||||
return this.plugin.settings.GiantBombAPI_disabledMediaTypes as MediaType[];
|
return this.plugin.settings.GiantBombAPI_disabledMediaTypes;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,12 @@
|
||||||
|
import createClient from 'openapi-fetch';
|
||||||
|
import { isTruthy, obsidianFetch } from 'src/utils/Utils';
|
||||||
import type MediaDbPlugin from '../../main';
|
import type MediaDbPlugin from '../../main';
|
||||||
import type { MediaTypeModel } from '../../models/MediaTypeModel';
|
import type { MediaTypeModel } from '../../models/MediaTypeModel';
|
||||||
import { MovieModel } from '../../models/MovieModel';
|
import { MovieModel } from '../../models/MovieModel';
|
||||||
import { SeriesModel } from '../../models/SeriesModel';
|
import { SeriesModel } from '../../models/SeriesModel';
|
||||||
import { MediaType } from '../../utils/MediaType';
|
import { MediaType } from '../../utils/MediaType';
|
||||||
import { APIModel } from '../APIModel';
|
import { APIModel } from '../APIModel';
|
||||||
|
import type { paths } from '../schemas/MALAPI';
|
||||||
|
|
||||||
export class MALAPI extends APIModel {
|
export class MALAPI extends APIModel {
|
||||||
plugin: MediaDbPlugin;
|
plugin: MediaDbPlugin;
|
||||||
|
|
@ -28,30 +31,42 @@ export class MALAPI extends APIModel {
|
||||||
async searchByTitle(title: string): Promise<MediaTypeModel[]> {
|
async searchByTitle(title: string): Promise<MediaTypeModel[]> {
|
||||||
console.log(`MDB | api "${this.apiName}" queried by Title`);
|
console.log(`MDB | api "${this.apiName}" queried by Title`);
|
||||||
|
|
||||||
const searchUrl = `https://api.jikan.moe/v4/anime?q=${encodeURIComponent(title)}&limit=20${this.plugin.settings.sfwFilter ? '&sfw' : ''}`;
|
const client = createClient<paths>({ baseUrl: 'https://api.jikan.moe/v4/' });
|
||||||
|
|
||||||
const fetchData = await fetch(searchUrl);
|
const response = await client.GET('/anime', {
|
||||||
// console.debug(fetchData);
|
params: {
|
||||||
if (fetchData.status !== 200) {
|
query: {
|
||||||
throw Error(`MDB | Received status code ${fetchData.status} from ${this.apiName}.`);
|
q: title,
|
||||||
|
limit: 20,
|
||||||
|
sfw: this.plugin.settings.sfwFilter ? true : false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
fetch: obsidianFetch,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (response.error !== undefined) {
|
||||||
|
throw Error(`MDB | Received status code ${response.response.status} from ${this.apiName}.`);
|
||||||
}
|
}
|
||||||
const data = await fetchData.json();
|
|
||||||
|
|
||||||
// console.debug(data);
|
const data = response.data?.data;
|
||||||
|
|
||||||
const ret: MediaTypeModel[] = [];
|
const ret: MediaTypeModel[] = [];
|
||||||
|
|
||||||
for (const result of data.data) {
|
for (const result of data ?? []) {
|
||||||
const type = this.typeMappings.get(result.type?.toLowerCase());
|
const resType = result.type?.toLowerCase();
|
||||||
|
const type = resType ? this.typeMappings.get(resType) : undefined;
|
||||||
|
const year = result.year?.toString() ?? result.aired?.prop?.from?.year?.toString() ?? '';
|
||||||
|
const id = result.mal_id?.toString();
|
||||||
|
|
||||||
if (type === undefined) {
|
if (type === undefined) {
|
||||||
ret.push(
|
ret.push(
|
||||||
new MovieModel({
|
new MovieModel({
|
||||||
subType: '',
|
subType: '',
|
||||||
title: result.title,
|
title: result.title,
|
||||||
englishTitle: result.title_english ?? result.title,
|
englishTitle: result.title_english ?? result.title,
|
||||||
year: result.year ?? result.aired?.prop?.from?.year ?? '',
|
year,
|
||||||
dataSource: this.apiName,
|
dataSource: this.apiName,
|
||||||
id: result.mal_id,
|
id,
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -61,9 +76,9 @@ export class MALAPI extends APIModel {
|
||||||
subType: type,
|
subType: type,
|
||||||
title: result.title,
|
title: result.title,
|
||||||
englishTitle: result.title_english ?? result.title,
|
englishTitle: result.title_english ?? result.title,
|
||||||
year: result.year ?? result.aired?.prop?.from?.year ?? '',
|
year,
|
||||||
dataSource: this.apiName,
|
dataSource: this.apiName,
|
||||||
id: result.mal_id,
|
id,
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
} else if (type === 'series' || type === 'ova') {
|
} else if (type === 'series' || type === 'ova') {
|
||||||
|
|
@ -72,9 +87,9 @@ export class MALAPI extends APIModel {
|
||||||
subType: type,
|
subType: type,
|
||||||
title: result.title,
|
title: result.title,
|
||||||
englishTitle: result.title_english ?? result.title,
|
englishTitle: result.title_english ?? result.title,
|
||||||
year: result.year ?? result.aired?.prop?.from?.year ?? '',
|
year,
|
||||||
dataSource: this.apiName,
|
dataSource: this.apiName,
|
||||||
id: result.mal_id,
|
id,
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -86,41 +101,52 @@ export class MALAPI extends APIModel {
|
||||||
async getById(id: string): Promise<MediaTypeModel> {
|
async getById(id: string): Promise<MediaTypeModel> {
|
||||||
console.log(`MDB | api "${this.apiName}" queried by ID`);
|
console.log(`MDB | api "${this.apiName}" queried by ID`);
|
||||||
|
|
||||||
const searchUrl = `https://api.jikan.moe/v4/anime/${encodeURIComponent(id)}/full`;
|
const client = createClient<paths>({ baseUrl: 'https://api.jikan.moe/v4/' });
|
||||||
const fetchData = await fetch(searchUrl);
|
|
||||||
|
|
||||||
if (fetchData.status !== 200) {
|
const response = await client.GET('/anime/{id}/full', {
|
||||||
throw Error(`MDB | Received status code ${fetchData.status} from ${this.apiName}.`);
|
params: {
|
||||||
|
path: {
|
||||||
|
id: id as unknown as number, // This is fine
|
||||||
|
},
|
||||||
|
},
|
||||||
|
fetch: obsidianFetch,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (response.error !== undefined) {
|
||||||
|
throw Error(`MDB | Received status code ${response.response.status} from ${this.apiName}.`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const data = await fetchData.json();
|
const result = response.data?.data;
|
||||||
// console.debug(data);
|
|
||||||
const result = data.data;
|
if (result === undefined) {
|
||||||
|
throw Error(`MDB | No data found for ID ${id} in ${this.apiName}.`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const resType = result.type?.toLowerCase();
|
||||||
|
const type = resType ? this.typeMappings.get(resType) : undefined;
|
||||||
|
const year = result.year?.toString() ?? result.aired?.prop?.from?.year?.toString();
|
||||||
|
const new_id = result.mal_id?.toString();
|
||||||
|
|
||||||
const type = this.typeMappings.get(result.type?.toLowerCase());
|
|
||||||
if (type === undefined) {
|
if (type === undefined) {
|
||||||
return new MovieModel({
|
return new MovieModel({
|
||||||
subType: '',
|
subType: undefined,
|
||||||
title: result.title,
|
title: result.title,
|
||||||
englishTitle: result.title_english ?? result.title,
|
englishTitle: result.title_english ?? result.title,
|
||||||
year: result.year ?? result.aired?.prop?.from?.year ?? '',
|
year: year,
|
||||||
dataSource: this.apiName,
|
dataSource: this.apiName,
|
||||||
url: result.url,
|
url: result.url,
|
||||||
id: result.mal_id,
|
id: new_id,
|
||||||
|
|
||||||
plot: result.synopsis,
|
plot: result.synopsis,
|
||||||
genres: result.genres?.map((x: any) => x.name) ?? [],
|
genres: result.genres?.map(x => x.name).filter(isTruthy),
|
||||||
director: [],
|
studio: result.studios?.map(x => x.name).filter(isTruthy),
|
||||||
writer: [],
|
duration: result.duration,
|
||||||
studio: result.studios?.map((x: any) => x.name).join(', ') ?? 'unknown',
|
onlineRating: result.score,
|
||||||
duration: result.duration ?? 'unknown',
|
image: result.images?.jpg?.image_url,
|
||||||
onlineRating: result.score ?? 0,
|
|
||||||
actors: [],
|
|
||||||
image: result.images?.jpg?.image_url ?? '',
|
|
||||||
|
|
||||||
released: true,
|
released: true,
|
||||||
premiere: this.plugin.dateFormatter.format(result.aired?.from, this.apiDateFormat) ?? 'unknown',
|
premiere: this.plugin.dateFormatter.format(result.aired?.from, this.apiDateFormat),
|
||||||
streamingServices: result.streaming?.map((x: any) => x.name) ?? [],
|
streamingServices: result.streaming?.map(x => x.name).filter(isTruthy),
|
||||||
|
|
||||||
userData: {
|
userData: {
|
||||||
watched: false,
|
watched: false,
|
||||||
|
|
@ -135,24 +161,21 @@ export class MALAPI extends APIModel {
|
||||||
subType: type,
|
subType: type,
|
||||||
title: result.title,
|
title: result.title,
|
||||||
englishTitle: result.title_english ?? result.title,
|
englishTitle: result.title_english ?? result.title,
|
||||||
year: result.year ?? result.aired?.prop?.from?.year ?? '',
|
year: year,
|
||||||
dataSource: this.apiName,
|
dataSource: this.apiName,
|
||||||
url: result.url,
|
url: result.url,
|
||||||
id: result.mal_id,
|
id: new_id,
|
||||||
|
|
||||||
plot: result.synopsis,
|
plot: result.synopsis,
|
||||||
genres: result.genres?.map((x: any) => x.name) ?? [],
|
genres: result.genres?.map(x => x.name).filter(isTruthy),
|
||||||
director: [],
|
studio: result.studios?.map(x => x.name).filter(isTruthy),
|
||||||
writer: [],
|
duration: result.duration,
|
||||||
studio: result.studios?.map((x: any) => x.name).join(', ') ?? 'unknown',
|
onlineRating: result.score,
|
||||||
duration: result.duration ?? 'unknown',
|
image: result.images?.jpg?.image_url,
|
||||||
onlineRating: result.score ?? 0,
|
|
||||||
actors: [],
|
|
||||||
image: result.images?.jpg?.image_url ?? '',
|
|
||||||
|
|
||||||
released: true,
|
released: true,
|
||||||
premiere: this.plugin.dateFormatter.format(result.aired?.from, this.apiDateFormat) ?? 'unknown',
|
premiere: this.plugin.dateFormatter.format(result.aired?.from, this.apiDateFormat),
|
||||||
streamingServices: result.streaming?.map((x: any) => x.name) ?? [],
|
streamingServices: result.streaming?.map(x => x.name).filter(isTruthy),
|
||||||
|
|
||||||
userData: {
|
userData: {
|
||||||
watched: false,
|
watched: false,
|
||||||
|
|
@ -165,24 +188,23 @@ export class MALAPI extends APIModel {
|
||||||
subType: type,
|
subType: type,
|
||||||
title: result.title,
|
title: result.title,
|
||||||
englishTitle: result.title_english ?? result.title,
|
englishTitle: result.title_english ?? result.title,
|
||||||
year: result.year ?? result.aired?.prop?.from?.year ?? '',
|
year: year,
|
||||||
dataSource: this.apiName,
|
dataSource: this.apiName,
|
||||||
url: result.url,
|
url: result.url,
|
||||||
id: result.mal_id,
|
id: new_id,
|
||||||
|
|
||||||
plot: result.synopsis,
|
plot: result.synopsis,
|
||||||
genres: result.genres?.map((x: any) => x.name) ?? [],
|
genres: result.genres?.map(x => x.name).filter(isTruthy),
|
||||||
writer: [],
|
studio: result.studios?.map(x => x.name).filter(isTruthy),
|
||||||
studio: result.studios?.map((x: any) => x.name) ?? [],
|
|
||||||
episodes: result.episodes,
|
episodes: result.episodes,
|
||||||
duration: result.duration ?? 'unknown',
|
duration: result.duration,
|
||||||
onlineRating: result.score ?? 0,
|
onlineRating: result.score,
|
||||||
streamingServices: result.streaming?.map((x: any) => x.name) ?? [],
|
streamingServices: result.streaming?.map(x => x.name).filter(isTruthy),
|
||||||
image: result.images?.jpg?.image_url ?? '',
|
image: result.images?.jpg?.image_url,
|
||||||
|
|
||||||
released: true,
|
released: true,
|
||||||
airedFrom: this.plugin.dateFormatter.format(result.aired?.from, this.apiDateFormat) ?? 'unknown',
|
airedFrom: this.plugin.dateFormatter.format(result.aired?.from, this.apiDateFormat),
|
||||||
airedTo: this.plugin.dateFormatter.format(result.aired?.to, this.apiDateFormat) ?? 'unknown',
|
airedTo: this.plugin.dateFormatter.format(result.aired?.to, this.apiDateFormat),
|
||||||
airing: result.airing,
|
airing: result.airing,
|
||||||
|
|
||||||
userData: {
|
userData: {
|
||||||
|
|
@ -196,6 +218,6 @@ export class MALAPI extends APIModel {
|
||||||
throw new Error(`MDB | Unknown media type for id ${id}`);
|
throw new Error(`MDB | Unknown media type for id ${id}`);
|
||||||
}
|
}
|
||||||
getDisabledMediaTypes(): MediaType[] {
|
getDisabledMediaTypes(): MediaType[] {
|
||||||
return this.plugin.settings.MALAPI_disabledMediaTypes as MediaType[];
|
return this.plugin.settings.MALAPI_disabledMediaTypes;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,16 @@
|
||||||
|
import createClient from 'openapi-fetch';
|
||||||
|
import { isTruthy, obsidianFetch } from 'src/utils/Utils';
|
||||||
import type MediaDbPlugin from '../../main';
|
import type MediaDbPlugin from '../../main';
|
||||||
import { ComicMangaModel } from '../../models/ComicMangaModel';
|
import { ComicMangaModel } from '../../models/ComicMangaModel';
|
||||||
import type { MediaTypeModel } from '../../models/MediaTypeModel';
|
import type { MediaTypeModel } from '../../models/MediaTypeModel';
|
||||||
import { MediaType } from '../../utils/MediaType';
|
import { MediaType } from '../../utils/MediaType';
|
||||||
import { APIModel } from '../APIModel';
|
import { APIModel } from '../APIModel';
|
||||||
|
import type { paths } from '../schemas/MALAPI';
|
||||||
|
|
||||||
export class MALAPIManga extends APIModel {
|
export class MALAPIManga extends APIModel {
|
||||||
plugin: MediaDbPlugin;
|
plugin: MediaDbPlugin;
|
||||||
typeMappings: Map<string, string>;
|
typeMappings: Map<string, string>;
|
||||||
|
apiDateFormat: string = 'YYYY-MM-DDTHH:mm:ssZ'; // ISO
|
||||||
|
|
||||||
constructor(plugin: MediaDbPlugin) {
|
constructor(plugin: MediaDbPlugin) {
|
||||||
super();
|
super();
|
||||||
|
|
@ -29,43 +33,55 @@ export class MALAPIManga extends APIModel {
|
||||||
async searchByTitle(title: string): Promise<MediaTypeModel[]> {
|
async searchByTitle(title: string): Promise<MediaTypeModel[]> {
|
||||||
console.log(`MDB | api "${this.apiName}" queried by Title`);
|
console.log(`MDB | api "${this.apiName}" queried by Title`);
|
||||||
|
|
||||||
const searchUrl = `https://api.jikan.moe/v4/manga?q=${encodeURIComponent(title)}&limit=20${this.plugin.settings.sfwFilter ? '&sfw' : ''}`;
|
const client = createClient<paths>({ baseUrl: 'https://api.jikan.moe/v4/' });
|
||||||
|
|
||||||
const fetchData = await fetch(searchUrl);
|
const response = await client.GET('/manga', {
|
||||||
// console.debug(fetchData);
|
params: {
|
||||||
if (fetchData.status !== 200) {
|
query: {
|
||||||
throw Error(`MDB | Received status code ${fetchData.status} from ${this.apiName}.`);
|
q: title,
|
||||||
|
limit: 20,
|
||||||
|
sfw: this.plugin.settings.sfwFilter ? true : false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
fetch: obsidianFetch,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (response.error !== undefined) {
|
||||||
|
throw Error(`MDB | Received status code ${response.response.status} from ${this.apiName}.`);
|
||||||
}
|
}
|
||||||
const data = await fetchData.json();
|
|
||||||
|
|
||||||
// console.debug(data);
|
const data = response.data?.data;
|
||||||
|
|
||||||
const ret: MediaTypeModel[] = [];
|
const ret: MediaTypeModel[] = [];
|
||||||
|
|
||||||
for (const result of data.data) {
|
for (const result of data ?? []) {
|
||||||
const type = this.typeMappings.get(result.type?.toLowerCase());
|
const resType = result.type?.toLowerCase();
|
||||||
|
const type = resType ? this.typeMappings.get(resType) : undefined;
|
||||||
|
const year = result.published?.prop?.from?.year?.toString() ?? '';
|
||||||
|
const id = result.mal_id?.toString();
|
||||||
|
|
||||||
ret.push(
|
ret.push(
|
||||||
new ComicMangaModel({
|
new ComicMangaModel({
|
||||||
subType: type,
|
subType: type,
|
||||||
title: result.title,
|
title: result.title,
|
||||||
plot: result.synopsis,
|
plot: result.synopsis ?? undefined,
|
||||||
englishTitle: result.title_english ?? result.title,
|
englishTitle: result.title_english ?? result.title,
|
||||||
alternateTitles: result.titles?.map((x: any) => x.title) ?? [],
|
alternateTitles: result.titles?.map(x => x.title).filter(isTruthy),
|
||||||
year: result.year ?? result.published?.prop?.from?.year ?? '',
|
year: year,
|
||||||
dataSource: this.apiName,
|
dataSource: this.apiName,
|
||||||
url: result.url,
|
url: result.url,
|
||||||
id: result.mal_id,
|
id: id,
|
||||||
|
|
||||||
genres: result.genres?.map((x: any) => x.name) ?? [],
|
genres: result.genres?.map(x => x.name).filter(isTruthy),
|
||||||
authors: result.authors?.map((x: any) => x.name) ?? [],
|
authors: result.authors?.map(x => x.name).filter(isTruthy),
|
||||||
chapters: result.chapters,
|
chapters: result.chapters,
|
||||||
volumes: result.volumes,
|
volumes: result.volumes,
|
||||||
onlineRating: result.score ?? 0,
|
onlineRating: result.score,
|
||||||
image: result.images?.jpg?.image_url ?? '',
|
image: result.images?.jpg?.image_url,
|
||||||
|
|
||||||
released: true,
|
released: true,
|
||||||
publishedFrom: new Date(result.published?.from).toLocaleDateString() ?? 'unknown',
|
publishedFrom: this.plugin.dateFormatter.format(result.published?.from, this.apiDateFormat),
|
||||||
publishedTo: new Date(result.published?.to).toLocaleDateString() ?? 'unknown',
|
publishedTo: this.plugin.dateFormatter.format(result.published?.to, this.apiDateFormat),
|
||||||
status: result.status,
|
status: result.status,
|
||||||
|
|
||||||
userData: {
|
userData: {
|
||||||
|
|
@ -83,40 +99,53 @@ export class MALAPIManga extends APIModel {
|
||||||
async getById(id: string): Promise<MediaTypeModel> {
|
async getById(id: string): Promise<MediaTypeModel> {
|
||||||
console.log(`MDB | api "${this.apiName}" queried by ID`);
|
console.log(`MDB | api "${this.apiName}" queried by ID`);
|
||||||
|
|
||||||
const searchUrl = `https://api.jikan.moe/v4/manga/${encodeURIComponent(id)}/full`;
|
const client = createClient<paths>({ baseUrl: 'https://api.jikan.moe/v4/' });
|
||||||
const fetchData = await fetch(searchUrl);
|
|
||||||
|
|
||||||
if (fetchData.status !== 200) {
|
const response = await client.GET('/manga/{id}/full', {
|
||||||
throw Error(`MDB | Received status code ${fetchData.status} from ${this.apiName}.`);
|
params: {
|
||||||
|
path: {
|
||||||
|
id: id as unknown as number, // This is fine
|
||||||
|
},
|
||||||
|
},
|
||||||
|
fetch: obsidianFetch,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (response.error !== undefined) {
|
||||||
|
throw Error(`MDB | Received status code ${response.response.status} from ${this.apiName}.`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const data = await fetchData.json();
|
const result = response.data?.data;
|
||||||
// console.debug(data);
|
|
||||||
const result = data.data;
|
if (!result) {
|
||||||
|
throw Error(`MDB | No data found for ID ${id} in ${this.apiName}.`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const resType = result.type?.toLowerCase();
|
||||||
|
const type = resType ? this.typeMappings.get(resType) : undefined;
|
||||||
|
const year = result.published?.prop?.from?.year?.toString() ?? '';
|
||||||
|
const new_id = result.mal_id?.toString();
|
||||||
|
|
||||||
const type = this.typeMappings.get(result.type?.toLowerCase());
|
|
||||||
return new ComicMangaModel({
|
return new ComicMangaModel({
|
||||||
subType: type,
|
subType: type,
|
||||||
title: result.title,
|
title: result.title,
|
||||||
|
plot: result.synopsis ?? undefined,
|
||||||
englishTitle: result.title_english ?? result.title,
|
englishTitle: result.title_english ?? result.title,
|
||||||
alternateTitles: result.titles?.map((x: any) => x.title) ?? [],
|
alternateTitles: result.titles?.map(x => x.title).filter(isTruthy),
|
||||||
year: result.year ?? result.published?.prop?.from?.year ?? '',
|
year: year,
|
||||||
dataSource: this.apiName,
|
dataSource: this.apiName,
|
||||||
url: result.url,
|
url: result.url,
|
||||||
id: result.mal_id,
|
id: new_id,
|
||||||
|
|
||||||
plot: (result.synopsis ?? 'unknown').replace(/"/g, "'") ?? 'unknown',
|
genres: result.genres?.map(x => x.name).filter(isTruthy),
|
||||||
genres: result.genres?.map((x: any) => x.name) ?? [],
|
authors: result.authors?.map(x => x.name).filter(isTruthy),
|
||||||
authors: result.authors?.map((x: any) => x.name) ?? [],
|
|
||||||
chapters: result.chapters,
|
chapters: result.chapters,
|
||||||
volumes: result.volumes,
|
volumes: result.volumes,
|
||||||
onlineRating: result.score ?? 0,
|
onlineRating: result.score,
|
||||||
image: result.images?.jpg?.image_url ?? '',
|
image: result.images?.jpg?.image_url,
|
||||||
|
|
||||||
released: true,
|
released: true,
|
||||||
publishers: result.serializations?.map((x: any) => x.name) ?? [],
|
publishedFrom: this.plugin.dateFormatter.format(result.published?.from, this.apiDateFormat),
|
||||||
publishedFrom: new Date(result.published?.from).toLocaleDateString() ?? 'unknown',
|
publishedTo: this.plugin.dateFormatter.format(result.published?.to, this.apiDateFormat),
|
||||||
publishedTo: new Date(result.published?.to).toLocaleDateString() ?? 'unknown',
|
|
||||||
status: result.status,
|
status: result.status,
|
||||||
|
|
||||||
userData: {
|
userData: {
|
||||||
|
|
@ -127,6 +156,6 @@ export class MALAPIManga extends APIModel {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
getDisabledMediaTypes(): MediaType[] {
|
getDisabledMediaTypes(): MediaType[] {
|
||||||
return this.plugin.settings.MALAPIManga_disabledMediaTypes as MediaType[];
|
return this.plugin.settings.MALAPIManga_disabledMediaTypes;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import { Notice } from 'obsidian';
|
/* eslint-disable @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-argument */
|
||||||
|
|
||||||
import { requestUrl } from 'obsidian';
|
import { requestUrl } from 'obsidian';
|
||||||
import type MediaDbPlugin from '../../main';
|
import type MediaDbPlugin from '../../main';
|
||||||
import { GameModel } from '../../models/GameModel';
|
import { GameModel } from '../../models/GameModel';
|
||||||
|
|
@ -6,6 +7,10 @@ import type { MediaTypeModel } from '../../models/MediaTypeModel';
|
||||||
import { MediaType } from '../../utils/MediaType';
|
import { MediaType } from '../../utils/MediaType';
|
||||||
import { APIModel } from '../APIModel';
|
import { APIModel } from '../APIModel';
|
||||||
|
|
||||||
|
// sadly no open api schema available
|
||||||
|
|
||||||
|
// TODO: maybe we should remove this API, as it can no longer be tested without paying for an API key
|
||||||
|
|
||||||
export class MobyGamesAPI extends APIModel {
|
export class MobyGamesAPI extends APIModel {
|
||||||
plugin: MediaDbPlugin;
|
plugin: MediaDbPlugin;
|
||||||
apiDateFormat: string = 'YYYY-DD-MM';
|
apiDateFormat: string = 'YYYY-DD-MM';
|
||||||
|
|
@ -19,6 +24,7 @@ export class MobyGamesAPI extends APIModel {
|
||||||
this.apiUrl = 'https://api.mobygames.com/v1';
|
this.apiUrl = 'https://api.mobygames.com/v1';
|
||||||
this.types = [MediaType.Game];
|
this.types = [MediaType.Game];
|
||||||
}
|
}
|
||||||
|
|
||||||
async searchByTitle(title: string): Promise<MediaTypeModel[]> {
|
async searchByTitle(title: string): Promise<MediaTypeModel[]> {
|
||||||
console.log(`MDB | api "${this.apiName}" queried by Title`);
|
console.log(`MDB | api "${this.apiName}" queried by Title`);
|
||||||
|
|
||||||
|
|
@ -108,6 +114,6 @@ export class MobyGamesAPI extends APIModel {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
getDisabledMediaTypes(): MediaType[] {
|
getDisabledMediaTypes(): MediaType[] {
|
||||||
return this.plugin.settings.MobyGamesAPI_disabledMediaTypes as MediaType[];
|
return this.plugin.settings.MobyGamesAPI_disabledMediaTypes;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,73 @@ import { MediaType } from '../../utils/MediaType';
|
||||||
import { contactEmail, mediaDbVersion, pluginName } from '../../utils/Utils';
|
import { contactEmail, mediaDbVersion, pluginName } from '../../utils/Utils';
|
||||||
import { APIModel } from '../APIModel';
|
import { APIModel } from '../APIModel';
|
||||||
|
|
||||||
|
// sadly no open api schema available
|
||||||
|
|
||||||
|
interface Tag {
|
||||||
|
name: string;
|
||||||
|
count: number;
|
||||||
|
}
|
||||||
|
interface Genre {
|
||||||
|
name: string;
|
||||||
|
count: number;
|
||||||
|
id: string;
|
||||||
|
disambiguation: string;
|
||||||
|
}
|
||||||
|
interface Release {
|
||||||
|
id: string;
|
||||||
|
'status-id': string;
|
||||||
|
title: string;
|
||||||
|
status: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface SearchResponse {
|
||||||
|
id: string;
|
||||||
|
'type-id': string;
|
||||||
|
score: number;
|
||||||
|
'primary-type-id': string;
|
||||||
|
'artists-credit-id': string;
|
||||||
|
count: number;
|
||||||
|
title: string;
|
||||||
|
'first-release-date': string;
|
||||||
|
'primary-type': string;
|
||||||
|
'artist-credit': {
|
||||||
|
name: string;
|
||||||
|
artist: {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
'short-name': string;
|
||||||
|
};
|
||||||
|
}[];
|
||||||
|
releases: Release[];
|
||||||
|
tags: Tag[];
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IdResponse {
|
||||||
|
id: string;
|
||||||
|
tags: Tag[];
|
||||||
|
'primary-type-id': string;
|
||||||
|
'artist-credit': {
|
||||||
|
name: string;
|
||||||
|
artist: {
|
||||||
|
tags: Tag[];
|
||||||
|
type: string;
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
'short-name': string;
|
||||||
|
country: string;
|
||||||
|
};
|
||||||
|
}[];
|
||||||
|
title: string;
|
||||||
|
genres: Genre[];
|
||||||
|
'first-release-date': string;
|
||||||
|
releases: Release[];
|
||||||
|
'primary-type': string;
|
||||||
|
rating: {
|
||||||
|
value: number;
|
||||||
|
'votes-count': number;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
export class MusicBrainzAPI extends APIModel {
|
export class MusicBrainzAPI extends APIModel {
|
||||||
plugin: MediaDbPlugin;
|
plugin: MediaDbPlugin;
|
||||||
|
|
||||||
|
|
@ -37,7 +104,9 @@ export class MusicBrainzAPI extends APIModel {
|
||||||
throw Error(`MDB | Received status code ${fetchData.status} from ${this.apiName}.`);
|
throw Error(`MDB | Received status code ${fetchData.status} from ${this.apiName}.`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const data = await fetchData.json;
|
const data = (await fetchData.json) as {
|
||||||
|
'release-groups': SearchResponse[];
|
||||||
|
};
|
||||||
// console.debug(data);
|
// console.debug(data);
|
||||||
const ret: MediaTypeModel[] = [];
|
const ret: MediaTypeModel[] = [];
|
||||||
|
|
||||||
|
|
@ -53,7 +122,7 @@ export class MusicBrainzAPI extends APIModel {
|
||||||
id: result.id,
|
id: result.id,
|
||||||
image: 'https://coverartarchive.org/release-group/' + result.id + '/front',
|
image: 'https://coverartarchive.org/release-group/' + result.id + '/front',
|
||||||
|
|
||||||
artists: result['artist-credit'].map((a: any) => a.name),
|
artists: result['artist-credit'].map(a => a.name),
|
||||||
subType: result['primary-type'],
|
subType: result['primary-type'],
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
@ -77,7 +146,7 @@ export class MusicBrainzAPI extends APIModel {
|
||||||
throw Error(`MDB | Received status code ${fetchData.status} from ${this.apiName}.`);
|
throw Error(`MDB | Received status code ${fetchData.status} from ${this.apiName}.`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const result = await fetchData.json;
|
const result = (await fetchData.json) as IdResponse;
|
||||||
|
|
||||||
return new MusicReleaseModel({
|
return new MusicReleaseModel({
|
||||||
type: 'musicRelease',
|
type: 'musicRelease',
|
||||||
|
|
@ -89,8 +158,8 @@ export class MusicBrainzAPI extends APIModel {
|
||||||
id: result.id,
|
id: result.id,
|
||||||
image: 'https://coverartarchive.org/release-group/' + result.id + '/front',
|
image: 'https://coverartarchive.org/release-group/' + result.id + '/front',
|
||||||
|
|
||||||
artists: result['artist-credit'].map((a: any) => a.name),
|
artists: result['artist-credit'].map(a => a.name),
|
||||||
genres: result.genres.map((g: any) => g.name),
|
genres: result.genres.map(g => g.name),
|
||||||
subType: result['primary-type'],
|
subType: result['primary-type'],
|
||||||
rating: result.rating.value * 2,
|
rating: result.rating.value * 2,
|
||||||
|
|
||||||
|
|
@ -100,6 +169,6 @@ export class MusicBrainzAPI extends APIModel {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
getDisabledMediaTypes(): MediaType[] {
|
getDisabledMediaTypes(): MediaType[] {
|
||||||
return this.plugin.settings.MusicBrainzAPI_disabledMediaTypes as MediaType[];
|
return this.plugin.settings.MusicBrainzAPI_disabledMediaTypes;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import { Notice } from 'obsidian';
|
import createClient from 'openapi-fetch';
|
||||||
|
import { obsidianFetch } from 'src/utils/Utils';
|
||||||
import type MediaDbPlugin from '../../main';
|
import type MediaDbPlugin from '../../main';
|
||||||
import { GameModel } from '../../models/GameModel';
|
import { GameModel } from '../../models/GameModel';
|
||||||
import type { MediaTypeModel } from '../../models/MediaTypeModel';
|
import type { MediaTypeModel } from '../../models/MediaTypeModel';
|
||||||
|
|
@ -6,6 +7,56 @@ import { MovieModel } from '../../models/MovieModel';
|
||||||
import { SeriesModel } from '../../models/SeriesModel';
|
import { SeriesModel } from '../../models/SeriesModel';
|
||||||
import { MediaType } from '../../utils/MediaType';
|
import { MediaType } from '../../utils/MediaType';
|
||||||
import { APIModel } from '../APIModel';
|
import { APIModel } from '../APIModel';
|
||||||
|
import type { paths } from '../schemas/OMDb';
|
||||||
|
|
||||||
|
type SearchResponse =
|
||||||
|
| {
|
||||||
|
Response: 'True';
|
||||||
|
totalResults: string;
|
||||||
|
Search: {
|
||||||
|
Title: string;
|
||||||
|
Year: string;
|
||||||
|
Poster: string;
|
||||||
|
imdbID: string;
|
||||||
|
Type: string;
|
||||||
|
}[];
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
Response: 'False';
|
||||||
|
Error: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
type IdResponse =
|
||||||
|
| {
|
||||||
|
Response: 'True';
|
||||||
|
Title: string;
|
||||||
|
Year: string;
|
||||||
|
Rated: string;
|
||||||
|
Released: string;
|
||||||
|
Runtime: string;
|
||||||
|
Genre: string;
|
||||||
|
Director: string;
|
||||||
|
Writer: string;
|
||||||
|
Actors: string;
|
||||||
|
Plot: string;
|
||||||
|
Language: string;
|
||||||
|
Country: string;
|
||||||
|
Awards: string;
|
||||||
|
Poster: string;
|
||||||
|
Metascore: string;
|
||||||
|
imdbRating: string;
|
||||||
|
imdbVotes: string;
|
||||||
|
imdbID: string;
|
||||||
|
Type: string;
|
||||||
|
DVD: string;
|
||||||
|
BoxOffice: string;
|
||||||
|
Production: string;
|
||||||
|
Website: string;
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
Response: 'False';
|
||||||
|
Error: string;
|
||||||
|
};
|
||||||
|
|
||||||
export class OMDbAPI extends APIModel {
|
export class OMDbAPI extends APIModel {
|
||||||
plugin: MediaDbPlugin;
|
plugin: MediaDbPlugin;
|
||||||
|
|
@ -33,24 +84,37 @@ export class OMDbAPI extends APIModel {
|
||||||
throw new Error(`MDB | API key for ${this.apiName} missing.`);
|
throw new Error(`MDB | API key for ${this.apiName} missing.`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const searchUrl = `https://www.omdbapi.com/?s=${encodeURIComponent(title)}&apikey=${this.plugin.settings.OMDbKey}`;
|
const client = createClient<paths>({ baseUrl: 'https://www.omdbapi.com/' });
|
||||||
const fetchData = await fetch(searchUrl);
|
|
||||||
|
|
||||||
if (fetchData.status === 401) {
|
const response = await client.GET('/?s', {
|
||||||
|
params: {
|
||||||
|
query: {
|
||||||
|
s: title,
|
||||||
|
apikey: this.plugin.settings.OMDbKey,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
fetch: obsidianFetch,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (response.response.status === 401) {
|
||||||
throw Error(`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) {
|
if (response.response.status !== 200) {
|
||||||
throw Error(`MDB | Received status code ${fetchData.status} from ${this.apiName}.`);
|
throw Error(`MDB | Received status code ${response.response.status} from ${this.apiName}.`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const data = await fetchData.json();
|
const data = response.data as SearchResponse | undefined;
|
||||||
|
|
||||||
|
if (!data) {
|
||||||
|
throw Error(`MDB | No data received from ${this.apiName}.`);
|
||||||
|
}
|
||||||
|
|
||||||
if (data.Response === 'False') {
|
if (data.Response === 'False') {
|
||||||
if (data.Error === 'Movie not found!') {
|
if (data.Error === 'Movie not found!') {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
throw Error(`MDB | Received error from ${this.apiName}: \n${JSON.stringify(data, undefined, 4)}`);
|
throw Error(`MDB | Received error from ${this.apiName}: ${data.Error}`);
|
||||||
}
|
}
|
||||||
if (!data.Search) {
|
if (!data.Search) {
|
||||||
return [];
|
return [];
|
||||||
|
|
@ -111,18 +175,30 @@ export class OMDbAPI extends APIModel {
|
||||||
throw Error(`MDB | API key for ${this.apiName} missing.`);
|
throw Error(`MDB | API key for ${this.apiName} missing.`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const searchUrl = `https://www.omdbapi.com/?i=${encodeURIComponent(id)}&apikey=${this.plugin.settings.OMDbKey}`;
|
const client = createClient<paths>({ baseUrl: 'https://www.omdbapi.com/' });
|
||||||
const fetchData = await fetch(searchUrl);
|
|
||||||
|
|
||||||
if (fetchData.status === 401) {
|
const response = await client.GET('/?i', {
|
||||||
|
params: {
|
||||||
|
query: {
|
||||||
|
i: id,
|
||||||
|
apikey: this.plugin.settings.OMDbKey,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
fetch: obsidianFetch,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (response.response.status === 401) {
|
||||||
throw Error(`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) {
|
if (response.response.status !== 200) {
|
||||||
throw Error(`MDB | Received status code ${fetchData.status} from ${this.apiName}.`);
|
throw Error(`MDB | Received status code ${response.response.status} from ${this.apiName}.`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const result = await fetchData.json();
|
const result = response.data as IdResponse | undefined;
|
||||||
// console.debug(result);
|
|
||||||
|
if (!result) {
|
||||||
|
throw Error(`MDB | No data received from ${this.apiName}.`);
|
||||||
|
}
|
||||||
|
|
||||||
if (result.Response === 'False') {
|
if (result.Response === 'False') {
|
||||||
throw Error(`MDB | Received error from ${this.apiName}: ${result.Error}`);
|
throw Error(`MDB | Received error from ${this.apiName}: ${result.Error}`);
|
||||||
|
|
@ -130,7 +206,7 @@ export class OMDbAPI extends APIModel {
|
||||||
|
|
||||||
const type = this.typeMappings.get(result.Type.toLowerCase());
|
const type = this.typeMappings.get(result.Type.toLowerCase());
|
||||||
if (type === undefined) {
|
if (type === undefined) {
|
||||||
throw Error(`${result.type.toLowerCase()} is an unsupported type.`);
|
throw Error(`${result.Type.toLowerCase()} is an unsupported type.`);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type === 'movie') {
|
if (type === 'movie') {
|
||||||
|
|
@ -143,19 +219,17 @@ export class OMDbAPI extends APIModel {
|
||||||
url: `https://www.imdb.com/title/${result.imdbID}/`,
|
url: `https://www.imdb.com/title/${result.imdbID}/`,
|
||||||
id: result.imdbID,
|
id: result.imdbID,
|
||||||
|
|
||||||
plot: result.Plot ?? '',
|
plot: result.Plot,
|
||||||
genres: result.Genre?.split(', ') ?? [],
|
genres: result.Genre?.split(', '),
|
||||||
director: result.Director?.split(', ') ?? [],
|
director: result.Director?.split(', '),
|
||||||
writer: result.Writer?.split(', ') ?? [],
|
writer: result.Writer?.split(', '),
|
||||||
studio: ['N/A'],
|
duration: result.Runtime,
|
||||||
duration: result.Runtime ?? 'unknown',
|
|
||||||
onlineRating: Number.parseFloat(result.imdbRating ?? 0),
|
onlineRating: Number.parseFloat(result.imdbRating ?? 0),
|
||||||
actors: result.Actors?.split(', ') ?? [],
|
actors: result.Actors?.split(', '),
|
||||||
image: result.Poster ? result.Poster.replace('_SX300', '_SX600') : '',
|
image: result.Poster.replace('_SX300', '_SX600'),
|
||||||
|
|
||||||
released: true,
|
released: true,
|
||||||
streamingServices: [],
|
premiere: this.plugin.dateFormatter.format(result.Released, this.apiDateFormat),
|
||||||
premiere: this.plugin.dateFormatter.format(result.Released, this.apiDateFormat) ?? 'unknown',
|
|
||||||
|
|
||||||
userData: {
|
userData: {
|
||||||
watched: false,
|
watched: false,
|
||||||
|
|
@ -173,21 +247,18 @@ export class OMDbAPI extends APIModel {
|
||||||
url: `https://www.imdb.com/title/${result.imdbID}/`,
|
url: `https://www.imdb.com/title/${result.imdbID}/`,
|
||||||
id: result.imdbID,
|
id: result.imdbID,
|
||||||
|
|
||||||
plot: result.Plot ?? '',
|
plot: result.Plot,
|
||||||
genres: result.Genre?.split(', ') ?? [],
|
genres: result.Genre?.split(', '),
|
||||||
writer: result.Writer?.split(', ') ?? [],
|
writer: result.Writer?.split(', '),
|
||||||
studio: [],
|
studio: [],
|
||||||
episodes: 0,
|
episodes: 0,
|
||||||
duration: result.Runtime ?? 'unknown',
|
duration: result.Runtime,
|
||||||
onlineRating: Number.parseFloat(result.imdbRating ?? 0),
|
onlineRating: Number.parseFloat(result.imdbRating ?? 0),
|
||||||
actors: result.Actors?.split(', ') ?? [],
|
actors: result.Actors?.split(', '),
|
||||||
image: result.Poster ? result.Poster.replace('_SX300', '_SX600') : '',
|
image: result.Poster.replace('_SX300', '_SX600'),
|
||||||
|
|
||||||
released: true,
|
released: true,
|
||||||
streamingServices: [],
|
airedFrom: this.plugin.dateFormatter.format(result.Released, this.apiDateFormat),
|
||||||
airing: false,
|
|
||||||
airedFrom: this.plugin.dateFormatter.format(result.Released, this.apiDateFormat) ?? 'unknown',
|
|
||||||
airedTo: 'unknown',
|
|
||||||
|
|
||||||
userData: {
|
userData: {
|
||||||
watched: false,
|
watched: false,
|
||||||
|
|
@ -205,14 +276,12 @@ export class OMDbAPI extends APIModel {
|
||||||
url: `https://www.imdb.com/title/${result.imdbID}/`,
|
url: `https://www.imdb.com/title/${result.imdbID}/`,
|
||||||
id: result.imdbID,
|
id: result.imdbID,
|
||||||
|
|
||||||
developers: [],
|
genres: result.Genre?.split(', '),
|
||||||
publishers: [],
|
|
||||||
genres: result.Genre?.split(', ') ?? [],
|
|
||||||
onlineRating: Number.parseFloat(result.imdbRating ?? 0),
|
onlineRating: Number.parseFloat(result.imdbRating ?? 0),
|
||||||
image: result.Poster ? result.Poster.replace('_SX300', '_SX600') : '',
|
image: result.Poster.replace('_SX300', '_SX600'),
|
||||||
|
|
||||||
released: true,
|
released: true,
|
||||||
releaseDate: this.plugin.dateFormatter.format(result.Released, this.apiDateFormat) ?? 'unknown',
|
releaseDate: this.plugin.dateFormatter.format(result.Released, this.apiDateFormat),
|
||||||
|
|
||||||
userData: {
|
userData: {
|
||||||
played: false,
|
played: false,
|
||||||
|
|
@ -225,6 +294,6 @@ export class OMDbAPI extends APIModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
getDisabledMediaTypes(): MediaType[] {
|
getDisabledMediaTypes(): MediaType[] {
|
||||||
return this.plugin.settings.OMDbAPI_disabledMediaTypes as MediaType[];
|
return this.plugin.settings.OMDbAPI_disabledMediaTypes;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,26 @@
|
||||||
|
import createClient from 'openapi-fetch';
|
||||||
import { BookModel } from 'src/models/BookModel';
|
import { BookModel } from 'src/models/BookModel';
|
||||||
|
import { obsidianFetch } from 'src/utils/Utils';
|
||||||
import type MediaDbPlugin from '../../main';
|
import type MediaDbPlugin from '../../main';
|
||||||
import type { MediaTypeModel } from '../../models/MediaTypeModel';
|
import type { MediaTypeModel } from '../../models/MediaTypeModel';
|
||||||
import { MediaType } from '../../utils/MediaType';
|
import { MediaType } from '../../utils/MediaType';
|
||||||
import { APIModel } from '../APIModel';
|
import { APIModel } from '../APIModel';
|
||||||
|
import type { paths } from '../schemas/OpenLibrary';
|
||||||
|
|
||||||
|
interface SearchResponse {
|
||||||
|
cover_i: number;
|
||||||
|
has_fulltext: boolean;
|
||||||
|
edition_count: number;
|
||||||
|
title: string;
|
||||||
|
author_name: string[];
|
||||||
|
first_publish_year: number;
|
||||||
|
key: string;
|
||||||
|
|
||||||
|
number_of_pages_median?: number;
|
||||||
|
cover_edition_key?: string;
|
||||||
|
isbn?: string[];
|
||||||
|
ratings_average?: number;
|
||||||
|
}
|
||||||
|
|
||||||
export class OpenLibraryAPI extends APIModel {
|
export class OpenLibraryAPI extends APIModel {
|
||||||
plugin: MediaDbPlugin;
|
plugin: MediaDbPlugin;
|
||||||
|
|
@ -20,14 +38,24 @@ export class OpenLibraryAPI extends APIModel {
|
||||||
async searchByTitle(title: string): Promise<MediaTypeModel[]> {
|
async searchByTitle(title: string): Promise<MediaTypeModel[]> {
|
||||||
console.log(`MDB | api "${this.apiName}" queried by Title`);
|
console.log(`MDB | api "${this.apiName}" queried by Title`);
|
||||||
|
|
||||||
const searchUrl = `https://openlibrary.org/search.json?title=${encodeURIComponent(title)}`;
|
const client = createClient<paths>({ baseUrl: 'https://openlibrary.org/' });
|
||||||
|
|
||||||
const fetchData = await fetch(searchUrl);
|
const response = await client.GET('/search.json', {
|
||||||
// console.debug(fetchData);
|
params: {
|
||||||
if (fetchData.status !== 200) {
|
query: {
|
||||||
throw Error(`MDB | Received status code ${fetchData.status} from ${this.apiName}.`);
|
q: title,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
fetch: obsidianFetch,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (response.error !== undefined) {
|
||||||
|
throw Error(`MDB | Received status code ${response.response.status} from ${this.apiName}.`);
|
||||||
}
|
}
|
||||||
const data = await fetchData.json();
|
|
||||||
|
const data = response.data as {
|
||||||
|
docs: SearchResponse[];
|
||||||
|
};
|
||||||
|
|
||||||
// console.debug(data);
|
// console.debug(data);
|
||||||
|
|
||||||
|
|
@ -37,11 +65,11 @@ export class OpenLibraryAPI extends APIModel {
|
||||||
ret.push(
|
ret.push(
|
||||||
new BookModel({
|
new BookModel({
|
||||||
title: result.title,
|
title: result.title,
|
||||||
englishTitle: result.title_english ?? result.title,
|
englishTitle: result.title,
|
||||||
year: result.first_publish_year,
|
year: result.first_publish_year.toString(),
|
||||||
dataSource: this.apiName,
|
dataSource: this.apiName,
|
||||||
id: result.key,
|
id: result.key,
|
||||||
author: result.author_name ?? 'unknown',
|
author: result.author_name.join(', '),
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -52,33 +80,47 @@ export class OpenLibraryAPI extends APIModel {
|
||||||
async getById(id: string): Promise<MediaTypeModel> {
|
async getById(id: string): Promise<MediaTypeModel> {
|
||||||
console.log(`MDB | api "${this.apiName}" queried by ID`);
|
console.log(`MDB | api "${this.apiName}" queried by ID`);
|
||||||
|
|
||||||
const searchUrl = `https://openlibrary.org/search.json?q=key:${encodeURIComponent(id)}`;
|
const client = createClient<paths>({ baseUrl: 'https://openlibrary.org/' });
|
||||||
const fetchData = await fetch(searchUrl);
|
|
||||||
// console.debug(fetchData);
|
|
||||||
|
|
||||||
if (fetchData.status !== 200) {
|
const response = await client.GET('/search.json', {
|
||||||
throw Error(`MDB | Received status code ${fetchData.status} from ${this.apiName}.`);
|
params: {
|
||||||
|
query: {
|
||||||
|
q: `key:${id}`,
|
||||||
|
fields: 'key,title,author_name,number_of_pages_median,first_publish_year,isbn,ratings_score,first_sentence,title_suggest,rating*,cover_edition_key',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
fetch: obsidianFetch,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (response.error !== undefined) {
|
||||||
|
throw Error(`MDB | Received status code ${response.response.status} from ${this.apiName}.`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const data = await fetchData.json();
|
const data = response.data as {
|
||||||
|
docs: SearchResponse[];
|
||||||
|
};
|
||||||
|
|
||||||
// console.debug(data);
|
// console.debug(data);
|
||||||
const result = data.docs[0];
|
const result = data.docs[0];
|
||||||
|
|
||||||
|
const pages = Number(result.number_of_pages_median);
|
||||||
|
const isbn = Number((result.isbn ?? []).find((el: string) => el.length <= 10));
|
||||||
|
const isbn13 = Number((result.isbn ?? []).find((el: string) => el.length == 13));
|
||||||
|
|
||||||
return new BookModel({
|
return new BookModel({
|
||||||
title: result.title,
|
title: result.title,
|
||||||
year: result.first_publish_year,
|
year: result.first_publish_year.toString(),
|
||||||
dataSource: this.apiName,
|
dataSource: this.apiName,
|
||||||
url: `https://openlibrary.org` + result.key,
|
url: `https://openlibrary.org` + result.key,
|
||||||
id: result.key,
|
id: result.key,
|
||||||
isbn: (result.isbn ?? []).find((el: string | any[]) => el.length <= 10) ?? 'unknown',
|
isbn: Number.isNaN(isbn) ? undefined : isbn,
|
||||||
isbn13: (result.isbn ?? []).find((el: string | any[]) => el.length == 13) ?? 'unknown',
|
isbn13: Number.isNaN(isbn13) ? undefined : isbn13,
|
||||||
englishTitle: result.title_english ?? result.title,
|
englishTitle: result.title,
|
||||||
|
|
||||||
author: result.author_name ?? 'unknown',
|
author: result.author_name.join(', '),
|
||||||
plot: result.description ?? 'unknown',
|
pages: Number.isNaN(pages) ? undefined : pages,
|
||||||
pages: result.number_of_pages_median ?? 'unknown',
|
onlineRating: result.ratings_average,
|
||||||
onlineRating: Number.parseFloat(Number(result.ratings_average ?? 0).toFixed(2)),
|
image: result.cover_edition_key ? `https://covers.openlibrary.org/b/OLID/` + result.cover_edition_key + `-L.jpg` : undefined,
|
||||||
image: `https://covers.openlibrary.org/b/OLID/` + result.cover_edition_key + `-L.jpg`,
|
|
||||||
|
|
||||||
released: true,
|
released: true,
|
||||||
|
|
||||||
|
|
@ -90,6 +132,6 @@ export class OpenLibraryAPI extends APIModel {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
getDisabledMediaTypes(): MediaType[] {
|
getDisabledMediaTypes(): MediaType[] {
|
||||||
return this.plugin.settings.OpenLibraryAPI_disabledMediaTypes as MediaType[];
|
return this.plugin.settings.OpenLibraryAPI_disabledMediaTypes;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,128 @@ import type MediaDbPlugin from '../../main';
|
||||||
import { GameModel } from '../../models/GameModel';
|
import { GameModel } from '../../models/GameModel';
|
||||||
import type { MediaTypeModel } from '../../models/MediaTypeModel';
|
import type { MediaTypeModel } from '../../models/MediaTypeModel';
|
||||||
import { MediaType } from '../../utils/MediaType';
|
import { MediaType } from '../../utils/MediaType';
|
||||||
import { APIModel } from '../APIModel';
|
|
||||||
import { imageUrlExists } from '../../utils/Utils';
|
import { imageUrlExists } from '../../utils/Utils';
|
||||||
|
import { APIModel } from '../APIModel';
|
||||||
|
|
||||||
|
interface SearchResponse {
|
||||||
|
appid: string;
|
||||||
|
name: string;
|
||||||
|
icon: string;
|
||||||
|
logo: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
type IdResponse = Record<
|
||||||
|
string,
|
||||||
|
{
|
||||||
|
success: boolean;
|
||||||
|
data: GameDetails;
|
||||||
|
}
|
||||||
|
>;
|
||||||
|
|
||||||
|
interface GameDetails {
|
||||||
|
type: string;
|
||||||
|
name: string;
|
||||||
|
steam_appid: number;
|
||||||
|
required_age: string;
|
||||||
|
is_free: boolean;
|
||||||
|
controller_support: string;
|
||||||
|
dlc: number[];
|
||||||
|
detailed_description: string;
|
||||||
|
about_the_game: string;
|
||||||
|
short_description: string;
|
||||||
|
supported_languages: string;
|
||||||
|
reviews: string;
|
||||||
|
header_image: string;
|
||||||
|
capsule_image: string;
|
||||||
|
capsule_imagev5: string;
|
||||||
|
website: string;
|
||||||
|
pc_requirements: Requirements;
|
||||||
|
mac_requirements: Requirements;
|
||||||
|
linux_requirements: Requirements;
|
||||||
|
legal_notice: string;
|
||||||
|
drm_notice: string;
|
||||||
|
developers: string[];
|
||||||
|
publishers: string[];
|
||||||
|
price_overview: PriceOverview;
|
||||||
|
packages: number[];
|
||||||
|
platforms: Platforms;
|
||||||
|
metacritic?: {
|
||||||
|
score: number;
|
||||||
|
url: string;
|
||||||
|
};
|
||||||
|
categories: Category[];
|
||||||
|
genres: Genre[];
|
||||||
|
recommendations: {
|
||||||
|
total: number;
|
||||||
|
};
|
||||||
|
achievements: {
|
||||||
|
total: number;
|
||||||
|
highlighted: Achievement[];
|
||||||
|
};
|
||||||
|
release_date: {
|
||||||
|
coming_soon: boolean;
|
||||||
|
date: string;
|
||||||
|
};
|
||||||
|
support_info: {
|
||||||
|
url: string;
|
||||||
|
email: string;
|
||||||
|
};
|
||||||
|
background: string;
|
||||||
|
background_raw: string;
|
||||||
|
content_descriptors: {
|
||||||
|
ids: number[];
|
||||||
|
notes: string;
|
||||||
|
};
|
||||||
|
ratings: Ratings;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Requirements {
|
||||||
|
minimum: string;
|
||||||
|
recommended: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface PriceOverview {
|
||||||
|
currency: string;
|
||||||
|
initial: number;
|
||||||
|
final: number;
|
||||||
|
discount_percent: number;
|
||||||
|
initial_formatted: string;
|
||||||
|
final_formatted: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Platforms {
|
||||||
|
windows: boolean;
|
||||||
|
mac: boolean;
|
||||||
|
linux: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Category {
|
||||||
|
id: number;
|
||||||
|
description: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Genre {
|
||||||
|
id: string;
|
||||||
|
description: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface Achievement {
|
||||||
|
name: string;
|
||||||
|
path: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
type Ratings = Record<
|
||||||
|
string,
|
||||||
|
{
|
||||||
|
rating: string;
|
||||||
|
descriptors: string;
|
||||||
|
use_age_gate: string;
|
||||||
|
required_age: string;
|
||||||
|
rating_id?: string;
|
||||||
|
banned?: string;
|
||||||
|
rating_generated?: string;
|
||||||
|
}
|
||||||
|
>;
|
||||||
|
|
||||||
export class SteamAPI extends APIModel {
|
export class SteamAPI extends APIModel {
|
||||||
plugin: MediaDbPlugin;
|
plugin: MediaDbPlugin;
|
||||||
|
|
@ -35,7 +155,7 @@ export class SteamAPI extends APIModel {
|
||||||
throw Error(`MDB | Received status code ${fetchData.status} from ${this.apiName}.`);
|
throw Error(`MDB | Received status code ${fetchData.status} from ${this.apiName}.`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const data = await fetchData.json;
|
const data = (await fetchData.json) as SearchResponse[];
|
||||||
|
|
||||||
// console.debug(data);
|
// console.debug(data);
|
||||||
|
|
||||||
|
|
@ -70,14 +190,13 @@ export class SteamAPI extends APIModel {
|
||||||
}
|
}
|
||||||
|
|
||||||
// console.debug(await fetchData.json);
|
// console.debug(await fetchData.json);
|
||||||
|
const data = (await fetchData.json) as IdResponse;
|
||||||
|
|
||||||
let result: any;
|
let result: GameDetails | undefined = undefined;
|
||||||
for (const [key, value] of Object.entries(await fetchData.json)) {
|
for (const [key, value] of Object.entries(data)) {
|
||||||
// console.log(typeof key, key)
|
|
||||||
// console.log(typeof id, id)
|
|
||||||
// after some testing I found out that id is somehow a number despite that it's defined as string...
|
// after some testing I found out that id is somehow a number despite that it's defined as string...
|
||||||
if (key === String(id)) {
|
if (key === String(id)) {
|
||||||
result = (value as any).data;
|
result = value.data;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!result) {
|
if (!result) {
|
||||||
|
|
@ -103,16 +222,16 @@ export class SteamAPI extends APIModel {
|
||||||
year: new Date(result.release_date.date).getFullYear().toString(),
|
year: new Date(result.release_date.date).getFullYear().toString(),
|
||||||
dataSource: this.apiName,
|
dataSource: this.apiName,
|
||||||
url: `https://store.steampowered.com/app/${result.steam_appid}`,
|
url: `https://store.steampowered.com/app/${result.steam_appid}`,
|
||||||
id: result.steam_appid,
|
id: result.steam_appid.toString(),
|
||||||
|
|
||||||
developers: result.developers,
|
developers: result.developers,
|
||||||
publishers: result.publishers,
|
publishers: result.publishers,
|
||||||
genres: result.genres?.map((x: any) => x.description) ?? [],
|
genres: result.genres?.map(x => x.description),
|
||||||
onlineRating: Number.parseFloat(result.metacritic?.score ?? 0),
|
onlineRating: result.metacritic?.score,
|
||||||
image: finalimageurl ?? '',
|
image: finalimageurl,
|
||||||
|
|
||||||
released: !result.release_date?.coming_soon,
|
released: !result.release_date?.coming_soon,
|
||||||
releaseDate: this.plugin.dateFormatter.format(result.release_date?.date, this.apiDateFormat) ?? 'unknown',
|
releaseDate: this.plugin.dateFormatter.format(result.release_date?.date, this.apiDateFormat),
|
||||||
|
|
||||||
userData: {
|
userData: {
|
||||||
played: false,
|
played: false,
|
||||||
|
|
@ -121,6 +240,6 @@ export class SteamAPI extends APIModel {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
getDisabledMediaTypes(): MediaType[] {
|
getDisabledMediaTypes(): MediaType[] {
|
||||||
return this.plugin.settings.SteamAPI_disabledMediaTypes as MediaType[];
|
return this.plugin.settings.SteamAPI_disabledMediaTypes;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,35 @@ import { WikiModel } from '../../models/WikiModel';
|
||||||
import { MediaType } from '../../utils/MediaType';
|
import { MediaType } from '../../utils/MediaType';
|
||||||
import { APIModel } from '../APIModel';
|
import { APIModel } from '../APIModel';
|
||||||
|
|
||||||
|
interface SearchResponse {
|
||||||
|
query: {
|
||||||
|
search: {
|
||||||
|
title: string;
|
||||||
|
pageid: number;
|
||||||
|
}[];
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IdResponse {
|
||||||
|
query: {
|
||||||
|
pages: Record<string, WikipediaPage>;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
interface WikipediaPage {
|
||||||
|
pageid: number;
|
||||||
|
title: string;
|
||||||
|
contentmodel: string;
|
||||||
|
pagelanguage: string;
|
||||||
|
pagelanguagehtmlcode: string;
|
||||||
|
pagelanguagedir: string;
|
||||||
|
touched: string; // ISO date string
|
||||||
|
lastrevid: number;
|
||||||
|
length: number;
|
||||||
|
fullurl: string;
|
||||||
|
editurl: string;
|
||||||
|
canonicalurl: string;
|
||||||
|
}
|
||||||
export class WikipediaAPI extends APIModel {
|
export class WikipediaAPI extends APIModel {
|
||||||
plugin: MediaDbPlugin;
|
plugin: MediaDbPlugin;
|
||||||
apiDateFormat: string = 'YYYY-MM-DDTHH:mm:ssZ'; // ISO
|
apiDateFormat: string = 'YYYY-MM-DDTHH:mm:ssZ'; // ISO
|
||||||
|
|
@ -29,7 +58,7 @@ export class WikipediaAPI extends APIModel {
|
||||||
throw Error(`MDB | Received status code ${fetchData.status} from ${this.apiName}.`);
|
throw Error(`MDB | Received status code ${fetchData.status} from ${this.apiName}.`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const data = await fetchData.json();
|
const data = (await fetchData.json()) as SearchResponse;
|
||||||
console.debug(data);
|
console.debug(data);
|
||||||
const ret: MediaTypeModel[] = [];
|
const ret: MediaTypeModel[] = [];
|
||||||
|
|
||||||
|
|
@ -41,7 +70,7 @@ export class WikipediaAPI extends APIModel {
|
||||||
englishTitle: result.title,
|
englishTitle: result.title,
|
||||||
year: '',
|
year: '',
|
||||||
dataSource: this.apiName,
|
dataSource: this.apiName,
|
||||||
id: result.pageid,
|
id: result.pageid.toString(),
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -59,27 +88,25 @@ export class WikipediaAPI extends APIModel {
|
||||||
throw Error(`MDB | Received status code ${fetchData.status} from ${this.apiName}.`);
|
throw Error(`MDB | Received status code ${fetchData.status} from ${this.apiName}.`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const data = await fetchData.json();
|
const data = (await fetchData.json()) as IdResponse;
|
||||||
// console.debug(data);
|
// console.debug(data);
|
||||||
const result: any = Object.entries(data?.query?.pages)[0][1];
|
const result = Object.values(data?.query?.pages)[0];
|
||||||
|
|
||||||
return new WikiModel({
|
return new WikiModel({
|
||||||
type: 'wiki',
|
|
||||||
title: result.title,
|
title: result.title,
|
||||||
englishTitle: result.title,
|
englishTitle: result.title,
|
||||||
year: '',
|
|
||||||
dataSource: this.apiName,
|
dataSource: this.apiName,
|
||||||
url: result.fullurl,
|
url: result.fullurl,
|
||||||
id: result.pageid,
|
id: result.pageid.toString(),
|
||||||
|
|
||||||
wikiUrl: result.fullurl,
|
wikiUrl: result.fullurl,
|
||||||
lastUpdated: this.plugin.dateFormatter.format(result.touched, this.apiDateFormat) ?? undefined,
|
lastUpdated: this.plugin.dateFormatter.format(result.touched, this.apiDateFormat),
|
||||||
length: result.length,
|
length: result.length,
|
||||||
|
|
||||||
userData: {},
|
userData: {},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
getDisabledMediaTypes(): MediaType[] {
|
getDisabledMediaTypes(): MediaType[] {
|
||||||
return this.plugin.settings.WikipediaAPI_disabledMediaTypes as MediaType[];
|
return this.plugin.settings.WikipediaAPI_disabledMediaTypes;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
11226
src/api/schemas/GiantBomb.json
Normal file
11226
src/api/schemas/GiantBomb.json
Normal file
File diff suppressed because it is too large
Load diff
6454
src/api/schemas/GiantBomb.ts
Normal file
6454
src/api/schemas/GiantBomb.ts
Normal file
File diff suppressed because it is too large
Load diff
6761
src/api/schemas/MALAPI.ts
Normal file
6761
src/api/schemas/MALAPI.ts
Normal file
File diff suppressed because it is too large
Load diff
269
src/api/schemas/OMDb.json
Normal file
269
src/api/schemas/OMDb.json
Normal file
|
|
@ -0,0 +1,269 @@
|
||||||
|
{
|
||||||
|
"openapi": "3.0.1",
|
||||||
|
"info": {
|
||||||
|
"title": "OMDb API",
|
||||||
|
"description": "This API requires authorization, you can get a free key here: [http://omdbapi.com/apikey.aspx](http://omdbapi.com/apikey.aspx)",
|
||||||
|
"termsOfService": "http://omdbapi.com/legal.htm",
|
||||||
|
"contact": {
|
||||||
|
"email": "bfritz@fadingsignal.com"
|
||||||
|
},
|
||||||
|
"license": {
|
||||||
|
"name": "CC BY-NC 4.0",
|
||||||
|
"url": "https://creativecommons.org/licenses/by-nc/4.0/"
|
||||||
|
},
|
||||||
|
"version": "1.0"
|
||||||
|
},
|
||||||
|
"externalDocs": {
|
||||||
|
"description": "Find out more about Swagger",
|
||||||
|
"url": "http://swagger.io"
|
||||||
|
},
|
||||||
|
"servers": [
|
||||||
|
{
|
||||||
|
"url": "http://omdbapi.com/"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"url": "https://omdbapi.com/"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"APIKeyQueryParam": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
{
|
||||||
|
"name": "Title Parameter",
|
||||||
|
"description": "e.g. ?t=title"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "ID Parameter",
|
||||||
|
"description": "e.g. ?i=tt0000001"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Search Parameter",
|
||||||
|
"description": "e.g. ?s=title"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"paths": {
|
||||||
|
"/?t": {
|
||||||
|
"get": {
|
||||||
|
"tags": ["Title Parameter"],
|
||||||
|
"summary": "Returns the most popular match for a given title",
|
||||||
|
"operationId": "getTitle",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"name": "t",
|
||||||
|
"in": "query",
|
||||||
|
"description": "Title of movie or series",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "y",
|
||||||
|
"in": "query",
|
||||||
|
"description": "Year of release",
|
||||||
|
"schema": {
|
||||||
|
"type": "integer"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "type",
|
||||||
|
"in": "query",
|
||||||
|
"description": "Return movie or series",
|
||||||
|
"schema": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": ["movie", "series"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "plot",
|
||||||
|
"in": "query",
|
||||||
|
"description": "Return short or full plot",
|
||||||
|
"schema": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": ["short", "full"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "r",
|
||||||
|
"in": "query",
|
||||||
|
"description": "The response type to return",
|
||||||
|
"schema": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": ["json", "xml"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "callback",
|
||||||
|
"in": "query",
|
||||||
|
"description": "JSONP callback name",
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "Successful operation",
|
||||||
|
"content": {}
|
||||||
|
},
|
||||||
|
"401": {
|
||||||
|
"description": "Not authenticated",
|
||||||
|
"content": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"APIKeyQueryParam": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/?i": {
|
||||||
|
"get": {
|
||||||
|
"tags": ["ID Parameter"],
|
||||||
|
"summary": "Returns a single result based on the ID provided",
|
||||||
|
"operationId": "getId",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"name": "i",
|
||||||
|
"in": "query",
|
||||||
|
"description": "A valid IMDb ID (e.g. tt0000001)",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "plot",
|
||||||
|
"in": "query",
|
||||||
|
"description": "Return short or full plot",
|
||||||
|
"schema": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": ["short", "full"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "r",
|
||||||
|
"in": "query",
|
||||||
|
"description": "The response type to return",
|
||||||
|
"schema": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": ["json", "xml"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "callback",
|
||||||
|
"in": "query",
|
||||||
|
"description": "JSONP callback name",
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "Successful operation",
|
||||||
|
"content": {}
|
||||||
|
},
|
||||||
|
"401": {
|
||||||
|
"description": "Not authenticated",
|
||||||
|
"content": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"APIKeyQueryParam": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/?s": {
|
||||||
|
"get": {
|
||||||
|
"tags": ["Search Parameter"],
|
||||||
|
"summary": "Returns an array of results for a given title",
|
||||||
|
"operationId": "titleSearch",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"name": "s",
|
||||||
|
"in": "query",
|
||||||
|
"description": "Title of movie or series",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "y",
|
||||||
|
"in": "query",
|
||||||
|
"description": "Year of release",
|
||||||
|
"schema": {
|
||||||
|
"type": "integer"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "type",
|
||||||
|
"in": "query",
|
||||||
|
"description": "Return movie or series",
|
||||||
|
"schema": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": ["movie", "series"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "r",
|
||||||
|
"in": "query",
|
||||||
|
"description": "The response type to return",
|
||||||
|
"schema": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": ["json", "xml"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "page",
|
||||||
|
"in": "query",
|
||||||
|
"description": "Page number to return",
|
||||||
|
"schema": {
|
||||||
|
"type": "integer"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "callback",
|
||||||
|
"in": "query",
|
||||||
|
"description": "JSONP callback name",
|
||||||
|
"schema": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "Successful operation",
|
||||||
|
"content": {}
|
||||||
|
},
|
||||||
|
"401": {
|
||||||
|
"description": "Not authenticated",
|
||||||
|
"content": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"APIKeyQueryParam": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"components": {
|
||||||
|
"securitySchemes": {
|
||||||
|
"APIKeyQueryParam": {
|
||||||
|
"type": "apiKey",
|
||||||
|
"name": "apikey",
|
||||||
|
"in": "query"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"x-original-swagger-version": "2.0"
|
||||||
|
}
|
||||||
180
src/api/schemas/OMDb.ts
Normal file
180
src/api/schemas/OMDb.ts
Normal file
|
|
@ -0,0 +1,180 @@
|
||||||
|
/**
|
||||||
|
* This file was auto-generated by openapi-typescript.
|
||||||
|
* Do not make direct changes to the file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export interface paths {
|
||||||
|
'/?t': {
|
||||||
|
parameters: {
|
||||||
|
query?: never;
|
||||||
|
header?: never;
|
||||||
|
path?: never;
|
||||||
|
cookie?: never;
|
||||||
|
};
|
||||||
|
/** Returns the most popular match for a given title */
|
||||||
|
get: operations['getTitle'];
|
||||||
|
put?: never;
|
||||||
|
post?: never;
|
||||||
|
delete?: never;
|
||||||
|
options?: never;
|
||||||
|
head?: never;
|
||||||
|
patch?: never;
|
||||||
|
trace?: never;
|
||||||
|
};
|
||||||
|
'/?i': {
|
||||||
|
parameters: {
|
||||||
|
query?: never;
|
||||||
|
header?: never;
|
||||||
|
path?: never;
|
||||||
|
cookie?: never;
|
||||||
|
};
|
||||||
|
/** Returns a single result based on the ID provided */
|
||||||
|
get: operations['getId'];
|
||||||
|
put?: never;
|
||||||
|
post?: never;
|
||||||
|
delete?: never;
|
||||||
|
options?: never;
|
||||||
|
head?: never;
|
||||||
|
patch?: never;
|
||||||
|
trace?: never;
|
||||||
|
};
|
||||||
|
'/?s': {
|
||||||
|
parameters: {
|
||||||
|
query?: never;
|
||||||
|
header?: never;
|
||||||
|
path?: never;
|
||||||
|
cookie?: never;
|
||||||
|
};
|
||||||
|
/** Returns an array of results for a given title */
|
||||||
|
get: operations['titleSearch'];
|
||||||
|
put?: never;
|
||||||
|
post?: never;
|
||||||
|
delete?: never;
|
||||||
|
options?: never;
|
||||||
|
head?: never;
|
||||||
|
patch?: never;
|
||||||
|
trace?: never;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
export type webhooks = Record<string, never>;
|
||||||
|
export interface components {
|
||||||
|
schemas: never;
|
||||||
|
responses: never;
|
||||||
|
parameters: never;
|
||||||
|
requestBodies: never;
|
||||||
|
headers: never;
|
||||||
|
pathItems: never;
|
||||||
|
}
|
||||||
|
export type $defs = Record<string, never>;
|
||||||
|
export interface operations {
|
||||||
|
getTitle: {
|
||||||
|
parameters: {
|
||||||
|
query: {
|
||||||
|
/** @description Title of movie or series */
|
||||||
|
t: string;
|
||||||
|
/** @description Year of release */
|
||||||
|
y?: number;
|
||||||
|
/** @description Return movie or series */
|
||||||
|
type?: 'movie' | 'series';
|
||||||
|
/** @description Return short or full plot */
|
||||||
|
plot?: 'short' | 'full';
|
||||||
|
/** @description The response type to return */
|
||||||
|
r?: 'json' | 'xml';
|
||||||
|
/** @description JSONP callback name */
|
||||||
|
callback?: string;
|
||||||
|
};
|
||||||
|
header?: never;
|
||||||
|
path?: never;
|
||||||
|
cookie?: never;
|
||||||
|
};
|
||||||
|
requestBody?: never;
|
||||||
|
responses: {
|
||||||
|
/** @description Successful operation */
|
||||||
|
200: {
|
||||||
|
headers: {
|
||||||
|
[name: string]: unknown;
|
||||||
|
};
|
||||||
|
content?: never;
|
||||||
|
};
|
||||||
|
/** @description Not authenticated */
|
||||||
|
401: {
|
||||||
|
headers: {
|
||||||
|
[name: string]: unknown;
|
||||||
|
};
|
||||||
|
content?: never;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
getId: {
|
||||||
|
parameters: {
|
||||||
|
query: {
|
||||||
|
/** @description A valid IMDb ID (e.g. tt0000001) */
|
||||||
|
i: string;
|
||||||
|
/** @description Return short or full plot */
|
||||||
|
plot?: 'short' | 'full';
|
||||||
|
/** @description The response type to return */
|
||||||
|
r?: 'json' | 'xml';
|
||||||
|
/** @description JSONP callback name */
|
||||||
|
callback?: string;
|
||||||
|
};
|
||||||
|
header?: never;
|
||||||
|
path?: never;
|
||||||
|
cookie?: never;
|
||||||
|
};
|
||||||
|
requestBody?: never;
|
||||||
|
responses: {
|
||||||
|
/** @description Successful operation */
|
||||||
|
200: {
|
||||||
|
headers: {
|
||||||
|
[name: string]: unknown;
|
||||||
|
};
|
||||||
|
content?: never;
|
||||||
|
};
|
||||||
|
/** @description Not authenticated */
|
||||||
|
401: {
|
||||||
|
headers: {
|
||||||
|
[name: string]: unknown;
|
||||||
|
};
|
||||||
|
content?: never;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
titleSearch: {
|
||||||
|
parameters: {
|
||||||
|
query: {
|
||||||
|
/** @description Title of movie or series */
|
||||||
|
s: string;
|
||||||
|
/** @description Year of release */
|
||||||
|
y?: number;
|
||||||
|
/** @description Return movie or series */
|
||||||
|
type?: 'movie' | 'series';
|
||||||
|
/** @description The response type to return */
|
||||||
|
r?: 'json' | 'xml';
|
||||||
|
/** @description Page number to return */
|
||||||
|
page?: number;
|
||||||
|
/** @description JSONP callback name */
|
||||||
|
callback?: string;
|
||||||
|
};
|
||||||
|
header?: never;
|
||||||
|
path?: never;
|
||||||
|
cookie?: never;
|
||||||
|
};
|
||||||
|
requestBody?: never;
|
||||||
|
responses: {
|
||||||
|
/** @description Successful operation */
|
||||||
|
200: {
|
||||||
|
headers: {
|
||||||
|
[name: string]: unknown;
|
||||||
|
};
|
||||||
|
content?: never;
|
||||||
|
};
|
||||||
|
/** @description Not authenticated */
|
||||||
|
401: {
|
||||||
|
headers: {
|
||||||
|
[name: string]: unknown;
|
||||||
|
};
|
||||||
|
content?: never;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
602
src/api/schemas/OpenLibrary.json
Normal file
602
src/api/schemas/OpenLibrary.json
Normal file
|
|
@ -0,0 +1,602 @@
|
||||||
|
{
|
||||||
|
"components": {
|
||||||
|
"schemas": {
|
||||||
|
"HTTPValidationError": {
|
||||||
|
"properties": {
|
||||||
|
"detail": {
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/components/schemas/ValidationError"
|
||||||
|
},
|
||||||
|
"title": "Detail",
|
||||||
|
"type": "array"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"title": "HTTPValidationError",
|
||||||
|
"type": "object"
|
||||||
|
},
|
||||||
|
"ValidationError": {
|
||||||
|
"properties": {
|
||||||
|
"loc": {
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"title": "Location",
|
||||||
|
"type": "array"
|
||||||
|
},
|
||||||
|
"msg": {
|
||||||
|
"title": "Message",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"type": {
|
||||||
|
"title": "Error Type",
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": ["loc", "msg", "type"],
|
||||||
|
"title": "ValidationError",
|
||||||
|
"type": "object"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"info": {
|
||||||
|
"description": "- These are still in development and may not be perfect\n- Contribute by proposing edits to [openapi.json](https://github.com/internetarchive/openlibrary/blob/master/static/openapi.json)\n- Please do not use our APIs for bulk downloads, see [dev center](https://openlibrary.org/developers/api)",
|
||||||
|
"title": "Open Library API",
|
||||||
|
"version": "0.1.0"
|
||||||
|
},
|
||||||
|
"openapi": "3.0.2",
|
||||||
|
"paths": {
|
||||||
|
"/api/books": {
|
||||||
|
"get": {
|
||||||
|
"operationId": "read_api_books_api_books_get",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"examples": {
|
||||||
|
"isbn": {
|
||||||
|
"value": "ISBN:0201558025"
|
||||||
|
},
|
||||||
|
"multiple": {
|
||||||
|
"value": "ISBN:9781408113479,OCLC:420517"
|
||||||
|
},
|
||||||
|
"oclc": {
|
||||||
|
"value": "OCLC:263296519"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"in": "query",
|
||||||
|
"name": "bibkeys",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"title": "Bibkeys",
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "Specifies the response format. Possible values are json and javascript. When not specified the format is javascript.",
|
||||||
|
"in": "query",
|
||||||
|
"name": "format",
|
||||||
|
"required": false,
|
||||||
|
"schema": {
|
||||||
|
"default": "json",
|
||||||
|
"title": "Format",
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "The name of the JavaScript function to call with the result. This is considered only when the format is javascript.",
|
||||||
|
"in": "query",
|
||||||
|
"name": "callback",
|
||||||
|
"required": false,
|
||||||
|
"schema": {
|
||||||
|
"title": "Callback"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "Decides what information to provide for each matched bib_key. Possible values are viewapi and data. The default value is viewapi.",
|
||||||
|
"in": "query",
|
||||||
|
"name": "jscmd",
|
||||||
|
"required": false,
|
||||||
|
"schema": {
|
||||||
|
"default": "viewapi",
|
||||||
|
"title": "Jscmd",
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"description": "Successful Response"
|
||||||
|
},
|
||||||
|
"422": {
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/HTTPValidationError"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"description": "Validation Error"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"summary": "Read Api Books",
|
||||||
|
"tags": ["books"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/api/volumes/brief/{key_type}/{value}.json": {
|
||||||
|
"get": {
|
||||||
|
"operationId": "read_api_volumes_brief_api_volumes_brief__key_type___value__json_get",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"in": "path",
|
||||||
|
"name": "key_type",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"title": "Key Type"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"in": "path",
|
||||||
|
"name": "value",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"title": "Value"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"in": "query",
|
||||||
|
"name": "callback",
|
||||||
|
"required": false,
|
||||||
|
"schema": {
|
||||||
|
"title": "Callback"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"description": "Successful Response"
|
||||||
|
},
|
||||||
|
"422": {
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/HTTPValidationError"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"description": "Validation Error"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"summary": "Read Api Volumes Brief",
|
||||||
|
"tags": ["books"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/authors/{olid}.json": {
|
||||||
|
"get": {
|
||||||
|
"operationId": "read_authors_authors__olid__json_get",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"in": "path",
|
||||||
|
"name": "olid",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"title": "Olid"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"description": "Successful Response"
|
||||||
|
},
|
||||||
|
"422": {
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/HTTPValidationError"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"description": "Validation Error"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"summary": "Read Authors",
|
||||||
|
"tags": ["authors"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/authors/{olid}/works.json": {
|
||||||
|
"get": {
|
||||||
|
"operationId": "read_authors_works_authors__olid__works_json_get",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"in": "path",
|
||||||
|
"name": "olid",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"title": "Olid"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"in": "query",
|
||||||
|
"name": "limit",
|
||||||
|
"required": false,
|
||||||
|
"schema": {
|
||||||
|
"title": "Limit",
|
||||||
|
"type": "integer"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"description": "Successful Response"
|
||||||
|
},
|
||||||
|
"422": {
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/HTTPValidationError"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"description": "Validation Error"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"summary": "Read Authors Works",
|
||||||
|
"tags": ["authors"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/books/{olid}": {
|
||||||
|
"get": {
|
||||||
|
"operationId": "read_books_books__olid__get",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"in": "path",
|
||||||
|
"name": "olid",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"example": "OL53924W",
|
||||||
|
"title": "Olid"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"description": "Successful Response"
|
||||||
|
},
|
||||||
|
"422": {
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/HTTPValidationError"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"description": "Validation Error"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"summary": "Read Books",
|
||||||
|
"tags": ["books"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/covers/{key_type}/{value}-{size}.jpg": {
|
||||||
|
"get": {
|
||||||
|
"operationId": "read_covers_key_type_value_size_jpeg_covers__key_type___value___size__jpg_get",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"in": "path",
|
||||||
|
"name": "key_type",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"title": "Key Type"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"in": "path",
|
||||||
|
"name": "value",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"title": "Value"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"in": "path",
|
||||||
|
"name": "size",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"title": "Size"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"description": "Successful Response"
|
||||||
|
},
|
||||||
|
"422": {
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/HTTPValidationError"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"description": "Validation Error"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"summary": "Read Covers Key Type Value Size Jpeg",
|
||||||
|
"tags": ["covers"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/isbn/{isbn}": {
|
||||||
|
"get": {
|
||||||
|
"operationId": "read_isbn_isbn__isbn__get",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"in": "path",
|
||||||
|
"name": "isbn",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"title": "Isbn"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"description": "Successful Response"
|
||||||
|
},
|
||||||
|
"422": {
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/HTTPValidationError"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"description": "Validation Error"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"summary": "Read Isbn",
|
||||||
|
"tags": ["books"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/search.json": {
|
||||||
|
"get": {
|
||||||
|
"operationId": "read_search_json_search_json_get",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"in": "query",
|
||||||
|
"name": "q",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"title": "Q"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"in": "query",
|
||||||
|
"name": "page",
|
||||||
|
"required": false,
|
||||||
|
"schema": {
|
||||||
|
"title": "Page",
|
||||||
|
"type": "integer"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"description": "Successful Response"
|
||||||
|
},
|
||||||
|
"422": {
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/HTTPValidationError"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"description": "Validation Error"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"summary": "Read Search Json",
|
||||||
|
"tags": ["search"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/search/authors.json": {
|
||||||
|
"get": {
|
||||||
|
"operationId": "read_search_authors_json_search_authors_json_get",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"in": "query",
|
||||||
|
"name": "q",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"title": "Q"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"description": "Successful Response"
|
||||||
|
},
|
||||||
|
"422": {
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/HTTPValidationError"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"description": "Validation Error"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"summary": "Read Search Authors Json",
|
||||||
|
"tags": ["search"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/subjects/{subject}.json": {
|
||||||
|
"get": {
|
||||||
|
"operationId": "read_subjects_subjects__subject__json_get",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"in": "path",
|
||||||
|
"name": "subject",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"title": "Subject"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"in": "query",
|
||||||
|
"name": "details",
|
||||||
|
"required": false,
|
||||||
|
"schema": {
|
||||||
|
"default": false,
|
||||||
|
"title": "Details",
|
||||||
|
"type": "boolean"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"description": "Successful Response"
|
||||||
|
},
|
||||||
|
"422": {
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/HTTPValidationError"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"description": "Validation Error"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"summary": "Read Subjects",
|
||||||
|
"tags": ["subjects"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/works/{olid}": {
|
||||||
|
"get": {
|
||||||
|
"operationId": "read_works_works__olid__get",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"in": "path",
|
||||||
|
"name": "olid",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"title": "Olid"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"description": "Successful Response"
|
||||||
|
},
|
||||||
|
"422": {
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/components/schemas/HTTPValidationError"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"description": "Validation Error"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"summary": "Read Works",
|
||||||
|
"tags": ["books"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"tags": [
|
||||||
|
{
|
||||||
|
"description": "Retrieve a specific work or edition by identifier",
|
||||||
|
"externalDocs": {
|
||||||
|
"description": "Find out more",
|
||||||
|
"url": "https://openlibrary.org/dev/docs/api/books"
|
||||||
|
},
|
||||||
|
"name": "books"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "Retrieve an author and their works by author identifier",
|
||||||
|
"externalDocs": {
|
||||||
|
"description": "Find out more",
|
||||||
|
"url": "https://openlibrary.org/dev/docs/api/authors"
|
||||||
|
},
|
||||||
|
"name": "authors"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "Search results for books, authors, and more",
|
||||||
|
"externalDocs": {
|
||||||
|
"description": "Find out more",
|
||||||
|
"url": "https://openlibrary.org/dev/docs/api/search"
|
||||||
|
},
|
||||||
|
"name": "search"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "Fetch book covers by ISBN or Open Library identifier",
|
||||||
|
"externalDocs": {
|
||||||
|
"description": "Find out more",
|
||||||
|
"url": "https://openlibrary.org/dev/docs/api/covers"
|
||||||
|
},
|
||||||
|
"name": "covers"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"description": "Fetch books by subject name ",
|
||||||
|
"externalDocs": {
|
||||||
|
"description": "Find out more",
|
||||||
|
"url": "https://openlibrary.org/dev/docs/api/subjects"
|
||||||
|
},
|
||||||
|
"name": "subjects"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
578
src/api/schemas/OpenLibrary.ts
Normal file
578
src/api/schemas/OpenLibrary.ts
Normal file
|
|
@ -0,0 +1,578 @@
|
||||||
|
/**
|
||||||
|
* This file was auto-generated by openapi-typescript.
|
||||||
|
* Do not make direct changes to the file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export interface paths {
|
||||||
|
'/api/books': {
|
||||||
|
parameters: {
|
||||||
|
query?: never;
|
||||||
|
header?: never;
|
||||||
|
path?: never;
|
||||||
|
cookie?: never;
|
||||||
|
};
|
||||||
|
/** Read Api Books */
|
||||||
|
get: operations['read_api_books_api_books_get'];
|
||||||
|
put?: never;
|
||||||
|
post?: never;
|
||||||
|
delete?: never;
|
||||||
|
options?: never;
|
||||||
|
head?: never;
|
||||||
|
patch?: never;
|
||||||
|
trace?: never;
|
||||||
|
};
|
||||||
|
'/api/volumes/brief/{key_type}/{value}.json': {
|
||||||
|
parameters: {
|
||||||
|
query?: never;
|
||||||
|
header?: never;
|
||||||
|
path?: never;
|
||||||
|
cookie?: never;
|
||||||
|
};
|
||||||
|
/** Read Api Volumes Brief */
|
||||||
|
get: operations['read_api_volumes_brief_api_volumes_brief__key_type___value__json_get'];
|
||||||
|
put?: never;
|
||||||
|
post?: never;
|
||||||
|
delete?: never;
|
||||||
|
options?: never;
|
||||||
|
head?: never;
|
||||||
|
patch?: never;
|
||||||
|
trace?: never;
|
||||||
|
};
|
||||||
|
'/authors/{olid}.json': {
|
||||||
|
parameters: {
|
||||||
|
query?: never;
|
||||||
|
header?: never;
|
||||||
|
path?: never;
|
||||||
|
cookie?: never;
|
||||||
|
};
|
||||||
|
/** Read Authors */
|
||||||
|
get: operations['read_authors_authors__olid__json_get'];
|
||||||
|
put?: never;
|
||||||
|
post?: never;
|
||||||
|
delete?: never;
|
||||||
|
options?: never;
|
||||||
|
head?: never;
|
||||||
|
patch?: never;
|
||||||
|
trace?: never;
|
||||||
|
};
|
||||||
|
'/authors/{olid}/works.json': {
|
||||||
|
parameters: {
|
||||||
|
query?: never;
|
||||||
|
header?: never;
|
||||||
|
path?: never;
|
||||||
|
cookie?: never;
|
||||||
|
};
|
||||||
|
/** Read Authors Works */
|
||||||
|
get: operations['read_authors_works_authors__olid__works_json_get'];
|
||||||
|
put?: never;
|
||||||
|
post?: never;
|
||||||
|
delete?: never;
|
||||||
|
options?: never;
|
||||||
|
head?: never;
|
||||||
|
patch?: never;
|
||||||
|
trace?: never;
|
||||||
|
};
|
||||||
|
'/books/{olid}': {
|
||||||
|
parameters: {
|
||||||
|
query?: never;
|
||||||
|
header?: never;
|
||||||
|
path?: never;
|
||||||
|
cookie?: never;
|
||||||
|
};
|
||||||
|
/** Read Books */
|
||||||
|
get: operations['read_books_books__olid__get'];
|
||||||
|
put?: never;
|
||||||
|
post?: never;
|
||||||
|
delete?: never;
|
||||||
|
options?: never;
|
||||||
|
head?: never;
|
||||||
|
patch?: never;
|
||||||
|
trace?: never;
|
||||||
|
};
|
||||||
|
'/covers/{key_type}/{value}-{size}.jpg': {
|
||||||
|
parameters: {
|
||||||
|
query?: never;
|
||||||
|
header?: never;
|
||||||
|
path?: never;
|
||||||
|
cookie?: never;
|
||||||
|
};
|
||||||
|
/** Read Covers Key Type Value Size Jpeg */
|
||||||
|
get: operations['read_covers_key_type_value_size_jpeg_covers__key_type___value___size__jpg_get'];
|
||||||
|
put?: never;
|
||||||
|
post?: never;
|
||||||
|
delete?: never;
|
||||||
|
options?: never;
|
||||||
|
head?: never;
|
||||||
|
patch?: never;
|
||||||
|
trace?: never;
|
||||||
|
};
|
||||||
|
'/isbn/{isbn}': {
|
||||||
|
parameters: {
|
||||||
|
query?: never;
|
||||||
|
header?: never;
|
||||||
|
path?: never;
|
||||||
|
cookie?: never;
|
||||||
|
};
|
||||||
|
/** Read Isbn */
|
||||||
|
get: operations['read_isbn_isbn__isbn__get'];
|
||||||
|
put?: never;
|
||||||
|
post?: never;
|
||||||
|
delete?: never;
|
||||||
|
options?: never;
|
||||||
|
head?: never;
|
||||||
|
patch?: never;
|
||||||
|
trace?: never;
|
||||||
|
};
|
||||||
|
'/search.json': {
|
||||||
|
parameters: {
|
||||||
|
query?: never;
|
||||||
|
header?: never;
|
||||||
|
path?: never;
|
||||||
|
cookie?: never;
|
||||||
|
};
|
||||||
|
/** Read Search Json */
|
||||||
|
get: operations['read_search_json_search_json_get'];
|
||||||
|
put?: never;
|
||||||
|
post?: never;
|
||||||
|
delete?: never;
|
||||||
|
options?: never;
|
||||||
|
head?: never;
|
||||||
|
patch?: never;
|
||||||
|
trace?: never;
|
||||||
|
};
|
||||||
|
'/search/authors.json': {
|
||||||
|
parameters: {
|
||||||
|
query?: never;
|
||||||
|
header?: never;
|
||||||
|
path?: never;
|
||||||
|
cookie?: never;
|
||||||
|
};
|
||||||
|
/** Read Search Authors Json */
|
||||||
|
get: operations['read_search_authors_json_search_authors_json_get'];
|
||||||
|
put?: never;
|
||||||
|
post?: never;
|
||||||
|
delete?: never;
|
||||||
|
options?: never;
|
||||||
|
head?: never;
|
||||||
|
patch?: never;
|
||||||
|
trace?: never;
|
||||||
|
};
|
||||||
|
'/subjects/{subject}.json': {
|
||||||
|
parameters: {
|
||||||
|
query?: never;
|
||||||
|
header?: never;
|
||||||
|
path?: never;
|
||||||
|
cookie?: never;
|
||||||
|
};
|
||||||
|
/** Read Subjects */
|
||||||
|
get: operations['read_subjects_subjects__subject__json_get'];
|
||||||
|
put?: never;
|
||||||
|
post?: never;
|
||||||
|
delete?: never;
|
||||||
|
options?: never;
|
||||||
|
head?: never;
|
||||||
|
patch?: never;
|
||||||
|
trace?: never;
|
||||||
|
};
|
||||||
|
'/works/{olid}': {
|
||||||
|
parameters: {
|
||||||
|
query?: never;
|
||||||
|
header?: never;
|
||||||
|
path?: never;
|
||||||
|
cookie?: never;
|
||||||
|
};
|
||||||
|
/** Read Works */
|
||||||
|
get: operations['read_works_works__olid__get'];
|
||||||
|
put?: never;
|
||||||
|
post?: never;
|
||||||
|
delete?: never;
|
||||||
|
options?: never;
|
||||||
|
head?: never;
|
||||||
|
patch?: never;
|
||||||
|
trace?: never;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
export type webhooks = Record<string, never>;
|
||||||
|
export interface components {
|
||||||
|
schemas: {
|
||||||
|
/** HTTPValidationError */
|
||||||
|
HTTPValidationError: {
|
||||||
|
/** Detail */
|
||||||
|
detail?: components['schemas']['ValidationError'][];
|
||||||
|
};
|
||||||
|
/** ValidationError */
|
||||||
|
ValidationError: {
|
||||||
|
/** Location */
|
||||||
|
loc: string[];
|
||||||
|
/** Message */
|
||||||
|
msg: string;
|
||||||
|
/** Error Type */
|
||||||
|
type: string;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
responses: never;
|
||||||
|
parameters: never;
|
||||||
|
requestBodies: never;
|
||||||
|
headers: never;
|
||||||
|
pathItems: never;
|
||||||
|
}
|
||||||
|
export type $defs = Record<string, never>;
|
||||||
|
export interface operations {
|
||||||
|
read_api_books_api_books_get: {
|
||||||
|
parameters: {
|
||||||
|
query: {
|
||||||
|
bibkeys: string;
|
||||||
|
/** @description Specifies the response format. Possible values are json and javascript. When not specified the format is javascript. */
|
||||||
|
format?: string;
|
||||||
|
/** @description The name of the JavaScript function to call with the result. This is considered only when the format is javascript. */
|
||||||
|
callback?: unknown;
|
||||||
|
/** @description Decides what information to provide for each matched bib_key. Possible values are viewapi and data. The default value is viewapi. */
|
||||||
|
jscmd?: string;
|
||||||
|
};
|
||||||
|
header?: never;
|
||||||
|
path?: never;
|
||||||
|
cookie?: never;
|
||||||
|
};
|
||||||
|
requestBody?: never;
|
||||||
|
responses: {
|
||||||
|
/** @description Successful Response */
|
||||||
|
200: {
|
||||||
|
headers: {
|
||||||
|
[name: string]: unknown;
|
||||||
|
};
|
||||||
|
content: {
|
||||||
|
'application/json': unknown;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
/** @description Validation Error */
|
||||||
|
422: {
|
||||||
|
headers: {
|
||||||
|
[name: string]: unknown;
|
||||||
|
};
|
||||||
|
content: {
|
||||||
|
'application/json': components['schemas']['HTTPValidationError'];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
read_api_volumes_brief_api_volumes_brief__key_type___value__json_get: {
|
||||||
|
parameters: {
|
||||||
|
query?: {
|
||||||
|
callback?: unknown;
|
||||||
|
};
|
||||||
|
header?: never;
|
||||||
|
path: {
|
||||||
|
key_type: unknown;
|
||||||
|
value: unknown;
|
||||||
|
};
|
||||||
|
cookie?: never;
|
||||||
|
};
|
||||||
|
requestBody?: never;
|
||||||
|
responses: {
|
||||||
|
/** @description Successful Response */
|
||||||
|
200: {
|
||||||
|
headers: {
|
||||||
|
[name: string]: unknown;
|
||||||
|
};
|
||||||
|
content: {
|
||||||
|
'application/json': unknown;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
/** @description Validation Error */
|
||||||
|
422: {
|
||||||
|
headers: {
|
||||||
|
[name: string]: unknown;
|
||||||
|
};
|
||||||
|
content: {
|
||||||
|
'application/json': components['schemas']['HTTPValidationError'];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
read_authors_authors__olid__json_get: {
|
||||||
|
parameters: {
|
||||||
|
query?: never;
|
||||||
|
header?: never;
|
||||||
|
path: {
|
||||||
|
olid: unknown;
|
||||||
|
};
|
||||||
|
cookie?: never;
|
||||||
|
};
|
||||||
|
requestBody?: never;
|
||||||
|
responses: {
|
||||||
|
/** @description Successful Response */
|
||||||
|
200: {
|
||||||
|
headers: {
|
||||||
|
[name: string]: unknown;
|
||||||
|
};
|
||||||
|
content: {
|
||||||
|
'application/json': unknown;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
/** @description Validation Error */
|
||||||
|
422: {
|
||||||
|
headers: {
|
||||||
|
[name: string]: unknown;
|
||||||
|
};
|
||||||
|
content: {
|
||||||
|
'application/json': components['schemas']['HTTPValidationError'];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
read_authors_works_authors__olid__works_json_get: {
|
||||||
|
parameters: {
|
||||||
|
query?: {
|
||||||
|
limit?: number;
|
||||||
|
};
|
||||||
|
header?: never;
|
||||||
|
path: {
|
||||||
|
olid: unknown;
|
||||||
|
};
|
||||||
|
cookie?: never;
|
||||||
|
};
|
||||||
|
requestBody?: never;
|
||||||
|
responses: {
|
||||||
|
/** @description Successful Response */
|
||||||
|
200: {
|
||||||
|
headers: {
|
||||||
|
[name: string]: unknown;
|
||||||
|
};
|
||||||
|
content: {
|
||||||
|
'application/json': unknown;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
/** @description Validation Error */
|
||||||
|
422: {
|
||||||
|
headers: {
|
||||||
|
[name: string]: unknown;
|
||||||
|
};
|
||||||
|
content: {
|
||||||
|
'application/json': components['schemas']['HTTPValidationError'];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
read_books_books__olid__get: {
|
||||||
|
parameters: {
|
||||||
|
query?: never;
|
||||||
|
header?: never;
|
||||||
|
path: {
|
||||||
|
olid: unknown;
|
||||||
|
};
|
||||||
|
cookie?: never;
|
||||||
|
};
|
||||||
|
requestBody?: never;
|
||||||
|
responses: {
|
||||||
|
/** @description Successful Response */
|
||||||
|
200: {
|
||||||
|
headers: {
|
||||||
|
[name: string]: unknown;
|
||||||
|
};
|
||||||
|
content: {
|
||||||
|
'application/json': unknown;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
/** @description Validation Error */
|
||||||
|
422: {
|
||||||
|
headers: {
|
||||||
|
[name: string]: unknown;
|
||||||
|
};
|
||||||
|
content: {
|
||||||
|
'application/json': components['schemas']['HTTPValidationError'];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
read_covers_key_type_value_size_jpeg_covers__key_type___value___size__jpg_get: {
|
||||||
|
parameters: {
|
||||||
|
query?: never;
|
||||||
|
header?: never;
|
||||||
|
path: {
|
||||||
|
key_type: unknown;
|
||||||
|
value: unknown;
|
||||||
|
size: unknown;
|
||||||
|
};
|
||||||
|
cookie?: never;
|
||||||
|
};
|
||||||
|
requestBody?: never;
|
||||||
|
responses: {
|
||||||
|
/** @description Successful Response */
|
||||||
|
200: {
|
||||||
|
headers: {
|
||||||
|
[name: string]: unknown;
|
||||||
|
};
|
||||||
|
content: {
|
||||||
|
'application/json': unknown;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
/** @description Validation Error */
|
||||||
|
422: {
|
||||||
|
headers: {
|
||||||
|
[name: string]: unknown;
|
||||||
|
};
|
||||||
|
content: {
|
||||||
|
'application/json': components['schemas']['HTTPValidationError'];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
read_isbn_isbn__isbn__get: {
|
||||||
|
parameters: {
|
||||||
|
query?: never;
|
||||||
|
header?: never;
|
||||||
|
path: {
|
||||||
|
isbn: unknown;
|
||||||
|
};
|
||||||
|
cookie?: never;
|
||||||
|
};
|
||||||
|
requestBody?: never;
|
||||||
|
responses: {
|
||||||
|
/** @description Successful Response */
|
||||||
|
200: {
|
||||||
|
headers: {
|
||||||
|
[name: string]: unknown;
|
||||||
|
};
|
||||||
|
content: {
|
||||||
|
'application/json': unknown;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
/** @description Validation Error */
|
||||||
|
422: {
|
||||||
|
headers: {
|
||||||
|
[name: string]: unknown;
|
||||||
|
};
|
||||||
|
content: {
|
||||||
|
'application/json': components['schemas']['HTTPValidationError'];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
read_search_json_search_json_get: {
|
||||||
|
parameters: {
|
||||||
|
query: {
|
||||||
|
q: unknown;
|
||||||
|
page?: number;
|
||||||
|
};
|
||||||
|
header?: never;
|
||||||
|
path?: never;
|
||||||
|
cookie?: never;
|
||||||
|
};
|
||||||
|
requestBody?: never;
|
||||||
|
responses: {
|
||||||
|
/** @description Successful Response */
|
||||||
|
200: {
|
||||||
|
headers: {
|
||||||
|
[name: string]: unknown;
|
||||||
|
};
|
||||||
|
content: {
|
||||||
|
'application/json': unknown;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
/** @description Validation Error */
|
||||||
|
422: {
|
||||||
|
headers: {
|
||||||
|
[name: string]: unknown;
|
||||||
|
};
|
||||||
|
content: {
|
||||||
|
'application/json': components['schemas']['HTTPValidationError'];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
read_search_authors_json_search_authors_json_get: {
|
||||||
|
parameters: {
|
||||||
|
query: {
|
||||||
|
q: unknown;
|
||||||
|
};
|
||||||
|
header?: never;
|
||||||
|
path?: never;
|
||||||
|
cookie?: never;
|
||||||
|
};
|
||||||
|
requestBody?: never;
|
||||||
|
responses: {
|
||||||
|
/** @description Successful Response */
|
||||||
|
200: {
|
||||||
|
headers: {
|
||||||
|
[name: string]: unknown;
|
||||||
|
};
|
||||||
|
content: {
|
||||||
|
'application/json': unknown;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
/** @description Validation Error */
|
||||||
|
422: {
|
||||||
|
headers: {
|
||||||
|
[name: string]: unknown;
|
||||||
|
};
|
||||||
|
content: {
|
||||||
|
'application/json': components['schemas']['HTTPValidationError'];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
read_subjects_subjects__subject__json_get: {
|
||||||
|
parameters: {
|
||||||
|
query?: {
|
||||||
|
details?: boolean;
|
||||||
|
};
|
||||||
|
header?: never;
|
||||||
|
path: {
|
||||||
|
subject: unknown;
|
||||||
|
};
|
||||||
|
cookie?: never;
|
||||||
|
};
|
||||||
|
requestBody?: never;
|
||||||
|
responses: {
|
||||||
|
/** @description Successful Response */
|
||||||
|
200: {
|
||||||
|
headers: {
|
||||||
|
[name: string]: unknown;
|
||||||
|
};
|
||||||
|
content: {
|
||||||
|
'application/json': unknown;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
/** @description Validation Error */
|
||||||
|
422: {
|
||||||
|
headers: {
|
||||||
|
[name: string]: unknown;
|
||||||
|
};
|
||||||
|
content: {
|
||||||
|
'application/json': components['schemas']['HTTPValidationError'];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
read_works_works__olid__get: {
|
||||||
|
parameters: {
|
||||||
|
query?: never;
|
||||||
|
header?: never;
|
||||||
|
path: {
|
||||||
|
olid: unknown;
|
||||||
|
};
|
||||||
|
cookie?: never;
|
||||||
|
};
|
||||||
|
requestBody?: never;
|
||||||
|
responses: {
|
||||||
|
/** @description Successful Response */
|
||||||
|
200: {
|
||||||
|
headers: {
|
||||||
|
[name: string]: unknown;
|
||||||
|
};
|
||||||
|
content: {
|
||||||
|
'application/json': unknown;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
/** @description Validation Error */
|
||||||
|
422: {
|
||||||
|
headers: {
|
||||||
|
[name: string]: unknown;
|
||||||
|
};
|
||||||
|
content: {
|
||||||
|
'application/json': components['schemas']['HTTPValidationError'];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
50
src/main.ts
50
src/main.ts
|
|
@ -3,6 +3,7 @@ import { requestUrl, normalizePath } from 'obsidian'; // Add requestUrl import
|
||||||
import type { MediaType } from 'src/utils/MediaType';
|
import type { MediaType } from 'src/utils/MediaType';
|
||||||
import { APIManager } from './api/APIManager';
|
import { APIManager } from './api/APIManager';
|
||||||
import { BoardGameGeekAPI } from './api/apis/BoardGameGeekAPI';
|
import { BoardGameGeekAPI } from './api/apis/BoardGameGeekAPI';
|
||||||
|
import { ComicVineAPI } from './api/apis/ComicVineAPI';
|
||||||
import { GiantBombAPI } from './api/apis/GiantBombAPI';
|
import { GiantBombAPI } from './api/apis/GiantBombAPI';
|
||||||
import { MALAPI } from './api/apis/MALAPI';
|
import { MALAPI } from './api/apis/MALAPI';
|
||||||
import { MALAPIManga } from './api/apis/MALAPIManga';
|
import { MALAPIManga } from './api/apis/MALAPIManga';
|
||||||
|
|
@ -12,9 +13,8 @@ import { OMDbAPI } from './api/apis/OMDbAPI';
|
||||||
import { OpenLibraryAPI } from './api/apis/OpenLibraryAPI';
|
import { OpenLibraryAPI } from './api/apis/OpenLibraryAPI';
|
||||||
import { SteamAPI } from './api/apis/SteamAPI';
|
import { SteamAPI } from './api/apis/SteamAPI';
|
||||||
import { WikipediaAPI } from './api/apis/WikipediaAPI';
|
import { WikipediaAPI } from './api/apis/WikipediaAPI';
|
||||||
import { ComicVineAPI } from './api/apis/ComicVineAPI';
|
|
||||||
import { MediaDbFolderImportModal } from './modals/MediaDbFolderImportModal';
|
|
||||||
import { ConfirmOverwriteModal } from './modals/ConfirmOverwriteModal';
|
import { ConfirmOverwriteModal } from './modals/ConfirmOverwriteModal';
|
||||||
|
import { MediaDbFolderImportModal } from './modals/MediaDbFolderImportModal';
|
||||||
import type { MediaTypeModel } from './models/MediaTypeModel';
|
import type { MediaTypeModel } from './models/MediaTypeModel';
|
||||||
import { PropertyMapper } from './settings/PropertyMapper';
|
import { PropertyMapper } from './settings/PropertyMapper';
|
||||||
import { PropertyMapping, PropertyMappingModel } from './settings/PropertyMapping';
|
import { PropertyMapping, PropertyMappingModel } from './settings/PropertyMapping';
|
||||||
|
|
@ -123,7 +123,7 @@ export default class MediaDbPlugin extends Plugin {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!checking) {
|
if (!checking) {
|
||||||
this.updateActiveNote(false);
|
void this.updateActiveNote(false);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
|
|
@ -136,7 +136,7 @@ export default class MediaDbPlugin extends Plugin {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!checking) {
|
if (!checking) {
|
||||||
this.updateActiveNote(true);
|
void this.updateActiveNote(true);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
|
|
@ -150,7 +150,7 @@ export default class MediaDbPlugin extends Plugin {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!checking) {
|
if (!checking) {
|
||||||
this.createLinkWithSearchModal();
|
void this.createLinkWithSearchModal();
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
|
|
@ -213,7 +213,7 @@ export default class MediaDbPlugin extends Plugin {
|
||||||
apiSearchResults = apiSearchResults.filter(x => types.contains(x.type));
|
apiSearchResults = apiSearchResults.filter(x => types.contains(x.type));
|
||||||
|
|
||||||
let selectResults: MediaTypeModel[];
|
let selectResults: MediaTypeModel[];
|
||||||
let proceed: boolean = false;
|
const proceed: boolean = false;
|
||||||
|
|
||||||
while (!proceed) {
|
while (!proceed) {
|
||||||
selectResults =
|
selectResults =
|
||||||
|
|
@ -247,7 +247,7 @@ export default class MediaDbPlugin extends Plugin {
|
||||||
}
|
}
|
||||||
|
|
||||||
let selectResults: MediaTypeModel[];
|
let selectResults: MediaTypeModel[];
|
||||||
let proceed: boolean = false;
|
const proceed: boolean = false;
|
||||||
|
|
||||||
while (!proceed) {
|
while (!proceed) {
|
||||||
selectResults =
|
selectResults =
|
||||||
|
|
@ -322,9 +322,7 @@ export default class MediaDbPlugin extends Plugin {
|
||||||
|
|
||||||
const fileContent = await this.generateMediaDbNoteContents(mediaTypeModel, options);
|
const fileContent = await this.generateMediaDbNoteContents(mediaTypeModel, options);
|
||||||
|
|
||||||
if (!options.folder) {
|
options.folder ??= await this.mediaTypeManager.getFolder(mediaTypeModel, this.app);
|
||||||
options.folder = await this.mediaTypeManager.getFolder(mediaTypeModel, this.app);
|
|
||||||
}
|
|
||||||
|
|
||||||
const targetFile = await this.createNote(this.mediaTypeManager.getFileName(mediaTypeModel), fileContent, options);
|
const targetFile = await this.createNote(this.mediaTypeManager.getFileName(mediaTypeModel), fileContent, options);
|
||||||
|
|
||||||
|
|
@ -347,7 +345,7 @@ export default class MediaDbPlugin extends Plugin {
|
||||||
if (mediaTypeModel.image && typeof mediaTypeModel.image === 'string' && mediaTypeModel.image.startsWith('http')) {
|
if (mediaTypeModel.image && typeof mediaTypeModel.image === 'string' && mediaTypeModel.image.startsWith('http')) {
|
||||||
try {
|
try {
|
||||||
const imageUrl = mediaTypeModel.image;
|
const imageUrl = mediaTypeModel.image;
|
||||||
const imageExt = imageUrl.split('.').pop()?.split(/\#|\?/)[0] || 'jpg';
|
const imageExt = imageUrl.split('.').pop()?.split(/#|\?/)[0] ?? 'jpg';
|
||||||
const imageFileName = `${replaceIllegalFileNameCharactersInString(`${mediaTypeModel.type}_${mediaTypeModel.title} (${mediaTypeModel.year})`)}.${imageExt}`;
|
const imageFileName = `${replaceIllegalFileNameCharactersInString(`${mediaTypeModel.type}_${mediaTypeModel.title} (${mediaTypeModel.year})`)}.${imageExt}`;
|
||||||
const imagePath = normalizePath(`${this.settings.imageFolder}/${imageFileName}`);
|
const imagePath = normalizePath(`${this.settings.imageFolder}/${imageFileName}`);
|
||||||
|
|
||||||
|
|
@ -441,7 +439,7 @@ export default class MediaDbPlugin extends Plugin {
|
||||||
|
|
||||||
// Update updated front matter with entries from the old front matter, if it isn't defined in the new front matter
|
// Update updated front matter with entries from the old front matter, if it isn't defined in the new front matter
|
||||||
Object.keys(previousMetadata).forEach(key => {
|
Object.keys(previousMetadata).forEach(key => {
|
||||||
const value = previousMetadata[key];
|
const value: unknown = previousMetadata[key];
|
||||||
|
|
||||||
if (!frontMatter[key] && value) {
|
if (!frontMatter[key] && value) {
|
||||||
frontMatter[key] = value;
|
frontMatter[key] = value;
|
||||||
|
|
@ -450,17 +448,9 @@ export default class MediaDbPlugin extends Plugin {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure that id, type, and dataSource are defined
|
// Ensure that id, type, and dataSource are defined
|
||||||
if (!frontMatter.id) {
|
frontMatter.id ??= mediaTypeModel.id;
|
||||||
frontMatter.id = mediaTypeModel.id;
|
frontMatter.type ??= mediaTypeModel.type;
|
||||||
}
|
frontMatter.dataSource ??= mediaTypeModel.dataSource;
|
||||||
|
|
||||||
if (!frontMatter.type) {
|
|
||||||
frontMatter.type = mediaTypeModel.type;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!frontMatter.dataSource) {
|
|
||||||
frontMatter.dataSource = mediaTypeModel.dataSource;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.settings.enableTemplaterIntegration && hasTemplaterPlugin(this.app)) {
|
if (this.settings.enableTemplaterIntegration && hasTemplaterPlugin(this.app)) {
|
||||||
// Only support stringifyYaml for templater plugin
|
// Only support stringifyYaml for templater plugin
|
||||||
|
|
@ -478,7 +468,7 @@ export default class MediaDbPlugin extends Plugin {
|
||||||
return { fileMetadata: fileMetadata, fileContent: fileContent };
|
return { fileMetadata: fileMetadata, fileContent: fileContent };
|
||||||
}
|
}
|
||||||
|
|
||||||
const attachFileMetadata: any = this.getMetadataFromFileCache(fileToAttach);
|
const attachFileMetadata = this.getMetadataFromFileCache(fileToAttach);
|
||||||
// TODO: better object merging
|
// TODO: better object merging
|
||||||
fileMetadata = Object.assign(attachFileMetadata, fileMetadata);
|
fileMetadata = Object.assign(attachFileMetadata, fileMetadata);
|
||||||
|
|
||||||
|
|
@ -496,7 +486,7 @@ export default class MediaDbPlugin extends Plugin {
|
||||||
return { fileMetadata: fileMetadata, fileContent: fileContent };
|
return { fileMetadata: fileMetadata, fileContent: fileContent };
|
||||||
}
|
}
|
||||||
|
|
||||||
const templateMetadata: Metadata = this.getMetaDataFromFileContent(template);
|
const templateMetadata = this.getMetaDataFromFileContent(template);
|
||||||
// TODO: better object merging
|
// TODO: better object merging
|
||||||
fileMetadata = Object.assign(templateMetadata, fileMetadata);
|
fileMetadata = Object.assign(templateMetadata, fileMetadata);
|
||||||
|
|
||||||
|
|
@ -522,7 +512,7 @@ export default class MediaDbPlugin extends Plugin {
|
||||||
frontMatter = frontMatter.substring(4);
|
frontMatter = frontMatter.substring(4);
|
||||||
frontMatter = frontMatter.substring(0, frontMatter.length - 3);
|
frontMatter = frontMatter.substring(0, frontMatter.length - 3);
|
||||||
|
|
||||||
metadata = parseYaml(frontMatter);
|
metadata = parseYaml(frontMatter) as Metadata;
|
||||||
|
|
||||||
if (!metadata) {
|
if (!metadata) {
|
||||||
metadata = {};
|
metadata = {};
|
||||||
|
|
@ -645,11 +635,11 @@ export default class MediaDbPlugin extends Plugin {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const metadata: any = this.getMetadataFromFileCache(file);
|
const metadata = this.getMetadataFromFileCache(file);
|
||||||
|
|
||||||
const title = metadata[titleFieldName];
|
const title = metadata[titleFieldName];
|
||||||
if (!title) {
|
if (!title || typeof title !== 'string') {
|
||||||
erroredFiles.push({ filePath: file.path, error: `metadata field '${titleFieldName}' not found or empty` });
|
erroredFiles.push({ filePath: file.path, error: `metadata field '${titleFieldName}' not found, empty, or not a string` });
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -715,7 +705,7 @@ export default class MediaDbPlugin extends Plugin {
|
||||||
|
|
||||||
async loadSettings(): Promise<void> {
|
async loadSettings(): Promise<void> {
|
||||||
// console.log(DEFAULT_SETTINGS);
|
// console.log(DEFAULT_SETTINGS);
|
||||||
const diskSettings: MediaDbPluginSettings = await this.loadData();
|
const diskSettings: MediaDbPluginSettings = (await this.loadData()) as MediaDbPluginSettings;
|
||||||
const defaultSettings: MediaDbPluginSettings = getDefaultSettings(this);
|
const defaultSettings: MediaDbPluginSettings = getDefaultSettings(this);
|
||||||
const loadedSettings: MediaDbPluginSettings = Object.assign({}, defaultSettings, diskSettings);
|
const loadedSettings: MediaDbPluginSettings = Object.assign({}, defaultSettings, diskSettings);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ export class ConfirmOverwriteModal extends Modal {
|
||||||
this.onSubmit = onSubmit;
|
this.onSubmit = onSubmit;
|
||||||
}
|
}
|
||||||
|
|
||||||
onOpen() {
|
onOpen(): void {
|
||||||
const { contentEl } = this;
|
const { contentEl } = this;
|
||||||
contentEl.createEl('h2', { text: 'File already exists' });
|
contentEl.createEl('h2', { text: 'File already exists' });
|
||||||
contentEl.createEl('p', { text: `The file "${this.fileName}" already exists. Do you want to overwrite it?` });
|
contentEl.createEl('p', { text: `The file "${this.fileName}" already exists. Do you want to overwrite it?` });
|
||||||
|
|
@ -36,7 +36,7 @@ export class ConfirmOverwriteModal extends Modal {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
onClose() {
|
onClose(): void {
|
||||||
const { contentEl } = this;
|
const { contentEl } = this;
|
||||||
contentEl.empty();
|
contentEl.empty();
|
||||||
this.onSubmit(this.result);
|
this.onSubmit(this.result);
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
import type { ButtonComponent } from 'obsidian';
|
import type { ButtonComponent } from 'obsidian';
|
||||||
import { Modal, Notice, Setting, TextComponent, ToggleComponent } from 'obsidian';
|
import { Modal, Notice, Setting, TextComponent, ToggleComponent } from 'obsidian';
|
||||||
import type MediaDbPlugin from '../main';
|
import type MediaDbPlugin from '../main';
|
||||||
import type { MediaTypeModel } from '../models/MediaTypeModel';
|
|
||||||
import type { AdvancedSearchModalData, AdvancedSearchModalOptions } from '../utils/ModalHelper';
|
import type { AdvancedSearchModalData, AdvancedSearchModalOptions } from '../utils/ModalHelper';
|
||||||
import { ADVANCED_SEARCH_MODAL_DEFAULT_OPTIONS } from '../utils/ModalHelper';
|
import { ADVANCED_SEARCH_MODAL_DEFAULT_OPTIONS } from '../utils/ModalHelper';
|
||||||
|
|
||||||
|
|
@ -39,7 +38,7 @@ export class MediaDbAdvancedSearchModal extends Modal {
|
||||||
|
|
||||||
keyPressCallback(event: KeyboardEvent): void {
|
keyPressCallback(event: KeyboardEvent): void {
|
||||||
if (event.key === 'Enter') {
|
if (event.key === 'Enter') {
|
||||||
this.search();
|
void this.search();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -119,7 +118,7 @@ export class MediaDbAdvancedSearchModal extends Modal {
|
||||||
btn.setButtonText('Ok');
|
btn.setButtonText('Ok');
|
||||||
btn.setCta();
|
btn.setCta();
|
||||||
btn.onClick(() => {
|
btn.onClick(() => {
|
||||||
this.search();
|
void this.search();
|
||||||
});
|
});
|
||||||
btn.buttonEl.addClass('media-db-plugin-button');
|
btn.buttonEl.addClass('media-db-plugin-button');
|
||||||
this.searchBtn = btn;
|
this.searchBtn = btn;
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
import type { ButtonComponent } from 'obsidian';
|
import type { ButtonComponent } from 'obsidian';
|
||||||
import { DropdownComponent, Modal, Notice, Setting, TextComponent } from 'obsidian';
|
import { DropdownComponent, Modal, Notice, Setting, TextComponent } from 'obsidian';
|
||||||
import type MediaDbPlugin from '../main';
|
import type MediaDbPlugin from '../main';
|
||||||
import type { MediaTypeModel } from '../models/MediaTypeModel';
|
|
||||||
import type { IdSearchModalData, IdSearchModalOptions } from '../utils/ModalHelper';
|
import type { IdSearchModalData, IdSearchModalOptions } from '../utils/ModalHelper';
|
||||||
import { ID_SEARCH_MODAL_DEFAULT_OPTIONS } from '../utils/ModalHelper';
|
import { ID_SEARCH_MODAL_DEFAULT_OPTIONS } from '../utils/ModalHelper';
|
||||||
|
|
||||||
|
|
@ -24,7 +23,7 @@ export class MediaDbIdSearchModal extends Modal {
|
||||||
|
|
||||||
this.plugin = plugin;
|
this.plugin = plugin;
|
||||||
this.title = idSearchModalOptions.modalTitle ?? '';
|
this.title = idSearchModalOptions.modalTitle ?? '';
|
||||||
this.selectedApi = idSearchModalOptions.preselectedAPI || plugin.apiManager.apis[0].apiName;
|
this.selectedApi = idSearchModalOptions.preselectedAPI ?? plugin.apiManager.apis[0].apiName;
|
||||||
this.query = '';
|
this.query = '';
|
||||||
this.isBusy = false;
|
this.isBusy = false;
|
||||||
}
|
}
|
||||||
|
|
@ -39,7 +38,7 @@ export class MediaDbIdSearchModal extends Modal {
|
||||||
|
|
||||||
keyPressCallback(event: KeyboardEvent): void {
|
keyPressCallback(event: KeyboardEvent): void {
|
||||||
if (event.key === 'Enter') {
|
if (event.key === 'Enter') {
|
||||||
this.search();
|
void this.search();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -105,7 +104,7 @@ export class MediaDbIdSearchModal extends Modal {
|
||||||
btn.setButtonText('Ok');
|
btn.setButtonText('Ok');
|
||||||
btn.setCta();
|
btn.setCta();
|
||||||
btn.onClick(() => {
|
btn.onClick(() => {
|
||||||
this.search();
|
void this.search();
|
||||||
});
|
});
|
||||||
btn.buttonEl.addClass('media-db-plugin-button');
|
btn.buttonEl.addClass('media-db-plugin-button');
|
||||||
this.searchBtn = btn;
|
this.searchBtn = btn;
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
import type { ButtonComponent } from 'obsidian';
|
|
||||||
import { Component, MarkdownRenderer, Modal, Setting } from 'obsidian';
|
import { Component, MarkdownRenderer, Modal, Setting } from 'obsidian';
|
||||||
import type MediaDbPlugin from 'src/main';
|
import type MediaDbPlugin from 'src/main';
|
||||||
import type { MediaTypeModel } from 'src/models/MediaTypeModel';
|
import type { MediaTypeModel } from 'src/models/MediaTypeModel';
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
import type { ButtonComponent } from 'obsidian';
|
import type { ButtonComponent } from 'obsidian';
|
||||||
import { Modal, Notice, Setting, TextComponent, ToggleComponent } from 'obsidian';
|
import { Modal, Notice, Setting, TextComponent, ToggleComponent } from 'obsidian';
|
||||||
import type MediaDbPlugin from '../main';
|
import type MediaDbPlugin from '../main';
|
||||||
import type { MediaTypeModel } from '../models/MediaTypeModel';
|
|
||||||
import type { MediaType } from '../utils/MediaType';
|
import type { MediaType } from '../utils/MediaType';
|
||||||
import { MEDIA_TYPES } from '../utils/MediaTypeManager';
|
import { MEDIA_TYPES } from '../utils/MediaTypeManager';
|
||||||
import type { SearchModalData, SearchModalOptions } from '../utils/ModalHelper';
|
import type { SearchModalData, SearchModalOptions } from '../utils/ModalHelper';
|
||||||
|
|
@ -42,7 +41,7 @@ export class MediaDbSearchModal extends Modal {
|
||||||
|
|
||||||
keyPressCallback(event: KeyboardEvent): void {
|
keyPressCallback(event: KeyboardEvent): void {
|
||||||
if (event.key === 'Enter') {
|
if (event.key === 'Enter') {
|
||||||
this.search();
|
void this.search();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -131,7 +130,7 @@ export class MediaDbSearchModal extends Modal {
|
||||||
btn.setButtonText('Ok');
|
btn.setButtonText('Ok');
|
||||||
btn.setCta();
|
btn.setCta();
|
||||||
btn.onClick(() => {
|
btn.onClick(() => {
|
||||||
this.search();
|
void this.search();
|
||||||
});
|
});
|
||||||
btn.buttonEl.addClass('media-db-plugin-button');
|
btn.buttonEl.addClass('media-db-plugin-button');
|
||||||
this.searchBtn = btn;
|
this.searchBtn = btn;
|
||||||
|
|
|
||||||
|
|
@ -54,7 +54,7 @@ export abstract class SelectModal<T> extends Modal {
|
||||||
this.scope.register([], 'Enter', () => this.submit());
|
this.scope.register([], 'Enter', () => this.submit());
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract renderElement(value: T, el: HTMLElement): any;
|
abstract renderElement(value: T, el: HTMLElement): void;
|
||||||
|
|
||||||
abstract submit(): void;
|
abstract submit(): void;
|
||||||
|
|
||||||
|
|
@ -76,7 +76,7 @@ export abstract class SelectModal<T> extends Modal {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async onOpen(): Promise<void> {
|
onOpen(): void {
|
||||||
const { contentEl, titleEl } = this;
|
const { contentEl, titleEl } = this;
|
||||||
|
|
||||||
titleEl.createEl('h2', { text: this.title });
|
titleEl.createEl('h2', { text: this.title });
|
||||||
|
|
|
||||||
|
|
@ -43,7 +43,7 @@ export class BoardGameModel extends MediaTypeModel {
|
||||||
|
|
||||||
migrateObject(this, obj, this);
|
migrateObject(this, obj, this);
|
||||||
|
|
||||||
if (!obj.hasOwnProperty('userData')) {
|
if (!Object.hasOwn(obj, 'userData')) {
|
||||||
migrateObject(this.userData, obj, this.userData);
|
migrateObject(this.userData, obj, this.userData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -43,7 +43,7 @@ export class BookModel extends MediaTypeModel {
|
||||||
|
|
||||||
migrateObject(this, obj, this);
|
migrateObject(this, obj, this);
|
||||||
|
|
||||||
if (!obj.hasOwnProperty('userData')) {
|
if (!Object.hasOwn(obj, 'userData')) {
|
||||||
migrateObject(this.userData, obj, this.userData);
|
migrateObject(this.userData, obj, this.userData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -53,7 +53,7 @@ export class ComicMangaModel extends MediaTypeModel {
|
||||||
|
|
||||||
migrateObject(this, obj, this);
|
migrateObject(this, obj, this);
|
||||||
|
|
||||||
if (!obj.hasOwnProperty('userData')) {
|
if (!Object.hasOwn(obj, 'userData')) {
|
||||||
migrateObject(this.userData, obj, this.userData);
|
migrateObject(this.userData, obj, this.userData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,7 @@ export class GameModel extends MediaTypeModel {
|
||||||
|
|
||||||
migrateObject(this, obj, this);
|
migrateObject(this, obj, this);
|
||||||
|
|
||||||
if (!obj.hasOwnProperty('userData')) {
|
if (!Object.hasOwn(obj, 'userData')) {
|
||||||
migrateObject(this.userData, obj, this.userData);
|
migrateObject(this.userData, obj, this.userData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -51,7 +51,7 @@ export class MovieModel extends MediaTypeModel {
|
||||||
|
|
||||||
migrateObject(this, obj, this);
|
migrateObject(this, obj, this);
|
||||||
|
|
||||||
if (!obj.hasOwnProperty('userData')) {
|
if (!Object.hasOwn(obj, 'userData')) {
|
||||||
migrateObject(this.userData, obj, this.userData);
|
migrateObject(this.userData, obj, this.userData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ export class MusicReleaseModel extends MediaTypeModel {
|
||||||
|
|
||||||
migrateObject(this, obj, this);
|
migrateObject(this, obj, this);
|
||||||
|
|
||||||
if (!obj.hasOwnProperty('userData')) {
|
if (!Object.hasOwn(obj, 'userData')) {
|
||||||
migrateObject(this.userData, obj, this.userData);
|
migrateObject(this.userData, obj, this.userData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -55,7 +55,7 @@ export class SeriesModel extends MediaTypeModel {
|
||||||
|
|
||||||
migrateObject(this, obj, this);
|
migrateObject(this, obj, this);
|
||||||
|
|
||||||
if (!obj.hasOwnProperty('userData')) {
|
if (!Object.hasOwn(obj, 'userData')) {
|
||||||
migrateObject(this.userData, obj, this.userData);
|
migrateObject(this.userData, obj, this.userData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ export class WikiModel extends MediaTypeModel {
|
||||||
|
|
||||||
migrateObject(this, obj, this);
|
migrateObject(this, obj, this);
|
||||||
|
|
||||||
if (!obj.hasOwnProperty('userData')) {
|
if (!Object.hasOwn(obj, 'userData')) {
|
||||||
migrateObject(this.userData, obj, this.userData);
|
migrateObject(this.userData, obj, this.userData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
import type { MediaType } from 'src/utils/MediaType';
|
||||||
import type MediaDbPlugin from '../main';
|
import type MediaDbPlugin from '../main';
|
||||||
import { MEDIA_TYPES } from '../utils/MediaTypeManager';
|
import { MEDIA_TYPES } from '../utils/MediaTypeManager';
|
||||||
import { PropertyMappingOption } from './PropertyMapping';
|
import { PropertyMappingOption } from './PropertyMapping';
|
||||||
|
|
@ -16,7 +17,7 @@ export class PropertyMapper {
|
||||||
* @param obj
|
* @param obj
|
||||||
*/
|
*/
|
||||||
convertObject(obj: Record<string, unknown>): Record<string, unknown> {
|
convertObject(obj: Record<string, unknown>): Record<string, unknown> {
|
||||||
if (!obj.hasOwnProperty('type')) {
|
if (!Object.hasOwn(obj, 'type')) {
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -58,7 +59,7 @@ export class PropertyMapper {
|
||||||
* @param obj
|
* @param obj
|
||||||
*/
|
*/
|
||||||
convertObjectBack(obj: Record<string, unknown>): Record<string, unknown> {
|
convertObjectBack(obj: Record<string, unknown>): Record<string, unknown> {
|
||||||
if (!obj.hasOwnProperty('type')) {
|
if (!Object.hasOwn(obj, 'type')) {
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -66,7 +67,7 @@ export class PropertyMapper {
|
||||||
obj.type = 'comicManga';
|
obj.type = 'comicManga';
|
||||||
console.debug(`MDB | updated metadata type`, obj.type);
|
console.debug(`MDB | updated metadata type`, obj.type);
|
||||||
}
|
}
|
||||||
if (MEDIA_TYPES.contains(obj.type as any)) {
|
if (MEDIA_TYPES.contains(obj.type as MediaType)) {
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,4 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { run } from 'svelte/legacy';
|
|
||||||
|
|
||||||
import { PropertyMappingModel, PropertyMappingOption, propertyMappingOptions } from './PropertyMapping';
|
import { PropertyMappingModel, PropertyMappingOption, propertyMappingOptions } from './PropertyMapping';
|
||||||
import { capitalizeFirstLetter } from '../utils/Utils';
|
import { capitalizeFirstLetter } from '../utils/Utils';
|
||||||
import Icon from './Icon.svelte';
|
import Icon from './Icon.svelte';
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
import type { App } from 'obsidian';
|
import type { App } from 'obsidian';
|
||||||
import { Notice, PluginSettingTab, Setting } from 'obsidian';
|
import { Notice, PluginSettingTab, Setting } from 'obsidian';
|
||||||
|
import type { MediaType } from 'src/utils/MediaType';
|
||||||
import { mount } from 'svelte';
|
import { mount } from 'svelte';
|
||||||
import type MediaDbPlugin from '../main';
|
import type MediaDbPlugin from '../main';
|
||||||
import type { MediaTypeModel } from '../models/MediaTypeModel';
|
import type { MediaTypeModel } from '../models/MediaTypeModel';
|
||||||
|
|
@ -9,7 +10,6 @@ import { PropertyMapping, PropertyMappingModel, PropertyMappingOption } from './
|
||||||
import PropertyMappingModelsComponent from './PropertyMappingModelsComponent.svelte';
|
import PropertyMappingModelsComponent from './PropertyMappingModelsComponent.svelte';
|
||||||
import { FileSuggest } from './suggesters/FileSuggest';
|
import { FileSuggest } from './suggesters/FileSuggest';
|
||||||
import { FolderSuggest } from './suggesters/FolderSuggest';
|
import { FolderSuggest } from './suggesters/FolderSuggest';
|
||||||
import type { MediaType } from 'src/utils/MediaType';
|
|
||||||
|
|
||||||
export interface MediaDbPluginSettings {
|
export interface MediaDbPluginSettings {
|
||||||
OMDbKey: string;
|
OMDbKey: string;
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,11 @@
|
||||||
import type { TAbstractFile } from 'obsidian';
|
import type { TAbstractFile } from 'obsidian';
|
||||||
import { TFile } from 'obsidian';
|
import { AbstractInputSuggest, TFile } from 'obsidian';
|
||||||
import { TextInputSuggest } from './Suggest';
|
|
||||||
|
|
||||||
export class FileSuggest extends TextInputSuggest<TFile> {
|
export class FileSuggest extends AbstractInputSuggest<TFile> {
|
||||||
getSuggestions(inputStr: string): TFile[] {
|
protected getSuggestions(query: string): TFile[] | Promise<TFile[]> {
|
||||||
const abstractFiles = this.app.vault.getAllLoadedFiles();
|
const abstractFiles = this.app.vault.getAllLoadedFiles();
|
||||||
const files: TFile[] = [];
|
const files: TFile[] = [];
|
||||||
const lowerCaseInputStr = inputStr.toLowerCase();
|
const lowerCaseInputStr = query.toLowerCase();
|
||||||
|
|
||||||
abstractFiles.forEach((file: TAbstractFile) => {
|
abstractFiles.forEach((file: TAbstractFile) => {
|
||||||
if (file instanceof TFile && file.name.toLowerCase().contains(lowerCaseInputStr)) {
|
if (file instanceof TFile && file.name.toLowerCase().contains(lowerCaseInputStr)) {
|
||||||
|
|
@ -17,13 +16,7 @@ export class FileSuggest extends TextInputSuggest<TFile> {
|
||||||
return files;
|
return files;
|
||||||
}
|
}
|
||||||
|
|
||||||
renderSuggestion(file: TFile, el: HTMLElement): void {
|
renderSuggestion(value: TFile, el: HTMLElement): void {
|
||||||
el.setText(file.path);
|
el.setText(value.path);
|
||||||
}
|
|
||||||
|
|
||||||
selectSuggestion(file: TFile): void {
|
|
||||||
this.inputEl.value = file.path;
|
|
||||||
this.inputEl.trigger('input');
|
|
||||||
this.close();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,11 @@
|
||||||
// Credits go to Liam's Periodic Notes Plugin: https://github.com/liamcain/obsidian-periodic-notes
|
|
||||||
|
|
||||||
import type { TAbstractFile } from 'obsidian';
|
import type { TAbstractFile } from 'obsidian';
|
||||||
import { TFolder } from 'obsidian';
|
import { AbstractInputSuggest, TFolder } from 'obsidian';
|
||||||
import { TextInputSuggest } from './Suggest';
|
|
||||||
|
|
||||||
export class FolderSuggest extends TextInputSuggest<TFolder> {
|
export class FolderSuggest extends AbstractInputSuggest<TFolder> {
|
||||||
getSuggestions(inputStr: string): TFolder[] {
|
protected getSuggestions(query: string): TFolder[] | Promise<TFolder[]> {
|
||||||
const abstractFiles = this.app.vault.getAllLoadedFiles();
|
const abstractFiles = this.app.vault.getAllLoadedFiles();
|
||||||
const folders: TFolder[] = [];
|
const folders: TFolder[] = [];
|
||||||
const lowerCaseInputStr = inputStr.toLowerCase();
|
const lowerCaseInputStr = query.toLowerCase();
|
||||||
|
|
||||||
abstractFiles.forEach((folder: TAbstractFile) => {
|
abstractFiles.forEach((folder: TAbstractFile) => {
|
||||||
if (folder instanceof TFolder && folder.path.toLowerCase().contains(lowerCaseInputStr)) {
|
if (folder instanceof TFolder && folder.path.toLowerCase().contains(lowerCaseInputStr)) {
|
||||||
|
|
@ -19,13 +16,7 @@ export class FolderSuggest extends TextInputSuggest<TFolder> {
|
||||||
return folders;
|
return folders;
|
||||||
}
|
}
|
||||||
|
|
||||||
renderSuggestion(file: TFolder, el: HTMLElement): void {
|
renderSuggestion(value: TFolder, el: HTMLElement): void {
|
||||||
el.setText(file.path);
|
el.setText(value.path);
|
||||||
}
|
|
||||||
|
|
||||||
selectSuggestion(file: TFolder): void {
|
|
||||||
this.inputEl.value = file.path;
|
|
||||||
this.inputEl.trigger('input');
|
|
||||||
this.close();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,185 +0,0 @@
|
||||||
// Credits go to Liam's Periodic Notes Plugin: https://github.com/liamcain/obsidian-periodic-notes
|
|
||||||
|
|
||||||
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: 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', (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 => {
|
|
||||||
if (!event.isComposing) {
|
|
||||||
this.setSelectedItem(this.selectedItem + 1, true);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return undefined;
|
|
||||||
});
|
|
||||||
|
|
||||||
scope.register([], 'Enter', event => {
|
|
||||||
if (!event.isComposing) {
|
|
||||||
this.useSelectedItem(event);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return undefined;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
onSuggestionClick(event: MouseEvent, el: HTMLElement): void {
|
|
||||||
event.preventDefault();
|
|
||||||
|
|
||||||
const item = this.suggestions.indexOf(el);
|
|
||||||
this.setSelectedItem(item, false);
|
|
||||||
this.useSelectedItem(event);
|
|
||||||
}
|
|
||||||
|
|
||||||
onSuggestionMouseover(_event: MouseEvent, el: HTMLElement): void {
|
|
||||||
const item = this.suggestions.indexOf(el);
|
|
||||||
this.setSelectedItem(item, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
setSuggestions(values: T[]): void {
|
|
||||||
this.containerEl.empty();
|
|
||||||
const suggestionEls: HTMLDivElement[] = [];
|
|
||||||
|
|
||||||
values.forEach(value => {
|
|
||||||
const suggestionEl = this.containerEl.createDiv('suggestion-item');
|
|
||||||
this.owner.renderSuggestion(value, suggestionEl);
|
|
||||||
suggestionEls.push(suggestionEl);
|
|
||||||
});
|
|
||||||
|
|
||||||
this.values = values;
|
|
||||||
this.suggestions = suggestionEls;
|
|
||||||
this.setSelectedItem(0, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
useSelectedItem(event: MouseEvent | KeyboardEvent): void {
|
|
||||||
const currentValue = this.values[this.selectedItem];
|
|
||||||
if (currentValue) {
|
|
||||||
this.owner.selectSuggestion(currentValue, event);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
setSelectedItem(selectedIndex: number, scrollIntoView: boolean): void {
|
|
||||||
const normalizedIndex = this.suggestions.length > 0 ? wrapAround(selectedIndex, this.suggestions.length) : 0;
|
|
||||||
const prevSelectedSuggestion = this.suggestions[this.selectedItem];
|
|
||||||
const selectedSuggestion = this.suggestions[normalizedIndex];
|
|
||||||
|
|
||||||
prevSelectedSuggestion?.removeClass('is-selected');
|
|
||||||
selectedSuggestion?.addClass('is-selected');
|
|
||||||
|
|
||||||
this.selectedItem = normalizedIndex;
|
|
||||||
|
|
||||||
if (scrollIntoView) {
|
|
||||||
selectedSuggestion.scrollIntoView(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export abstract class TextInputSuggest<T> implements ISuggestOwner<T> {
|
|
||||||
protected app: App;
|
|
||||||
protected inputEl: HTMLInputElement;
|
|
||||||
|
|
||||||
private popper?: PopperInstance;
|
|
||||||
private scope: Scope;
|
|
||||||
private suggestEl: HTMLElement;
|
|
||||||
private suggest: Suggest<T>;
|
|
||||||
|
|
||||||
constructor(app: App, inputEl: HTMLInputElement) {
|
|
||||||
this.app = app;
|
|
||||||
this.inputEl = inputEl;
|
|
||||||
this.scope = new Scope();
|
|
||||||
|
|
||||||
this.suggestEl = createDiv('suggestion-container');
|
|
||||||
const suggestion = this.suggestEl.createDiv('suggestion');
|
|
||||||
this.suggest = new Suggest(this, suggestion, this.scope);
|
|
||||||
|
|
||||||
this.scope.register([], 'Escape', this.close.bind(this));
|
|
||||||
|
|
||||||
this.inputEl.addEventListener('input', this.onInputChanged.bind(this));
|
|
||||||
this.inputEl.addEventListener('focus', this.onInputChanged.bind(this));
|
|
||||||
this.inputEl.addEventListener('blur', this.close.bind(this));
|
|
||||||
this.suggestEl.on('mousedown', '.suggestion-container', (event: MouseEvent) => {
|
|
||||||
event.preventDefault();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
onInputChanged(): void {
|
|
||||||
const inputStr = this.inputEl.value;
|
|
||||||
const suggestions = this.getSuggestions(inputStr);
|
|
||||||
|
|
||||||
if (suggestions.length > 0) {
|
|
||||||
this.suggest.setSuggestions(suggestions);
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
||||||
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
|
|
||||||
(this.app as any).keymap.pushScope(this.scope);
|
|
||||||
|
|
||||||
container.appendChild(this.suggestEl);
|
|
||||||
this.popper = createPopper(inputEl, this.suggestEl, {
|
|
||||||
placement: 'bottom-start',
|
|
||||||
modifiers: [
|
|
||||||
{
|
|
||||||
name: 'sameWidth',
|
|
||||||
enabled: true,
|
|
||||||
fn: ({ state, instance }): void => {
|
|
||||||
// Note: positioning needs to be calculated twice -
|
|
||||||
// first pass - positioning it according to the width of the popper
|
|
||||||
// second pass - position it with the width bound to the reference element
|
|
||||||
// we need to early exit to avoid an infinite loop
|
|
||||||
const targetWidth = `${state.rects.reference.width}px`;
|
|
||||||
if (state.styles.popper.width === targetWidth) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
state.styles.popper.width = targetWidth;
|
|
||||||
instance.update();
|
|
||||||
},
|
|
||||||
phase: 'beforeWrite',
|
|
||||||
requires: ['computeStyles'],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
close(): void {
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
||||||
(this.app as any).keymap.popScope(this.scope);
|
|
||||||
|
|
||||||
this.suggest.setSuggestions([]);
|
|
||||||
this.popper?.destroy();
|
|
||||||
this.suggestEl.detach();
|
|
||||||
}
|
|
||||||
|
|
||||||
abstract getSuggestions(inputStr: string): T[];
|
|
||||||
|
|
||||||
abstract renderSuggestion(item: T, el: HTMLElement): void;
|
|
||||||
|
|
||||||
abstract selectSuggestion(item: T): void;
|
|
||||||
}
|
|
||||||
|
|
@ -17,9 +17,7 @@ export class DateFormatter {
|
||||||
getPreview(format?: string): string {
|
getPreview(format?: string): string {
|
||||||
const today = moment();
|
const today = moment();
|
||||||
|
|
||||||
if (!format) {
|
format ??= this.toFormat;
|
||||||
format = this.toFormat;
|
|
||||||
}
|
|
||||||
|
|
||||||
return today.locale(this.locale).format(format);
|
return today.locale(this.locale).format(format);
|
||||||
}
|
}
|
||||||
|
|
@ -35,7 +33,7 @@ export class DateFormatter {
|
||||||
* from the locale of this machine.
|
* from the locale of this machine.
|
||||||
* @returns formatted date string or null if `dateString` is not a valid date
|
* @returns formatted date string or null if `dateString` is not a valid date
|
||||||
*/
|
*/
|
||||||
format(dateString: string, dateFormat?: string, locale: string = 'en'): string | null {
|
format(dateString: string | null | undefined, dateFormat?: string, locale: string = 'en'): string | null {
|
||||||
if (!dateString) {
|
if (!dateString) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
import type { App, TAbstractFile, TFile } from 'obsidian';
|
import type { App, TFile } from 'obsidian';
|
||||||
import { TFolder } from 'obsidian';
|
import { TFolder } from 'obsidian';
|
||||||
import { BoardGameModel } from '../models/BoardGameModel';
|
import { BoardGameModel } from '../models/BoardGameModel';
|
||||||
import { BookModel } from '../models/BookModel';
|
import { BookModel } from '../models/BookModel';
|
||||||
import { GameModel } from '../models/GameModel';
|
|
||||||
import { ComicMangaModel } from '../models/ComicMangaModel';
|
import { ComicMangaModel } from '../models/ComicMangaModel';
|
||||||
|
import { GameModel } from '../models/GameModel';
|
||||||
import type { MediaTypeModel } from '../models/MediaTypeModel';
|
import type { MediaTypeModel } from '../models/MediaTypeModel';
|
||||||
import { MovieModel } from '../models/MovieModel';
|
import { MovieModel } from '../models/MovieModel';
|
||||||
import { MusicReleaseModel } from '../models/MusicReleaseModel';
|
import { MusicReleaseModel } from '../models/MusicReleaseModel';
|
||||||
|
|
@ -104,9 +104,7 @@ export class MediaTypeManager {
|
||||||
async getFolder(mediaTypeModel: MediaTypeModel, app: App): Promise<TFolder> {
|
async getFolder(mediaTypeModel: MediaTypeModel, app: App): Promise<TFolder> {
|
||||||
let folderPath = this.mediaFolderMap.get(mediaTypeModel.getMediaType());
|
let folderPath = this.mediaFolderMap.get(mediaTypeModel.getMediaType());
|
||||||
|
|
||||||
if (!folderPath) {
|
folderPath ??= `/`;
|
||||||
folderPath = `/`;
|
|
||||||
}
|
|
||||||
// console.log(folderPath);
|
// console.log(folderPath);
|
||||||
|
|
||||||
if (!(await app.vault.adapter.exists(folderPath))) {
|
if (!(await app.vault.adapter.exists(folderPath))) {
|
||||||
|
|
@ -115,7 +113,7 @@ export class MediaTypeManager {
|
||||||
const folder = app.vault.getAbstractFileByPath(folderPath);
|
const folder = app.vault.getAbstractFileByPath(folderPath);
|
||||||
|
|
||||||
if (!(folder instanceof TFolder)) {
|
if (!(folder instanceof TFolder)) {
|
||||||
throw Error(`Expected ${folder} to be instance of TFolder`);
|
throw Error(`Expected ${folder?.path} to be instance of TFolder`);
|
||||||
}
|
}
|
||||||
|
|
||||||
return folder;
|
return folder;
|
||||||
|
|
@ -127,7 +125,7 @@ export class MediaTypeManager {
|
||||||
* @param obj
|
* @param obj
|
||||||
* @param mediaType
|
* @param mediaType
|
||||||
*/
|
*/
|
||||||
createMediaTypeModelFromMediaType(obj: any, mediaType: MediaType): MediaTypeModel {
|
createMediaTypeModelFromMediaType(obj: object, mediaType: MediaType): MediaTypeModel {
|
||||||
if (mediaType === MediaType.Movie) {
|
if (mediaType === MediaType.Movie) {
|
||||||
return new MovieModel(obj);
|
return new MovieModel(obj);
|
||||||
} else if (mediaType === MediaType.Series) {
|
} else if (mediaType === MediaType.Series) {
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import type { TFile, TFolder, App } from 'obsidian';
|
import type { TFile, TFolder, App } from 'obsidian';
|
||||||
|
import { requestUrl } from 'obsidian';
|
||||||
import type { MediaTypeModel } from '../models/MediaTypeModel';
|
import type { MediaTypeModel } from '../models/MediaTypeModel';
|
||||||
|
|
||||||
export const pluginName: string = 'obsidian-media-db-plugin';
|
export const pluginName: string = 'obsidian-media-db-plugin';
|
||||||
|
|
@ -42,7 +43,8 @@ function replaceTag(match: string, mediaTypeModel: MediaTypeModel, ignoreUndefin
|
||||||
return ignoreUndefined ? '' : '{{ INVALID TEMPLATE TAG - object undefined }}';
|
return ignoreUndefined ? '' : '{{ INVALID TEMPLATE TAG - object undefined }}';
|
||||||
}
|
}
|
||||||
|
|
||||||
return obj;
|
// eslint-disable-next-line @typescript-eslint/no-base-to-string
|
||||||
|
return obj?.toString() ?? 'null';
|
||||||
} else if (parts.length === 2) {
|
} else if (parts.length === 2) {
|
||||||
const operator = parts[0];
|
const operator = parts[0];
|
||||||
|
|
||||||
|
|
@ -58,7 +60,8 @@ function replaceTag(match: string, mediaTypeModel: MediaTypeModel, ignoreUndefin
|
||||||
if (!Array.isArray(obj)) {
|
if (!Array.isArray(obj)) {
|
||||||
return '{{ INVALID TEMPLATE TAG - operator LIST is only applicable on an array }}';
|
return '{{ INVALID TEMPLATE TAG - operator LIST is only applicable on an array }}';
|
||||||
}
|
}
|
||||||
return obj.map((e: any) => `- ${e}`).join('\n');
|
|
||||||
|
return obj.map((e: unknown) => `- ${e}`).join('\n');
|
||||||
} else if (operator === 'ENUM') {
|
} else if (operator === 'ENUM') {
|
||||||
if (!Array.isArray(obj)) {
|
if (!Array.isArray(obj)) {
|
||||||
return '{{ INVALID TEMPLATE TAG - operator ENUM is only applicable on an array }}';
|
return '{{ INVALID TEMPLATE TAG - operator ENUM is only applicable on an array }}';
|
||||||
|
|
@ -68,12 +71,16 @@ function replaceTag(match: string, mediaTypeModel: MediaTypeModel, ignoreUndefin
|
||||||
if (!Array.isArray(obj)) {
|
if (!Array.isArray(obj)) {
|
||||||
return '{{ INVALID TEMPLATE TAG - operator FIRST is only applicable on an array }}';
|
return '{{ INVALID TEMPLATE TAG - operator FIRST is only applicable on an array }}';
|
||||||
}
|
}
|
||||||
return obj[0];
|
|
||||||
|
const first = obj[0] as unknown;
|
||||||
|
return first?.toString() ?? 'null';
|
||||||
} else if (operator === 'LAST') {
|
} else if (operator === 'LAST') {
|
||||||
if (!Array.isArray(obj)) {
|
if (!Array.isArray(obj)) {
|
||||||
return '{{ INVALID TEMPLATE TAG - operator LAST is only applicable on an array }}';
|
return '{{ INVALID TEMPLATE TAG - operator LAST is only applicable on an array }}';
|
||||||
}
|
}
|
||||||
return obj[obj.length - 1];
|
|
||||||
|
const last = obj[obj.length - 1] as unknown;
|
||||||
|
return last?.toString() ?? 'null';
|
||||||
}
|
}
|
||||||
|
|
||||||
return `{{ INVALID TEMPLATE TAG - unknown operator ${operator} }}`;
|
return `{{ INVALID TEMPLATE TAG - unknown operator ${operator} }}`;
|
||||||
|
|
@ -82,12 +89,12 @@ function replaceTag(match: string, mediaTypeModel: MediaTypeModel, ignoreUndefin
|
||||||
return '{{ INVALID TEMPLATE TAG }}';
|
return '{{ INVALID TEMPLATE TAG }}';
|
||||||
}
|
}
|
||||||
|
|
||||||
function traverseMetaData(path: string[], mediaTypeModel: MediaTypeModel): any {
|
function traverseMetaData(path: string[], mediaTypeModel: MediaTypeModel): unknown {
|
||||||
let o: any = mediaTypeModel;
|
let o: unknown = mediaTypeModel;
|
||||||
|
|
||||||
for (const part of path) {
|
for (const part of path) {
|
||||||
if (o !== undefined) {
|
if (o !== undefined) {
|
||||||
o = o[part];
|
o = (o as Record<string, unknown>)[part];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -195,9 +202,9 @@ export interface CreateNoteOptions {
|
||||||
folder?: TFolder;
|
folder?: TFolder;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function migrateObject<T extends object>(object: T, oldData: any, defaultData: T): void {
|
export function migrateObject<T extends object>(object: T, oldData: Record<string, unknown>, defaultData: T): void {
|
||||||
for (const key in object) {
|
for (const key in object) {
|
||||||
object[key] = oldData.hasOwnProperty(key) ? oldData[key] : defaultData[key];
|
object[key] = Object.hasOwn(oldData, key) && oldData[key] !== undefined && oldData[key] !== null ? (oldData[key] as T[typeof key]) : defaultData[key];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -215,6 +222,8 @@ export function unCamelCase(str: string): string {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* eslint-disable */
|
||||||
|
|
||||||
export function hasTemplaterPlugin(app: App): boolean {
|
export function hasTemplaterPlugin(app: App): boolean {
|
||||||
const templater = (app as any).plugins.plugins['templater-obsidian'];
|
const templater = (app as any).plugins.plugins['templater-obsidian'];
|
||||||
|
|
||||||
|
|
@ -224,15 +233,17 @@ export function hasTemplaterPlugin(app: App): boolean {
|
||||||
// Copied from https://github.com/anpigon/obsidian-book-search-plugin
|
// Copied from https://github.com/anpigon/obsidian-book-search-plugin
|
||||||
// Licensed under the MIT license. Copyright (c) 2020 Jake Runzer
|
// Licensed under the MIT license. Copyright (c) 2020 Jake Runzer
|
||||||
export async function useTemplaterPluginInFile(app: App, file: TFile): Promise<void> {
|
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'];
|
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);
|
await templater.templater.overwrite_file_commands(file);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* eslint-enable */
|
||||||
|
|
||||||
export type ModelToData<T> = {
|
export type ModelToData<T> = {
|
||||||
[K in keyof T as T[K] extends Function ? never : K]?: T[K];
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
|
||||||
|
[K in keyof T as T[K] extends Function ? never : K]?: T[K] | null;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Checks if a given URL points to an existing image (status 200), or returns false for 404/other errors.
|
// Checks if a given URL points to an existing image (status 200), or returns false for 404/other errors.
|
||||||
|
|
@ -250,3 +261,38 @@ export async function imageUrlExists(url: string): Promise<boolean> {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function isTruthy<T>(value: T): value is Exclude<T, false | 0 | '' | null | undefined> {
|
||||||
|
return Boolean(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wraps Obsidians `requestUrl` in a fetch like API.
|
||||||
|
*/
|
||||||
|
export async function obsidianFetch(input: Request): Promise<Response> {
|
||||||
|
const obs_headers: Record<string, string> = {};
|
||||||
|
input.headers.forEach((header, value) => {
|
||||||
|
obs_headers[header] = value;
|
||||||
|
});
|
||||||
|
|
||||||
|
const res = await requestUrl({
|
||||||
|
url: input.url,
|
||||||
|
method: input.method,
|
||||||
|
headers: obs_headers,
|
||||||
|
throw: false, // Do not throw on error, handle it manually
|
||||||
|
});
|
||||||
|
|
||||||
|
const responseHeaders: Headers = new Headers();
|
||||||
|
for (const [key, value] of Object.entries(res.headers)) {
|
||||||
|
responseHeaders.append(key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
ok: res.status >= 200 && res.status < 300,
|
||||||
|
status: res.status,
|
||||||
|
headers: responseHeaders,
|
||||||
|
// eslint-disable-next-line
|
||||||
|
json: async () => res.json,
|
||||||
|
text: async () => res.text,
|
||||||
|
} as Response;
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue