generated from tpl/obsidian-sample-plugin
Fix images, handlebars escaping, and organize covers by title sort value
This commit is contained in:
parent
d5e4810d8f
commit
cb0c66a48b
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"id": "obsidian-book-tracker",
|
||||
"name": "Book Tracker",
|
||||
"version": "1.4.1",
|
||||
"version": "1.4.2",
|
||||
"minAppVersion": "0.15.0",
|
||||
"description": "Simplifies tracking your reading progress and managing your book collection in Obsidian.",
|
||||
"author": "FiFiTiDo",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "obsidian-book-tracker",
|
||||
"version": "1.4.1",
|
||||
"version": "1.4.2",
|
||||
"description": "Simplifies tracking your reading progress and managing your book collection in Obsidian.",
|
||||
"main": "main.js",
|
||||
"scripts": {
|
||||
|
|
55
src/main.ts
55
src/main.ts
|
@ -10,7 +10,7 @@ import {
|
|||
DEFAULT_SETTINGS,
|
||||
BookTrackerSettingTab,
|
||||
} from "@ui/settings";
|
||||
import { Templater } from "@utils/Templater";
|
||||
import { safeString, Templater } from "@utils/Templater";
|
||||
import { CONTENT_TYPE_EXTENSIONS } from "./const";
|
||||
import { Storage } from "@utils/Storage";
|
||||
import { ReadingLog } from "@utils/ReadingLog";
|
||||
|
@ -34,6 +34,7 @@ import { registerReadingCalendarCodeBlockProcessor } from "@ui/code-blocks/Readi
|
|||
import { registerAToZChallengeCodeBlockProcessor } from "@ui/code-blocks/AToZChallengeCodeBlock";
|
||||
import moment from "@external/moment";
|
||||
import { compressImage } from "@utils/image";
|
||||
import { titleSortValue } from "@utils/text";
|
||||
|
||||
export default class BookTrackerPlugin extends Plugin {
|
||||
public settings: BookTrackerPluginSettings;
|
||||
|
@ -112,14 +113,14 @@ export default class BookTrackerPlugin extends Plugin {
|
|||
): Promise<TFile> {
|
||||
const response = await requestUrl(coverImageUrl);
|
||||
const contentType = response.headers["content-type"];
|
||||
const extension = CONTENT_TYPE_EXTENSIONS[contentType || ""] || "";
|
||||
if (extension === "") {
|
||||
throw new Error("Unsupported content type: " + contentType);
|
||||
}
|
||||
|
||||
const urlExtension = coverImageUrl.split(".").pop();
|
||||
const extension =
|
||||
CONTENT_TYPE_EXTENSIONS[contentType || ""] ?? urlExtension ?? "jpg";
|
||||
|
||||
let filePath = this.settings.coverFolder + "/";
|
||||
if (this.settings.groupCoversByFirstLetter) {
|
||||
let groupName = fileName.charAt(0).toUpperCase();
|
||||
let groupName = titleSortValue(fileName).charAt(0).toUpperCase();
|
||||
if (!/^[A-Z]$/.test(groupName)) {
|
||||
groupName = "#";
|
||||
}
|
||||
|
@ -162,19 +163,43 @@ export default class BookTrackerPlugin extends Plugin {
|
|||
async createEntry(book: Book): Promise<void> {
|
||||
const fileName = this.templater
|
||||
.renderTemplate(this.settings.fileNameFormat, {
|
||||
title: book.title,
|
||||
authors: book.authors.map((a) => a.name).join(", "),
|
||||
title: safeString(book.title),
|
||||
authors: safeString(book.authors.map((a) => a.name).join(", ")),
|
||||
})
|
||||
.replace(/[/:*?<>|""]/g, "");
|
||||
|
||||
const data: Record<string, unknown> = { book };
|
||||
// Wrap strings as safe strings to avoid Handlebars escaping
|
||||
const data: Record<string, unknown> = {
|
||||
book: {
|
||||
title: safeString(book.title),
|
||||
subtitle: safeString(book.subtitle),
|
||||
description: book.description,
|
||||
authors: book.authors.map((a) => ({
|
||||
...a,
|
||||
name: safeString(a.name),
|
||||
})),
|
||||
series: book.series
|
||||
? {
|
||||
...book.series,
|
||||
title: safeString(book.series.title),
|
||||
}
|
||||
: null,
|
||||
publisher: safeString(book.publisher),
|
||||
publishedAt: book.publishedAt,
|
||||
genres: book.genres.map((g) => safeString(g)),
|
||||
coverImageUrl: safeString(book.coverImageUrl),
|
||||
pageCount: book.pageCount,
|
||||
isbn: safeString(book.isbn),
|
||||
isbn13: safeString(book.isbn13),
|
||||
},
|
||||
};
|
||||
|
||||
if (this.settings.downloadCovers && book.coverImageUrl) {
|
||||
const coverImageFile = await this.downloadCoverImage(
|
||||
book.coverImageUrl,
|
||||
fileName
|
||||
);
|
||||
data.coverImagePath = coverImageFile.path;
|
||||
data.coverImagePath = safeString(coverImageFile.path);
|
||||
}
|
||||
|
||||
const renderedContent = await this.templater.renderTemplateFile(
|
||||
|
@ -225,7 +250,15 @@ export default class BookTrackerPlugin extends Plugin {
|
|||
|
||||
const getDate = (key: string) => {
|
||||
const value = fm?.[key];
|
||||
if (typeof value === "string" || value instanceof Date) {
|
||||
if (typeof value === "string") {
|
||||
if (value.includes(" ")) {
|
||||
return moment(value, "YYYY-MM-DD HH:mm:ss");
|
||||
} else if (value.includes("T")) {
|
||||
return moment(value, "YYYY-MM-DDTHH:mm:ss");
|
||||
} else {
|
||||
return moment(value, "YYYY-MM-DD");
|
||||
}
|
||||
} else if (value instanceof Date) {
|
||||
return moment(value);
|
||||
}
|
||||
return null;
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
import DateFilter from "@ui/components/DateFilter.svelte";
|
||||
import BookCover from "@ui/components/BookCover.svelte";
|
||||
import { setAppContext } from "@ui/stores/app";
|
||||
import { titleSortValue } from "@utils/text";
|
||||
|
||||
const { plugin }: SvelteCodeBlockProps = $props();
|
||||
setAppContext(plugin.app);
|
||||
|
@ -26,25 +27,15 @@
|
|||
disableMonthFilter: true,
|
||||
});
|
||||
|
||||
const getSortValue = (value: string) => {
|
||||
if (value.startsWith("A ")) {
|
||||
return value.slice(2) + ", A";
|
||||
} else if (value.startsWith("An ")) {
|
||||
return value.slice(3) + ", An";
|
||||
} else if (value.startsWith("The ")) {
|
||||
return value.slice(4) + ", The";
|
||||
} else {
|
||||
return value;
|
||||
}
|
||||
};
|
||||
|
||||
const alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".split("");
|
||||
|
||||
const metadata = $derived(
|
||||
metadataStore.metadata.reduce(
|
||||
(acc, meta) => {
|
||||
const title = meta.book.title;
|
||||
const firstLetter = getSortValue(title).charAt(0).toUpperCase();
|
||||
const firstLetter = titleSortValue(title)
|
||||
.charAt(0)
|
||||
.toUpperCase();
|
||||
|
||||
if (!firstLetter.match(/[A-Z]/)) {
|
||||
return acc;
|
||||
|
|
|
@ -87,16 +87,17 @@
|
|||
}
|
||||
|
||||
.book-cover {
|
||||
&,
|
||||
& img {
|
||||
width: var(--book-cover-width);
|
||||
height: var(
|
||||
--book-cover-height,
|
||||
calc(var(--book-cover-width) / (var(--book-cover-aspect-ratio)))
|
||||
);
|
||||
}
|
||||
|
||||
img {
|
||||
border-radius: var(--radius-l);
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
object-fit: cover;
|
||||
object-position: center;
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
import OpenFileLink from "./OpenFileLink.svelte";
|
||||
import BookCover from "./BookCover.svelte";
|
||||
import { getReadingLogContext } from "@ui/stores/reading-log.svelte";
|
||||
import { Platform } from "obsidian";
|
||||
|
||||
interface Props {
|
||||
settings: ShelfSettings;
|
||||
|
@ -21,7 +22,10 @@
|
|||
<div class="book-details-list">
|
||||
{#each metadataStore.metadata as meta}
|
||||
<div class="book-details">
|
||||
<BookCover book={meta.book} />
|
||||
<BookCover
|
||||
book={meta.book}
|
||||
size={Platform.isMobile ? "20rem" : "fill"}
|
||||
/>
|
||||
<div class="book-info">
|
||||
<OpenFileLink file={meta.file}>
|
||||
<h2 class="book-title">
|
||||
|
|
|
@ -25,6 +25,10 @@ Handlebars.registerHelper("indent", (text: string, indent = " ") => {
|
|||
);
|
||||
});
|
||||
|
||||
export function safeString(str: string) {
|
||||
return new Handlebars.SafeString(str);
|
||||
}
|
||||
|
||||
export class Templater {
|
||||
public constructor(private readonly app: App) {}
|
||||
|
||||
|
|
|
@ -47,8 +47,6 @@ export async function compressImage(
|
|||
}
|
||||
}
|
||||
|
||||
console.log(width, height);
|
||||
|
||||
canvas.width = width!;
|
||||
canvas.height = height!;
|
||||
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
export function titleSortValue(title: string): string {
|
||||
if (title.toLowerCase().startsWith("a ")) {
|
||||
return title.slice(2) + ", A";
|
||||
} else if (title.toLowerCase().startsWith("an ")) {
|
||||
return title.slice(3) + ", An";
|
||||
} else if (title.toLowerCase().startsWith("the ")) {
|
||||
return title.slice(4) + ", The";
|
||||
} else {
|
||||
return title;
|
||||
}
|
||||
}
|
|
@ -6,5 +6,6 @@
|
|||
"1.3.1": "0.15.0",
|
||||
"1.3.2": "0.15.0",
|
||||
"1.4.0": "0.15.0",
|
||||
"1.4.1": "0.15.0"
|
||||
"1.4.1": "0.15.0",
|
||||
"1.4.2": "0.15.0"
|
||||
}
|
Loading…
Reference in New Issue