Skip to content

Commit 9b1b23d

Browse files
committed
v0.0.21
2 parents d55b46b + bbbd276 commit 9b1b23d

12 files changed

+103
-45
lines changed

README.md

+7-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,13 @@ Obsidian Raindrop Highlights (Community Plugin) is an unofficial plugin to synch
1919

2020
After installing the plugin, configure the the settings of the plugin then initiate the first sync manually. Thereafter, the plugin can be configured to sync automatically or manually.
2121

22-
Use Raindrop icon in the sidebar or command `Raindrop Highlights: Sync highlights` to trigger manual sync.
22+
Use Raindrop icon in the sidebar or command `Raindrop Highlights: Sync newly created bookmarks (sync from last sync time)` to trigger manual sync from the last sync time.
23+
24+
> ⚠️ The above command only sync the newly created bookmarks, the old bookmarks with updates are not synced! Use the following two commands to update the existing files.
25+
26+
Use `Raindrop Highlights: Sync all bookmarks (full sync)` to trigger full sync.
27+
28+
Use `Raindrop Highlights: Sync this bookmark` to sync the current active file.
2329

2430
Use `Raindrop Highlights: Show last sync time` command to check last sync time for each collection.
2531

manifest.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"id": "obsidian-raindrop-highlights",
33
"name": "Raindrop Highlights",
4-
"version": "0.0.20",
4+
"version": "0.0.21",
55
"minAppVersion": "0.14.0",
66
"description": "Sync your Raindrop.io highlights.",
77
"author": "kaiiiz",

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "obsidian-raindrop-highlights",
3-
"version": "0.0.20",
3+
"version": "0.0.21",
44
"description": "Sync your Raindrop.io highlights.",
55
"main": "main.js",
66
"scripts": {

src/api.ts

+9-9
Original file line numberDiff line numberDiff line change
@@ -109,13 +109,13 @@ export class RaindropAPI {
109109
const id = collection["_id"];
110110
nestedCollectionMap[id] = {
111111
title: collection["title"],
112-
parentId: collection["parent"]["$id"],
112+
parentId: collection["parent"]?.["$id"] ?? 0,
113113
};
114114
});
115115

