diff --git a/README.md b/README.md index bca5d44..c8911f6 100644 --- a/README.md +++ b/README.md @@ -10,15 +10,15 @@ There ara four main settings: - `Keep in sync` that define if the plugin **should** keep the notes in sync with KOReader importing them again (see [sync](#sync)) - `Create a folder for each book` if you are a fan of folders enabling this setting the **new notes** will be created in a subfolder named as the book itself -### Template configuration +### View configuration The plugin use [Eta.js](https://eta.js.org/) as template engine to create the body of the note (the same used from the plugin [Templater](https://github.com/SilentVoid13/Templater)). The default template is pretty minimal ``` -# Title: [[<%= it.bookPath %>|<%= it.title %>]] +## Title: [[<%= it.bookPath %>|<%= it.title %>]] -by: [[<%= it.authors %>]] +### by: [[<%= it.authors %>]] -## Chapter: <%= it.chapter %> +### Chapter: <%= it.chapter %> Page: <%= it.page %> @@ -26,7 +26,7 @@ Page: <%= it.page %> <%= it.text %> ``` -In the `Template settings` section you can found the the option to use a custom template. If you chose to do so you must create a `.md` file in the vault and write your template in it (I suggest to copy the default in it as a starting point) and write the full path in `Template file` +In the `View settings` section you can found the the option to use a custom template. If you chose to do so you must create a `.md` file in the vault and write your template in it (I suggest to copy the default in it as a starting point) and write the path in `Template file` The template receive the following arguments: - `bookPath`: koreader/(book) How to Take Smart Notes_... {book suffix}-Sönke Ahrens @@ -36,6 +36,15 @@ The template receive the following arguments: - `highlight`: Clance and Imes 1978; Brems et al. 1994 - `text`: Clance (1978) first identified the Impostor Phenomenon in therapeutic sessions with highly successful women who attributed achievements to external factors - `datetime`: 2022-01-22 09:57:29 +- `page`: 19 + +#### Dataview embedded +Besides a native support for [Dataview](https://github.com/blacksmithgu/obsidian-dataview) (look at the [example](#dataview-examples)) the plugin let the user chose to automatically create a note for each book with a dataview query inside. +The note is created in the same folder of the notes of the book but can be moved and renamed and Obsidian will take care of updating the links. +To use this feature Dataview needs to be installed and its `Enable JavaScript Queries` must be enabled. +The query itself will embed the single notes and a CSS will hide every `h2` and `h3` tags (with the default template this will hide the title, the author and the chapter). + +**ATTENTION**: this feature require at least Obsidian v0.13.19 but there is a glitch that sometimes show only the filename of the notes instead of their contents. Try to close the note and open it again (sorry, not my fault) ## Usage Once the plugin is configured properly you can plug the device with KOReader and click on the icon with two documents and the tooltip `KOReader Plugin`. The plugin should propmplty create a single file for each note. @@ -62,7 +71,7 @@ The default value for `keep_in_sync` is `false` so the default behaviour is that If you modify your notes in KOReader and want them to be synced in obsidian you have to enable the `Keep in sync` setting **OR** to manually change the `keep_in_sync` frontmatter of a specific note from `false` to `true` and if the `yet_to_be_edited` of that note is `true` then the note will be deleted and recreated. ## Dataview examples -Thanks to the frontmatter data in each note you can use [Dataview](https://github.com/blacksmithgu/obsidian-dataview) to easily query your notes +Thanks to the frontmatter data in each note you can use Dataview to easily query your notes ### Books ~~~markdown diff --git a/manifest.json b/manifest.json index d64c4cf..481bc4a 100644 --- a/manifest.json +++ b/manifest.json @@ -1,8 +1,8 @@ { "id": "obsidian-koreader-plugin", "name": "KOReader Highlights", - "version": "0.2.2", - "minAppVersion": "0.12.0", + "version": "0.3.0", + "minAppVersion": "0.13.19", "description": "This is a plugin for Obsidian. This plugin syncs highlights and notes taken in KOReader.", "author": "Federico \"Edo\" Granata", "authorUrl": "https://federicogranata.dev", diff --git a/package-lock.json b/package-lock.json index 30935b4..dfa37f6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "obsidian-koreader-plugin", - "version": "0.2.2", + "version": "0.3.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "obsidian-koreader-plugin", - "version": "0.2.2", + "version": "0.3.0", "license": "MIT", "dependencies": { "eta": "^1.12.3", diff --git a/package.json b/package.json index ecb2782..ad2e025 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "obsidian-koreader-plugin", - "version": "0.2.2", + "version": "0.3.0", "description": "This is a plugin for Obsidian. This plugin syncs highlights and notes taken in KOReader.", "main": "main.js", "scripts": { diff --git a/src/main.ts b/src/main.ts index 3a6c9c6..7ecdc15 100644 --- a/src/main.ts +++ b/src/main.ts @@ -22,12 +22,14 @@ interface KOReaderSettings { aFolderForEachBook: boolean; customTemplate: boolean; templatePath?: string; + createDataviewQuery: boolean; } const DEFAULT_SETTINGS: KOReaderSettings = { keepInSync: false, aFolderForEachBook: false, customTemplate: false, + createDataviewQuery: false, koreaderBasePath: '/media/user/KOBOeReader', obsidianNoteFolder: '/', noteTitleOptions: { @@ -125,11 +127,11 @@ export default class KOReader extends Plugin { )} - ${book.authors}`; const notePath = normalizePath(`${path}/${noteTitle}`); - const defaultTemplate = `# Title: [[<%= it.bookPath %>|<%= it.title %>]] + const defaultTemplate = `## Title: [[<%= it.bookPath %>|<%= it.title %>]] -by: [[<%= it.authors %>]] +### by: [[<%= it.authors %>]] -## Chapter: <%= it.chapter %> +### Chapter: <%= it.chapter %> Page: <%= it.page %> @@ -143,8 +145,9 @@ Page: <%= it.page %> const template = templateFile ? await this.app.vault.read(templateFile as TFile) : defaultTemplate; + const bookPath = normalizePath(`${path}/${managedBookTitle}`); const content = (await eta.render(template, { - bookPath: normalizePath(`${path}/${managedBookTitle}`), + bookPath, title: book.title, authors: book.authors, chapter: bookmark.chapter, @@ -156,6 +159,7 @@ Page: <%= it.page %> const frontmatterData: { [key: string]: FrontMatter } = { [KOREADERKEY]: { + type: 'koreader-sync-note', uniqueId, data: { title: book.title, @@ -170,6 +174,7 @@ Page: <%= it.page %> body_hash: crypto.createHash('md5').update(content).digest('hex'), keep_in_sync: keepInSync || this.settings.keepInSync, yet_to_be_edited: true, + managed_book_title: managedBookTitle, }, }, }; @@ -177,6 +182,39 @@ Page: <%= it.page %> return { content, frontmatterData, notePath }; } + async createDataviewQueryPerBook(dataview: { + path: string; + managedBookTitle: string; + title: string; + }) { + const { path, title, managedBookTitle } = dataview; + const frontMatter = { + cssclass: 'koreader-sync-dataview', + [KOREADERKEY]: { + type: 'koreader-sync-dataview', + managed_title: managedBookTitle, + }, + }; + console.log('frontMatter', frontMatter); + const defaultTemplate = `# Title: <%= it.title %> + +\`\`\`dataviewjs +const title = dv.current()['koreader-sync'].managed_title +dv.pages().where(n => { +return n['koreader-sync'] && n['koreader-sync'].type == 'koreader-sync-note' && n['koreader-sync'].metadata.managed_book_title == title +}).sort(p => p['koreader-sync'].data.page).forEach(p => dv.paragraph(dv.fileLink(p.file.name, true), {style: 'test-css'})) +\`\`\` + `; + const template = defaultTemplate; + const content = (await eta.render(template, { + title, + })) as string; + this.app.vault.create( + `${path}/${managedBookTitle}.md`, + matter.stringify(content, frontMatter) + ); + } + async importNotes(evt: MouseEvent) { const metadata = new KOReaderMetadata(this.settings.koreaderBasePath); const data: Books = await metadata.scan(); @@ -205,15 +243,31 @@ Page: <%= it.page %> data[book].title, this.settings.bookTitleOptions )}-${data[book].authors}`; + // if the setting aFolderForEachBook is true, we add the managedBookTitle to the path specified in obsidianNoteFolder + const path = this.settings.aFolderForEachBook + ? `${this.settings.obsidianNoteFolder}/${managedBookTitle}` + : this.settings.obsidianNoteFolder; // if aFolderForEachBook is set, create a folder for each book if (this.settings.aFolderForEachBook) { - const bookFolder = normalizePath( - `${this.settings.obsidianNoteFolder}/${managedBookTitle}` - ); - if (!this.app.vault.getAbstractFileByPath(bookFolder)) { - this.app.vault.createFolder(bookFolder); + if (!this.app.vault.getAbstractFileByPath(path)) { + this.app.vault.createFolder(path); } } + // if createDataviewQuery is set, create a dataview query, for each book, with the book's managed title (if it doesn't exist) + if ( + this.settings.createDataviewQuery && + !this.app.vault.getAbstractFileByPath(`${path}/${managedBookTitle}.md`) + ) { + console.log( + `Creating dataview query in ${path}/${managedBookTitle}.md` + ); + this.createDataviewQueryPerBook({ + path, + managedBookTitle, + title: data[book].title, + }); + } + for (const bookmark in data[book].bookmarks) { const uniqueId = crypto .createHash('md5') @@ -233,10 +287,7 @@ Page: <%= it.page %> continue; } } - // if the setting aFolderForEachBook is true, we add the managedBookTitle to the path specified in obsidianNoteFolder - const path = this.settings.aFolderForEachBook - ? `${this.settings.obsidianNoteFolder}/${managedBookTitle}` - : this.settings.obsidianNoteFolder; + const { content, frontmatterData, notePath } = await this.createNote({ path, uniqueId, @@ -345,7 +396,7 @@ class KoreaderSettingTab extends PluginSettingTab { }) ); - containerEl.createEl('h2', { text: 'Template settings' }); + containerEl.createEl('h2', { text: 'View settings' }); new Setting(containerEl) .setName('Custom template') @@ -372,6 +423,35 @@ class KoreaderSettingTab extends PluginSettingTab { }) ); + new Setting(containerEl) + .setName('Create a dataview query') + .setDesc( + createFragment((frag) => { + frag.appendText( + 'Create a note (for each book) with a dataview query (read the ' + ); + frag.createEl( + 'a', + { + text: 'documentation', + href: 'https://github.com/Edo78/obsidian-koreader-sync#dateview-embedded', + }, + (a) => { + a.setAttr('target', '_blank'); + } + ); + frag.appendText(')'); + }) + ) + .addToggle((toggle) => + toggle + .setValue(this.plugin.settings.createDataviewQuery) + .onChange(async (value) => { + this.plugin.settings.createDataviewQuery = value; + await this.plugin.saveSettings(); + }) + ); + containerEl.createEl('h2', { text: 'Note title settings' }); new Setting(containerEl).setName('Prefix').addText((text) => diff --git a/src/types.d.ts b/src/types.d.ts index a18b017..1e88c4d 100644 --- a/src/types.d.ts +++ b/src/types.d.ts @@ -38,9 +38,11 @@ export interface FrontMatterMetadata { body_hash: string; keep_in_sync: boolean; yet_to_be_edited: boolean; + managed_book_title: string; } export interface FrontMatter { + type: string; uniqueId: string; data: FrontMatterData, metadata: FrontMatterMetadata, diff --git a/styles.css b/styles.css index e69de29..a88323a 100644 --- a/styles.css +++ b/styles.css @@ -0,0 +1,8 @@ +/* This stile hide the title of embedded notes only if the container has a frontmatter like this +--- +cssclass: koreader-sync +--- +*/ +.koreader-sync-dataview .markdown-embed-title, .koreader-sync-dataview h2, .koreader-sync-dataview h3 { + display: none; +} diff --git a/versions.json b/versions.json index 8262fac..57fc49a 100644 --- a/versions.json +++ b/versions.json @@ -10,5 +10,6 @@ "0.1.2": "0.12.0", "0.2.0": "0.12.0", "0.2.1": "0.12.0", - "0.2.2": "0.12.0" + "0.2.2": "0.12.0", + "0.3.0": "0.13.19" }