diff --git a/README.md b/README.md index 5622d01..ce59da7 100644 --- a/README.md +++ b/README.md @@ -40,11 +40,19 @@ Check Obsidian Help for more information about [Community plugins](https://help. - `Cmd+P > Apple Books - Import Highlights: From a specific book...` - **Ribbon**: Select the plugin icon in the Ribbon (left sidebar) -## Template variables +## Customization + +The plugin uses Handlebars and Markdown to customize the output of your highlights the way you want. + +### Template variables - `{{{bookTitle}}}` - The title of the book. - `{{bookId}}` - A unique identifier of the book. It is used to create a link to the book in Apple Books: `[Apple Books Link](ibooks://assetid/{{bookId}})`. - `{{{bookAuthor}}}` - The author of the book. +- `{{{bookGenre}}}` - The genre of the book. +- `{{bookLanguage}}` - The language of the book. +- `{{bookLastOpenedDate}}` - The date when you last opened the book. +- `{{bookCoverUrl}}` - The URL of the book cover. - `{{annotations}}` - An array of all the annotations in the book. You can use `{{annotations.length}}` to get the total number of annotations you made in the book. Each annotation has the following properties: - `{{{chapter}}}` - The chapter of the highlight in the book. It may not be available for all highlights due to the initial formatting of the book. - `{{{contextualText}}}` - The text surrounding the highlight to give you more context. For example: @@ -52,12 +60,59 @@ Check Obsidian Help for more information about [Community plugins](https://help. - If you highlight parts of two adjacent sentences, the `contextualText` will contain both sentences. - `{{{highlight}}}` - The highlighted text. - `{{{note}}}` - A note you added for the highlight. + - `{{highlightStyle}}` - The style of the highlight. It can be one of the following values: + - `0` (underline) + - `1` (green) + - `2` (blue) + - `3` (yellow) + - `4` (pink) + - `5` (violet) + > [!NOTE] > When customizing the template, make sure to wrap variables with triple curly braces (`{{{variable}}}`) to avoid escaping the HTML characters in Markdown files (default behavior). > > If you want escaped output, use double curly braces: `{{variable}}`. +### Templates + +#### Template with colored highlights + +![template colors](template-colors.png) + +```hbs +Title:: 📕 {{{bookTitle}}} +Author:: {{{bookAuthor}}} +Genre:: {{#if bookGenre}}{{{bookGenre}}}{{else}}N/A{{/if}} +Language:: {{#if bookLanguage}}{{bookLanguage}}{{else}}N/A{{/if}} +Last Read:: {{dateFormat bookLastOpenedDate "YYYY-MM-DD hh:mm:ss A Z"}} +Link:: [Apple Books Link](ibooks://assetid/{{bookId}}) + +{{#if bookCoverUrl}}![Book Cover]({{{bookCoverUrl}}}){{/if}} + +## Annotations + +Number of annotations:: {{annotations.length}} + +{{#each annotations}} +---- + +- 📖 Chapter:: {{#if chapter}}{{{chapter}}}{{else}}N/A{{/if}} +- 🔖 Context:: {{#if contextualText}}{{{contextualText}}}{{else}}N/A{{/if}} +{{#if (eq highlightStyle "0")}}- 🎯 Highlight:: {{{highlight}}}{{/if}} +{{#if (eq highlightStyle "1")}}- 🎯 Highlight:: {{{highlight}}}{{/if}} +{{#if (eq highlightStyle "2")}}- 🎯 Highlight:: {{{highlight}}}{{/if}} +{{#if (eq highlightStyle "3")}}- 🎯 Highlight:: {{{highlight}}}{{/if}} +{{#if (eq highlightStyle "4")}}- 🎯 Highlight:: {{{highlight}}}{{/if}} +{{#if (eq highlightStyle "5")}}- 🎯 Highlight:: {{{highlight}}}{{/if}} +- 📝 Note:: {{#if note}}{{{note}}}{{else}}N/A{{/if}} +- 📅 Highlight taken on:: {{dateFormat highlightCreationDate "YYYY-MM-DD hh:mm:ss A Z"}} +- 📅 Highlight modified on:: {{dateFormat highlightModificationDate "YYYY-MM-DD hh:mm:ss A Z"}} + +{{/each}} +``` + + ## Contributing Your feedback and ideas are more than welcome and highly appreciated! Join the discussion in the [Obsidian Forum](https://forum.obsidian.md/t/new-plugin-apple-books-import-highlights/76856). diff --git a/main.ts b/main.ts index 3d931cf..abb7755 100644 --- a/main.ts +++ b/main.ts @@ -1,6 +1,7 @@ import * as child_process from 'child_process'; import * as Handlebars from 'handlebars'; import { normalizePath, Notice, Plugin } from 'obsidian'; +import dayjs from 'dayjs'; import * as path from 'path'; import { promisify } from 'util'; import { DEFAULT_SETTINGS, IBookHighlightsSettingTab } from './src/settings'; @@ -66,7 +67,7 @@ export default class IBookHighlightsPlugin extends Plugin { async getBooks(): Promise { const IBOOK_LIBRARY = '~/Library/Containers/com.apple.iBooksX/Data/Documents/BKLibrary/BKLibrary-1-091020131601.sqlite'; const booksSql = ` - SELECT ZASSETID, ZTITLE, ZAUTHOR, ZGENRE + SELECT ZASSETID, ZTITLE, ZAUTHOR, ZGENRE, ZLANGUAGE, ZLASTOPENDATE, ZCOVERURL FROM ZBKLIBRARYASSET WHERE ZPURCHASEDATE IS NOT NULL`; @@ -85,7 +86,7 @@ export default class IBookHighlightsPlugin extends Plugin { async getAnnotations(): Promise { const IBOOK_ANNOTATION_DB = '~/Library/Containers/com.apple.iBooksX/Data/Documents/AEAnnotation/AEAnnotation_v10312011_1727_local.sqlite'; const annotationsSql = ` - SELECT ZANNOTATIONASSETID, ZFUTUREPROOFING5, ZANNOTATIONREPRESENTATIVETEXT, ZANNOTATIONSELECTEDTEXT, ZANNOTATIONNOTE + SELECT ZANNOTATIONASSETID, ZFUTUREPROOFING5, ZANNOTATIONREPRESENTATIVETEXT, ZANNOTATIONSELECTEDTEXT, ZANNOTATIONNOTE, ZANNOTATIONCREATIONDATE, ZANNOTATIONMODIFICATIONDATE, ZANNOTATIONSTYLE FROM ZAEANNOTATION WHERE ZANNOTATIONSELECTEDTEXT IS NOT NULL AND ZANNOTATIONDELETED IS 0`; @@ -118,12 +119,19 @@ export default class IBookHighlightsPlugin extends Plugin { bookTitle: normalizedBookTitle, bookId: book.ZASSETID, bookAuthor: book.ZAUTHOR, + bookGenre: book.ZGENRE, + bookLanguage: book.ZLANGUAGE, + bookLastOpenedDate: book.ZLASTOPENDATE, + bookCoverUrl: book.ZCOVERURL, annotations: bookRelatedAnnotations.map(annotation => { return { chapter: annotation.ZFUTUREPROOFING5, contextualText: annotation.ZANNOTATIONREPRESENTATIVETEXT, highlight: annotation.ZANNOTATIONSELECTEDTEXT, note: annotation.ZANNOTATIONNOTE, + highlightStyle: annotation.ZANNOTATIONSTYLE, + highlightCreationDate: annotation.ZANNOTATIONCREATIONDATE, + highlightModificationDate: annotation.ZANNOTATIONMODIFICATIONDATE } }) }) @@ -163,7 +171,18 @@ export default class IBookHighlightsPlugin extends Plugin { await this.app.vault.createFolder(this.settings.highlightsFolder); - highlights.forEach(async (highlight: CombinedHighlight) => { + highlights.forEach(async (highlight: CombinedHighlight) => { + // TODO: Consider moving to a separate file if there are several helpers to be added + Handlebars.registerHelper('eq', (a, b) => { + if (a == b) { + return this; + } + }); + + Handlebars.registerHelper('dateFormat', (date, format) => { + return dayjs('2001-01-01').add(date, 's').format(format); + }); + const template = Handlebars.compile(this.settings.template); const renderedTemplate = template(highlight); diff --git a/manifest.json b/manifest.json index 818fd5d..24395c6 100644 --- a/manifest.json +++ b/manifest.json @@ -1,7 +1,7 @@ { "id": "apple-books-import-highlights", "name": "Apple Books - Import Highlights", - "version": "1.1.1", + "version": "1.2.0", "minAppVersion": "0.15.0", "description": "Import your Apple Books highlights and notes to Obsidian.", "author": "bandantonio", diff --git a/package-lock.json b/package-lock.json index 19f2e9d..a8ffd81 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,14 +1,15 @@ { "name": "obsidian-apple-books-highlights-plugin", - "version": "1.1.1", + "version": "1.2.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "obsidian-apple-books-highlights-plugin", - "version": "1.1.1", + "version": "1.2.0", "license": "MIT", "dependencies": { + "dayjs": "^1.11.10", "handlebars": "^4.7.8", "sqlite3": "^5.1.7-rc.0" }, @@ -1155,6 +1156,11 @@ "node": ">= 8" } }, + "node_modules/dayjs": { + "version": "1.11.10", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.10.tgz", + "integrity": "sha512-vjAczensTgRcqDERK0SR2XMwsF/tSvnvlv6VcF2GIhg6Sx4yOIt/irsr1RDJsKiIyBzJDpCoXiWWq28MqH2cnQ==" + }, "node_modules/debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", @@ -4003,6 +4009,11 @@ "which": "^2.0.1" } }, + "dayjs": { + "version": "1.11.10", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.10.tgz", + "integrity": "sha512-vjAczensTgRcqDERK0SR2XMwsF/tSvnvlv6VcF2GIhg6Sx4yOIt/irsr1RDJsKiIyBzJDpCoXiWWq28MqH2cnQ==" + }, "debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", diff --git a/package.json b/package.json index 4c89a9c..1b29a30 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "obsidian-apple-books-highlights-plugin", - "version": "1.1.1", + "version": "1.2.0", "description": "Import highlights and notes from your Apple Books to Obsidian", "main": "main.js", "scripts": { @@ -38,7 +38,8 @@ "typescript": "4.7.4" }, "dependencies": { + "dayjs": "^1.11.10", "handlebars": "^4.7.8", "sqlite3": "^5.1.7-rc.0" } -} \ No newline at end of file +} diff --git a/src/template.ts b/src/template.ts index 91df0b6..fb82e59 100644 --- a/src/template.ts +++ b/src/template.ts @@ -1,7 +1,12 @@ const defaultTemplate = `Title:: 📕 {{{bookTitle}}} Author:: {{{bookAuthor}}} +Genre:: {{#if bookGenre}}{{{bookGenre}}}{{else}}N/A{{/if}} +Language:: {{#if bookLanguage}}{{bookLanguage}}{{else}}N/A{{/if}} +Last Read:: {{dateFormat bookLastOpenedDate "YYYY-MM-DD hh:mm:ss A Z"}} Link:: [Apple Books Link](ibooks://assetid/{{bookId}}) +{{#if bookCoverUrl}}![Book Cover]({{{bookCoverUrl}}}){{/if}} + ## Annotations Number of annotations:: {{annotations.length}} @@ -11,8 +16,15 @@ Number of annotations:: {{annotations.length}} - 📖 Chapter:: {{#if chapter}}{{{chapter}}}{{else}}N/A{{/if}} - 🔖 Context:: {{#if contextualText}}{{{contextualText}}}{{else}}N/A{{/if}} -- 🎯 Highlight:: {{{highlight}}} +{{#if (eq highlightStyle "0")}}- 🎯 Highlight:: {{{highlight}}}{{/if}} +{{#if (eq highlightStyle "1")}}- 🎯 Highlight:: {{{highlight}}}{{/if}} +{{#if (eq highlightStyle "2")}}- 🎯 Highlight:: {{{highlight}}}{{/if}} +{{#if (eq highlightStyle "3")}}- 🎯 Highlight:: {{{highlight}}}{{/if}} +{{#if (eq highlightStyle "4")}}- 🎯 Highlight:: {{{highlight}}}{{/if}} +{{#if (eq highlightStyle "5")}}- 🎯 Highlight:: {{{highlight}}}{{/if}} - 📝 Note:: {{#if note}}{{{note}}}{{else}}N/A{{/if}} +- 📅 Highlight taken on:: {{dateFormat highlightCreationDate "YYYY-MM-DD hh:mm:ss A Z"}} +- 📅 Highlight modified on:: {{dateFormat highlightModificationDate "YYYY-MM-DD hh:mm:ss A Z"}} {{/each}} `; diff --git a/src/types.ts b/src/types.ts index 88c9bcc..bcf6e5a 100644 --- a/src/types.ts +++ b/src/types.ts @@ -10,6 +10,9 @@ export interface IBook { ZTITLE: string; ZAUTHOR: string; ZGENRE: string; + ZLANGUAGE: string; + ZLASTOPENDATE: number; + ZCOVERURL: string; } export interface IBookAnnotation { @@ -18,6 +21,9 @@ export interface IBookAnnotation { ZANNOTATIONREPRESENTATIVETEXT: string; ZANNOTATIONSELECTEDTEXT: string; ZANNOTATIONNOTE: string; + ZANNOTATIONCREATIONDATE: number; + ZANNOTATIONMODIFICATIONDATE: number; + ZANNOTATIONSTYLE: 0 | 1 | 2 | 3 | 4 | 5; } export interface Highlight { @@ -30,5 +36,9 @@ export interface CombinedHighlight { bookTitle: string; bookId: string; bookAuthor: string; + bookGenre: string; + bookLanguage: string; + bookLastOpenedDate: number; + bookCoverUrl: string; annotations: Highlight[]; } \ No newline at end of file diff --git a/template-colors.png b/template-colors.png new file mode 100644 index 0000000..bf9bace Binary files /dev/null and b/template-colors.png differ diff --git a/tsconfig.json b/tsconfig.json index 7cd0e5e..3eea23a 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -11,6 +11,7 @@ "importHelpers": true, "isolatedModules": true, "resolveJsonModule": true, + "allowSyntheticDefaultImports": true, "strictNullChecks": true, "lib": [ "DOM",