Skip to content

Commit c0edcaa

Browse files
authored
Merge pull request #76 from omnivore-app/fix/remove-duplicates
fix/remove duplicates
2 parents be1b982 + 0e60788 commit c0edcaa

File tree

4 files changed

+79
-40
lines changed

4 files changed

+79
-40
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
"icon": "./public/icon.png"
2525
},
2626
"dependencies": {
27-
"@logseq/libs": "^0.0.10",
27+
"@logseq/libs": "^0.0.14",
2828
"date-fns": "^2.29.3",
2929
"diff-match-patch": "^1.0.5",
3030
"luxon": "^3.2.1",

src/index.ts

Lines changed: 62 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ interface Settings {
4343
pageName: string
4444
articleTemplate: string
4545
highlightTemplate: string
46+
loading: boolean
4647
}
4748

4849
const siteNameFromUrl = (originalArticleUrl: string): string => {
@@ -54,7 +55,6 @@ const siteNameFromUrl = (originalArticleUrl: string): string => {
5455
}
5556

5657
const delay = (t = 100) => new Promise((r) => setTimeout(r, t))
57-
let loading = false
5858

5959
const getQueryFromFilter = (filter: Filter, customQuery: string): string => {
6060
switch (filter) {
@@ -76,9 +76,13 @@ const isValidCurrentGraph = async (): Promise<boolean> => {
7676
return currentGraph?.name === settings.graph
7777
}
7878

79-
const fetchOmnivore = async (inBackground = false) => {
80-
if (loading) return
79+
const deleteBlocks = async (blocks: BlockEntity[]) => {
80+
for await (const block of blocks) {
81+
await logseq.Editor.removeBlock(block.uuid)
82+
}
83+
}
8184

85+
const fetchOmnivore = async (inBackground = false) => {
8286
const {
8387
syncAt,
8488
apiKey,
@@ -89,7 +93,16 @@ const fetchOmnivore = async (inBackground = false) => {
8993
articleTemplate,
9094
highlightTemplate,
9195
graph,
96+
loading,
9297
} = logseq.settings as Settings
98+
// prevent multiple fetches
99+
if (loading) {
100+
await logseq.UI.showMsg('Omnivore is already syncing', 'warning', {
101+
timeout: 3000,
102+
})
103+
return
104+
}
105+
logseq.updateSettings({ loading: true })
93106

94107
if (!apiKey) {
95108
await logseq.UI.showMsg('Missing Omnivore api key', 'warning', {
@@ -119,15 +132,17 @@ const fetchOmnivore = async (inBackground = false) => {
119132

120133
await delay(300)
121134

122-
loading = true
123135
let targetBlock: BlockEntity | null = null
124136
const userConfigs = await logseq.App.getUserConfigs()
125137
const preferredDateFormat: string = userConfigs.preferredDateFormat
138+
const fetchingMsgKey = 'omnivore-fetching'
126139

127140
try {
128141
console.log(`logseq-omnivore starting sync since: '${syncAt}`)
129-
130-
!inBackground && (await logseq.UI.showMsg('🚀 Fetching articles ...'))
142+
!inBackground &&
143+
(await logseq.UI.showMsg(fetchingTitle, 'success', {
144+
key: fetchingMsgKey,
145+
}))
131146

132147
let omnivorePage = await logseq.Editor.getPage(pageName)
133148
if (!omnivorePage) {
@@ -175,9 +190,11 @@ const fetchOmnivore = async (inBackground = false) => {
175190
new Date(article.savedAt),
176191
preferredDateFormat
177192
)
193+
const datePublished = article.publishedAt
194+
? formatDate(new Date(article.publishedAt), preferredDateFormat)
195+
: undefined
178196
// Build content string based on template
179-
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
180-
const content = render(articleTemplate, {
197+
const articleView = {
181198
title: article.title,
182199
omnivoreUrl: `https://omnivore.app/me/${article.slug}`,
183200
siteName,
@@ -186,8 +203,10 @@ const fetchOmnivore = async (inBackground = false) => {
186203
labels: article.labels,
187204
dateSaved,
188205
content: article.content,
189-
})
190-
206+
datePublished,
207+
}
208+
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
209+
const content = render(articleTemplate, articleView)
191210
// sort highlights by location if selected in options
192211
highlightOrder === HighlightOrder.LOCATION &&
193212
article.highlights?.sort((a, b) => {
@@ -210,6 +229,7 @@ const fetchOmnivore = async (inBackground = false) => {
210229
// Build content string based on template
211230
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
212231
const content = render(highlightTemplate, {
232+
...articleView,
213233
text: it.quote,
214234
labels: it.labels,
215235
highlightUrl: `https://omnivore.app/me/${article.slug}#${it.id}`,
@@ -247,10 +267,12 @@ const fetchOmnivore = async (inBackground = false) => {
247267
if (existingBlocks.length > 0) {
248268
isNewArticle = false
249269
const existingBlock = existingBlocks[0]
250-
// update existing block
270+
// update the first existing block
251271
if (existingBlock.content !== content) {
252272
await logseq.Editor.updateBlock(existingBlock.uuid, content)
253273
}
274+
// delete the rest of the existing blocks
275+
await deleteBlocks(existingBlocks.slice(1))
254276
if (highlightBatch.length > 0) {
255277
// append highlights to existing block
256278
for (const highlight of highlightBatch) {
@@ -357,21 +379,26 @@ const fetchOmnivore = async (inBackground = false) => {
357379
).flat()
358380

359381
if (existingBlocks.length > 0) {
360-
await logseq.Editor.removeBlock(existingBlocks[0].uuid)
382+
await deleteBlocks(existingBlocks)
361383
}
362384
}
363385
}
364386

365-
!inBackground && (await logseq.UI.showMsg('🔖 Articles fetched'))
387+
if (!inBackground) {
388+
logseq.UI.closeMsg(fetchingMsgKey)
389+
await logseq.UI.showMsg('🔖 Articles fetched', 'success', {
390+
timeout: 2000,
391+
})
392+
}
366393
logseq.updateSettings({ syncAt: DateTime.local().toFormat(DATE_FORMAT) })
367394
} catch (e) {
368395
!inBackground &&
369-
(await logseq.UI.showMsg('Failed to fetch articles', 'warning'))
396+
(await logseq.UI.showMsg('Failed to fetch articles', 'error'))
370397
console.error(e)
371398
} finally {
372-
loading = false
373399
targetBlock &&
374400
(await logseq.Editor.updateBlock(targetBlock.uuid, blockTitle))
401+
logseq.updateSettings({ loading: false })
375402
}
376403
}
377404

@@ -477,26 +504,29 @@ const main = async (baseInfo: LSPluginBaseInfo) => {
477504
type: 'string',
478505
title: 'Enter the template to use for new articles',
479506
description:
480-
'Enter the template to use for new articles. Required variables are: {{{title}}}, {{{omnivoreUrl}}}. Optional variables are: {{{siteName}}}, {{{originalUrl}}}, {{{author}}}, {{{labels}}}, {{{dateSaved}}}',
507+
'Enter the template to use for new articles. Required variables are: {{{title}}}, {{{omnivoreUrl}}}. Optional variables are: {{{siteName}}}, {{{originalUrl}}}, {{{author}}}, {{{labels}}}, {{{dateSaved}}}, {{{datePublished}}}',
481508
default: `[{{{title}}}]({{{omnivoreUrl}}})
482-
collapsed:: true
483-
site:: {{#siteName}}[{{{siteName}}}]{{/siteName}}({{{originalUrl}}})
484-
{{#author}}
485-
author:: {{{author}}}
486-
{{/author}}
487-
{{#labels.length}}
488-
labels:: {{#labels}}[[{{{name}}}]]{{/labels}}
489-
{{/labels.length}}
490-
date_saved:: {{{dateSaved}}}`,
509+
collapsed:: true
510+
site:: {{#siteName}}[{{{siteName}}}]{{/siteName}}({{{originalUrl}}})
511+
{{#author}}
512+
author:: {{{author}}}
513+
{{/author}}
514+
{{#labels.length}}
515+
labels:: {{#labels}}[[{{{name}}}]]{{/labels}}
516+
{{/labels.length}}
517+
date-saved:: {{{dateSaved}}}
518+
{{#datePublished}}
519+
date-published:: {{{datePublished}}}
520+
{{/datePublished}}`,
491521
inputAs: 'textarea',
492522
},
493523
{
494524
key: 'highlightTemplate',
495525
type: 'string',
496526
title: 'Enter the template to use for new highlights',
497527
description:
498-
'Enter the template to use for new highlights. Required variables are: {{{text}}}, {{{highlightUrl}}}. Optional variables are {{{dateHighlighted}}}',
499-
default: `> {{{text}}} [⤴️]({{{highlightUrl}}}) {{#labels}}#[[{{{name}}}]] {{/labels}}`,
528+
'Enter the template to use for new highlights. Required variables are: {{{text}}}, {{{highlightUrl}}}. Optional variables are {{{dateHighlighted}}}. You can also use the variables in the article template.',
529+
default: `> {{{text}}} [⤴️]({{{highlightUrl}}}) {{#labels}} #[[{{{name}}}]] {{/labels}}`,
500530
inputAs: 'textarea',
501531
},
502532
]
@@ -565,17 +595,18 @@ const main = async (baseInfo: LSPluginBaseInfo) => {
565595
void (async () => {
566596
// reset the last sync time
567597
logseq.updateSettings({ syncAt: '' })
568-
await logseq.UI.showMsg('Omnivore Last Sync reset')
598+
await logseq.UI.showMsg('Omnivore Last Sync reset', 'warning', {
599+
timeout: 3000,
600+
})
569601

570602
await fetchOmnivore()
571603
})()
572604
}
573605
)
574606

575607
logseq.provideStyle(`
576-
[data-injected-ui=logseq-omnivore-${baseInfo.id}] {
577-
display: flex;
578-
align-items: center;
608+
div[data-id="${baseInfo.id}"] div[data-key="articleTemplate"] textarea {
609+
height: 14rem;
579610
}
580611
`)
581612

src/util.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ export interface Article {
6565
savedAt: string
6666
pageType: PageType
6767
content?: string
68+
publishedAt?: string
6869
}
6970

7071
export interface Label {
@@ -135,6 +136,7 @@ export const loadArticles = async (
135136
savedAt
136137
pageType
137138
content
139+
publishedAt
138140
highlights {
139141
id
140142
quote
@@ -248,5 +250,11 @@ export const parseDateTime = (str: string): DateTime => {
248250
}
249251

250252
export const formatDate = (date: Date, preferredDateFormat: string): string => {
251-
return `[[${format(date, preferredDateFormat)}]]`
253+
return `[[${format(date, preferredDateFormat, {
254+
// YY and YYYY represent the local week-numbering year (44, 01, 00, 17)
255+
// are often confused with yy and yyyy that represent the calendar year
256+
// Here, we accept tokens YY and DD
257+
useAdditionalDayOfYearTokens: true,
258+
useAdditionalWeekYearTokens: true,
259+
})}]]`
252260
}

yarn.lock

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -119,10 +119,10 @@
119119
dependencies:
120120
"@lezer/common" "^0.15.0"
121121

122-
"@logseq/libs@^0.0.10":
123-
version "0.0.10"
124-
resolved "https://registry.yarnpkg.com/@logseq/libs/-/libs-0.0.10.tgz#305d65b733ed16d157f57a1a0759e0233d1b1a81"
125-
integrity sha512-Ah5wAhLcgrlOtk/9nEe11UsqOzvpcEaEWDV+oFD3TIGTeP4mfv2HjDiPYPBGXuMZRgvsW6klQLzzaxMieksXXg==
122+
"@logseq/libs@^0.0.14":
123+
version "0.0.14"
124+
resolved "https://registry.yarnpkg.com/@logseq/libs/-/libs-0.0.14.tgz#2fbce790d61c28e124063a20153f748f90ffa352"
125+
integrity sha512-QcNeVxb4LIvV4Tid0ABZXV7fxYdZHynzLlukSk6Ydkuus+hBzLcjfK15nzybIRbiV7ANqSgTooDZkV/E4WP57Q==
126126
dependencies:
127127
csstype "3.1.0"
128128
debug "4.3.4"
@@ -1654,9 +1654,9 @@ camelcase@^6.0.0:
16541654
integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==
16551655

16561656
caniuse-lite@^1.0.30001349:
1657-
version "1.0.30001352"
1658-
resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001352.tgz"
1659-
integrity sha512-GUgH8w6YergqPQDGWhJGt8GDRnY0L/iJVQcU3eJ46GYf52R8tk0Wxp0PymuFVZboJYXGiCqwozAYZNRjVj6IcA==
1657+
version "1.0.30001460"
1658+
resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001460.tgz"
1659+
integrity sha512-Bud7abqjvEjipUkpLs4D7gR0l8hBYBHoa+tGtKJHvT2AYzLp1z7EmVkUT4ERpVUfca8S2HGIVs883D8pUH1ZzQ==
16601660

16611661
cardinal@^2.1.1:
16621662
version "2.1.1"

0 commit comments

Comments
 (0)