From 3befc82b8771e05dd4732dd50a4fb4b7dae00509 Mon Sep 17 00:00:00 2001 From: ltctceplrm <14954927+ltctceplrm@users.noreply.github.com> Date: Tue, 11 Feb 2025 15:45:20 +0100 Subject: [PATCH] Added comic book support - Created a new model for comic books - Added comic vine support --- src/api/apis/ComicVineAPI.ts | 97 +++++++++++++++++++++++++++++++++++ src/main.ts | 2 + src/models/ComicBookModel.ts | 67 ++++++++++++++++++++++++ src/utils/MediaType.ts | 1 + src/utils/MediaTypeManager.ts | 7 +++ 5 files changed, 174 insertions(+) create mode 100644 src/api/apis/ComicVineAPI.ts create mode 100644 src/models/ComicBookModel.ts diff --git a/src/api/apis/ComicVineAPI.ts b/src/api/apis/ComicVineAPI.ts new file mode 100644 index 0000000..02cfffc --- /dev/null +++ b/src/api/apis/ComicVineAPI.ts @@ -0,0 +1,97 @@ +import { requestUrl } from 'obsidian'; +import { ComicBookModel } from 'src/models/ComicBookModel'; +import type MediaDbPlugin from '../../main'; +import type { MediaTypeModel } from '../../models/MediaTypeModel'; +import { MediaType } from '../../utils/MediaType'; +import { APIModel } from '../APIModel'; + +export class ComicVineAPI extends APIModel { + plugin: MediaDbPlugin; + + constructor(plugin: MediaDbPlugin) { + super(); + + this.plugin = plugin; + this.apiName = 'ComicVineAPI'; + this.apiDescription = 'A free API for comic books.'; + this.apiUrl = 'https://comicvine.gamespot.com/api'; + this.types = [MediaType.ComicBook]; + } + + async searchByTitle(title: string): Promise { + console.log(`MDB | api "${this.apiName}" queried by Title`); + + const searchUrl = `${this.apiUrl}/search/?api_key=${this.plugin.settings.ComicVineKey}&format=json&resources=volume&query=${encodeURIComponent(title)}`; + const fetchData = await requestUrl({ + url: searchUrl, + }); + // console.debug(fetchData); + if (fetchData.status !== 200) { + throw Error(`MDB | Received status code ${fetchData.status} from ${this.apiName}.`); + } + + const data = await fetchData.json; + // console.debug(data); + const ret: MediaTypeModel[] = []; + for (const result of data.results) { + ret.push( + new ComicBookModel({ + title: result.name, + englishTitle: result.name, + year: result.start_year, + dataSource: this.apiName, + id: result.id, + publisher: result.publisher.name ?? 'unknown', + }), + ); + } + + return ret; + } + + async getById(id: string): Promise { + console.log(`MDB | api "${this.apiName}" queried by ID`); + + const searchUrl = `${this.apiUrl}/volume/4050-${encodeURIComponent(id)}/?api_key=${this.plugin.settings.ComicVineKey}&format=json`; + const fetchData = await requestUrl({ + url: searchUrl, + }); + + console.debug(fetchData); + + if (fetchData.status !== 200) { + throw Error(`MDB | Received status code ${fetchData.status} from ${this.apiName}.`); + } + + const data = await fetchData.json; + // console.debug(data); + const result = data.results; + + return new ComicBookModel({ + type: MediaType.ComicBook, + title: result.name, + plot: result.deck, + year: result.start_year ?? '', + dataSource: this.apiName, + url: result.site_detail_url, + id: result.id, + + creators: result.people?.map((x: any) => x.name) ?? [], + issues: result.count_of_issues, + onlineRating: result.score ?? 0, + image: result.image?.original_url ?? '', + + released: true, + publisher: result.publisher.name ?? '', + publishedFrom: result.start_year ?? 'unknown', + publishedTo: 'unknown', + status: result.status, + + userData: { + read: false, + lastRead: '', + personalRating: 0, + }, + }); + } +} diff --git a/src/main.ts b/src/main.ts index 625a1ed..a6b5b2f 100644 --- a/src/main.ts +++ b/src/main.ts @@ -11,6 +11,7 @@ import { OMDbAPI } from './api/apis/OMDbAPI'; import { OpenLibraryAPI } from './api/apis/OpenLibraryAPI'; import { SteamAPI } from './api/apis/SteamAPI'; import { WikipediaAPI } from './api/apis/WikipediaAPI'; +import { ComicVineAPI } from './api/apis/ComicVineAPI'; import { MediaDbFolderImportModal } from './modals/MediaDbFolderImportModal'; import type { MediaTypeModel } from './models/MediaTypeModel'; import { PropertyMapper } from './settings/PropertyMapper'; @@ -53,6 +54,7 @@ export default class MediaDbPlugin extends Plugin { this.apiManager.registerAPI(new SteamAPI(this)); this.apiManager.registerAPI(new BoardGameGeekAPI(this)); this.apiManager.registerAPI(new OpenLibraryAPI(this)); + this.apiManager.registerAPI(new ComicVineAPI(this)); this.apiManager.registerAPI(new MobyGamesAPI(this)); this.apiManager.registerAPI(new GiantBombAPI(this)); // this.apiManager.registerAPI(new LocGovAPI(this)); // TODO: parse data diff --git a/src/models/ComicBookModel.ts b/src/models/ComicBookModel.ts new file mode 100644 index 0000000..a3990df --- /dev/null +++ b/src/models/ComicBookModel.ts @@ -0,0 +1,67 @@ +import { MediaType } from '../utils/MediaType'; +import type { ModelToData } from '../utils/Utils'; +import { mediaDbTag, migrateObject } from '../utils/Utils'; +import { MediaTypeModel } from './MediaTypeModel'; + +export type ComicBookData = ModelToData; + +export class ComicBookModel extends MediaTypeModel { + creators: string[]; + publisher: string; + plot: string; + issues: number; + image: string; + onlineRating: number; + status: string; + released: boolean; + publishedFrom: string; + publishedTo: string; + + userData: { + read: boolean; + lastRead: string; + personalRating: number; + }; + + constructor(obj: ComicBookData) { + super(); + + this.creators = []; + this.publisher = ''; + this.plot = ''; + this.issues = 0; + this.image = ''; + this.onlineRating = 0; + + this.released = false; + this.status = ''; + this.publishedFrom = ''; + this.publishedTo = ''; + + this.userData = { + read: false, + lastRead: '', + personalRating: 0, + }; + + migrateObject(this, obj, this); + + if (!obj.hasOwnProperty('userData')) { + migrateObject(this.userData, obj, this.userData); + } + + this.type = this.getMediaType(); + } + + getTags(): string[] { + return [mediaDbTag, 'comicbook']; + } + + getMediaType(): MediaType { + return MediaType.ComicBook; + } + + getSummary(): string { + return this.englishTitle + ' (' + this.year + ') - ' + this.publisher; + } +} diff --git a/src/utils/MediaType.ts b/src/utils/MediaType.ts index dd39945..8844e11 100644 --- a/src/utils/MediaType.ts +++ b/src/utils/MediaType.ts @@ -7,4 +7,5 @@ export enum MediaType { Wiki = 'wiki', BoardGame = 'boardgame', Book = 'book', + ComicBook = 'comicBook', } diff --git a/src/utils/MediaTypeManager.ts b/src/utils/MediaTypeManager.ts index 531da63..8eee245 100644 --- a/src/utils/MediaTypeManager.ts +++ b/src/utils/MediaTypeManager.ts @@ -4,6 +4,7 @@ import { BoardGameModel } from '../models/BoardGameModel'; import { BookModel } from '../models/BookModel'; import { GameModel } from '../models/GameModel'; import { MangaModel } from '../models/MangaModel'; +import { ComicBookModel } from '../models/ComicBookModel'; import type { MediaTypeModel } from '../models/MediaTypeModel'; import { MovieModel } from '../models/MovieModel'; import { MusicReleaseModel } from '../models/MusicReleaseModel'; @@ -22,6 +23,7 @@ export const MEDIA_TYPES: MediaType[] = [ MediaType.MusicRelease, MediaType.BoardGame, MediaType.Book, + MediaType.ComicBook, ]; export class MediaTypeManager { @@ -45,6 +47,7 @@ export class MediaTypeManager { this.mediaFileNameTemplateMap.set(MediaType.MusicRelease, settings.musicReleaseFileNameTemplate); this.mediaFileNameTemplateMap.set(MediaType.BoardGame, settings.boardgameFileNameTemplate); this.mediaFileNameTemplateMap.set(MediaType.Book, settings.bookFileNameTemplate); + this.mediaFileNameTemplateMap.set(MediaType.ComicBook, settings.bookFileNameTemplate); this.mediaTemplateMap = new Map(); this.mediaTemplateMap.set(MediaType.Movie, settings.movieTemplate); @@ -55,6 +58,7 @@ export class MediaTypeManager { this.mediaTemplateMap.set(MediaType.MusicRelease, settings.musicReleaseTemplate); this.mediaTemplateMap.set(MediaType.BoardGame, settings.boardgameTemplate); this.mediaTemplateMap.set(MediaType.Book, settings.bookTemplate); + this.mediaTemplateMap.set(MediaType.ComicBook, settings.bookTemplate); } updateFolders(settings: MediaDbPluginSettings): void { @@ -67,6 +71,7 @@ export class MediaTypeManager { this.mediaFolderMap.set(MediaType.MusicRelease, settings.musicReleaseFolder); this.mediaFolderMap.set(MediaType.BoardGame, settings.boardgameFolder); this.mediaFolderMap.set(MediaType.Book, settings.bookFolder); + this.mediaFolderMap.set(MediaType.ComicBook, settings.bookFolder); } getFileName(mediaTypeModel: MediaTypeModel): string { @@ -144,6 +149,8 @@ export class MediaTypeManager { return new BoardGameModel(obj); } else if (mediaType === MediaType.Book) { return new BookModel(obj); + } else if (mediaType === MediaType.ComicBook) { + return new ComicBookModel(obj); } throw new Error(`Unknown media type: ${mediaType}`);