Merge pull request #183 from ltctceplrm/api-toggle

Restored and updated the api toggle + added a download option for poster images
This commit is contained in:
Moritz Jung 2025-05-20 12:05:56 +02:00 committed by GitHub
commit 917f7ab411
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
18 changed files with 219 additions and 133 deletions

View file

@ -1,6 +1,6 @@
## Obsidian Media DB Plugin ## Obsidian Media DB Plugin
A plugin that can query multiple APIs for movies, series, anime, manga, games, music and wiki articles, and import them into your vault. A plugin that can query multiple APIs for movies, series, anime, manga, books, games, music and wiki articles, and import them into your vault.
### Features ### Features
@ -36,6 +36,10 @@ Available variables that can be used in template tags are the same variables fro
I also published my own templates [here](https://github.com/mProjectsCode/obsidian-media-db-templates). I also published my own templates [here](https://github.com/mProjectsCode/obsidian-media-db-templates).
#### Download poster images
Allows you to automatically download the poster images for a new media, ensuring offline access. The images are saved as `type_title (year)` e.g. `movie_The Perfect Storm (2000)` with a user chosen save location.
#### Metadata field customization #### Metadata field customization
Allows you to rename the metadata fields this plugin generates through mappings. Allows you to rename the metadata fields this plugin generates through mappings.
@ -113,7 +117,6 @@ Now you select the result you want and the plugin will cast it's magic and creat
### Currently supported APIs: ### Currently supported APIs:
| Name | Description | Supported formats | Authentification | Rate limiting | SFW filter support | | Name | Description | Supported formats | Authentification | Rate limiting | SFW filter support |
| ---------------------------------------------------- | ------------------------------------------------------------------------------------------------- | ----------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------ | | ---------------------------------------------------- | ------------------------------------------------------------------------------------------------- | ----------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------ |
| [Jikan](https://jikan.moe/) | Jikan is an API that uses [My Anime List](https://myanimelist.net) and offers metadata for anime. | series, movies, specials, OVAs, manga, manwha, novels | No | 60 per minute and 3 per second | Yes | | [Jikan](https://jikan.moe/) | Jikan is an API that uses [My Anime List](https://myanimelist.net) and offers metadata for anime. | series, movies, specials, OVAs, manga, manwha, novels | No | 60 per minute and 3 per second | Yes |
@ -124,7 +127,7 @@ Now you select the result you want and the plugin will cast it's magic and creat
| [Open Library](https://openlibrary.org) | The OpenLibrary API offers metadata for books | books | No | Cover access is rate-limited when not using CoverID or OLID by max 100 requests/IP every 5 minutes. This plugin uses OLID so there shouldn't be a rate limit. | No | | [Open Library](https://openlibrary.org) | The OpenLibrary API offers metadata for books | books | No | Cover access is rate-limited when not using CoverID or OLID by max 100 requests/IP every 5 minutes. This plugin uses OLID so there shouldn't be a rate limit. | No |
| [Moby Games](https://www.mobygames.com) | The Moby Games API offers metadata for games for all platforms | games | Yes, by making an account [here](https://www.mobygames.com/user/register/). NOTE: As of September 2024 the API key is no longer free so consider using Giant Bomb or steam instead | API requests are limited to 360 per hour (one every ten seconds). In addition, requests should be made no more frequently than one per second. | No | | [Moby Games](https://www.mobygames.com) | The Moby Games API offers metadata for games for all platforms | games | Yes, by making an account [here](https://www.mobygames.com/user/register/). NOTE: As of September 2024 the API key is no longer free so consider using Giant Bomb or steam instead | API requests are limited to 360 per hour (one every ten seconds). In addition, requests should be made no more frequently than one per second. | No |
| [Giant Bomb](https://www.giantbomb.com) | The Giant Bomb API offers metadata for games for all platforms | games | Yes, by making an account [here](https://www.giantbomb.com/login-signup/) | API requests are limited to 200 requests per resource, per hour. In addition, they implement velocity detection to prevent malicious use. If too many requests are made per second, you may receive temporary blocks to resources. | No | | [Giant Bomb](https://www.giantbomb.com) | The Giant Bomb API offers metadata for games for all platforms | games | Yes, by making an account [here](https://www.giantbomb.com/login-signup/) | API requests are limited to 200 requests per resource, per hour. In addition, they implement velocity detection to prevent malicious use. If too many requests are made per second, you may receive temporary blocks to resources. | No |
| Comic Vine | The Comic Vine API offers metadata for comic books | comicbooks | Yes, by making an account [here](https://comicvine.gamespot.com/login-signup/) and going to the [api section](https://comicvine.gamespot.com/api/) of the site | 200 requests per resource, per hour. There is also a velocity detection to prevent malicious use. If too many requests are made per second, you may receive temporary blocks to resources. | No | Comic Vine | The Comic Vine API offers metadata for comic books | comicbooks | Yes, by making an account [here](https://comicvine.gamespot.com/login-signup/) and going to the [api section](https://comicvine.gamespot.com/api/) of the site | 200 requests per resource, per hour. There is also a velocity detection to prevent malicious use. If too many requests are made per second, you may receive temporary blocks to resources. | No |
#### Notes #### Notes
@ -149,6 +152,10 @@ Now you select the result you want and the plugin will cast it's magic and creat
- e.g. for "Rogue One" the URL looks like this `https://www.imdb.com/title/tt3748528/` so the ID is `tt3748528` - e.g. for "Rogue One" the URL looks like this `https://www.imdb.com/title/tt3748528/` so the ID is `tt3748528`
- [MusicBrainz](https://musicbrainz.org/) - [MusicBrainz](https://musicbrainz.org/)
- the id of a release is not easily accessible, you are better off just searching by title - the id of a release is not easily accessible, you are better off just searching by title
- the search is generally for albums but you can have a more granular search like so:
- search for albums by a specific `artist:"Lady Gaga" AND primarytype:"album"`
- search for a specific album by a specific artist `artist:"Lady Gaga" AND primarytype:"album" AND releasegroup:"The Fame"`
- search for a specific entry (song or album) by a specific `artist:"Lady Gaga" AND releasegroup:"Poker face"`
- [Wikipedia](https://en.wikipedia.org/wiki/Main_Page) - [Wikipedia](https://en.wikipedia.org/wiki/Main_Page)
- [here](https://en.wikipedia.org/wiki/Wikipedia:Finding_a_Wikidata_ID) is a guide to finding the Wikipedia ID for an article - [here](https://en.wikipedia.org/wiki/Wikipedia:Finding_a_Wikidata_ID) is a guide to finding the Wikipedia ID for an article
- [Steam](https://store.steampowered.com/) - [Steam](https://store.steampowered.com/)

View file

@ -10,7 +10,7 @@ export abstract class APIModel {
plugin!: MediaDbPlugin; plugin!: MediaDbPlugin;
/** /**
* This function should query the api and return a list of matches. The matches should be caped at 20. * This function should query the api and return a list of matches. The matches should be capped at 20.
* *
* @param title the title to query for * @param title the title to query for
*/ */
@ -18,14 +18,11 @@ export abstract class APIModel {
abstract getById(id: string): Promise<MediaTypeModel>; abstract getById(id: string): Promise<MediaTypeModel>;
abstract getDisabledMediaTypes(): MediaType[];
hasType(type: MediaType): boolean { hasType(type: MediaType): boolean {
// if ( const disabledMediaTypes = this.getDisabledMediaTypes();
// this.types.contains(type) && return this.types.includes(type) && !disabledMediaTypes.includes(type);
// (Boolean((this.plugin.settings.apiToggle as any)?.[this.apiName]?.[type]) === true || (this.plugin.settings.apiToggle as any)?.[this.apiName]?.[type] === undefined)
// ) {
// return true;
// }
return this.types.contains(type);
} }
hasTypeOverlap(types: MediaType[]): boolean { hasTypeOverlap(types: MediaType[]): boolean {

View file

@ -117,4 +117,7 @@ export class BoardGameGeekAPI extends APIModel {
}, },
}); });
} }
getDisabledMediaTypes(): MediaType[] {
return this.plugin.settings.BoardgameGeekAPI_disabledMediaTypes as MediaType[];
}
} }

View file

@ -95,4 +95,7 @@ export class ComicVineAPI extends APIModel {
}, },
}); });
} }
getDisabledMediaTypes(): MediaType[] {
return this.plugin.settings.ComicVineAPI_disabledMediaTypes as MediaType[];
}
} }

