diff --git a/manifest.json b/manifest.json index 476b058..594be7f 100644 --- a/manifest.json +++ b/manifest.json @@ -1,7 +1,7 @@ { "id": "obsidian-raindrop-highlights", "name": "Raindrop Highlights", - "version": "0.0.2", + "version": "0.0.3", "minAppVersion": "0.14.0", "description": "Sync your Raindrop.io highlights.", "author": "kaiiiz", diff --git a/package.json b/package.json index 5d73237..401037b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "obsidian-raindrop-highlights", - "version": "0.0.2", + "version": "0.0.3", "description": "Sync your Raindrop.io highlights.", "main": "main.js", "scripts": { diff --git a/src/api.ts b/src/api.ts index fb13652..f1a8ee8 100644 --- a/src/api.ts +++ b/src/api.ts @@ -15,8 +15,7 @@ export class RaindropAPI { } async get(url: string, params: any) { - const token = this.plugin.settings.token; - + const token = this.plugin.tokenManager.get(); if (!token) { throw new Error("Invalid token"); } @@ -111,6 +110,7 @@ export class RaindropAPI { excerpt: raindrop['excerpt'], link: raindrop['link'], lastUpdate: new Date(raindrop['lastUpdate']), + tags: raindrop['tags'], }; return article; }); diff --git a/src/assets/defaultTemplate.njk b/src/assets/defaultTemplate.njk index 3ab4f34..792cf7d 100644 --- a/src/assets/defaultTemplate.njk +++ b/src/assets/defaultTemplate.njk @@ -1,6 +1,7 @@ {% if is_new_article %} # Metadata {% if link %}Source URL:: {{link}}{% endif %} +{% if tags|length %}Topics:: {{ tags | join(", ") }}{% endif %} --- # {{title}} diff --git a/src/main.ts b/src/main.ts index 269b571..ceede28 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,12 +1,12 @@ import { Plugin } from 'obsidian'; import { RaindropSettingTab } from './settings'; import RaindropSync from './sync'; -import type { RaindropPluginSettings } from './types'; +import type { RaindropCollection, RaindropPluginSettings } from './types'; import DEFAULT_TEMPLATE from './assets/defaultTemplate.njk'; +import TokenManager from './tokenManager'; const DEFAULT_SETTINGS: RaindropPluginSettings = { - token: '', highlightsFolder: '', syncCollections: {}, template: DEFAULT_TEMPLATE, @@ -15,11 +15,13 @@ const DEFAULT_SETTINGS: RaindropPluginSettings = { export default class RaindropPlugin extends Plugin { private raindropSync: RaindropSync; - settings: RaindropPluginSettings; + public settings: RaindropPluginSettings; + public tokenManager: TokenManager; async onload() { await this.loadSettings(); + this.tokenManager = new TokenManager(); this.raindropSync = new RaindropSync(this.app, this); this.addCommand({ @@ -44,4 +46,23 @@ export default class RaindropPlugin extends Plugin { async saveSettings() { await this.saveData(this.settings); } + + async updateCollectionSettings(collections: RaindropCollection[]) { + const syncCollections = this.settings.syncCollections; + collections.forEach(async (collection) => { + const {id, title} = collection; + + if (!(id in syncCollections)) { + syncCollections[id] = { + id: id, + title: title, + sync: false, + lastSyncDate: undefined, + }; + } else { + syncCollections[id].title = title; + } + }); + await this.saveSettings(); + } } diff --git a/src/renderer.ts b/src/renderer.ts index 85bc6f0..e6bfa8b 100644 --- a/src/renderer.ts +++ b/src/renderer.ts @@ -20,6 +20,7 @@ type RenderTemplate = { excerpt: string; link: string; highlights: RenderHighlight[]; + tags: string[], }; export default class Renderer { @@ -40,7 +41,7 @@ export default class Renderer { } renderContent(article: RaindropArticle, newArticle = true) { - const { id , title, highlights, excerpt, link } = article; + const { id , title, highlights, excerpt, link, tags } = article; const dateTimeFormat = this.plugin.settings.dateTimeFormat; const renderHighlights: RenderHighlight[] = highlights.map(hl => { @@ -62,8 +63,9 @@ export default class Renderer { excerpt, link, highlights: renderHighlights, + tags, }; - + const template = this.plugin.settings.template; const content = nunjucks.renderString(template, context); return content; @@ -72,6 +74,7 @@ export default class Renderer { addFrontMatter(markdownContent: string, article: RaindropArticle) { const fm: ArticleFileFrontMatter = { raindrop_id: article.id, + raindrop_last_update: (new Date()).toISOString(), }; return matter.stringify(markdownContent, fm); } diff --git a/src/settings.ts b/src/settings.ts index 5b77939..9de6b4e 100644 --- a/src/settings.ts +++ b/src/settings.ts @@ -63,14 +63,17 @@ export class RaindropSettingTab extends PluginSettingTab { .setDesc(tokenDescFragment) .addText(async (text) => { try { - text.setValue(this.plugin.settings.token); + const token = this.plugin.tokenManager.get(); + if (token) { + text.setValue(token); + } } catch (e) { /* Throw away read error if file does not exist. */ } text.onChange(async (value) => { try { - this.plugin.settings.token = value; + this.plugin.tokenManager.set(value); new Notice('Token saved'); } catch (e) { new Notice('Invalid token'); @@ -90,20 +93,7 @@ export class RaindropSettingTab extends PluginSettingTab { .onClick(async () => { // update for new collections const allCollections = await this.api.getCollections(); - const syncCollections = this.plugin.settings.syncCollections; - allCollections.forEach(async (collection) => { - const {id, title} = collection; - - if (!(id in syncCollections)) { - syncCollections[id] = { - id: id, - title: title, - sync: false, - lastSyncDate: undefined, - }; - } - }); - await this.plugin.saveSettings(); + this.plugin.updateCollectionSettings(allCollections); const collectionsModal = new CollectionsModal(this.app, this.plugin); this.display(); // rerender diff --git a/src/sync.ts b/src/sync.ts index b71a7a8..d7c4446 100644 --- a/src/sync.ts +++ b/src/sync.ts @@ -19,6 +19,9 @@ export default class RaindropSync { } async sync() { + const allCollections = await this.api.getCollections(); + this.plugin.updateCollectionSettings(allCollections); + for (const id in this.plugin.settings.syncCollections) { const collection = this.plugin.settings.syncCollections[id]; if (collection.sync) { @@ -80,6 +83,19 @@ export default class RaindropSync { } async updateFile(file: TFile, article: RaindropArticle) { + const metadata = this.app.metadataCache.getFileCache(file); + if (metadata?.frontmatter && 'raindrop_last_update' in metadata.frontmatter) { + const localLastUpdate = new Date(metadata.frontmatter.raindrop_last_update); + if (localLastUpdate >= article.lastUpdate) { + console.debug('skip update file', file.path); + return; + } + + article.highlights = article.highlights.filter(hl => { + return localLastUpdate < hl.lastUpdate; + }); + } + console.debug("update file", file.path); const newMdContent = this.renderer.renderContent(article, false); const oldMdContent = await this.app.vault.cachedRead(file); diff --git a/src/templates/templateInstructions.html b/src/templates/templateInstructions.html index 6f96a52..7e6d95d 100644 --- a/src/templates/templateInstructions.html +++ b/src/templates/templateInstructions.html @@ -13,6 +13,7 @@
  • {{excerpt}} - Article excerpt
  • {{link}} - Link to source
  • {{highlights}} - List of your Highlights
  • +
  • {{tags}} - List of tag
  • Highlight diff --git a/src/tokenManager.ts b/src/tokenManager.ts new file mode 100644 index 0000000..8fc272d --- /dev/null +++ b/src/tokenManager.ts @@ -0,0 +1,21 @@ +export default class TokenManager { + localStorage: any; + + constructor() { + this.localStorage = window.localStorage; + } + + get(): string|null { + const token = this.localStorage.getItem('raindrop_token'); + + if (token === null || token.length == 0) { + return null; + } + + return token; + } + + set(token: string) { + this.localStorage.setItem('raindrop_token', token); + } +} diff --git a/src/types.ts b/src/types.ts index 91b5489..46ba938 100644 --- a/src/types.ts +++ b/src/types.ts @@ -25,6 +25,7 @@ export interface RaindropArticle { // Remote state excerpt: string, link: string, lastUpdate: Date, + tags: string[], } // ---------- @@ -36,6 +37,7 @@ export interface ArticleFile { export interface ArticleFileFrontMatter { // use snake_case in front matter raindrop_id: number, + raindrop_last_update: string, } // ---------- @@ -50,7 +52,6 @@ export interface SyncCollection { // Local state export interface SyncCollectionSettings {[id: number]: SyncCollection} export interface RaindropPluginSettings { - token: string, highlightsFolder: string; syncCollections: SyncCollectionSettings; template: string; diff --git a/versions.json b/versions.json index df9c349..a13d9e6 100644 --- a/versions.json +++ b/versions.json @@ -1,4 +1,5 @@ { "0.0.1": "0.12.0", - "0.0.2": "0.14.0" + "0.0.2": "0.14.0", + "0.0.3": "0.14.0" }