diff --git a/src/commands/CreateBookFromGoodreadsUrlCommand.ts b/src/commands/CreateBookFromGoodreadsUrlCommand.ts new file mode 100644 index 0000000..d3ee324 --- /dev/null +++ b/src/commands/CreateBookFromGoodreadsUrlCommand.ts @@ -0,0 +1,46 @@ +import { Notice } from "obsidian"; +import { Command } from "./Command"; +import type { Goodreads } from "@data-sources/Goodreads"; +import type { Book } from "@src/types"; + +const GOODREADS_URL_PATTERN = /https:\/\/www.goodreads.com\/book\/show\/(\d+)/; + +export class CreateBookFromGoodreadsUrlCommand extends Command { + constructor( + private readonly goodreads: Goodreads, + private readonly cb: (book: Book) => void | PromiseLike + ) { + super( + "create-book-from-goodreads-url", + "Create Book from Goodreads URL" + ); + } + + async callback() { + const url = await navigator.clipboard.readText(); + const legacyId = parseInt( + GOODREADS_URL_PATTERN.exec(url)?.[1] ?? "", + 10 + ); + + if (isNaN(legacyId)) { + new Notice("Clipboard does not contain a valid Goodreads URL."); + return; + } + + let book: Book; + try { + // eslint-disable-next-line prefer-const + book = await this.goodreads.getBookByLegacyId(legacyId); + } catch (error) { + console.error("Failed to get book from Goodreads:", error); + new Notice( + "Failed to get book from Goodreads. Check console for details." + ); + return; + } + + await this.cb(book); + new Notice("Book created from Goodreads URL."); + } +} diff --git a/src/main.ts b/src/main.ts index 04af241..7738e26 100644 --- a/src/main.ts +++ b/src/main.ts @@ -18,6 +18,7 @@ import { ResetReadingStatusCommand } from "@commands/ResetReadingStatusCommand"; import { BackupReadingLogCommand } from "@commands/CreateReadingLogBackupCommand"; import { RestoreReadingLogBackupCommand } from "@commands/RestoreReadingLogBackupCommand"; import { Goodreads } from "@data-sources/Goodreads"; +import { CreateBookFromGoodreadsUrlCommand } from "@commands/CreateBookFromGoodreadsUrlCommand"; export default class BookTrackerPlugin extends Plugin { public settings: BookTrackerPluginSettings; @@ -70,6 +71,12 @@ export default class BookTrackerPlugin extends Plugin { this.readingLog ) ); + this.addCommand( + new CreateBookFromGoodreadsUrlCommand( + this.goodreads, + this.createEntry.bind(this) + ) + ); this.addSettingTab(new BookTrackerSettingTab(this)); @@ -153,12 +160,9 @@ export default class BookTrackerPlugin extends Plugin { data ); - if (renderedContent) { - await this.app.vault.create( - this.settings.tbrFolder + "/" + fileName + ".md", - renderedContent - ); - } + const filePath = this.settings.tbrFolder + "/" + fileName + ".md"; + const file = await this.app.vault.create(filePath, renderedContent); + await this.app.workspace.getLeaf().openFile(file); } catch (error) { console.error("Failed to create book entry:", error); } diff --git a/src/utils/Templater.ts b/src/utils/Templater.ts index d07a41e..5e18127 100644 --- a/src/utils/Templater.ts +++ b/src/utils/Templater.ts @@ -42,9 +42,11 @@ export class Templater { public async renderTemplateFile( filePath: string, data: Record - ): Promise { + ): Promise { const templateContent = await this.getTemplateContent(filePath); - if (!templateContent) return null; + if (!templateContent) { + throw new Error("Template file not found"); + } return this.renderTemplate(templateContent, data); }