116116
nestedCollections.items.forEach((collection: any) => {
117117
const id = collection["_id"];
118-
let parentId = collection["parent"]["$id"];
118+
let parentId = collection["parent"]?.["$id"] ?? 0;
119119
let title = collection["title"];
120120
while (parentId && parentId in nestedCollectionMap) {
121121
title = `${nestedCollectionMap[parentId].title}/${title}`;
@@ -143,7 +143,7 @@ export class RaindropAPI {
143143
const res = await this.get(`${BASEURL}/raindrops/${collectionId}`, {
144144
page: 0,
145145
perpage: pageSize,
146-
sort: "-lastUpdate",
146+
sort: "-created",
147147
});
148148
const raindropsCnt = res.count;
149149
let bookmarks = this.parseRaindrops(res.items);
@@ -155,7 +155,7 @@ export class RaindropAPI {
155155
const res = await this.get(`${BASEURL}/raindrops/${collectionId}`, {
156156
page: page,
157157
perpage: pageSize,
158-
sort: "-lastUpdate",
158+
sort: "-created",
159159
});
160160
return this.parseRaindrops(res.items);
161161
};
@@ -169,18 +169,18 @@ export class RaindropAPI {
169169
}
170170
}
171171
} else {
172-
const filterLastUpdate = (bookmarks: RaindropBookmark[]) => {
172+
const filterCreated = (bookmarks: RaindropBookmark[]) => {
173173
return bookmarks.filter((bookmark) => {
174-
return bookmark.lastUpdate.getTime() >= lastSync.getTime();
174+
return bookmark.created.getTime() >= lastSync.getTime();
175175
});
176176
};
177-
const filteredBookmark = filterLastUpdate(bookmarks);
177+
const filteredBookmark = filterCreated(bookmarks);
178178
if (filteredBookmark.length > 0) {
179179
yield filteredBookmark;
180-
while (bookmarks[bookmarks.length - 1].lastUpdate.getTime() >= lastSync.getTime() && remainPages--) {
180+
while (bookmarks[bookmarks.length - 1].created.getTime() >= lastSync.getTime() && remainPages--) {
181181
notice?.setMessage(`Sync Raindrop pages: ${page + 1}/${totalPages}`);
182182
let bookmarks = await getPage(page++);
183-
yield filterLastUpdate(bookmarks);
183+
yield filterCreated(bookmarks);
184184
}
185185
}
186186
}

src/constants.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import DEFAULT_TEMPLATE from "./assets/defaultTemplate.njk";
22
import type { RaindropPluginSettings } from "./types";
33

4-
export const VERSION = "0.0.20";
4+
export const VERSION = "0.0.21";
55

66
export const DEFAULT_SETTINGS: RaindropPluginSettings = {
77
version: VERSION,

src/main.ts

+23-7
Original file line numberDiff line numberDiff line change
@@ -21,20 +21,36 @@ export default class RaindropPlugin extends Plugin {
2121
this.raindropSync = new RaindropSync(this.app, this, this.api);
2222

2323
if (this.settings.ribbonIcon) {
24-
this.addRibbonIcon("cloud", "Sync your Raindrop highlights", () => {
24+
this.addRibbonIcon("cloud", "Sync your Raindrop bookmarks", () => {
2525
if (!this.settings.isConnected) {
2626
new Notice("Please configure Raindrop API token in the plugin setting");
2727
} else {
28-
this.raindropSync.sync();
28+
this.raindropSync.sync({ fullSync: false });
2929
}
3030
});
3131
}
3232

3333
this.addCommand({
34-
id: "raindrop-sync",
35-
name: "Sync highlights",
34+
id: "raindrop-sync-new",
35+
name: "Sync newly created bookmarks (sync from last sync time)",
3636
callback: async () => {
37-
await this.raindropSync.sync();
37+
await this.raindropSync.sync({ fullSync: false });
38+
},
39+
});
40+
41+
this.addCommand({
42+
id: "raindrop-sync-all",
43+
name: "Sync all bookmarks (full sync)",
44+
callback: async () => {
45+
await this.raindropSync.sync({ fullSync: true });
46+
},
47+
});
48+
49+
this.addCommand({
50+
id: "raindrop-sync-this",
51+
name: "Sync this bookmark",
52+
callback: async () => {
53+
const file = app.workspace.getActiveFile();
3854
},
3955
});
4056

@@ -63,7 +79,7 @@ export default class RaindropPlugin extends Plugin {
6379
const bookmark = await this.api.getRaindrop(fmc.raindrop_id);
6480
window.open(`https://app.raindrop.io/my/${bookmark.collectionId}/item/${bookmark.id}/edit`);
6581
} else {
66-
new Notice("This is not a Raindrop article file");
82+
new Notice("This is not a Raindrop bookmark file");
6783
}
6884
} else {
6985
new Notice("No active file");
@@ -159,7 +175,7 @@ export default class RaindropPlugin extends Plugin {
159175
const minutesToSync = minutes ?? this.settings.autoSyncInterval;
160176
if (minutesToSync > 0) {
161177
this.timeoutIDAutoSync = window.setTimeout(() => {
162-
this.raindropSync.sync();
178+
this.raindropSync.sync({ fullSync: false });
163179
this.startAutoSync();
164180
}, minutesToSync * 60000);
165181
}

src/modal/breakingChange.ts

+11-5
Original file line numberDiff line numberDiff line change
@@ -8,28 +8,34 @@ export default class BreadkingChangeModal extends Modal {
88
constructor(app: App, currentVersion: string) {
99
super(app);
1010

11-
this.waitForClose = new Promise(
12-
(resolve) => (this.resolvePromise = resolve)
13-
);
11+
this.waitForClose = new Promise((resolve) => (this.resolvePromise = resolve));
1412

1513
this.titleEl.innerText = "Raindrop Highlight - Breaking Changes";
1614

1715
let breakingChanges = "";
16+
if (semver.lt(currentVersion, "0.0.21")) {
17+
breakingChanges += `<p>v0.0.21</p>
18+
<ul>
19+
<li>Sync collections from last update time is now changed to sync from created time. You should now use either \`Raindrop Highlights: Sync all bookmarks (full sync)\` or \`Raindrop Highlights: Sync this bookmark\` command to update existing files. See issue <a href="https://github.com/kaiiiz/obsidian-raindrop-highlights-plugin/issues/72">#72</a> for details.</li>
20+
</ul>
21+
`;
22+
}
23+
1824
if (semver.lt(currentVersion, "0.0.19")) {
1925
breakingChanges += `<p>v0.0.19</p>
2026
<ul>
2127
<li>The front matter property <code>raindrop_last_update</code> has now been replaced by <code>raindrop_highlights</code>, which stores the highlight signature for each highlight entry to fix the duplicate highlight entry bug in append mode.</li>
2228
<li>The file name and front matter are now synced with templates while performing updates.</li>
2329
</ul>
24-
`
30+
`;
2531
}
2632

2733
if (semver.lt(currentVersion, "0.0.18")) {
2834
breakingChanges += `<p>v0.0.18</p>
2935
<ul>
3036
<li>Date &amp; time format field is replaced by the <code>date</code> filter in template. Update <code>created</code> and <code>lastUpdate</code> in template accordingly.</li>
3137
</ul>
32-
`
38+
`;
3339
}
3440

3541
if (breakingChanges !== "") {

src/sync.ts

+46-16
Original file line numberDiff line numberDiff line change
@@ -23,20 +23,41 @@ export default class RaindropSync {
2323
this.renderer = new Renderer(plugin);
2424
}
2525

26-
async sync() {
26+
async sync({ fullSync }: { fullSync: boolean }) {
2727
const collectionGroup = this.plugin.settings.collectionGroups;
2828
const allCollections = await this.api.getCollections(collectionGroup);
2929
this.plugin.updateCollectionSettings(allCollections);
3030

3131
for (const id in this.plugin.settings.syncCollections) {
3232
const collection = this.plugin.settings.syncCollections[id];
3333
if (collection.sync) {
34-
await this.syncCollection(collection);
34+
await this.syncCollection(collection, fullSync);
3535
}
3636
}
3737
}
3838

39-
async syncCollection(collection: SyncCollection) {
39+
async syncSingle({ file }: { file: TFile }) {
40+
let raindropId: number;
41+
if (file) {
42+
const fmc = this.app.metadataCache.getFileCache(file)?.frontmatter;
43+
if (!fmc?.raindrop_id) {
44+
new Notice("This is not a Raindrop bookmark file");
45+
return;
46+
} else {
47+
raindropId = Number(fmc.raindrop_id);
48+
}
49+
} else {
50+
new Notice("No active file");
51+
return;
52+
}
53+
54+
const bookmark = await this.api.getRaindrop(raindropId);
55+
await this.updateFileContent(file, bookmark);
56+
// Do not perform path sync here!
57+
// Since we do not know which collection sync this bookmark (e.g. bookmark "b1" in "Collection 1" may also be synced if you enable "All Bookmarks" collection), which leads to ambiguity.
58+
}
59+
60+
private getSyncFolder(collection: SyncCollection) {
4061
if (this.plugin.settings.autoSyncSuccessNotice) {
4162
new Notice(`Sync Raindrop collection: ${collection.title}`);
4263
}
@@ -45,12 +66,21 @@ export default class RaindropSync {
4566
if (this.plugin.settings.collectionsFolders) {
4667
collectionFolder = `${highlightsFolder}/${collection["title"]}`;
4768
}
48-
const lastSyncDate = this.plugin.settings.syncCollections[collection.id].lastSyncDate;
69+
return collectionFolder;
70+
}
71+
72+
private async syncCollection(collection: SyncCollection, fullSync: boolean) {
73+
const syncFolder = this.getSyncFolder(collection);
74+
const lastSyncDate = fullSync ? undefined : this.plugin.settings.syncCollections[collection.id].lastSyncDate;
4975

5076
try {
51-
console.debug(`start sync collection: ${collection.title}, last sync at: ${lastSyncDate}`);
77+
if (lastSyncDate === undefined) {
78+
console.debug(`start sync collection: ${collection.title}, full sync`);
79+
} else {
80+
console.debug(`start sync collection: ${collection.title}, last sync at: ${lastSyncDate}`);
81+
}
5282
for await (const bookmarks of this.api.getRaindropsAfter(collection.id, this.plugin.settings.autoSyncSuccessNotice, lastSyncDate)) {
53-
await this.syncBookmarks(bookmarks, collectionFolder);
83+
await this.syncBookmarks(bookmarks, syncFolder);
5484
}
5585
await this.syncCollectionComplete(collection);
5686
} catch (e) {
@@ -59,7 +89,7 @@ export default class RaindropSync {
5989
}
6090
}
6191

62-
async syncBookmarks(bookmarks: RaindropBookmark[], folderPath: string) {
92+
private async syncBookmarks(bookmarks: RaindropBookmark[], folderPath: string) {
6393
if (bookmarks.length == 0) return;
6494

6595
if (this.plugin.settings.onlyBookmarksWithHl) {
@@ -93,7 +123,7 @@ export default class RaindropSync {
93123
}
94124
}
95125

96-
buildFilePath(folderPath: string, renderedFilename: string, suffix?: number): string {
126+
private buildFilePath(folderPath: string, renderedFilename: string, suffix?: number): string {
97127
let fileSuffix = ".md";
98128
let fileName = truncate(`${renderedFilename}`, 255 - fileSuffix.length) + fileSuffix;
99129
if (suffix) {
@@ -103,7 +133,7 @@ export default class RaindropSync {
103133
return normalizePath(`${folderPath}/${fileName}`);
104134
}
105135

106-
async buildNonDupFilePath(folderPath: string, renderedFilename: string): Promise<string> {
136+
private async buildNonDupFilePath(folderPath: string, renderedFilename: string): Promise<string> {
107137
let filePath = this.buildFilePath(folderPath, renderedFilename);
108138
let suffix = 1;
109139
while (await this.app.vault.adapter.exists(filePath)) {
@@ -113,12 +143,12 @@ export default class RaindropSync {
113143
return filePath;
114144
}
115145

116-
async syncCollectionComplete(collection: RaindropCollection) {
146+
private async syncCollectionComplete(collection: RaindropCollection) {
117147
this.plugin.settings.syncCollections[collection.id].lastSyncDate = new Date();
118148
await this.plugin.saveSettings();
119149
}
120150

121-
async updateFileName(file: TFile, bookmark: RaindropBookmark, folderPath: string) {
151+
private async updateFileName(file: TFile, bookmark: RaindropBookmark, folderPath: string) {
122152
const renderedFilename = this.renderer.renderFileName(bookmark, true);
123153
let newFilePath = this.buildFilePath(folderPath, renderedFilename);
124154
const newFileMeta = this.app.metadataCache.getCache(newFilePath);
@@ -133,15 +163,15 @@ export default class RaindropSync {
133163
await this.app.fileManager.renameFile(file, newFilePath);
134164
}
135165

136-
async updateFileContent(file: TFile, bookmark: RaindropBookmark) {
166+
private async updateFileContent(file: TFile, bookmark: RaindropBookmark) {
137167
if (this.plugin.settings.appendMode) {
138168
await this.updateFileAppendMode(file, bookmark);
139169
} else {
140170
await this.updateFileOverwriteMode(file, bookmark);
141171
}
142172
}
143173

144-
async updateFileAppendMode(file: TFile, bookmark: RaindropBookmark) {
174+
private async updateFileAppendMode(file: TFile, bookmark: RaindropBookmark) {
145175
console.debug(`update file append mode ${file.path}`);
146176
const metadata = this.app.metadataCache.getFileCache(file);
147177
const highlightSigs = Object.fromEntries(bookmark.highlights.map((hl) => [hl.id, hl.signature]));
@@ -188,19 +218,19 @@ export default class RaindropSync {
188218
}
189219
}
190220

191-
async updateFileOverwriteMode(file: TFile, bookmark: RaindropBookmark) {
221+
private async updateFileOverwriteMode(file: TFile, bookmark: RaindropBookmark) {
192222
console.debug("update file overwrite mode", file.path);
193223
const mdContent = this.renderer.renderFullArticle(bookmark);
194224
return this.app.vault.modify(file, mdContent);
195225
}
196226

197-
async createFile(filePath: string, bookmark: RaindropBookmark): Promise<TFile> {
227+
private async createFile(filePath: string, bookmark: RaindropBookmark): Promise<TFile> {
198228
console.debug("create file", filePath);
199229
const mdContent = this.renderer.renderFullArticle(bookmark);
200230
return this.app.vault.create(filePath, mdContent);
201231
}
202232

203-
getBookmarkFiles(): BookmarkFile[] {
233+
private getBookmarkFiles(): BookmarkFile[] {
204234
return this.app.vault
205235
.getMarkdownFiles()
206236
.map((file) => {

src/templates/filenameTemplateInstructions.html

-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
</p>
77
<ul>
88
<li>The rendered result is used as the filename for the bookmark.</li>
9-
<li>This template is only used when creating the new file.</li>
109
<li>The rendered result is sanitized and truncated to 255 bytes.</li>
1110
<li>The plugin will reject the invalid template.</li>
1211
<li>If the file already exists in the vault, the auto generated suffix will be appended to the rendered result and used as the filename.</li>

src/templates/metadataTemplateInstructions.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,6 @@
77
<ul>
88
<li>The rendered result is placed in the front matter of the generated post.</li>
99
<li>If the rendered result does not follow the YAML syntax, the plugin will reject the update.</li>
10-
<li><code>raindrop_id</code> and <code>raindrop_highlights</code> properties are transparently added by the plugin.</li>
10+
<li><code>raindrop_id</code> and <code>raindrop_highlights</code> properties are transparently added and updated by the plugin.</li>
1111
<li>Available variables to use are the same as the previous template.</li>
1212
</ul>

src/templates/templateInstructions.html

+1-1
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
<li><span class="u-pop">{{highlights}}</span> (Highlight[]) - List of your Highlights (Detail attributes refer to the following <span class="u-pop">Highlight</span> section)</li>
2222
<li><span class="u-pop">{{collection}}</span> (Collection) - Collection data (Detail attributes refer to the following <span class="u-pop">Collection</span> section</li>
2323
<li><span class="u-pop">{{creator}}</span> (Creator) - Creator data (Detail attributes refer to the following <span class="u-pop">Creator</span> section</li>
24-
<li><span class="u-pop">{{tags}}</span> (string) - List of tag</li>
24+
<li><span class="u-pop">{{tags}}</span> (string[]) - List of tag</li>
2525
<li><span class="u-pop">{{cover}}</span> (string) - Article cover</li>
2626
<li><span class="u-pop">{{created}}</span> (Moment) - Created on</li>
2727
<li><span class="u-pop">{{type}}</span> (string) - Article type</li>

versions.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -18,5 +18,6 @@
1818
"0.0.17": "0.14.0",
1919
"0.0.18": "0.14.0",
2020
"0.0.19": "0.14.0",
21-
"0.0.20": "0.14.0"
21+
"0.0.20": "0.14.0",
22+
"0.0.21": "0.14.0"
2223
}

0 commit comments

Comments
 (0)