From a07e549ea4e86c3d8374e1d98046f9ab8861b1f4 Mon Sep 17 00:00:00 2001 From: ltctceplrm <14954927+ltctceplrm@users.noreply.github.com> Date: Tue, 11 Feb 2025 21:51:08 +0100 Subject: [PATCH] Merged comic book models with manga models into comicmanga model Updated both MALAPI Manga and ComicVine API to be more consistent with eachother. --- src/api/apis/ComicVineAPI.ts | 18 +++++---- src/api/apis/MALAPIManga.ts | 16 ++++---- src/main.ts | 24 ++++++----- src/models/ComicMangaModel.ts | 74 ++++++++++++++++++++++++++++++++++ src/settings/PropertyMapper.ts | 7 +++- src/settings/Settings.ts | 58 ++++---------------------- src/utils/MediaType.ts | 3 +- src/utils/MediaTypeManager.ts | 21 ++++------ 8 files changed, 128 insertions(+), 93 deletions(-) create mode 100644 src/models/ComicMangaModel.ts diff --git a/src/api/apis/ComicVineAPI.ts b/src/api/apis/ComicVineAPI.ts index 51815c2..c45da4e 100644 --- a/src/api/apis/ComicVineAPI.ts +++ b/src/api/apis/ComicVineAPI.ts @@ -1,5 +1,5 @@ import { requestUrl } from 'obsidian'; -import { ComicBookModel } from 'src/models/ComicBookModel'; +import { ComicMangaModel } from 'src/models/ComicMangaModel'; import type MediaDbPlugin from '../../main'; import type { MediaTypeModel } from '../../models/MediaTypeModel'; import { MediaType } from '../../utils/MediaType'; @@ -15,7 +15,7 @@ export class ComicVineAPI extends APIModel { this.apiName = 'ComicVineAPI'; this.apiDescription = 'A free API for comic books.'; this.apiUrl = 'https://comicvine.gamespot.com/api'; - this.types = [MediaType.ComicBook]; + this.types = [MediaType.ComicManga]; } async searchByTitle(title: string): Promise { @@ -35,7 +35,7 @@ export class ComicVineAPI extends APIModel { const ret: MediaTypeModel[] = []; for (const result of data.results) { ret.push( - new ComicBookModel({ + new ComicMangaModel({ title: result.name, englishTitle: result.name, year: result.start_year, @@ -67,18 +67,20 @@ export class ComicVineAPI extends APIModel { // console.debug(data); const result = data.results; - return new ComicBookModel({ - type: MediaType.ComicBook, + return new ComicMangaModel({ + type: MediaType.ComicManga, title: result.name, + englishTitle: result.name, + alternateTitles: result.aliases, 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, + + authors: result.people?.map((x: any) => x.name) ?? [], + chapters: result.count_of_issues, image: result.image?.original_url ?? '', released: true, diff --git a/src/api/apis/MALAPIManga.ts b/src/api/apis/MALAPIManga.ts index 95040e6..bd99476 100644 --- a/src/api/apis/MALAPIManga.ts +++ b/src/api/apis/MALAPIManga.ts @@ -1,5 +1,5 @@ import type MediaDbPlugin from '../../main'; -import { MangaModel } from '../../models/MangaModel'; +import { ComicMangaModel } from '../../models/ComicMangaModel'; import type { MediaTypeModel } from '../../models/MediaTypeModel'; import { MediaType } from '../../utils/MediaType'; import { APIModel } from '../APIModel'; @@ -15,7 +15,7 @@ export class MALAPIManga extends APIModel { this.apiName = 'MALAPI Manga'; this.apiDescription = 'A free API for Manga. Some results may take a long time to load.'; this.apiUrl = 'https://jikan.moe/'; - this.types = [MediaType.Manga]; + this.types = [MediaType.ComicManga]; this.typeMappings = new Map(); this.typeMappings.set('manga', 'manga'); this.typeMappings.set('manhwa', 'manhwa'); @@ -45,7 +45,7 @@ export class MALAPIManga extends APIModel { for (const result of data.data) { const type = this.typeMappings.get(result.type?.toLowerCase()); ret.push( - new MangaModel({ + new ComicMangaModel({ subType: type, title: result.title, plot: result.synopsis, @@ -69,8 +69,8 @@ export class MALAPIManga extends APIModel { status: result.status, userData: { - watched: false, - lastWatched: '', + read: false, + lastRead: '', personalRating: 0, }, }), @@ -95,7 +95,7 @@ export class MALAPIManga extends APIModel { const result = data.data; const type = this.typeMappings.get(result.type?.toLowerCase()); - return new MangaModel({ + return new ComicMangaModel({ subType: type, title: result.title, englishTitle: result.title_english ?? result.title, @@ -120,8 +120,8 @@ export class MALAPIManga extends APIModel { status: result.status, userData: { - watched: false, - lastWatched: '', + read: false, + lastRead: '', personalRating: 0, }, }); diff --git a/src/main.ts b/src/main.ts index a6b5b2f..f7e4f5f 100644 --- a/src/main.ts +++ b/src/main.ts @@ -12,6 +12,7 @@ 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 { VNDBAPI } from './api/apis/VNDBAPI'; import { MediaDbFolderImportModal } from './modals/MediaDbFolderImportModal'; import type { MediaTypeModel } from './models/MediaTypeModel'; import { PropertyMapper } from './settings/PropertyMapper'; @@ -57,6 +58,7 @@ export default class MediaDbPlugin extends Plugin { this.apiManager.registerAPI(new ComicVineAPI(this)); this.apiManager.registerAPI(new MobyGamesAPI(this)); this.apiManager.registerAPI(new GiantBombAPI(this)); + this.apiManager.registerAPI(new VNDBAPI(this)); // this.apiManager.registerAPI(new LocGovAPI(this)); // TODO: parse data this.mediaTypeManager = new MediaTypeManager(); @@ -540,35 +542,37 @@ export default class MediaDbPlugin extends Plugin { if (!activeFile) { throw new Error('MDB | there is no active note'); } - + let metadata = this.getMetadataFromFileCache(activeFile); metadata = this.modelPropertyMapper.convertObjectBack(metadata); - + console.debug(`MDB | read metadata`, metadata); - + if (!metadata?.type || !metadata?.dataSource || !metadata?.id) { throw new Error('MDB | active note is not a Media DB entry or is missing metadata'); } - + const validOldMetadata: MediaTypeModelObj = metadata as unknown as MediaTypeModelObj; - + console.debug(`MDB | validOldMetadata`, validOldMetadata); + const oldMediaTypeModel = this.mediaTypeManager.createMediaTypeModelFromMediaType(validOldMetadata, validOldMetadata.type); - // console.debug(oldMediaTypeModel); - + console.debug(`MDB | oldMediaTypeModel created`, oldMediaTypeModel); + let newMediaTypeModel = await this.apiManager.queryDetailedInfoById(validOldMetadata.id, validOldMetadata.dataSource); if (!newMediaTypeModel) { return; } - + newMediaTypeModel = Object.assign(oldMediaTypeModel, newMediaTypeModel.getWithOutUserData()); - // console.debug(newMediaTypeModel); - + console.debug(`MDB | newMediaTypeModel after merge`, newMediaTypeModel); + if (onlyMetadata) { await this.createMediaDbNoteFromModel(newMediaTypeModel, { attachFile: activeFile, folder: activeFile.parent ?? undefined, openNote: true }); } else { await this.createMediaDbNoteFromModel(newMediaTypeModel, { attachTemplate: true, folder: activeFile.parent ?? undefined, openNote: true }); } } + async createEntriesFromFolder(folder: TFolder): Promise { const erroredFiles: { filePath: string; error: string }[] = []; diff --git a/src/models/ComicMangaModel.ts b/src/models/ComicMangaModel.ts new file mode 100644 index 0000000..21bd282 --- /dev/null +++ b/src/models/ComicMangaModel.ts @@ -0,0 +1,74 @@ +import { MediaType } from '../utils/MediaType'; +import type { ModelToData } from '../utils/Utils'; +import { mediaDbTag, migrateObject } from '../utils/Utils'; +import { MediaTypeModel } from './MediaTypeModel'; + +export type ComicMangaData = ModelToData; + +export class ComicMangaModel extends MediaTypeModel { + plot: string; + alternateTitles: string[]; + genres: string[]; + authors: string[]; + chapters: number; + volumes: number; + onlineRating: number; + image: string; + + released: boolean; + status: string; + publishers: string[]; + publishedFrom: string; + publishedTo: string; + + userData: { + read: boolean; + lastRead: string; + personalRating: number; + }; + + constructor(obj: ComicMangaData) { + super(); + + this.plot = ''; + this.alternateTitles = []; + this.genres = []; + this.authors = []; + this.chapters = 0; + this.volumes = 0; + this.onlineRating = 0; + this.image = ''; + + this.released = false; + this.status = ''; + this.publishers = []; + 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, 'manga', 'light-novel', 'comicbook']; + } + + getMediaType(): MediaType { + return MediaType.ComicManga; + } + + getSummary(): string { + return this.title + ' (' + this.year + ')'; + } +} \ No newline at end of file diff --git a/src/settings/PropertyMapper.ts b/src/settings/PropertyMapper.ts index b5644dc..53ad049 100644 --- a/src/settings/PropertyMapper.ts +++ b/src/settings/PropertyMapper.ts @@ -62,7 +62,12 @@ export class PropertyMapper { return obj; } - if (MEDIA_TYPES.contains(obj.type as any)) { + + if (obj.type === "manga") { + obj.type = "comicManga"; + console.debug(`MDB | updated metadata type`, obj.type); + } + if (MEDIA_TYPES.contains(obj.type as any)) { return obj; } diff --git a/src/settings/Settings.ts b/src/settings/Settings.ts index ec9e27f..b02994e 100644 --- a/src/settings/Settings.ts +++ b/src/settings/Settings.ts @@ -47,7 +47,6 @@ export interface MediaDbPluginSettings { musicReleaseTemplate: string; boardgameTemplate: string; bookTemplate: string; - comicbookTemplate: string; movieFileNameTemplate: string; seriesFileNameTemplate: string; @@ -57,7 +56,6 @@ export interface MediaDbPluginSettings { musicReleaseFileNameTemplate: string; boardgameFileNameTemplate: string; bookFileNameTemplate: string; - comicbookFileNameTemplate: string; moviePropertyConversionRules: string; seriesPropertyConversionRules: string; @@ -67,7 +65,6 @@ export interface MediaDbPluginSettings { musicReleasePropertyConversionRules: string; boardgamePropertyConversionRules: string; bookPropertyConversionRules: string; - comicbookPropertyConversionRules: string; movieFolder: string; seriesFolder: string; @@ -77,7 +74,6 @@ export interface MediaDbPluginSettings { musicReleaseFolder: string; boardgameFolder: string; bookFolder: string; - comicbookFolder: string; propertyMappingModels: PropertyMappingModel[]; } @@ -118,7 +114,6 @@ const DEFAULT_SETTINGS: MediaDbPluginSettings = { musicReleaseTemplate: '', boardgameTemplate: '', bookTemplate: '', - comicbookTemplate: '', movieFileNameTemplate: '{{ title }} ({{ year }})', seriesFileNameTemplate: '{{ title }} ({{ year }})', @@ -128,7 +123,6 @@ const DEFAULT_SETTINGS: MediaDbPluginSettings = { musicReleaseFileNameTemplate: '{{ title }} (by {{ ENUM:artists }} - {{ year }})', boardgameFileNameTemplate: '{{ title }} ({{ year }})', bookFileNameTemplate: '{{ title }} ({{ year }})', - comicbookFileNameTemplate: '{{ title }} ({{ year }})', moviePropertyConversionRules: '', seriesPropertyConversionRules: '', @@ -138,17 +132,15 @@ const DEFAULT_SETTINGS: MediaDbPluginSettings = { musicReleasePropertyConversionRules: '', boardgamePropertyConversionRules: '', bookPropertyConversionRules: '', - comicbookPropertyConversionRules: '', movieFolder: 'Media DB/movies', seriesFolder: 'Media DB/series', - mangaFolder: 'Media DB/manga', + mangaFolder: 'Media DB/comics', gameFolder: 'Media DB/games', wikiFolder: 'Media DB/wiki', musicReleaseFolder: 'Media DB/music', boardgameFolder: 'Media DB/boardgames', bookFolder: 'Media DB/books', - comicbookFolder: 'Media DB/comicbooks', propertyMappingModels: [], }; @@ -423,8 +415,8 @@ export class MediaDbSettingTab extends PluginSettingTab { }); new Setting(containerEl) - .setName('Manga folder') - .setDesc('Where newly imported manga should be placed.') + .setName('Comic and manga folder') + .setDesc('Where newly imported comics and manga should be placed.') .addSearch(cb => { new FolderSuggest(this.app, cb.inputEl); cb.setPlaceholder(DEFAULT_SETTINGS.mangaFolder) @@ -498,18 +490,7 @@ export class MediaDbSettingTab extends PluginSettingTab { void this.plugin.saveSettings(); }); }); - new Setting(containerEl) - .setName('Comic Book folder') - .setDesc('Where newly imported comic books should be placed.') - .addSearch(cb => { - new FolderSuggest(this.app, cb.inputEl); - cb.setPlaceholder(DEFAULT_SETTINGS.comicbookFolder) - .setValue(this.plugin.settings.comicbookFolder) - .onChange(data => { - this.plugin.settings.comicbookFolder = data; - void this.plugin.saveSettings(); - }); - }); + // endregion new Setting(containerEl).setName('Template settings').setHeading(); @@ -541,8 +522,8 @@ export class MediaDbSettingTab extends PluginSettingTab { }); new Setting(containerEl) - .setName('Manga template') - .setDesc('Template file to be used when creating a new note for a manga.') + .setName('Manga and Comics template') + .setDesc('Template file to be used when creating a new note for a manga or a comic.') .addSearch(cb => { new FileSuggest(this.app, cb.inputEl); cb.setPlaceholder('Example: mangaTemplate.md') @@ -618,18 +599,6 @@ export class MediaDbSettingTab extends PluginSettingTab { }); }); - new Setting(containerEl) - .setName('Comic Book template') - .setDesc('Template file to be used when creating a new note for a comic book.') - .addSearch(cb => { - new FileSuggest(this.app, cb.inputEl); - cb.setPlaceholder('Example: comicbookTemplate.md') - .setValue(this.plugin.settings.comicbookTemplate) - .onChange(data => { - this.plugin.settings.comicbookTemplate = data; - void this.plugin.saveSettings(); - }); - }); // endregion new Setting(containerEl).setName('File name settings').setHeading(); @@ -659,8 +628,8 @@ export class MediaDbSettingTab extends PluginSettingTab { }); new Setting(containerEl) - .setName('Manga file name template') - .setDesc('Template for the file name used when creating a new note for a manga.') + .setName('Manga and comic file name template') + .setDesc('Template for the file name used when creating a new note for a manga or comic.') .addText(cb => { cb.setPlaceholder(`Example: ${DEFAULT_SETTINGS.mangaFileNameTemplate}`) .setValue(this.plugin.settings.mangaFileNameTemplate) @@ -730,17 +699,6 @@ export class MediaDbSettingTab extends PluginSettingTab { }); }); - new Setting(containerEl) - .setName('Comic Book file name template') - .setDesc('Template for the file name used when creating a new note for a book.') - .addText(cb => { - cb.setPlaceholder(`Example: ${DEFAULT_SETTINGS.comicbookFileNameTemplate}`) - .setValue(this.plugin.settings.comicbookFileNameTemplate) - .onChange(data => { - this.plugin.settings.comicbookFileNameTemplate = data; - void this.plugin.saveSettings(); - }); - }); // endregion // region Property Mappings diff --git a/src/utils/MediaType.ts b/src/utils/MediaType.ts index 8844e11..02d1c2c 100644 --- a/src/utils/MediaType.ts +++ b/src/utils/MediaType.ts @@ -1,11 +1,10 @@ export enum MediaType { Movie = 'movie', Series = 'series', - Manga = 'manga', + ComicManga = 'comicManga', Game = 'game', MusicRelease = 'musicRelease', Wiki = 'wiki', BoardGame = 'boardgame', Book = 'book', - ComicBook = 'comicBook', } diff --git a/src/utils/MediaTypeManager.ts b/src/utils/MediaTypeManager.ts index 8eee245..ec4a5ae 100644 --- a/src/utils/MediaTypeManager.ts +++ b/src/utils/MediaTypeManager.ts @@ -3,8 +3,7 @@ import { TFolder } from 'obsidian'; import { BoardGameModel } from '../models/BoardGameModel'; import { BookModel } from '../models/BookModel'; import { GameModel } from '../models/GameModel'; -import { MangaModel } from '../models/MangaModel'; -import { ComicBookModel } from '../models/ComicBookModel'; +import { ComicMangaModel } from '../models/ComicMangaModel'; import type { MediaTypeModel } from '../models/MediaTypeModel'; import { MovieModel } from '../models/MovieModel'; import { MusicReleaseModel } from '../models/MusicReleaseModel'; @@ -17,13 +16,12 @@ import { replaceTags } from './Utils'; export const MEDIA_TYPES: MediaType[] = [ MediaType.Movie, MediaType.Series, - MediaType.Manga, + MediaType.ComicManga, MediaType.Game, MediaType.Wiki, MediaType.MusicRelease, MediaType.BoardGame, MediaType.Book, - MediaType.ComicBook, ]; export class MediaTypeManager { @@ -41,37 +39,34 @@ export class MediaTypeManager { this.mediaFileNameTemplateMap = new Map(); this.mediaFileNameTemplateMap.set(MediaType.Movie, settings.movieFileNameTemplate); this.mediaFileNameTemplateMap.set(MediaType.Series, settings.seriesFileNameTemplate); - this.mediaFileNameTemplateMap.set(MediaType.Manga, settings.mangaFileNameTemplate); + this.mediaFileNameTemplateMap.set(MediaType.ComicManga, settings.mangaFileNameTemplate); this.mediaFileNameTemplateMap.set(MediaType.Game, settings.gameFileNameTemplate); this.mediaFileNameTemplateMap.set(MediaType.Wiki, settings.wikiFileNameTemplate); 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); this.mediaTemplateMap.set(MediaType.Series, settings.seriesTemplate); - this.mediaTemplateMap.set(MediaType.Manga, settings.mangaTemplate); + this.mediaTemplateMap.set(MediaType.ComicManga, settings.mangaTemplate); this.mediaTemplateMap.set(MediaType.Game, settings.gameTemplate); this.mediaTemplateMap.set(MediaType.Wiki, settings.wikiTemplate); 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 { this.mediaFolderMap = new Map(); this.mediaFolderMap.set(MediaType.Movie, settings.movieFolder); this.mediaFolderMap.set(MediaType.Series, settings.seriesFolder); - this.mediaFolderMap.set(MediaType.Manga, settings.mangaFolder); + this.mediaFolderMap.set(MediaType.ComicManga, settings.mangaFolder); this.mediaFolderMap.set(MediaType.Game, settings.gameFolder); this.mediaFolderMap.set(MediaType.Wiki, settings.wikiFolder); 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 { @@ -137,8 +132,8 @@ export class MediaTypeManager { return new MovieModel(obj); } else if (mediaType === MediaType.Series) { return new SeriesModel(obj); - } else if (mediaType === MediaType.Manga) { - return new MangaModel(obj); + } else if (mediaType === MediaType.ComicManga) { + return new ComicMangaModel(obj); } else if (mediaType === MediaType.Game) { return new GameModel(obj); } else if (mediaType === MediaType.Wiki) { @@ -149,8 +144,6 @@ 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}`);