Skip to content

Commit

Permalink
v0.0.21
Browse files Browse the repository at this point in the history
  • Loading branch information
kaiiiz committed Apr 15, 2024
2 parents d55b46b + bbbd276 commit 9b1b23d
Show file tree
Hide file tree
Showing 12 changed files with 103 additions and 45 deletions.
8 changes: 7 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,13 @@ Obsidian Raindrop Highlights (Community Plugin) is an unofficial plugin to synch

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.

Use Raindrop icon in the sidebar or command `Raindrop Highlights: Sync highlights` to trigger manual sync.
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.

> ⚠️ 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.
Use `Raindrop Highlights: Sync all bookmarks (full sync)` to trigger full sync.

Use `Raindrop Highlights: Sync this bookmark` to sync the current active file.

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

Expand Down
2 changes: 1 addition & 1 deletion manifest.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"id": "obsidian-raindrop-highlights",
"name": "Raindrop Highlights",
"version": "0.0.20",
"version": "0.0.21",
"minAppVersion": "0.14.0",
"description": "Sync your Raindrop.io highlights.",
"author": "kaiiiz",
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "obsidian-raindrop-highlights",
"version": "0.0.20",
"version": "0.0.21",
"description": "Sync your Raindrop.io highlights.",
"main": "main.js",
"scripts": {
Expand Down
18 changes: 9 additions & 9 deletions src/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,13 +109,13 @@ export class RaindropAPI {
const id = collection["_id"];
nestedCollectionMap[id] = {
title: collection["title"],
parentId: collection["parent"]["$id"],
parentId: collection["parent"]?.["$id"] ?? 0,
};
});

