Skip to content

Commit

Permalink
Merge pull request #83 from omnivore-app/add-note
Browse files Browse the repository at this point in the history
add note variable to the article and highlight template
  • Loading branch information
sywhb authored Apr 5, 2023
2 parents 8610e18 + 866528f commit 20f34ca
Show file tree
Hide file tree
Showing 2 changed files with 98 additions and 64 deletions.
137 changes: 80 additions & 57 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
escapeQuotationMarks,
formatDate,
getHighlightLocation,
HighlightType,
loadArticles,
loadDeletedArticleSlugs,
PageType,
Expand Down Expand Up @@ -45,6 +46,7 @@ interface Settings {
highlightTemplate: string
loading: boolean
syncJobId: number
endpoint: string
}

const siteNameFromUrl = (originalArticleUrl: string): string => {
Expand Down Expand Up @@ -95,6 +97,7 @@ const fetchOmnivore = async (inBackground = false) => {
highlightTemplate,
graph,
loading,
endpoint,
} = logseq.settings as Settings
// prevent multiple fetches
if (loading) {
Expand Down Expand Up @@ -180,7 +183,8 @@ const fetchOmnivore = async (inBackground = false) => {
parseDateTime(syncAt).toISO(),
getQueryFromFilter(filter, customQuery),
true,
'markdown'
'markdown',
endpoint
)

const articleBatch: IBatchBlock[] = []
Expand All @@ -194,8 +198,11 @@ const fetchOmnivore = async (inBackground = false) => {
const datePublished = article.publishedAt
? formatDate(new Date(article.publishedAt), preferredDateFormat)
: undefined
const note = article.highlights?.find(
(h) => h.type === HighlightType.Note
)
// Build content string based on template
const articleView = {
const articleVariables = {
title: article.title,
omnivoreUrl: `https://omnivore.app/me/${article.slug}`,
siteName,
Expand All @@ -205,12 +212,15 @@ const fetchOmnivore = async (inBackground = false) => {
dateSaved,
content: article.content,
datePublished,
note: note?.annotation,
}
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
const content = render(articleTemplate, articleView)
// filter out notes and redactions
const highlights = article.highlights?.filter(
(h) => h.type === HighlightType.Highlight
)
// sort highlights by location if selected in options
highlightOrder === HighlightOrder.LOCATION &&
article.highlights?.sort((a, b) => {
if (highlightOrder === HighlightOrder.LOCATION) {
highlights?.sort((a, b) => {
try {
if (article.pageType === PageType.File) {
// sort by location in file
Expand All @@ -225,12 +235,13 @@ const fetchOmnivore = async (inBackground = false) => {
return compareHighlightsInFile(a, b)
}
})
const highlightBatch: (IBatchBlock & { id: string })[] =
article.highlights?.map((it) => {
}
const highlightBatch: IBatchBlock[] =
highlights?.map((it) => {
// Build content string based on template
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
const content = render(highlightTemplate, {
...articleView,
...articleVariables,
text: it.quote,
labels: it.labels,
highlightUrl: `https://omnivore.app/me/${article.slug}#${it.id}`,
Expand All @@ -245,7 +256,9 @@ const fetchOmnivore = async (inBackground = false) => {
return {
content,
children: noteChild ? [noteChild] : undefined,
id: it.id,
properties: {
id: it.id,
},
}
}) || []

Expand All @@ -265,45 +278,48 @@ const fetchOmnivore = async (inBackground = false) => {
[(clojure.string/includes? ?c "${article.slug}")]]`
)
).flat()
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
const articleContent = render(articleTemplate, articleVariables)
if (existingBlocks.length > 0) {
isNewArticle = false
const existingBlock = existingBlocks[0]
// update the first existing block
if (existingBlock.content !== content) {
await logseq.Editor.updateBlock(existingBlock.uuid, content)
if (existingBlock.content !== articleContent) {
await logseq.Editor.updateBlock(existingBlock.uuid, articleContent)
}
// delete the rest of the existing blocks
await deleteBlocks(existingBlocks.slice(1))
if (highlightBatch.length > 0) {
// append highlights to existing block
for (const highlight of highlightBatch) {
const existingHighlights = (
await logseq.DB.datascriptQuery<BlockEntity[]>(
`[:find (pull ?b [*])
// append highlights to existing block
for (const highlight of highlightBatch) {
const existingHighlights = (
await logseq.DB.datascriptQuery<BlockEntity[]>(
`[:find (pull ?b [*])
:where
[?b :block/parent ?p]
[?p :block/uuid ?u]
[(str ?u) ?s]
[(= ?s "${existingBlock.uuid}")]
[?b :block/content ?c]
[(clojure.string/includes? ?c "${highlight.id}")]]`
)
).flat()
if (existingHighlights.length > 0) {
const existingHighlight = existingHighlights[0]
// update existing highlight if content is different
existingHighlight.content !== highlight.content &&
(await logseq.Editor.updateBlock(
existingHighlight.uuid,
highlight.content
))

// checking notes
const noteChild = highlight.children?.[0]
if (noteChild) {
const existingNotes = (
await logseq.DB.datascriptQuery<BlockEntity[]>(
`[:find (pull ?b [*])
[(clojure.string/includes? ?c "${
highlight.properties?.id as string
}")]]`
)
).flat()
if (existingHighlights.length > 0) {
const existingHighlight = existingHighlights[0]
// update existing highlight if content is different
existingHighlight.content !== highlight.content &&
(await logseq.Editor.updateBlock(
existingHighlight.uuid,
highlight.content
))

// checking notes
const noteChild = highlight.children?.[0]
if (noteChild) {
const existingNotes = (
await logseq.DB.datascriptQuery<BlockEntity[]>(
`[:find (pull ?b [*])
:where
[?b :block/parent ?p]
[?p :block/uuid ?u]
Expand All @@ -313,32 +329,31 @@ const fetchOmnivore = async (inBackground = false) => {
[(= ?c "${escapeQuotationMarks(
noteChild.content
)}")]]`
)
).flat()
if (existingNotes.length == 0) {
// append new note
await logseq.Editor.insertBlock(
existingHighlight.uuid,
noteChild.content,
{ sibling: false }
)
}
)
).flat()
if (existingNotes.length == 0) {
// append new note
await logseq.Editor.insertBlock(
existingHighlight.uuid,
noteChild.content,
{ sibling: false }
)
}
} else {
// append new highlight
await logseq.Editor.insertBatchBlock(
existingBlock.uuid,
highlight,
{ sibling: false }
)
}
} else {
// append new highlight
await logseq.Editor.insertBatchBlock(
existingBlock.uuid,
highlight,
{ sibling: false }
)
}
}
}

isNewArticle &&
articleBatch.unshift({
content,
content: articleContent,
children: highlightBatch,
})
}
Expand All @@ -360,7 +375,8 @@ const fetchOmnivore = async (inBackground = false) => {
apiKey,
after,
size,
parseDateTime(syncAt).toISO()
parseDateTime(syncAt).toISO(),
endpoint
)

for (const slug of deletedArticleSlugs) {
Expand Down Expand Up @@ -517,7 +533,7 @@ const main = async (baseInfo: LSPluginBaseInfo) => {
type: 'string',
title: 'Enter the template to use for new articles',
description:
'Enter the template to use for new articles. Required variables are: {{{title}}}, {{{omnivoreUrl}}}. Optional variables are: {{{siteName}}}, {{{originalUrl}}}, {{{author}}}, {{{labels}}}, {{{dateSaved}}}, {{{datePublished}}}',
'We use {{ mustache }} template: http://mustache.github.io/mustache.5.html. Required variables are: title, omnivoreUrl. Optional variables are: siteName, originalUrl, author, labels, dateSaved, datePublished, note',
default: `[{{{title}}}]({{{omnivoreUrl}}})
collapsed:: true
site:: {{#siteName}}[{{{siteName}}}]{{/siteName}}({{{originalUrl}}})
Expand All @@ -538,10 +554,17 @@ date-published:: {{{datePublished}}}
type: 'string',
title: 'Enter the template to use for new highlights',
description:
'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.',
'We use {{ mustache }} template: http://mustache.github.io/mustache.5.html. Required variables are: text, highlightUrl. Optional variables are dateHighlighted. You can also use the variables in the article template.',
default: `> {{{text}}} [⤴️]({{{highlightUrl}}}) {{#labels}} #[[{{{name}}}]] {{/labels}}`,
inputAs: 'textarea',
},
{
key: 'endpoint',
type: 'string',
title: 'API Endpoint',
description: "Enter the Omnivore server's API endpoint",
default: 'https://api-prod.omnivore.app/api/graphql',
},
]
logseq.useSettingsSchema(settingsSchema)

Expand Down
25 changes: 18 additions & 7 deletions src/util.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { format } from 'date-fns'
import { diff_match_patch } from 'diff-match-patch'
import { DateTime } from 'luxon'
import escape from 'markdown-escape'
import { format } from 'date-fns'

export const DATE_FORMAT_W_OUT_SECONDS = "yyyy-MM-dd'T'HH:mm"
export const DATE_FORMAT = `${DATE_FORMAT_W_OUT_SECONDS}:ss`
Expand Down Expand Up @@ -72,13 +72,20 @@ export interface Label {
name: string
}

export enum HighlightType {
Highlight = 'HIGHLIGHT',
Note = 'NOTE',
Redaction = 'REDACTION',
}

export interface Highlight {
id: string
quote: string
annotation: string
patch: string
updatedAt: string
labels?: Label[]
type: HighlightType
}

export interface HighlightPoint {
Expand All @@ -95,9 +102,10 @@ const requestHeaders = (apiKey: string) => ({

export const loadArticle = async (
slug: string,
apiKey: string
apiKey: string,
endpoint = ENDPOINT
): Promise<Article> => {
const res = await fetch(ENDPOINT, {
const res = await fetch(endpoint, {
headers: requestHeaders(apiKey),
body: `{"query":"\\n query GetArticle(\\n $username: String!\\n $slug: String!\\n ) {\\n article(username: $username, slug: $slug) {\\n ... on ArticleSuccess {\\n article {\\n ...ArticleFields\\n highlights {\\n ...HighlightFields\\n }\\n labels {\\n ...LabelFields\\n }\\n }\\n }\\n ... on ArticleError {\\n errorCodes\\n }\\n }\\n }\\n \\n fragment ArticleFields on Article {\\n savedAt\\n }\\n\\n \\n fragment HighlightFields on Highlight {\\n id\\n quote\\n annotation\\n }\\n\\n \\n fragment LabelFields on Label {\\n name\\n }\\n\\n","variables":{"username":"me","slug":"${slug}"}}`,
method: 'POST',
Expand All @@ -114,9 +122,10 @@ export const loadArticles = async (
updatedAt = '',
query = '',
includeContent = false,
format = 'html'
format = 'html',
endpoint = ENDPOINT
): Promise<[Article[], boolean]> => {
const res = await fetch(ENDPOINT, {
const res = await fetch(endpoint, {
headers: requestHeaders(apiKey),
body: JSON.stringify({
query: `
Expand Down Expand Up @@ -146,6 +155,7 @@ export const loadArticles = async (
labels {
name
}
type
}
labels {
name
Expand Down Expand Up @@ -184,9 +194,10 @@ export const loadDeletedArticleSlugs = async (
apiKey: string,
after = 0,
first = 10,
updatedAt = ''
updatedAt = '',
endpoint = ENDPOINT
): Promise<[string[], boolean]> => {
const res = await fetch(ENDPOINT, {
const res = await fetch(endpoint, {
headers: requestHeaders(apiKey),
body: `{"query":"\\n query UpdatesSince($after: String, $first: Int, $since: Date!) {\\n updatesSince(first: $first, after: $after, since: $since) {\\n ... on UpdatesSinceSuccess {\\n edges {\\n updateReason\\n node {\\n slug\\n }\\n }\\n pageInfo {\\n hasNextPage\\n }\\n }\\n ... on UpdatesSinceError {\\n errorCodes\\n }\\n }\\n }\\n ","variables":{"after":"${after}","first":${first}, "since":"${
updatedAt || '2021-01-01'
Expand Down

0 comments on commit 20f34ca

Please sign in to comment.