Skip to content

Commit e67da98

Browse files
[1.1.3] Readwise (#573)
* [1.1.3] Readwise - Code cleanup - Flow fixes - BugFix: escape leading quotes in titles Signed-off-by: Aaron Gascoigne <[email protected]> Change highlight web handler Signed-off-by: Aaron Gascoigne <[email protected]> Fix some titles not being escaped * Bugfix: Remove all new lines
1 parent 4b85730 commit e67da98

File tree

8 files changed

+116
-77
lines changed

8 files changed

+116
-77
lines changed

aaronpoweruser.ReadwiseUnofficial/CHANGELOG.md

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,62 +4,83 @@
44

55
See Plugin [README](https://github.com/NotePlan/plugins/blob/main/aaronpoweruser.ReadwiseUnofficial/README.md) for details on available commands and use case.
66

7+
## [1.1.3] Readwise 2024-05-22 (@aaronpoweruser)
8+
9+
- Ignore leading escaped quotes
10+
- Code cleanup
11+
- Remove illegal characters in daily review titles.
12+
- Switch book highlight links to Kindle web reader as deep links are [deprecated](https://help.readwise.io/article/40-can-i-jump-to-a-highlight-directly-in-the-kindle-app).
713

814
## [1.1.2] Readwise 2024-04-22 (aaronpoweruser)
15+
916
- Fix Sync log dates not respecting time zones.
1017

1118
## [1.1.1] Readwise 2024-04-20 (aaronpoweruser)
19+
1220
- Fix internal links in daily reviews.
1321

1422
## [1.1.0] Readwise 2024-04-19 (aaronpoweruser)
23+
1524
- Refactor
1625
- Added a sync log see [README](https://github.com/NotePlan/plugins/blob/main/aaronpoweruser.ReadwiseUnofficial/README.md).
1726
- Fixed alert dialog count being wrong sometimes.
1827
- Fixed illegal characters and newlines in titles.
1928
- Add support for daily reviews via template.
2029

2130
## [1.0.1] Readwise 2023-08-20 (aaronpoweruser)
22-
* [#452] Fix pagination issue for users with large libraries thanks @TobiasMende
31+
32+
- [#452] Fix pagination issue for users with large libraries thanks @TobiasMende
2333

2434
## [1.0.0] Readwise 2023-02-07 (aaronpoweruser)
25-
* public release
35+
36+
- public release
2637

2738
## [0.1.8] Readwise 2023-02-07 (aaronpoweruser)
28-
* Show user notes
29-
* Add support for highlight headings
39+
40+
- Show user notes
41+
- Add support for highlight headings
42+
3043
## [0.1.7] Readwise 2023-01-25 (aaronpoweruser)
31-
* Settings description clean up
32-
* Fix null highlight links
33-
* Fix unneeded long titles
44+
45+
- Settings description clean up
46+
- Fix null highlight links
47+
- Fix unneeded long titles
48+
3449
## [0.1.6] - 2023-01-12 (aaronpoweruser)
50+
3551
- Fix access token dialog
3652
- Use readable titles to make linking to notes easier
3753
- Add long title field
3854
- Allow Supplemental(readwise generated) notes to be grouped with main notes
3955
- Change highlights from list to quotes
4056

4157
## [0.1.5] - 2023-01-12 (aaronpoweruser)
58+
4259
- Fix metadata not being created
4360
- Fixed double metadata when not using group by type
4461
- Allow empty tag prefixes
4562

4663
Known issues:
64+
4765
- "Don’t Set Goals… Do This Instead" causes a new note to be created
4866
- Using heading as metadata does not support tag updates
4967
- Images are not handled gracefully
5068

5169
## [0.1.4] - 2023-01-09 (aaronpoweruser)
70+
5271
- Clean up new lines in notes
5372
- add success message
5473
- Fix rebuild
5574

5675
## [0.1.3] - 2023-01-03 (aaronpoweruser)
76+
5777
- Add front matter support
5878
- Add optional tag prefix
5979
- Clean up settings
6080
- Code cleanup
6181

6282
## [0.1.2] - 2023-01-02 (aaronpoweruser)
83+
6384
- Add missing highlight header
6485
- Increase timeout when checking for new note
6586

@@ -71,6 +92,7 @@ Known issues:
7192
- Add link to kindle for books (fixes links being null)
7293

7394
## [0.1.0] - 2022-12-28 (aaronpoweruser)
95+
7496
First release
7597

7698
## Changelog

aaronpoweruser.ReadwiseUnofficial/README.md

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
# Readwise Unofficial Noteplan Plugin
22

3-
## About This Plugin
3+
## About This Plugin
44

55
A sync engine for readwise
66

77
### Features
8+
89
- Daily review's via templates
910
- Full highlight download
1011
- Highlight updates
@@ -17,14 +18,15 @@ A sync engine for readwise
1718
![General features](docs/ReadwiseSync.png)
1819

1920
### Todo
20-
* Index note
21-
* Image support (needs Noteplan API update)
2221

23-
### Known issues:
22+
- Index note
23+
- Image support (needs Noteplan API update)
24+
25+
### Known issues
26+
2427
- Using heading as metadata does not support tag updates
2528
- Images are not handled gracefully
2629

27-
2830
## Commands
2931

3032
### //Readwise sync
@@ -36,19 +38,17 @@ Downloads new highlights since last sync
3638
**Only needs to be used if highlights are deleted**
3739
Downloads all highlights (if they already exist they will be duplicated)
3840

39-
4041
### //Readwise Daily review
4142

4243
Downloads daily reviews (does not mark as read) with links to note and author.
4344
Can be added to a note with templates using
4445

45-
```
46+
``` javascript
4647
<%- await DataStore.invokePluginCommandByName("Readwise Daily Review","aaronpoweruser.ReadwiseUnofficial") %>
4748
```
4849

4950
![Daily review](docs/dailyReview.png)
5051

51-
5252
## Settings
5353

5454
These commands require configuration.
@@ -87,4 +87,4 @@ A note that has all highlights synced during a sync with dated references.
8787

8888
## Latest Updates
8989

90-
See [CHANGELOG](https://github.com/NotePlan/plugins/blob/main/aaronpoweruser.ReadwiseUnofficial/CHANGELOG.md) for latest updates/changes to this plugin.
90+
See [CHANGELOG](https://github.com/NotePlan/plugins/blob/main/aaronpoweruser.ReadwiseUnofficial/CHANGELOG.md) for latest updates/changes to this plugin.

aaronpoweruser.ReadwiseUnofficial/plugin.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44
"noteplan.minAppVersion": "3.4.0",
55
"plugin.id": "aaronpoweruser.ReadwiseUnofficial",
66
"plugin.name": "📚 Readwise Unofficial",
7-
"plugin.version": "1.1.2",
8-
"plugin.lastUpdateInfo": "Fix sync log dates being wrong.\nAdd a sync log note. \nAdd support for daily reviews via templates",
7+
"plugin.version": "1.1.3",
8+
"plugin.lastUpdateInfo": "Ignore leading escaped quotes. Fixed links to highlights on web.\nFix sync log dates being wrong.\nAdd a sync log note. \nAdd support for daily reviews via templates",
99
"plugin.description": "A sync plugin for Readwise",
1010
"plugin.author": "aaronpoweruser",
1111
"plugin.dependencies": [],
@@ -118,7 +118,7 @@
118118
"required": true
119119
},
120120
{
121-
"COMMENT": "Enable to force resyncing of all highlights",
121+
"COMMENT": "Enable to force a resync of all highlights",
122122
"title": "Force sync all highlights",
123123
"key": "forceSync",
124124
"type": "hidden",

aaronpoweruser.ReadwiseUnofficial/src/NPReadwise.js

Lines changed: 19 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
// @flow
22
import { showMessage } from '../../helpers/userInput'
33
import pluginJson from '../plugin.json'
4-
import { checkAccessToken, escapeTwitterHandle } from './NPReadwiseHelpers'
4+
import { checkAccessToken, escapeTwitterHandle, removeInvalidChars, removeNewlines } from './NPReadwiseHelpers'
55
import { parseHighlightsAndWriteToNote } from './NPReadwiseNotes'
6-
import { startReadwiseSyncLog, finishReadwiseSyncLog } from './NPReadwiseSync'
6+
import { startReadwiseSyncLog, finishReadwiseSyncLog } from './NPReadwiseSyncLog'
77
import { log, logDebug, logError } from '@helpers/dev'
88

99
const LAST_SYNC_TIME = 'last_sync_time'
@@ -36,17 +36,17 @@ export async function readwiseDailyReview(): Promise<string> {
3636
}
3737

3838
async function handleReadwiseSync(response: any): Promise<void> {
39-
let downloadHiglightCount = 0,
39+
let downloadHighlightCount = 0,
4040
updatedSourceCount = 0
4141
await startReadwiseSyncLog()
42-
response.forEach((highightSource) => {
42+
response.forEach((highlightSource) => {
4343
updatedSourceCount++
44-
downloadHiglightCount += highightSource.highlights.length
45-
parseHighlightsAndWriteToNote(highightSource)
44+
downloadHighlightCount += highlightSource.highlights.length
45+
parseHighlightsAndWriteToNote(highlightSource)
4646
})
47-
log(pluginJson, `Downloaded ${downloadHiglightCount} highlights from Readwise. Updated ${updatedSourceCount} notes.`)
48-
await showMessage(`Downloaded ${downloadHiglightCount} highlights from Readwise. Updated ${updatedSourceCount} notes.`)
49-
await finishReadwiseSyncLog(downloadHiglightCount, updatedSourceCount)
47+
log(pluginJson, `Downloaded ${downloadHighlightCount} highlights from Readwise. Updated ${updatedSourceCount} notes.`)
48+
await showMessage(`Downloaded ${downloadHighlightCount} highlights from Readwise. Updated ${updatedSourceCount} notes.`)
49+
await finishReadwiseSyncLog(downloadHighlightCount, updatedSourceCount)
5050
}
5151

5252
/**
@@ -90,7 +90,6 @@ async function doReadWiseFetch(accessToken: string, lastFetchTime: string, downl
9090
DataStore.saveData(new Date().toISOString(), LAST_SYNC_TIME, true)
9191

9292
const parsedJson = JSON.parse(response)
93-
// DataStore.saveData(JSON.stringify(Json), 'readwise_data.json', true)
9493
const pageCursor = parsedJson.nextPageCursor
9594
logDebug(pluginJson, `page cursor is : ${pageCursor}`)
9695

@@ -99,15 +98,17 @@ async function doReadWiseFetch(accessToken: string, lastFetchTime: string, downl
9998
if (pageCursor !== null && pageCursor !== '') {
10099
data = await doReadWiseFetch(accessToken, lastFetchTime, count, pageCursor)
101100
}
102-
return parsedJson.results.concat(data)
101+
const result = parsedJson.results.concat(data)
102+
// DataStore.saveData(JSON.stringify(result), 'readwise_data.json', true)
103+
return result
103104
} catch (error) {
104105
logError(pluginJson, error)
105106
}
106107
}
107108
/*
108109
* Gets the users Daily review from the readwise api
109-
* @returns {string} - the daily review highlights
110-
*/
110+
* @returns {string} - the daily review highlights
111+
*/
111112
async function getReadwiseDailyReview(): Promise<string> {
112113
const accessToken = DataStore.settings.accessToken ?? ''
113114
let highlightString = ''
@@ -124,15 +125,16 @@ async function getReadwiseDailyReview(): Promise<string> {
124125
const highlights = JSON.parse(response).highlights
125126

126127
await highlights.map((highlight) => {
127-
const formattedHighlight = `${highlight.text.replace(/\n/g, ' ')} [ [[${highlight.title}]], [[${escapeTwitterHandle(highlight.author)}]] ]`
128+
const formattedHighlight = `${removeNewlines(highlight.text)} [ [[${removeInvalidChars(highlight.title)}]], [[${escapeTwitterHandle(highlight.author)}]] ]`
128129
highlightString += `> ${formattedHighlight}\n`
129130
})
130-
if (highlightString.length > 1) { // remove the last newline
131+
if (highlightString.endsWith('\n')) {
132+
// remove the last newline
131133
highlightString = highlightString.substring(0, highlightString.length - 1)
132134
}
133-
logDebug(pluginJson, `daily review highlights are \n\n ${highlightString}`)
134-
return highlightString
135+
logDebug(pluginJson, `Daily review highlights are\n\n ${highlightString}`)
135136
} catch (error) {
136137
logError(pluginJson, error)
137138
}
139+
return highlightString
138140
}

aaronpoweruser.ReadwiseUnofficial/src/NPReadwiseHelpers.js

Lines changed: 30 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ const READWISE_API_KEY_LENGTH = 50
88
/**
99
* Checks if the readwise access token is valid
1010
*/
11-
export async function checkAccessToken(): void {
11+
export async function checkAccessToken(): Promise<void> {
1212
const accessToken = DataStore.settings.accessToken ?? ''
1313
logDebug(pluginJson, `access token is : ${accessToken}`)
1414

@@ -25,38 +25,46 @@ export async function checkAccessToken(): void {
2525
*/
2626
export function buildReadwiseNoteTitle(source: any): string {
2727
if (source.readable_title !== '') {
28-
return source.readable_title
29-
.replace(/\/*$/, '')
30-
.replace(/^(.+)\/[^\/]*?$/, '$1')
31-
.replace('\n', '')
28+
return removeInvalidChars(source.readable_title)
3229
} else if (source.title !== '') {
33-
return source.title
34-
.replace(/\/*$/, '')
35-
.replace(/^(.+)\/[^\/]*?$/, '$1')
36-
.replace('\n', '')
30+
return removeInvalidChars(source.title)
3731
} else {
38-
return source.author
39-
.replace(/\/*$/, '')
40-
.replace(/^(.+)\/[^\/]*?$/, '$1')
41-
.replace('\n', '')
32+
return removeInvalidChars(source.author)
4233
}
4334
}
4435

36+
/**
37+
* Sanitize the string by removing invalid characters
38+
* @param {string} string - the string to sanitize
39+
* @returns {string} - the sanitized string
40+
*/
41+
export function removeInvalidChars(string: string): string {
42+
return removeNewlines(
43+
string
44+
.replace(/^"/, '') // remove leading double quote
45+
.trim(),
46+
)
47+
}
48+
4549
/**
4650
* Parse readwise data and generate front matter
4751
* @param {*} source - the readwise data as a JSON object
4852
* @returns
4953
*/
5054
export function buildReadwiseFrontMatter(source: any): any {
5155
const frontMatter = {}
56+
// $FlowIgnore[prop-missing] - intentionally setting properties dynamically as frontMatter keys are dynamic
5257
frontMatter.author = `[[${escapeTwitterHandle(source.author)}]]`
5358
if (source.readable_title.toLowerCase().trim() !== source.title.toLowerCase().trim()) {
54-
frontMatter.long_title = source.title
59+
// $FlowIgnore[prop-missing] - intentionally setting properties dynamically as frontMatter keys are dynamic
60+
frontMatter.long_title = removeInvalidChars(source.title)
5561
}
5662
if (source.book_tags !== null && source.book_tags.length > 0) {
63+
// $FlowIgnore[prop-missing] - intentionally setting properties dynamically as frontMatter keys are dynamic
5764
frontMatter.tags = source.book_tags.map((tag) => `${formatTag(tag.name)}`).join(', ')
5865
}
5966
if (source.unique_url !== null) {
67+
// $FlowIgnore[prop-missing] - we are intentionally setting properties dynamically
6068
frontMatter.url = source.unique_url
6169
}
6270
return frontMatter
@@ -68,15 +76,15 @@ export function buildReadwiseFrontMatter(source: any): any {
6876
* @returns {string} - the formatted heading
6977
*/
7078
export function buildReadwiseMetadataHeading(source: any): string {
71-
let metadata = `author: [[${escapeTwitterHandle(source.author)}]]` + '\n'
79+
let metadata = `author: [[${escapeTwitterHandle(source.author)}]]\n`
7280
if (source.book_tags !== null && source.book_tags.length > 0) {
7381
metadata += `tags: ${source.book_tags.map((tag) => `${formatTag(tag.name)}`).join(', ')}\n`
7482
}
7583
if (source.unique_url !== null) {
7684
metadata += `url: ${source.unique_url}`
7785
}
7886
if (source.readable_title.toLowerCase().trim() !== source.title.toLowerCase().trim()) {
79-
metadata += `long_title: ${source.title}`
87+
metadata += `long_title: ${removeInvalidChars(source.title)}`
8088
}
8189
return metadata
8290
}
@@ -95,12 +103,13 @@ function formatTag(tag: string): string {
95103
}
96104
}
97105

98-
/*
99-
* removes all empty lines in a note
100-
* @param {Tnote} note - the note to remove empty lines from
106+
/**
107+
* Remove all newline characters from a string
108+
* @param {string} text - the text to remove newline characters from
109+
* @returns {string} - the text with newline characters removed
101110
*/
102-
export function removeEmptyLines(note: ?Tnote): void {
103-
note.content = note?.content?.replace(/^\s*\n/gm, '')
111+
export function removeNewlines(text: string): string {
112+
return text.replaceAll(/\n/g, ' ')
104113
}
105114

106115
/**

0 commit comments

Comments
 (0)