View file

@ -106,4 +106,7 @@ export class GiantBombAPI extends APIModel {
}, },
}); });
} }
getDisabledMediaTypes(): MediaType[] {
return this.plugin.settings.GiantBombAPI_disabledMediaTypes as MediaType[];
}
} }

View file

@ -195,4 +195,7 @@ 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[] {
return this.plugin.settings.MALAPI_disabledMediaTypes as MediaType[];
}
} }

View file

@ -126,4 +126,7 @@ export class MALAPIManga extends APIModel {
}, },
}); });
} }
getDisabledMediaTypes(): MediaType[] {
return this.plugin.settings.MALAPIManga_disabledMediaTypes as MediaType[];
}
} }

View file

@ -107,4 +107,7 @@ export class MobyGamesAPI extends APIModel {
}, },
}); });
} }
getDisabledMediaTypes(): MediaType[] {
return this.plugin.settings.MobyGamesAPI_disabledMediaTypes as MediaType[];
}
} }

View file

@ -99,4 +99,7 @@ export class MusicBrainzAPI extends APIModel {
}, },
}); });
} }
getDisabledMediaTypes(): MediaType[] {
return this.plugin.settings.MusicBrainzAPI_disabledMediaTypes as MediaType[];
}
} }

View file

@ -151,7 +151,7 @@ export class OMDbAPI extends APIModel {
duration: result.Runtime ?? 'unknown', 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 ?? '', image: result.Poster ? result.Poster.replace('_SX300', '_SX600') : '',
released: true, released: true,
streamingServices: [], streamingServices: [],
@ -181,7 +181,7 @@ export class OMDbAPI extends APIModel {
duration: result.Runtime ?? 'unknown', 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 ?? '', image: result.Poster ? result.Poster.replace('_SX300', '_SX600') : '',
released: true, released: true,
streamingServices: [], streamingServices: [],
@ -209,7 +209,7 @@ export class OMDbAPI extends APIModel {
publishers: [], publishers: [],
genres: result.Genre?.split(', ') ?? [], genres: result.Genre?.split(', ') ?? [],
onlineRating: Number.parseFloat(result.imdbRating ?? 0), onlineRating: Number.parseFloat(result.imdbRating ?? 0),
image: result.Poster ?? '', image: result.Poster ? 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) ?? 'unknown',
@ -223,4 +223,8 @@ export class OMDbAPI extends APIModel {
throw new Error(`MDB | Unknown media type for id ${id}`); throw new Error(`MDB | Unknown media type for id ${id}`);
} }
getDisabledMediaTypes(): MediaType[] {
return this.plugin.settings.OMDbAPI_disabledMediaTypes as MediaType[];
}
} }

