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 apple books highlight links #24

Closed
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
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ The plugin uses Handlebars and Markdown to customize the output of your highligh
- 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.
- `{{{highlightLocation}}}` - The EPUB CFI of the highlighted text. It is used to create a link to the highlighted text in Apple Books: `[Apple Books Highlight Link](ibooks://assetid/{{bookId}}#{{highlightLocation}})`.
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- `{{{highlightLocation}}}` - The EPUB CFI of the highlighted text. It is used to create a link to the highlighted text in Apple Books: `[Apple Books Highlight Link](ibooks://assetid/{{bookId}}#{{highlightLocation}})`.
- `{{{highlightLocation}}}` - a unique identifier of the highlighted text. It is used to create a link to the highlighted text in Apple Books. For example: `[Apple Books Highlight Link](ibooks://assetid/{{bookId}}#{{highlightLocation}})`.

- `{{highlightStyle}}` - The style of the highlight. It can be one of the following values:
- `0` (underline)
- `1` (green)
Expand Down Expand Up @@ -132,6 +133,7 @@ Number of annotations:: {{annotations.length}}
{{#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}}
- 📙 Highlight Link:: {{#if highlightLocation}}[Apple Books Highlight Link](ibooks://assetid/{{../bookId}}#{{highlightLocation}}){{else}}N/A{{/if}}
Copy link
Owner

@bandantonio bandantonio Jul 8, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe it's not necessary to add a highlight link to this template, as its main focus is on colors.

Suggested change
- 📙 Highlight Link:: {{#if highlightLocation}}[Apple Books Highlight Link](ibooks://assetid/{{../bookId}}#{{highlightLocation}}){{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>

Expand Down
1 change: 1 addition & 0 deletions migrations/0001_misty_silver_centurion.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ALTER TABLE ZAEANNOTATION ADD `ZANNOTATIONLOCATION` text;
151 changes: 151 additions & 0 deletions migrations/meta/0001_snapshot.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
{
"version": "5",
"dialect": "sqlite",
"id": "7be16a02-e20b-4725-898a-4f88e7a3bf1a",
"prevId": "9ab8f1f7-710a-4b2c-9ba7-b286cb403847",
"tables": {
"ZAEANNOTATION": {
"name": "ZAEANNOTATION",
"columns": {
"ZANNOTATIONASSETID": {
"name": "ZANNOTATIONASSETID",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"ZFUTUREPROOFING5": {
"name": "ZFUTUREPROOFING5",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"ZANNOTATIONREPRESENTATIVETEXT": {
"name": "ZANNOTATIONREPRESENTATIVETEXT",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"ZANNOTATIONSELECTEDTEXT": {
"name": "ZANNOTATIONSELECTEDTEXT",
"type": "text",
"primaryKey": false,
"notNull": true,
"autoincrement": false
},
"ZANNOTATIONLOCATION": {
"name": "ZANNOTATIONLOCATION",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"ZANNOTATIONNOTE": {
"name": "ZANNOTATIONNOTE",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"ZANNOTATIONCREATIONDATE": {
"name": "ZANNOTATIONCREATIONDATE",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"ZANNOTATIONMODIFICATIONDATE": {
"name": "ZANNOTATIONMODIFICATIONDATE",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"ZANNOTATIONSTYLE": {
"name": "ZANNOTATIONSTYLE",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"ZANNOTATIONDELETED": {
"name": "ZANNOTATIONDELETED",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
},
"ZBKLIBRARYASSET": {
"name": "ZBKLIBRARYASSET",
"columns": {
"ZASSETID": {
"name": "ZASSETID",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"ZTITLE": {
"name": "ZTITLE",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"ZAUTHOR": {
"name": "ZAUTHOR",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"ZGENRE": {
"name": "ZGENRE",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"ZLANGUAGE": {
"name": "ZLANGUAGE",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"ZLASTOPENDATE": {
"name": "ZLASTOPENDATE",
"type": "integer",
"primaryKey": false,
"notNull": false,
"autoincrement": false
},
"ZCOVERURL": {
"name": "ZCOVERURL",
"type": "text",
"primaryKey": false,
"notNull": false,
"autoincrement": false
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {}
}
},
"enums": {},
"_meta": {
"schemas": {},
"tables": {},
"columns": {}
}
}
7 changes: 7 additions & 0 deletions migrations/meta/_journal.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,13 @@
"when": 1713726520358,
"tag": "0000_outstanding_wolf_cub",
"breakpoints": true
},
{
"idx": 1,
"version": "5",
"when": 1720316159179,
"tag": "0001_misty_silver_centurion",
"breakpoints": true
}
]
}
Binary file modified preview.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 src/db/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export const HIGHLIGHTS_LIBRARY_COLUMNS = [
'ZFUTUREPROOFING5',
'ZANNOTATIONREPRESENTATIVETEXT',
'ZANNOTATIONSELECTEDTEXT',
'ZANNOTATIONLOCATION',
'ZANNOTATIONNOTE',
'ZANNOTATIONCREATIONDATE',
'ZANNOTATIONMODIFICATIONDATE',
Expand Down
1 change: 1 addition & 0 deletions src/db/schemas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export const annotations = sqliteTable(HIGHLIGHTS_LIBRARY_NAME, {
ZFUTUREPROOFING5: text('ZFUTUREPROOFING5'),
ZANNOTATIONREPRESENTATIVETEXT: text('ZANNOTATIONREPRESENTATIVETEXT'),
ZANNOTATIONSELECTEDTEXT: text('ZANNOTATIONSELECTEDTEXT').notNull(),
ZANNOTATIONLOCATION: text('ZANNOTATIONLOCATION'),
ZANNOTATIONNOTE: text('ZANNOTATIONNOTE'),
ZANNOTATIONCREATIONDATE: integer('ZANNOTATIONCREATIONDATE'),
ZANNOTATIONMODIFICATIONDATE: integer('ZANNOTATIONMODIFICATIONDATE'),
Expand Down
56 changes: 32 additions & 24 deletions src/db/seedData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,79 +35,87 @@ export const defaultBooks = [{
export const defaultAnnotations = [{
"ZANNOTATIONASSETID": "THBFYNJKTGFTTVCGSAE1",
"ZFUTUREPROOFING5": "Introduction",
"ZANNOTATIONREPRESENTATIVETEXT": "This is a contextual text for the hightlight from the iPhone User Guide",
"ZANNOTATIONSELECTEDTEXT": "hightlight from the iPhone User Guide",
"ZANNOTATIONNOTE": "Test note for the hightlight from the iPhone User Guide",
"ZANNOTATIONREPRESENTATIVETEXT": "This is a contextual text for the highlight from the iPhone User Guide",
"ZANNOTATIONSELECTEDTEXT": "highlight from the iPhone User Guide",
"ZANNOTATIONLOCATION": "test-highlight-link-from-the-iphone-user-guide",
"ZANNOTATIONNOTE": "Test note for the highlight from the iPhone User Guide",
"ZANNOTATIONCREATIONDATE": 685151385.91602,
"ZANNOTATIONMODIFICATIONDATE": 685151385.91602,
"ZANNOTATIONSTYLE": 3,
"ZANNOTATIONDELETED": 0
}, {
"ZANNOTATIONASSETID": "THBFYNJKTGFTTVCGSAE2",
"ZFUTUREPROOFING5": "Introduction",
"ZANNOTATIONREPRESENTATIVETEXT": "This is a contextual text for the hightlight from the iPad User Guide",
"ZANNOTATIONSELECTEDTEXT": "hightlight from the iPad User Guide",
"ZANNOTATIONNOTE": "Test note for the hightlight from the iPad User Guide",
"ZANNOTATIONREPRESENTATIVETEXT": "This is a contextual text for the highlight from the iPad User Guide",
"ZANNOTATIONSELECTEDTEXT": "highlight from the iPad User Guide",
"ZANNOTATIONLOCATION": "test-highlight-link-from-the-ipad-user-guide",
"ZANNOTATIONNOTE": "Test note for the highlight from the iPad User Guide",
"ZANNOTATIONCREATIONDATE": 685151385.91602,
"ZANNOTATIONMODIFICATIONDATE": 685151385.91602,
"ZANNOTATIONSTYLE": 3,
"ZANNOTATIONDELETED": 0
}, {
"ZANNOTATIONASSETID": "THBFYNJKTGFTTVCGSAE3",
"ZFUTUREPROOFING5": "Introduction",
"ZANNOTATIONREPRESENTATIVETEXT": "This is a contextual text for the hightlight from the Mac User Guide",
"ZANNOTATIONSELECTEDTEXT": "hightlight from the Mac User Guide",
"ZANNOTATIONNOTE": "Test note for the hightlight from the Mac User Guide",
"ZANNOTATIONREPRESENTATIVETEXT": "This is a contextual text for the highlight from the Mac User Guide",
"ZANNOTATIONSELECTEDTEXT": "highlight from the Mac User Guide",
"ZANNOTATIONLOCATION": "test-highlight-link-from-the-mac-user-guide",
"ZANNOTATIONNOTE": "Test note for the highlight from the Mac User Guide",
"ZANNOTATIONCREATIONDATE": 685151385.91602,
"ZANNOTATIONMODIFICATIONDATE": 685151385.91602,
"ZANNOTATIONSTYLE": 3,
"ZANNOTATIONDELETED": 0
}, {
"ZANNOTATIONASSETID": "THBFYNJKTGFTTVCGSAE4",
"ZFUTUREPROOFING5": "Introduction",
"ZANNOTATIONREPRESENTATIVETEXT": "This is a contextual text for the hightlight from the Apple Watch User Guide",
"ZANNOTATIONSELECTEDTEXT": "hightlight from the Apple Watch User Guide",
"ZANNOTATIONNOTE": "Test note for the hightlight from the Apple Watch User Guide",
"ZANNOTATIONREPRESENTATIVETEXT": "This is a contextual text for the highlight from the Apple Watch User Guide",
"ZANNOTATIONSELECTEDTEXT": "highlight from the Apple Watch User Guide",
"ZANNOTATIONLOCATION": "test-highlight-link-from-the-apple-watch-user-guide",
"ZANNOTATIONNOTE": "Test note for the highlight from the Apple Watch User Guide",
"ZANNOTATIONCREATIONDATE": 685151385.91602,
"ZANNOTATIONMODIFICATIONDATE": 685151385.91602,
"ZANNOTATIONSTYLE": 3,
"ZANNOTATIONDELETED": 0
}, {
"ZANNOTATIONASSETID": "THBFYNJKTGFTTVCGSAE1",
"ZFUTUREPROOFING5": "Introduction",
"ZANNOTATIONREPRESENTATIVETEXT": "This is a contextual text for the hightlight from the iPhone User Guide",
"ZANNOTATIONSELECTEDTEXT": "hightlight from the iPhone User Guide",
"ZANNOTATIONNOTE": "Test note for the deleted hightlight from the iPhone User Guide",
"ZANNOTATIONREPRESENTATIVETEXT": "This is a contextual text for the highlight from the iPhone User Guide",
"ZANNOTATIONSELECTEDTEXT": "highlight from the iPhone User Guide",
"ZANNOTATIONLOCATION": "test-highlight-link-from-the-iphone-user-guide",
"ZANNOTATIONNOTE": "Test note for the deleted highlight from the iPhone User Guide",
"ZANNOTATIONCREATIONDATE": 685151385.91602,
"ZANNOTATIONMODIFICATIONDATE": 685151385.91602,
"ZANNOTATIONSTYLE": 3,
"ZANNOTATIONDELETED": 1
}, {
"ZANNOTATIONASSETID": "THBFYNJKTGFTTVCGSAE2",
"ZFUTUREPROOFING5": "Introduction",
"ZANNOTATIONREPRESENTATIVETEXT": "This is a contextual text for the hightlight from the iPad User Guide",
"ZANNOTATIONSELECTEDTEXT": "hightlight from the iPad User Guide",
"ZANNOTATIONNOTE": "Test note for the deleted hightlight from the iPad User Guide",
"ZANNOTATIONREPRESENTATIVETEXT": "This is a contextual text for the highlight from the iPad User Guide",
"ZANNOTATIONSELECTEDTEXT": "highlight from the iPad User Guide",
"ZANNOTATIONLOCATION": "test-highlight-link-from-the-ipad-user-guide",
"ZANNOTATIONNOTE": "Test note for the deleted highlight from the iPad User Guide",
"ZANNOTATIONCREATIONDATE": 685151385.91602,
"ZANNOTATIONMODIFICATIONDATE": 685151385.91602,
"ZANNOTATIONSTYLE": 3,
"ZANNOTATIONDELETED": 1
}, {
"ZANNOTATIONASSETID": "THBFYNJKTGFTTVCGSAE3",
"ZFUTUREPROOFING5": "Introduction",
"ZANNOTATIONREPRESENTATIVETEXT": "This is a contextual text for the hightlight from the Mac User Guide",
"ZANNOTATIONSELECTEDTEXT": "hightlight from the Mac User Guide",
"ZANNOTATIONNOTE": "Test note for the deleted hightlight from the Mac User Guide",
"ZANNOTATIONREPRESENTATIVETEXT": "This is a contextual text for the highlight from the Mac User Guide",
"ZANNOTATIONSELECTEDTEXT": "highlight from the Mac User Guide",
"ZANNOTATIONLOCATION": "test-highlight-link-from-the-mac-user-guide",
"ZANNOTATIONNOTE": "Test note for the deleted highlight from the Mac User Guide",
"ZANNOTATIONCREATIONDATE": 685151385.91602,
"ZANNOTATIONMODIFICATIONDATE": 685151385.91602,
"ZANNOTATIONSTYLE": 3,
"ZANNOTATIONDELETED": 1
}, {
"ZANNOTATIONASSETID": "THBFYNJKTGFTTVCGSAE4",
"ZFUTUREPROOFING5": "Introduction",
"ZANNOTATIONREPRESENTATIVETEXT": "This is a contextual text for the hightlight from the Apple Watch User Guide",
"ZANNOTATIONSELECTEDTEXT": "hightlight from the Apple Watch User Guide",
"ZANNOTATIONNOTE": "Test note for the deleted hightlight from the Apple Watch User Guide",
"ZANNOTATIONREPRESENTATIVETEXT": "This is a contextual text for the highlight from the Apple Watch User Guide",
"ZANNOTATIONSELECTEDTEXT": "highlight from the Apple Watch User Guide",
"ZANNOTATIONLOCATION": "test-highlight-link-from-the-apple-watch-user-guide",
"ZANNOTATIONNOTE": "Test note for the deleted highlight from the Apple Watch User Guide",
"ZANNOTATIONCREATIONDATE": 685151385.91602,
"ZANNOTATIONMODIFICATIONDATE": 685151385.91602,
"ZANNOTATIONSTYLE": 3,
Expand Down
14 changes: 11 additions & 3 deletions src/methods/aggregateDetails.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,10 @@ export const aggregateBookAndHighlightDetails = async (): Promise<ICombinedBooks

return {
chapter: annotation.ZFUTUREPROOFING5,
contextualText: textForContext ? preserveNewlineIndentation(textForContext) : textForContext,
highlight: preserveNewlineIndentation(annotation.ZANNOTATIONSELECTEDTEXT),
note: userNote ? preserveNewlineIndentation(userNote) : userNote,
contextualText: textForContext ? removeAllLastNewlines(preserveNewlineIndentation(textForContext)) : textForContext,
highlight: removeAllLastNewlines(preserveNewlineIndentation(annotation.ZANNOTATIONSELECTEDTEXT)),
note: userNote ? removeAllLastNewlines(preserveNewlineIndentation(userNote)) : userNote,
highlightLocation: annotation.ZANNOTATIONLOCATION,
highlightStyle: annotation.ZANNOTATIONSTYLE,
highlightCreationDate: annotation.ZANNOTATIONCREATIONDATE,
highlightModificationDate: annotation.ZANNOTATIONMODIFICATIONDATE
Expand All @@ -53,3 +54,10 @@ const preserveNewlineIndentation = (textBlock: string): string => {

return stringWithNewLines.test(textBlock) ? textBlock.replace(stringWithNewLines, '\n') : textBlock;
}

// Handler of all new line characters (\n) at the end of text blocks to prevent new lines appearing at the end of text blocks
const removeAllLastNewlines = (textBlock: string): string => {
const stringAllLastNewLines = /\n+$/;

return stringAllLastNewLines.test(textBlock) ? textBlock.replace(stringAllLastNewLines, "") : textBlock;
}
1 change: 1 addition & 0 deletions src/methods/renderHighlightsTemplate.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import * as Handlebars from 'handlebars';
import { ICombinedBooksAndHighlights } from '../types';
import 'src/utils/helpers'
export const renderHighlightsTemplate = async (highlight: ICombinedBooksAndHighlights, template: string) => {
const compiledTemplate = Handlebars.compile(template);
const renderedTemplate = compiledTemplate(highlight);
Expand Down
2 changes: 1 addition & 1 deletion src/settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ export class IBookHighlightsSettingTab extends PluginSettingTab {

new Setting(containerEl)
.setName('Import highlights on start')
.setDesc('Import all hightlights from all your books when Obsidian starts')
.setDesc('Import all highlights from all your books when Obsidian starts')
.addToggle((toggle) => {
toggle.setValue(this.plugin.settings.importOnStart)
.onChange(async (value) => {
Expand Down
1 change: 1 addition & 0 deletions src/template.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ Number of annotations:: {{annotations.length}}
- 🔖 Context:: {{#if contextualText}}{{{contextualText}}}{{else}}N/A{{/if}}
- 🎯 Highlight:: {{{highlight}}}
- 📝 Note:: {{#if note}}{{{note}}}{{else}}N/A{{/if}}
- 📙 Highlight Link:: {{#if highlightLocation}}[Apple Books Highlight Link](ibooks://assetid/{{../bookId}}#{{highlightLocation}}){{else}}N/A{{/if}}
{{/each}}
`;
Expand Down
2 changes: 2 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export interface IBookAnnotation {
ZFUTUREPROOFING5: string;
ZANNOTATIONREPRESENTATIVETEXT: string;
ZANNOTATIONSELECTEDTEXT: string;
ZANNOTATIONLOCATION: string;
ZANNOTATIONNOTE: string;
ZANNOTATIONCREATIONDATE: number;
ZANNOTATIONMODIFICATIONDATE: number;
Expand All @@ -23,6 +24,7 @@ export interface IHighlight {
chapter: string;
contextualText: string;
highlight: string;
highlightLocation: string;
note: string;
}
export interface ICombinedBooksAndHighlights {
Expand Down
Binary file modified 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.
Loading