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 (implement suggestions) #27

Merged
merged 1 commit into from
Jul 11, 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
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ node_modules

# tests
coverage
test/mocks/testDatabase.sqlite
# Don't include the compiled main.js file in the repo.
# They should be uploaded to GitHub releases instead.
main.js
Expand Down
1 change: 1 addition & 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}}}` - 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
1 change: 1 addition & 0 deletions migrations/0001_marvelous_mentallo.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": "0e719ef5-4a90-4b4c-8245-5cf855c5b3f1",
"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": 1720611694414,
"tag": "0001_marvelous_mentallo",
"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
8 changes: 8 additions & 0 deletions src/db/seedData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ export const defaultAnnotations = [{
"ZFUTUREPROOFING5": "Introduction",
"ZANNOTATIONREPRESENTATIVETEXT": "This is a contextual text for the hightlight from the iPhone User Guide",
"ZANNOTATIONSELECTEDTEXT": "hightlight from the iPhone User Guide",
"ZANNOTATIONLOCATION": "test-highlight-link-from-the-iphone-user-guide",
"ZANNOTATIONNOTE": "Test note for the hightlight from the iPhone User Guide",
"ZANNOTATIONCREATIONDATE": 685151385.91602,
"ZANNOTATIONMODIFICATIONDATE": 685151385.91602,
Expand All @@ -47,6 +48,7 @@ export const defaultAnnotations = [{
"ZFUTUREPROOFING5": "Introduction",
"ZANNOTATIONREPRESENTATIVETEXT": "This is a contextual text for the hightlight from the iPad User Guide",
"ZANNOTATIONSELECTEDTEXT": "hightlight from the iPad User Guide",
"ZANNOTATIONLOCATION": "test-highlight-link-from-the-ipad-user-guide",
"ZANNOTATIONNOTE": "Test note for the hightlight from the iPad User Guide",
"ZANNOTATIONCREATIONDATE": 685151385.91602,
"ZANNOTATIONMODIFICATIONDATE": 685151385.91602,
Expand All @@ -57,6 +59,7 @@ export const defaultAnnotations = [{
"ZFUTUREPROOFING5": "Introduction",
"ZANNOTATIONREPRESENTATIVETEXT": "This is a contextual text for the hightlight from the Mac User Guide",
"ZANNOTATIONSELECTEDTEXT": "hightlight from the Mac User Guide",
"ZANNOTATIONLOCATION": "test-highlight-link-from-the-mac-user-guide",
"ZANNOTATIONNOTE": "Test note for the hightlight from the Mac User Guide",
"ZANNOTATIONCREATIONDATE": 685151385.91602,
"ZANNOTATIONMODIFICATIONDATE": 685151385.91602,
Expand All @@ -67,6 +70,7 @@ export const defaultAnnotations = [{
"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",
"ZANNOTATIONLOCATION": "test-highlight-link-from-the-apple-watch-user-guide",
"ZANNOTATIONNOTE": "Test note for the hightlight from the Apple Watch User Guide",
"ZANNOTATIONCREATIONDATE": 685151385.91602,
"ZANNOTATIONMODIFICATIONDATE": 685151385.91602,
Expand All @@ -77,6 +81,7 @@ export const defaultAnnotations = [{
"ZFUTUREPROOFING5": "Introduction",
"ZANNOTATIONREPRESENTATIVETEXT": "This is a contextual text for the hightlight from the iPhone User Guide",
"ZANNOTATIONSELECTEDTEXT": "hightlight from the iPhone User Guide",
"ZANNOTATIONLOCATION": "test-highlight-link-from-the-iphone-user-guide",
"ZANNOTATIONNOTE": "Test note for the deleted hightlight from the iPhone User Guide",
"ZANNOTATIONCREATIONDATE": 685151385.91602,
"ZANNOTATIONMODIFICATIONDATE": 685151385.91602,
Expand All @@ -87,6 +92,7 @@ export const defaultAnnotations = [{
"ZFUTUREPROOFING5": "Introduction",
"ZANNOTATIONREPRESENTATIVETEXT": "This is a contextual text for the hightlight from the iPad User Guide",
"ZANNOTATIONSELECTEDTEXT": "hightlight from the iPad User Guide",
"ZANNOTATIONLOCATION": "test-highlight-link-from-the-ipad-user-guide",
"ZANNOTATIONNOTE": "Test note for the deleted hightlight from the iPad User Guide",
"ZANNOTATIONCREATIONDATE": 685151385.91602,
"ZANNOTATIONMODIFICATIONDATE": 685151385.91602,
Expand All @@ -97,6 +103,7 @@ export const defaultAnnotations = [{
"ZFUTUREPROOFING5": "Introduction",
"ZANNOTATIONREPRESENTATIVETEXT": "This is a contextual text for the hightlight from the Mac User Guide",
"ZANNOTATIONSELECTEDTEXT": "hightlight from the Mac User Guide",
"ZANNOTATIONLOCATION": "test-highlight-link-from-the-mac-user-guide",
"ZANNOTATIONNOTE": "Test note for the deleted hightlight from the Mac User Guide",
"ZANNOTATIONCREATIONDATE": 685151385.91602,
"ZANNOTATIONMODIFICATIONDATE": 685151385.91602,
Expand All @@ -107,6 +114,7 @@ export const defaultAnnotations = [{
"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",
"ZANNOTATIONLOCATION": "test-highlight-link-from-the-apple-watch-user-guide",
"ZANNOTATIONNOTE": "Test note for the deleted hightlight from the Apple Watch User Guide",
"ZANNOTATIONCREATIONDATE": 685151385.91602,
"ZANNOTATIONMODIFICATIONDATE": 685151385.91602,
Expand Down
1 change: 1 addition & 0 deletions src/methods/aggregateDetails.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ export const aggregateBookAndHighlightDetails = async (): Promise<ICombinedBooks
contextualText: textForContext ? preserveNewlineIndentation(textForContext) : textForContext,
highlight: preserveNewlineIndentation(annotation.ZANNOTATIONSELECTEDTEXT),
note: userNote ? preserveNewlineIndentation(userNote) : userNote,
highlightLocation: annotation.ZANNOTATIONLOCATION,
highlightStyle: annotation.ZANNOTATIONSTYLE,
highlightCreationDate: annotation.ZANNOTATIONCREATIONDATE,
highlightModificationDate: annotation.ZANNOTATIONMODIFICATIONDATE
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}}
bandantonio marked this conversation as resolved.
Show resolved Hide resolved

{{/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
17 changes: 17 additions & 0 deletions test/db.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,19 @@ describe('Database operations', () => {
expect(highlights[0].ZANNOTATIONNOTE).toEqual('Test note for the hightlight from the iPhone User Guide');
expect(highlights[3].ZANNOTATIONREPRESENTATIVETEXT).toEqual('This is a contextual text for the hightlight from the Apple Watch User Guide');
});

test('Should return a highlight link for each highlight when highlights library is not empty', async () => {
await seedDatabase(annotations, defaultAnnotations);

const dbPath = path.join(process.cwd(), TEST_DATABASE_PATH);
const highlights = await annotationsRequest(dbPath, `SELECT * FROM ${HIGHLIGHTS_LIBRARY_NAME} WHERE ZANNOTATIONDELETED = 0`);

expect(highlights.length).toEqual(4);
expect(highlights[0].ZANNOTATIONLOCATION).toEqual('test-highlight-link-from-the-iphone-user-guide');
expect(highlights[1].ZANNOTATIONLOCATION).toEqual('test-highlight-link-from-the-ipad-user-guide');
expect(highlights[2].ZANNOTATIONLOCATION).toEqual('test-highlight-link-from-the-mac-user-guide');
expect(highlights[3].ZANNOTATIONLOCATION).toEqual('test-highlight-link-from-the-apple-watch-user-guide');
});
});

describe('Database load testing', () => {
Expand All @@ -89,6 +102,7 @@ describe('Database load testing', () => {
ZFUTUREPROOFING5: `Introduction ${j}`,
ZANNOTATIONREPRESENTATIVETEXT: `This is a contextual text for the hightlight from the Book ${i}`,
ZANNOTATIONSELECTEDTEXT: `hightlight from the Book ${i}`,
ZANNOTATIONLOCATION: `test-highlight-link-from-the-book-${i}`,
ZANNOTATIONNOTE: `Test note for the hightlight from the Book ${i}`,
ZANNOTATIONCREATIONDATE: 685151385.91602,
ZANNOTATIONMODIFICATIONDATE: 685151385.91602,
Expand All @@ -110,6 +124,9 @@ describe('Database load testing', () => {
expect(dbBooks.length).toEqual(1000);
expect(dbAnnotations.length).toEqual(3000);

const dbAnnotationLocations = dbAnnotations.filter(({ZANNOTATIONLOCATION}) => ZANNOTATIONLOCATION !== null && ZANNOTATIONLOCATION !== undefined);
expect(dbAnnotationLocations.length).toEqual(3000);

expect(endTime - startTime).toBeLessThan(500);
});
});
4 changes: 4 additions & 0 deletions test/mocks/aggregatedDetailsData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export const annotationsToAggregate = [{
"ZFUTUREPROOFING5": "Aggregated Introduction",
"ZANNOTATIONREPRESENTATIVETEXT": "This is a contextual text for the aggregated hightlight from the Apple iPhone User Guide",
"ZANNOTATIONSELECTEDTEXT": "aggregated hightlight from the Apple iPhone User Guide",
"ZANNOTATIONLOCATION": "aggregated-highlight-link-from-the-apple-iphone-user-guide",
"ZANNOTATIONNOTE": "Test note for the aggregated hightlight from the Apple iPhone User Guide",
"ZANNOTATIONCREATIONDATE": 731876693.002279,
"ZANNOTATIONMODIFICATIONDATE": 731876693.002279,
Expand All @@ -23,6 +24,7 @@ export const annotationsToAggregate = [{
"ZFUTUREPROOFING5": "Another aggregated Introduction",
"ZANNOTATIONREPRESENTATIVETEXT": "This is a contextual text for the aggregated hightlight from the Apple iPhone User Guide\n\ncontaining a new line to test the preservation of indentation",
"ZANNOTATIONSELECTEDTEXT": "aggregated hightlight from the Apple iPhone User Guide\n\ncontaining a new line to test the preservation of indentation",
"ZANNOTATIONLOCATION": "aggregated-highlight-link-from-the-apple-iphone-user-guide",
"ZANNOTATIONNOTE": "Test note for the aggregated hightlight from the Apple iPhone User Guide\n\nalong with a new line to test the preservation of indentation",
"ZANNOTATIONCREATIONDATE": 731876693.002279,
"ZANNOTATIONMODIFICATIONDATE": 731876693.002279,
Expand All @@ -43,6 +45,7 @@ export const aggregatedHighlights = [{
"contextualText": "This is a contextual text for the aggregated hightlight from the Apple iPhone User Guide",
"highlight": "aggregated hightlight from the Apple iPhone User Guide",
"note": "Test note for the aggregated hightlight from the Apple iPhone User Guide",
"highlightLocation": "aggregated-highlight-link-from-the-apple-iphone-user-guide",
"highlightStyle": 3,
"highlightCreationDate": 731876693.002279,
"highlightModificationDate": 731876693.002279
Expand All @@ -51,6 +54,7 @@ export const aggregatedHighlights = [{
"contextualText": "This is a contextual text for the aggregated hightlight from the Apple iPhone User Guide\ncontaining a new line to test the preservation of indentation",
"highlight": "aggregated hightlight from the Apple iPhone User Guide\ncontaining a new line to test the preservation of indentation",
"note": "Test note for the aggregated hightlight from the Apple iPhone User Guide\nalong with a new line to test the preservation of indentation",
"highlightLocation": "aggregated-highlight-link-from-the-apple-iphone-user-guide",
"highlightStyle": 3,
"highlightCreationDate": 731876693.002279,
"highlightModificationDate": 731876693.002279
Expand Down
1 change: 1 addition & 0 deletions test/mocks/rawTemplates.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ Number of annotations:: {{annotations.length}}
{{else 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}}
- <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
Loading