diff --git a/package.json b/package.json index 6c7172b..dc9cad0 100644 --- a/package.json +++ b/package.json @@ -48,6 +48,7 @@ "typescript": "^4.2.4", "webpack": "^5.30.0", "webpack-cli": "^4.6.0", - "webpack-node-externals": "^2.5.2" + "webpack-node-externals": "^2.5.2", + "base-x": "^4.0.0" } } \ No newline at end of file diff --git a/src/fileManager.ts b/src/fileManager.ts index 265b26c..73f68c3 100644 --- a/src/fileManager.ts +++ b/src/fileManager.ts @@ -13,12 +13,19 @@ type AnnotationFile = { const articleFolderPath = (article: Article): string => { const settings = get(settingsStore); + let folderPath = settings.highlightsFolder; + if (settings.useDomainFolders) { // "metadata.author" is equal to the article domain at the moment - return `${settings.highlightsFolder}/${article.metadata.author}`; + folderPath = `${folderPath}/${article.metadata.author}`; + } + + if (settings.useURLPathFolders) { + const pathname = new URL(article.metadata.url).pathname.replace(/\/$/, ''); + folderPath = `${folderPath}/${pathname}`; } - return settings.highlightsFolder; + return folderPath; }; export default class FileManager { diff --git a/src/modals/resyncDelFileModal.ts b/src/modals/resyncDelFileModal.ts index 8ce9a0e..ac4cf64 100644 --- a/src/modals/resyncDelFileModal.ts +++ b/src/modals/resyncDelFileModal.ts @@ -70,9 +70,9 @@ export default class ResyncDelFileModal extends Modal { // Check which files are actually present const deletedArticles = await Promise.all(allArticles.filter(async article => !(await this.fileManager.isArticleSaved(article)))); - return deletedArticles.map((article: Article) => - ({ uri: article.metadata.url, filename: this.fileManager.getNewArticleFilePath(article)}) - ); + return await Promise.all(deletedArticles.map(async (article: Article) => + ({ uri: article.metadata.url, filename: (await this.fileManager.getNewArticleFilePath(article)).split('//')[1]}) + )); } async startResync(selectedFiles: SyncedFile[]): Promise { diff --git a/src/models.ts b/src/models.ts index c39a7a0..d347b44 100644 --- a/src/models.ts +++ b/src/models.ts @@ -14,6 +14,7 @@ export type Metadata = { export type Highlights = { id?: string; + id_base62?: string; created: string; updated: string; text: string; diff --git a/src/parser/parseSyncResponse.ts b/src/parser/parseSyncResponse.ts index 75a1527..b038b1a 100644 --- a/src/parser/parseSyncResponse.ts +++ b/src/parser/parseSyncResponse.ts @@ -2,8 +2,12 @@ import md5 from 'crypto-js/md5'; import { moment } from 'obsidian'; import { settingsStore } from '~/store'; import { get } from 'svelte/store'; +import basex from 'base-x'; import type { Article, Highlights } from '../models' +const BASE62_CHARSET = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; +const base62 = basex(BASE62_CHARSET); + const parseAuthorUrl = (url: string) => { const domain = (new URL(url)); const author = domain.hostname.replace('www.', ''); @@ -52,8 +56,16 @@ const parseHighlight = (annotationData, groupName: string, momentFormat: string) } } + const id = annotationData['id']; + let id_base62 = null; + if(id != null){ + const uint8Array = Buffer.from(id, 'utf-8'); + id_base62 = base62.encode(uint8Array); + } + return { - id: annotationData['id'], + id, + id_base62, created: moment(annotationData['created']).format(momentFormat), updated: moment(annotationData['updated']).format(momentFormat), text: highlightText && cleanTextSelectorHighlight(highlightText), diff --git a/src/settingsTab/index.ts b/src/settingsTab/index.ts index 031386b..e2a4097 100644 --- a/src/settingsTab/index.ts +++ b/src/settingsTab/index.ts @@ -43,6 +43,7 @@ export class SettingsTab extends PluginSettingTab { this.autoSyncInterval(); this.highlightsFolder(); this.folderPath(); + this.folderURLPath() this.syncOnBoot(); this.dateFormat(); this.template(); @@ -192,6 +193,22 @@ export class SettingsTab extends PluginSettingTab { ); } + private folderURLPath(): void { + + new Setting(this.containerEl) + .setName('Use URL path folders') + .setDesc('The generated file directory is based on the path of the highlight URL.' + + 'This option is designed to prevent filename conflicts caused by identical webpage titles under different paths of a website' + + 'It is recommended to enable this option only when "Use domain folders" is enabled.') + .addToggle((toggle) => + toggle + .setValue(get(settingsStore).useDomainFolders) + .onChange(async (value) => { + await settingsStore.actions.setURLPathFolders(value); + }) + ); + } + private syncOnBoot(): void { new Setting(this.containerEl) .setName('Sync on Startup') diff --git a/src/settingsTab/templateInstructions.html b/src/settingsTab/templateInstructions.html index 43dc0fd..e939344 100644 --- a/src/settingsTab/templateInstructions.html +++ b/src/settingsTab/templateInstructions.html @@ -16,7 +16,8 @@ Highlight