Add Create Book from Clipboard Command

This commit is contained in:
Evan Fiordeliso 2026-06-11 17:23:45 -04:00
parent 2f89a703d3
commit 9213e1ef0d
3 changed files with 69 additions and 14 deletions

View File

@ -0,0 +1,36 @@
import { Notice } from "obsidian";
import { Command } from "./Command";
import { bookSchema, type Book } from "@src/types";
export class CreateBookFromClipboardCommand extends Command {
constructor(
private readonly createEntry: (book: Book) => void | PromiseLike<void>
) {
super(
"create-book-from-clipboard",
"Create Book from Clipboard"
);
}
async callback() {
const data = await navigator.clipboard.readText();
const { data: book, success, error } = await bookSchema.safeParseAsync(JSON.parse(data));
if (!success) {
console.error(error.message);
new Notice("There is not a valid book in the clipboard. Check console for details");
return
}
try {
await this.createEntry(book);
} catch (error) {
console.error("Failed to create book:", error);
new Notice("Failed to create book. Check console for details.");
return;
}
new Notice("Book created from clipboard data.");
}
}

View File

@ -34,6 +34,7 @@ import {
import { CoverImageDownloaderService } from "./services/CoverImageDownloaderService";
import { ImageCompressorService } from "./services/ImageCompressorService";
import type { Book, BookMetadata, ReadingState } from "./types";
import { CreateBookFromClipboardCommand } from "@commands/CreateBookFromClipboardCommand";
export default class BookTrackerPlugin extends Plugin {
public settings: BookTrackerPluginSettings;
@ -86,6 +87,7 @@ export default class BookTrackerPlugin extends Plugin {
this.readingLog
)
);
this.addCommand(new CreateBookFromClipboardCommand(this.createEntry.bind(this)))
this.addCommand(
new CreateBookFromGoodreadsUrlCommand(
this.goodreads,

View File

@ -2,30 +2,47 @@ import moment from "@external/moment";
import { STATUS_IN_PROGRESS, STATUS_READ, STATUS_TO_BE_READ } from "./const";
import z from "zod/v4";
export const authorSchema = z.object({
name: z.string()
.transform(val => val.replace(/\s{2,}/g, ' ')),
description: z.string().optional(),
});
export interface Author {
name: string;
description?: string;
}
export const seriesSchema = z.object({
title: z.string(),
position: z.number().or(z.nan()),
})
export interface Series {
title: string;
position: number;
}
export interface Book {
title: string;
subtitle: string;
description: string;
authors: Author[];
series: Series | null;
publisher: string;
publishedAt: Date;
genres: string[];
coverImageUrl: string;
pageCount: number;
isbn: string;
isbn13: string;
}
export const bookSchema = z.object({
title: z.string(),
subtitle: z.string(),
description: z.string(),
authors: z.array(authorSchema),
series: seriesSchema.nullable(),
publisher: z.string(),
publishedAt: z.date(),
genres: z.array(z.string()),
coverImageUrl: z.url(),
pageCount: z.number().min(0),
isbn: z.string()
.transform(val => val.replace(/-+/g, ''))
.pipe(z.string().length(10)),
isbn13: z.string()
.transform(val => val.replace(/-+/g, ''))
.pipe(z.string().length(10)),
});
export type Book = z.infer<typeof bookSchema>;
export type ToBeReadState = typeof STATUS_TO_BE_READ;
export type InProgressState = typeof STATUS_IN_PROGRESS;