View file

@ -89,4 +89,7 @@ export class OpenLibraryAPI extends APIModel {
}, },
}); });
} }
getDisabledMediaTypes(): MediaType[] {
return this.plugin.settings.OpenLibraryAPI_disabledMediaTypes as MediaType[];
}
} }

View file

@ -4,6 +4,7 @@ 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 { imageUrlExists } from '../../utils/Utils';
export class SteamAPI extends APIModel { export class SteamAPI extends APIModel {
plugin: MediaDbPlugin; plugin: MediaDbPlugin;
@ -85,6 +86,16 @@ export class SteamAPI extends APIModel {
// console.debug(result); // console.debug(result);
// Check if a poster version of the image exists, else use the header image
const imageUrl = `https://steamcdn-a.akamaihd.net/steam/apps/${result.steam_appid}/library_600x900_2x.jpg`;
const exists = await imageUrlExists(imageUrl);
let finalimageurl;
if (exists) {
finalimageurl = imageUrl;
} else {
finalimageurl = result.header_image ?? '';
}
return new GameModel({ return new GameModel({
type: MediaType.Game, type: MediaType.Game,
title: result.name, title: result.name,
@ -98,7 +109,7 @@ export class SteamAPI extends APIModel {
publishers: result.publishers, publishers: result.publishers,
genres: result.genres?.map((x: any) => x.description) ?? [], genres: result.genres?.map((x: any) => x.description) ?? [],
onlineRating: Number.parseFloat(result.metacritic?.score ?? 0), onlineRating: Number.parseFloat(result.metacritic?.score ?? 0),
image: result.header_image ?? '', 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) ?? 'unknown',
@ -109,4 +120,7 @@ export class SteamAPI extends APIModel {
}, },
}); });
} }
getDisabledMediaTypes(): MediaType[] {
return this.plugin.settings.SteamAPI_disabledMediaTypes as MediaType[];
}
} }

