Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add colored template for highlights #8

Merged
merged 1 commit into from
Mar 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 77 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ Import all your Apple Books highlights to Obsidian.
This plugin aims to be a **fast**, **customizable**, **reliable**, and **up-to-date** solution to import your Apple Books highlights to Obsidian:

- **Fast**: It takes less than 1 second to import ~1000 highlights.
- **Customizable**: Use Handlebars and Markdown to customize the output of your highlights the way you want. All the variables to use are available in the default template. Check the `Template variables` section below for more information.
- **Customizable**: Use Handlebars and Markdown to customize the output of your highlights the way you want. Check the [`Template variables`](#template-variables) section below for more information.

- **Reliable**:
- Import actual highlights with only the metadata you need. No visual noise with the deleted but still exported highlights, or, on the contrary, highlights and notes that make no sense without the context.
Expand Down Expand Up @@ -40,24 +40,99 @@ 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. See the [Date formatting](#date-formatting) section for more information.
- `{{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:
- If you highlight a part of a sentence, the - `contextualText` will contain the whole sentence.
- 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)
- `{{highlightCreationDate}}` - The date when you created the highlight. See the [Date formatting](#date-formatting) section for more information.
- `{{highlightModificationDate}}` - The date when you last modified the highlight. See the [Date formatting](#date-formatting) section for more information.


> [!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}}`.

### Date formatting

The plugin uses the `dateFormat` helper that takes a unix timestamp and the [datajs-compatible string of tokens](https://day.js.org/docs/en/display/format#list-of-all-available-formats) to format dates in the template. For example:

```hbs
// Template
{{dateFormat dateVariable "date format"}}

// Example
{{dateFormat bookLastOpenedDate "YYYY-MM-DD hh:mm:ss A Z"}}
// Result
2024-03-04 05:50:28 PM +01:00

// Example
{{dateFormat bookLastOpenedDate "ddd, MMM DD YYYY, HH:mm:ss Z"}}
Mon, Mar 04 2024, 17:50:28 +02:00
```

### 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:: <u>{{{highlight}}}</u>{{/if}}
{{#if (eq highlightStyle "1")}}- 🎯 Highlight:: <mark style="background:rgb(175,213,151); color:#000; padding:2px;">{{{highlight}}}</mark>{{/if}}
{{#if (eq highlightStyle "2")}}- 🎯 Highlight:: <mark style="background:rgb(181,205,238); color:#000; padding:2px;">{{{highlight}}}</mark>{{/if}}
{{#if (eq highlightStyle "3")}}- 🎯 Highlight:: <mark style="background:rgb(249,213,108); color:#000; padding:2px;">{{{highlight}}}</mark>{{/if}}
{{#if (eq highlightStyle "4")}}- 🎯 Highlight:: <mark style="background:rgb(242,178,188); color:#000; padding:2px;">{{{highlight}}}</mark>{{/if}}
{{#if (eq highlightStyle "5")}}- 🎯 Highlight:: <mark style="background:rgb(214,192,238); color:#000; padding:2px;">{{{highlight}}}</mark>{{/if}}
- 📝 Note:: {{#if note}}{{{note}}}{{else}}N/A{{/if}}
- <small>📅 Highlight taken on:: {{dateFormat highlightCreationDate "YYYY-MM-DD hh:mm:ss A Z"}}</small>
- <small>📅 Highlight modified on:: {{dateFormat highlightModificationDate "YYYY-MM-DD hh:mm:ss A Z"}}</small>

{{/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).
Expand Down
25 changes: 22 additions & 3 deletions main.ts
Original file line number Diff line number Diff line change
@@ -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';
Expand Down Expand Up @@ -66,7 +67,7 @@ export default class IBookHighlightsPlugin extends Plugin {
async getBooks(): Promise<IBook[]> {
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`;

Expand All @@ -85,7 +86,7 @@ export default class IBookHighlightsPlugin extends Plugin {
async getAnnotations(): Promise<IBookAnnotation[]> {
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`;
Expand Down Expand Up @@ -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
}
})
})
Expand Down Expand Up @@ -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);

Expand Down
2 changes: 1 addition & 1 deletion manifest.json
Original file line number Diff line number Diff line change
@@ -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",
Expand Down
15 changes: 13 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -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": {
Expand Down Expand Up @@ -38,7 +38,8 @@
"typescript": "4.7.4"
},
"dependencies": {
"dayjs": "^1.11.10",
"handlebars": "^4.7.8",
"sqlite3": "^5.1.7-rc.0"
}
}
}
10 changes: 10 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ export interface IBook {
ZTITLE: string;
ZAUTHOR: string;
ZGENRE: string;
ZLANGUAGE: string;
ZLASTOPENDATE: number;
ZCOVERURL: string;
}

export interface IBookAnnotation {
Expand All @@ -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 {
Expand All @@ -30,5 +36,9 @@ export interface CombinedHighlight {
bookTitle: string;
bookId: string;
bookAuthor: string;
bookGenre: string;
bookLanguage: string;
bookLastOpenedDate: number;
bookCoverUrl: string;
annotations: Highlight[];
}
Binary file added template-colors.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
"importHelpers": true,
"isolatedModules": true,
"resolveJsonModule": true,
"allowSyntheticDefaultImports": true,
"strictNullChecks": true,
"lib": [
"DOM",
Expand Down