nestedCollections.items.forEach((collection: any) => {
const id = collection["_id"];
let parentId = collection["parent"]["$id"];
let parentId = collection["parent"]?.["$id"] ?? 0;
let title = collection["title"];
while (parentId && parentId in nestedCollectionMap) {
title = `${nestedCollectionMap[parentId].title}/${title}`;
Expand Down Expand Up @@ -143,7 +143,7 @@ export class RaindropAPI {
const res = await this.get(`${BASEURL}/raindrops/${collectionId}`, {
page: 0,
perpage: pageSize,
sort: "-lastUpdate",
sort: "-created",
});
const raindropsCnt = res.count;
let bookmarks = this.parseRaindrops(res.items);
Expand All @@ -155,7 +155,7 @@ export class RaindropAPI {
const res = await this.get(`${BASEURL}/raindrops/${collectionId}`, {
page: page,
perpage: pageSize,
sort: "-lastUpdate",
sort: "-created",
});
return this.parseRaindrops(res.items);
};
Expand All @@ -169,18 +169,18 @@ export class RaindropAPI {
}
}
} else {
const filterLastUpdate = (bookmarks: RaindropBookmark[]) => {
const filterCreated = (bookmarks: RaindropBookmark[]) => {
return bookmarks.filter((bookmark) => {
return bookmark.lastUpdate.getTime() >= lastSync.getTime();
return bookmark.created.getTime() >= lastSync.getTime();
});
};
const filteredBookmark = filterLastUpdate(bookmarks);
const filteredBookmark = filterCreated(bookmarks);
if (filteredBookmark.length > 0) {
yield filteredBookmark;
while (bookmarks[bookmarks.length - 1].lastUpdate.getTime() >= lastSync.getTime() && remainPages--) {
while (bookmarks[bookmarks.length - 1].created.getTime() >= lastSync.getTime() && remainPages--) {
notice?.setMessage(`Sync Raindrop pages: ${page + 1}/${totalPages}`);
let bookmarks = await getPage(page++);
yield filterLastUpdate(bookmarks);
yield filterCreated(bookmarks);
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/constants.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import DEFAULT_TEMPLATE from "./assets/defaultTemplate.njk";
import type { RaindropPluginSettings } from "./types";

export const VERSION = "0.0.20";
export const VERSION = "0.0.21";

export const DEFAULT_SETTINGS: RaindropPluginSettings = {
version: VERSION,
Expand Down
30 changes: 23 additions & 7 deletions src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,20 +21,36 @@ export default class RaindropPlugin extends Plugin {
this.raindropSync = new RaindropSync(this.app, this, this.api);

if (this.settings.ribbonIcon) {
this.addRibbonIcon("cloud", "Sync your Raindrop highlights", () => {
this.addRibbonIcon("cloud", "Sync your Raindrop bookmarks", () => {
if (!this.settings.isConnected) {
new Notice("Please configure Raindrop API token in the plugin setting");
} else {
this.raindropSync.sync();
this.raindropSync.sync({ fullSync: false });
}
});
}

this.addCommand({
id: "raindrop-sync",
name: "Sync highlights",
id: "raindrop-sync-new",
name: "Sync newly created bookmarks (sync from last sync time)",
callback: async () => {
await this.raindropSync.sync();
await this.raindropSync.sync({ fullSync: false });
},
});

this.addCommand({
id: "raindrop-sync-all",
name: "Sync all bookmarks (full sync)",
callback: async () => {
await this.raindropSync.sync({ fullSync: true });
},
});

this.addCommand({
id: "raindrop-sync-this",
name: "Sync this bookmark",
callback: async () => {
const file = app.workspace.getActiveFile();
},
});

Expand Down Expand Up @@ -63,7 +79,7 @@ export default class RaindropPlugin extends Plugin {
const bookmark = await this.api.getRaindrop(fmc.raindrop_id);
window.open(`https://app.raindrop.io/my/${bookmark.collectionId}/item/${bookmark.id}/edit`);
} else {
new Notice("This is not a Raindrop article file");
new Notice("This is not a Raindrop bookmark file");
}
} else {
new Notice("No active file");
Expand Down Expand Up @@ -159,7 +175,7 @@ export default class RaindropPlugin extends Plugin {
const minutesToSync = minutes ?? this.settings.autoSyncInterval;
if (minutesToSync > 0) {
this.timeoutIDAutoSync = window.setTimeout(() => {
this.raindropSync.sync();
this.raindropSync.sync({ fullSync: false });
this.startAutoSync();
}, minutesToSync * 60000);
}
Expand Down
16 changes: 11 additions & 5 deletions src/modal/breakingChange.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,28 +8,34 @@ export default class BreadkingChangeModal extends Modal {
constructor(app: App, currentVersion: string) {
super(app);

this.waitForClose = new Promise(
(resolve) => (this.resolvePromise = resolve)
);
this.waitForClose = new Promise((resolve) => (this.resolvePromise = resolve));

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

let breakingChanges = "";
if (semver.lt(currentVersion, "0.0.21")) {
breakingChanges += `<p>v0.0.21</p>
<ul>
<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>
</ul>
`;
}

if (semver.lt(currentVersion, "0.0.19")) {
breakingChanges += `<p>v0.0.19</p>
<ul>
<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>
<li>The file name and front matter are now synced with templates while performing updates.</li>
</ul>
`
`;
}

if (semver.lt(currentVersion, "0.0.18")) {
breakingChanges += `<p>v0.0.18</p>
<ul>
<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>
</ul>
`
`;
}

if (breakingChanges !== "") {
Expand Down
62 changes: 46 additions & 16 deletions src/sync.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,20 +23,41 @@ export default class RaindropSync {
this.renderer = new Renderer(plugin);
}

async sync() {
async sync({ fullSync }: { fullSync: boolean }) {
const collectionGroup = this.plugin.settings.collectionGroups;
const allCollections = await this.api.getCollections(collectionGroup);
this.plugin.updateCollectionSettings(allCollections);

for (const id in this.plugin.settings.syncCollections) {
const collection = this.plugin.settings.syncCollections[id];
if (collection.sync) {
await this.syncCollection(collection);
await this.syncCollection(collection, fullSync);
}
}
}

async syncCollection(collection: SyncCollection) {
async syncSingle({ file }: { file: TFile }) {
let raindropId: number;
if (file) {
const fmc = this.app.metadataCache.getFileCache(file)?.frontmatter;
if (!fmc?.raindrop_id) {
new Notice("This is not a Raindrop bookmark file");
return;
} else {
raindropId = Number(fmc.raindrop_id);
}
} else {
new Notice("No active file");
return;
}

const bookmark = await this.api.getRaindrop(raindropId);
await this.updateFileContent(file, bookmark);
// Do not perform path sync here!
// 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.
}

private getSyncFolder(collection: SyncCollection) {
if (this.plugin.settings.autoSyncSuccessNotice) {
new Notice(`Sync Raindrop collection: ${collection.title}`);
}
Expand All @@ -45,12 +66,21 @@ export default class RaindropSync {
if (this.plugin.settings.collectionsFolders) {
collectionFolder = `${highlightsFolder}/${collection["title"]}`;
}
const lastSyncDate = this.plugin.settings.syncCollections[collection.id].lastSyncDate;
return collectionFolder;
}

private async syncCollection(collection: SyncCollection, fullSync: boolean) {
const syncFolder = this.getSyncFolder(collection);
const lastSyncDate = fullSync ? undefined : this.plugin.settings.syncCollections[collection.id].lastSyncDate;

try {
console.debug(`start sync collection: ${collection.title}, last sync at: ${lastSyncDate}`);
if (lastSyncDate === undefined) {
console.debug(`start sync collection: ${collection.title}, full sync`);
} else {
console.debug(`start sync collection: ${collection.title}, last sync at: ${lastSyncDate}`);
}
for await (const bookmarks of this.api.getRaindropsAfter(collection.id, this.plugin.settings.autoSyncSuccessNotice, lastSyncDate)) {
await this.syncBookmarks(bookmarks, collectionFolder);
await this.syncBookmarks(bookmarks, syncFolder);
}
await this.syncCollectionComplete(collection);
} catch (e) {
Expand All @@ -59,7 +89,7 @@ export default class RaindropSync {
}
}

async syncBookmarks(bookmarks: RaindropBookmark[], folderPath: string) {
private async syncBookmarks(bookmarks: RaindropBookmark[], folderPath: string) {
if (bookmarks.length == 0) return;

if (this.plugin.settings.onlyBookmarksWithHl) {
Expand Down Expand Up @@ -93,7 +123,7 @@ export default class RaindropSync {
}
}

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

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

async syncCollectionComplete(collection: RaindropCollection) {
private async syncCollectionComplete(collection: RaindropCollection) {
this.plugin.settings.syncCollections[collection.id].lastSyncDate = new Date();
await this.plugin.saveSettings();
}

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

async updateFileContent(file: TFile, bookmark: RaindropBookmark) {
private async updateFileContent(file: TFile, bookmark: RaindropBookmark) {
if (this.plugin.settings.appendMode) {
await this.updateFileAppendMode(file, bookmark);
} else {
await this.updateFileOverwriteMode(file, bookmark);
}
}

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

async updateFileOverwriteMode(file: TFile, bookmark: RaindropBookmark) {
private async updateFileOverwriteMode(file: TFile, bookmark: RaindropBookmark) {
console.debug("update file overwrite mode", file.path);
const mdContent = this.renderer.renderFullArticle(bookmark);
return this.app.vault.modify(file, mdContent);
}

async createFile(filePath: string, bookmark: RaindropBookmark): Promise<TFile> {
private async createFile(filePath: string, bookmark: RaindropBookmark): Promise<TFile> {
console.debug("create file", filePath);
const mdContent = this.renderer.renderFullArticle(bookmark);
return this.app.vault.create(filePath, mdContent);
}

getBookmarkFiles(): BookmarkFile[] {
private getBookmarkFiles(): BookmarkFile[] {
return this.app.vault
.getMarkdownFiles()
.map((file) => {
Expand Down
1 change: 0 additions & 1 deletion src/templates/filenameTemplateInstructions.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
</p>
<ul>
<li>The rendered result is used as the filename for the bookmark.</li>
<li>This template is only used when creating the new file.</li>
<li>The rendered result is sanitized and truncated to 255 bytes.</li>
<li>The plugin will reject the invalid template.</li>
<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>
Expand Down
2 changes: 1 addition & 1 deletion src/templates/metadataTemplateInstructions.html
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@
<ul>
<li>The rendered result is placed in the front matter of the generated post.</li>
<li>If the rendered result does not follow the YAML syntax, the plugin will reject the update.</li>
<li><code>raindrop_id</code> and <code>raindrop_highlights</code> properties are transparently added by the plugin.</li>
<li><code>raindrop_id</code> and <code>raindrop_highlights</code> properties are transparently added and updated by the plugin.</li>
<li>Available variables to use are the same as the previous template.</li>
</ul>
2 changes: 1 addition & 1 deletion src/templates/templateInstructions.html
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
<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>
<li><span class="u-pop">{{collection}}</span> (Collection) - Collection data (Detail attributes refer to the following <span class="u-pop">Collection</span> section</li>
<li><span class="u-pop">{{creator}}</span> (Creator) - Creator data (Detail attributes refer to the following <span class="u-pop">Creator</span> section</li>
<li><span class="u-pop">{{tags}}</span> (string) - List of tag</li>
<li><span class="u-pop">{{tags}}</span> (string[]) - List of tag</li>
<li><span class="u-pop">{{cover}}</span> (string) - Article cover</li>
<li><span class="u-pop">{{created}}</span> (Moment) - Created on</li>
<li><span class="u-pop">{{type}}</span> (string) - Article type</li>
Expand Down
3 changes: 2 additions & 1 deletion versions.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,5 +18,6 @@
"0.0.17": "0.14.0",
"0.0.18": "0.14.0",
"0.0.19": "0.14.0",
"0.0.20": "0.14.0"
"0.0.20": "0.14.0",
"0.0.21": "0.14.0"
}

0 comments on commit 9b1b23d

Please sign in to comment.