View file

@ -79,4 +79,7 @@ export class WikipediaAPI extends APIModel {
userData: {}, userData: {},
}); });
} }
getDisabledMediaTypes(): MediaType[] {
return this.plugin.settings.WikipediaAPI_disabledMediaTypes as MediaType[];
}
} }

View file

@ -1,4 +1,5 @@
import { MarkdownView, Notice, parseYaml, Plugin, stringifyYaml, TFile, TFolder } from 'obsidian'; import { MarkdownView, Notice, parseYaml, Plugin, stringifyYaml, TFile, TFolder } from 'obsidian';
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';
@ -219,13 +220,17 @@ export default class MediaDbPlugin extends Plugin {
(await this.modalHelper.openSelectModal({ elements: apiSearchResults }, async selectModalData => { (await this.modalHelper.openSelectModal({ elements: apiSearchResults }, async selectModalData => {
return await this.queryDetails(selectModalData.selected); return await this.queryDetails(selectModalData.selected);
})) ?? []; })) ?? [];
if (!selectResults) { if (!selectResults || selectResults.length < 1) {
return; return;
} }
proceed = await this.modalHelper.openPreviewModal({ elements: selectResults }, async previewModalData => { const confirmed = await this.modalHelper.openPreviewModal({ elements: selectResults }, async previewModalData => {
return previewModalData.confirmed; return previewModalData.confirmed;
}); });
if (!confirmed) {
return;
}
break;
} }
await this.createMediaDbNotes(selectResults!); await this.createMediaDbNotes(selectResults!);
@ -249,13 +254,17 @@ export default class MediaDbPlugin extends Plugin {
(await this.modalHelper.openSelectModal({ elements: apiSearchResults }, async selectModalData => { (await this.modalHelper.openSelectModal({ elements: apiSearchResults }, async selectModalData => {
return await this.queryDetails(selectModalData.selected); return await this.queryDetails(selectModalData.selected);
})) ?? []; })) ?? [];
if (!selectResults) { if (!selectResults || selectResults.length < 1) {
return; return;
} }
proceed = await this.modalHelper.openPreviewModal({ elements: selectResults }, async previewModalData => { const confirmed = await this.modalHelper.openPreviewModal({ elements: selectResults }, async previewModalData => {
return previewModalData.confirmed; return previewModalData.confirmed;
}); });
if (!confirmed) {
return;
}
break;
} }
await this.createMediaDbNotes(selectResults!); await this.createMediaDbNotes(selectResults!);
@ -307,6 +316,33 @@ export default class MediaDbPlugin extends Plugin {
options.openNote = this.settings.openNoteInNewTab; options.openNote = this.settings.openNoteInNewTab;
if (mediaTypeModel.image && typeof mediaTypeModel.image === 'string' && mediaTypeModel.image.startsWith('http')) {
if (this.settings.imageDownload) {
try {
const imageurl = mediaTypeModel.image;
const imageext = imageurl.split('.').pop()?.split(/\#|\?/)[0] || 'jpg';
const imagefileName = `${replaceIllegalFileNameCharactersInString(`${mediaTypeModel.type}_${mediaTypeModel.title} (${mediaTypeModel.year})`)}.${imageext}`;
const imagepath = normalizePath(`${this.settings.imageFolder}/${imagefileName}`);
if (!this.app.vault.getAbstractFileByPath(this.settings.imageFolder)) {
await this.app.vault.createFolder(this.settings.imageFolder);
}
if (!this.app.vault.getAbstractFileByPath(imagepath)) {
const response = await requestUrl({ url: imageurl, method: 'GET' });
await this.app.vault.createBinary(imagepath, response.arrayBuffer);
}
// Update model to use local image path
mediaTypeModel.image = `[[${imagepath}]]`;
} catch (e) {
console.warn('MDB | Failed to download image:', e);
}
} else {
mediaTypeModel.image = mediaTypeModel.image;
}
}
const fileContent = await this.generateMediaDbNoteContents(mediaTypeModel, options); const fileContent = await this.generateMediaDbNoteContents(mediaTypeModel, options);
if (!options.folder) { if (!options.folder) {

View file

@ -9,6 +9,7 @@ export abstract class MediaTypeModel {
dataSource: string; dataSource: string;
url: string; url: string;
id: string; id: string;
image?: string;
userData: object; userData: object;
@ -21,6 +22,8 @@ export abstract class MediaTypeModel {
this.dataSource = ''; this.dataSource = '';
this.url = ''; this.url = '';
this.id = ''; this.id = '';
this.image = '';
this.userData = {}; this.userData = {};
} }

View file

@ -4,11 +4,12 @@ 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';
import { MEDIA_TYPES } from '../utils/MediaTypeManager'; import { MEDIA_TYPES } from '../utils/MediaTypeManager';
import { fragWithHTML } from '../utils/Utils'; import { fragWithHTML, unCamelCase } from '../utils/Utils';
import { PropertyMapping, PropertyMappingModel, PropertyMappingOption } from './PropertyMapping'; import { PropertyMapping, PropertyMappingModel, PropertyMappingOption } from './PropertyMapping';
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;
@ -21,24 +22,17 @@ export interface MediaDbPluginSettings {
openNoteInNewTab: boolean; openNoteInNewTab: boolean;
useDefaultFrontMatter: boolean; useDefaultFrontMatter: boolean;
enableTemplaterIntegration: boolean; enableTemplaterIntegration: boolean;
// TODO: disabled for now, as i currently don't have the time to fix this from the original PR that introduced it (#133) OMDbAPI_disabledMediaTypes: MediaType[];
// apiToggle: { MALAPI_disabledMediaTypes: MediaType[];
// OMDbAPI: { MALAPIManga_disabledMediaTypes: MediaType[];
// movie: boolean; ComicVineAPI_disabledMediaTypes: MediaType[];
// series: boolean; SteamAPI_disabledMediaTypes: MediaType[];
// game: boolean; MobyGamesAPI_disabledMediaTypes: MediaType[];
// }; GiantBombAPI_disabledMediaTypes: MediaType[];
// MALAPI: { WikipediaAPI_disabledMediaTypes: MediaType[];
// movie: boolean; BoardgameGeekAPI_disabledMediaTypes: MediaType[];
// series: boolean; MusicBrainzAPI_disabledMediaTypes: MediaType[];
// }; OpenLibraryAPI_disabledMediaTypes: MediaType[];
// SteamAPI: {
// game: boolean;
// };
// MobyGamesAPI: {
// game: boolean;
// };
// };
movieTemplate: string; movieTemplate: string;
seriesTemplate: string; seriesTemplate: string;
mangaTemplate: string; mangaTemplate: string;
@ -75,6 +69,8 @@ export interface MediaDbPluginSettings {
boardgameFolder: string; boardgameFolder: string;
bookFolder: string; bookFolder: string;
imageDownload: boolean;
imageFolder: string;
propertyMappingModels: PropertyMappingModel[]; propertyMappingModels: PropertyMappingModel[];
} }
@ -89,23 +85,17 @@ const DEFAULT_SETTINGS: MediaDbPluginSettings = {
openNoteInNewTab: true, openNoteInNewTab: true,
useDefaultFrontMatter: true, useDefaultFrontMatter: true,
enableTemplaterIntegration: false, enableTemplaterIntegration: false,
// apiToggle: { OMDbAPI_disabledMediaTypes: [],
// OMDbAPI: { MALAPI_disabledMediaTypes: [],
// movie: true, MALAPIManga_disabledMediaTypes: [],
// series: true, ComicVineAPI_disabledMediaTypes: [],
// game: true, SteamAPI_disabledMediaTypes: [],
// }, MobyGamesAPI_disabledMediaTypes: [],
// MALAPI: { GiantBombAPI_disabledMediaTypes: [],
// movie: true, WikipediaAPI_disabledMediaTypes: [],
// series: true, BoardgameGeekAPI_disabledMediaTypes: [],
// }, MusicBrainzAPI_disabledMediaTypes: [],
// SteamAPI: { OpenLibraryAPI_disabledMediaTypes: [],
// game: true,
// },
// MobyGamesAPI: {
// game: true,
// },
// },
movieTemplate: '', movieTemplate: '',
seriesTemplate: '', seriesTemplate: '',
mangaTemplate: '', mangaTemplate: '',
@ -142,6 +132,8 @@ const DEFAULT_SETTINGS: MediaDbPluginSettings = {
boardgameFolder: 'Media DB/boardgames', boardgameFolder: 'Media DB/boardgames',
bookFolder: 'Media DB/books', bookFolder: 'Media DB/books',
imageDownload: false,
imageFolder: 'Media DB/images',
propertyMappingModels: [], propertyMappingModels: [],
}; };
@ -310,82 +302,72 @@ export class MediaDbSettingTab extends PluginSettingTab {
}); });
}); });
// containerEl.createEl('h3', { text: 'APIs per media type' }); new Setting(containerEl)
// containerEl.createEl('h5', { text: 'Movies' }); .setName('Download images')
// new Setting(containerEl) .setDesc('Downloads images for new notes in the folder below')
// .setName('OMDb API') .addToggle(cb => {
// .setDesc('Use OMDb API for movies.') cb.setValue(this.plugin.settings.imageDownload).onChange(data => {
// .addToggle(cb => { this.plugin.settings.imageDownload = data;
// cb.setValue(this.plugin.settings.apiToggle.OMDbAPI.movie).onChange(data => { void this.plugin.saveSettings();
// this.plugin.settings.apiToggle.OMDbAPI.movie = data; });
// void this.plugin.saveSettings(); });
// });
// }); new Setting(containerEl)
// new Setting(containerEl) .setName('Image folder')
// .setName('MAL API') .setDesc('Where downloaded images should be stored.')
// .setDesc('Use MAL API for movies.') .addSearch(cb => {
// .addToggle(cb => { new FolderSuggest(this.app, cb.inputEl);
// cb.setValue(this.plugin.settings.apiToggle.MALAPI.movie).onChange(data => { cb.setPlaceholder(DEFAULT_SETTINGS.imageFolder)
// this.plugin.settings.apiToggle.MALAPI.movie = data; .setValue(this.plugin.settings.imageFolder)
// void this.plugin.saveSettings(); .onChange(data => {
// }); this.plugin.settings.imageFolder = data;
// }); void this.plugin.saveSettings();
// containerEl.createEl('h5', { text: 'Series' }); });
// new Setting(containerEl) });
// .setName('OMDb API')
// .setDesc('Use OMDb API for series.') // Create a map to store APIs for each media type
// .addToggle(cb => { const mediaTypeApiMap = new Map<MediaType, string[]>();
// cb.setValue(this.plugin.settings.apiToggle.OMDbAPI.series).onChange(data => {
// this.plugin.settings.apiToggle.OMDbAPI.series = data; // Populate the map with APIs for each media type dynamically
// void this.plugin.saveSettings(); for (const api of this.plugin.apiManager.apis) {
// }); for (const mediaType of api.types) {
// }); if (!mediaTypeApiMap.has(mediaType)) {
// new Setting(containerEl) mediaTypeApiMap.set(mediaType, []);
// .setName('MAL API') }
// .setDesc('Use MAL API for series.') mediaTypeApiMap.get(mediaType)!.push(api.apiName);
// .addToggle(cb => { }
// cb.setValue(this.plugin.settings.apiToggle.MALAPI.series).onChange(data => { }
// this.plugin.settings.apiToggle.MALAPI.series = data;
// void this.plugin.saveSettings(); // Filter out media types with only one API
// }); const filteredMediaTypes = Array.from(mediaTypeApiMap.entries()).filter(([_, apis]) => apis.length > 1);
// });
// containerEl.createEl('h5', { text: 'Games' }); // Dynamically create settings based on the filtered media types and their APIs
// new Setting(containerEl) for (const [mediaType, apis] of filteredMediaTypes) {
// .setName('OMDb API') new Setting(containerEl).setName(`Select APIs for ${unCamelCase(mediaType)}`).setHeading();
// .setDesc('Use OMDb API for games.') for (const apiName of apis) {
// .addToggle(cb => { const api = this.plugin.apiManager.apis.find(api => api.apiName === apiName);
// cb.setValue(this.plugin.settings.apiToggle.OMDbAPI.game).onChange(data => { if (api) {
// this.plugin.settings.apiToggle.OMDbAPI.game = data; const disabledMediaTypes = api.getDisabledMediaTypes();
// void this.plugin.saveSettings(); new Setting(containerEl)
// }); .setName(apiName)
// }); .setDesc(`Use ${apiName} API for ${unCamelCase(mediaType)}.`)
// new Setting(containerEl) .addToggle(cb => {
// .setName('Steam API') cb.setValue(!disabledMediaTypes.includes(mediaType)).onChange(data => {
// .setDesc('Use OMDb API for games.') if (data) {
// .addToggle(cb => { const index = disabledMediaTypes.indexOf(mediaType);
// cb.setValue(this.plugin.settings.apiToggle.SteamAPI.game).onChange(data => { if (index > -1) {
// this.plugin.settings.apiToggle.SteamAPI.game = data; disabledMediaTypes.splice(index, 1);
// void this.plugin.saveSettings(); }
// }); } else {
// }); disabledMediaTypes.push(mediaType);
// new Setting(containerEl) }
// .setName('MobyGames API') void this.plugin.saveSettings();
// .setDesc('Use MobyGames API for games.') });
// .addToggle(cb => { });
// cb.setValue(this.plugin.settings.apiToggle.MobyGamesAPI.game).onChange(data => { }
// this.plugin.settings.apiToggle.MobyGamesAPI.game = data; }
// void this.plugin.saveSettings(); }
// });
// });
// new Setting(containerEl)
// .setName('Giantbomb API')
// .setDesc('Use Giantbomb API for games.')
// .addToggle(cb => {
// cb.setValue(this.plugin.settings.apiToggle.GiantBombAPI.game).onChange(data => {
// this.plugin.settings.apiToggle.GiantBombAPI.game = data;
// void this.plugin.saveSettings();
// });
// });
new Setting(containerEl).setName('New file location').setHeading(); new Setting(containerEl).setName('New file location').setHeading();
// region new file location // region new file location
new Setting(containerEl) new Setting(containerEl)

View file

@ -505,12 +505,12 @@ export class ModalHelper {
console.warn(previewModalResult.error); console.warn(previewModalResult.error);
new Notice(previewModalResult.error.toString()); new Notice(previewModalResult.error.toString());
previewModal.close(); previewModal.close();
return true; return false;
} }
if (previewModalResult.code === ModalResultCode.CLOSE) { if (previewModalResult.code === ModalResultCode.CLOSE) {
// modal is already being closed // modal is already being closed
return true; return false;
} }
try { try {

View file

@ -234,3 +234,19 @@ export async function useTemplaterPluginInFile(app: App, file: TFile): Promise<v
export type ModelToData<T> = { export type ModelToData<T> = {
[K in keyof T as T[K] extends Function ? never : K]?: T[K]; [K in keyof T as T[K] extends Function ? never : K]?: T[K];
}; };
// Checks if a given URL points to an existing image (status 200), or returns false for 404/other errors.
export async function imageUrlExists(url: string): Promise<boolean> {
try {
// @ts-ignore
const response = await requestUrl({
url,
method: 'HEAD',
throw: false,
});
return response.status === 200;
} catch {
return false;
}
}