├── .npmrc ├── .eslintignore ├── versions.json ├── src ├── test │ ├── json │ │ ├── howtotakenotes-success │ │ │ ├── util.integerToRGBA.input-2022-11-19 14-04-29.json │ │ │ ├── util.integerToRGBA.output-2022-11-19 14-04-29.json │ │ │ ├── exporter.generateOutput.output-2022-11-19 14-04-30.json │ │ │ └── exporter.generateOutput.input-2022-11-19 14-04-30.json │ │ ├── parseMrexptContents.parseMrexptContents.input-2022-11-25 22-07-41.json │ │ └── parseMrexptContents.parseMrexptContents.output-2022-11-25 22-07-41.json │ ├── util.test.ts │ ├── parser.test.ts │ ├── exporter.test.ts │ └── __snapshots__ │ │ └── exporter.test.ts.snap ├── util.ts ├── types.ts ├── parser.ts ├── suggester.ts ├── epubExtracter.ts ├── parseMrexptContents.ts ├── colorpicker.ts ├── settings.ts ├── exporter.ts ├── devutils.ts └── main.ts ├── .editorconfig ├── styles.css ├── manifest.json ├── jest.config.ts ├── .gitignore ├── tsconfig.json ├── version-bump.mjs ├── .eslintrc ├── LICENSE ├── package.json ├── esbuild.config.mjs ├── CHANGELOG.md └── README.md /.npmrc: -------------------------------------------------------------------------------- 1 | tag-version-prefix="" -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | npm node_modules 2 | build -------------------------------------------------------------------------------- /versions.json: -------------------------------------------------------------------------------- 1 | { 2 | "0.1.0": "0.9.12", 3 | "0.2.2": "0.16.0" 4 | } -------------------------------------------------------------------------------- /src/test/json/howtotakenotes-success/util.integerToRGBA.input-2022-11-19 14-04-29.json: -------------------------------------------------------------------------------- 1 | { 2 | "number": 2281635925 3 | } -------------------------------------------------------------------------------- /src/test/json/howtotakenotes-success/util.integerToRGBA.output-2022-11-19 14-04-29.json: -------------------------------------------------------------------------------- 1 | { 2 | "convertedRGBA": "FF005587" 3 | } 4 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # top-most EditorConfig file 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | insert_final_newline = true 7 | indent_style = tab 8 | indent_size = 4 9 | tab_width = 4 10 | -------------------------------------------------------------------------------- /styles.css: -------------------------------------------------------------------------------- 1 | .color-box { 2 | width: 10px; 3 | height: 10px; 4 | display: inline-block; 5 | margin: 0 10px; 6 | } 7 | 8 | div.colorpicker { 9 | display: flex; 10 | align-items: center; 11 | } -------------------------------------------------------------------------------- /manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "obsidian-moon-reader", 3 | "name": "Obsidian Moon Reader", 4 | "version": "0.2.3", 5 | "minAppVersion": "0.16.0", 6 | "description": "This plugin will help you use your Moon+ Reader exports in Obsidian.", 7 | "author": "AB1908", 8 | "authorUrl": "https://github.com/AB1908", 9 | "isDesktopOnly": false 10 | } 11 | -------------------------------------------------------------------------------- /jest.config.ts: -------------------------------------------------------------------------------- 1 | import type { Config } from '@jest/types'; 2 | 3 | // Sync object 4 | const config: Config.InitialOptions = { 5 | verbose: true, 6 | transform: { 7 | '^.+\\.tsx?$': `ts-jest`, 8 | }, 9 | roots: ['', 'src'], 10 | modulePaths: [''], 11 | moduleDirectories: ['node_modules'], 12 | }; 13 | 14 | export default config; 15 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # vscode 2 | .vscode 3 | 4 | # Intellij 5 | *.iml 6 | .idea 7 | 8 | # npm 9 | node_modules 10 | 11 | # Don't include the compiled main.js file in the repo. 12 | # They should be uploaded to GitHub releases instead. 13 | main.js 14 | 15 | # Exclude sourcemaps 16 | *.map 17 | 18 | # obsidian 19 | data.json 20 | 21 | # Exclude macOS Finder (System Explorer) View States 22 | .DS_Store 23 | -------------------------------------------------------------------------------- /src/test/util.test.ts: -------------------------------------------------------------------------------- 1 | import {expect, test} from "@jest/globals"; 2 | import {number} from "./json/howtotakenotes-success/util.integerToRGBA.input-2022-11-19 14-04-29.json" 3 | import {convertedRGBA} from "./json/howtotakenotes-success/util.integerToRGBA.output-2022-11-19 14-04-29.json"; 4 | import integerToRGBA from "../util"; 5 | 6 | test("util.integerToRGBA", () => { 7 | expect(integerToRGBA(number)).toEqual(convertedRGBA); 8 | }) 9 | -------------------------------------------------------------------------------- /src/util.ts: -------------------------------------------------------------------------------- 1 | // import {logArgs} from "./devutils"; 2 | 3 | export default function integerToRGBA(number: number): string { 4 | if (number < 0) { 5 | number = 0xFFFFFFFF + number + 1; 6 | } 7 | const ARGB = number.toString(16).toUpperCase(); 8 | 9 | const output = `${ARGB.slice(2,)}${ARGB.slice(0, 2)}`; 10 | // eslint-disable-next-line prefer-rest-params 11 | // logArgs(arguments, output); 12 | return output; 13 | } 14 | -------------------------------------------------------------------------------- /src/test/parser.test.ts: -------------------------------------------------------------------------------- 1 | import {expect, test} from "@jest/globals"; 2 | import parserOutput from "./json/parseMrexptContents.parseMrexptContents.output-2022-11-25 22-07-41.json"; 3 | import {highlightContent} from "./json/parseMrexptContents.parseMrexptContents.input-2022-11-25 22-07-41.json"; 4 | import {parseMrexptContents} from "../parseMrexptContents"; 5 | 6 | test("regular MoonReader import parsing", () => { 7 | expect(parseMrexptContents(highlightContent)).toEqual(parserOutput); 8 | }) 9 | -------------------------------------------------------------------------------- /src/types.ts: -------------------------------------------------------------------------------- 1 | export class Annotation { 2 | //todo: check types 3 | indexCount: number; 4 | bookName: string; 5 | bookPath: string; 6 | lowerCasePath: string; 7 | sectionNumber: number; 8 | placeholder1: string; 9 | location: string; 10 | characterCount: number; 11 | signedColor: number; 12 | unixTimestamp: string; 13 | bookmarkText: string; 14 | noteText: string; 15 | highlightText: string; 16 | annotType1: number; 17 | annotType2: number; 18 | annotType3: number; 19 | } -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "baseUrl": ".", 4 | "inlineSourceMap": true, 5 | "inlineSources": true, 6 | "module": "ESNext", 7 | "target": "ES6", 8 | "allowJs": true, 9 | "noImplicitAny": true, 10 | "moduleResolution": "node", 11 | "importHelpers": true, 12 | "isolatedModules": true, 13 | "resolveJsonModule": true, 14 | "esModuleInterop": true, 15 | "lib": [ 16 | "DOM", 17 | "ES5", 18 | "ES6", 19 | "ES7", 20 | "ES2021.String" 21 | ] 22 | }, 23 | "include": [ 24 | "**/*.ts" 25 | ] 26 | } 27 | -------------------------------------------------------------------------------- /version-bump.mjs: -------------------------------------------------------------------------------- 1 | import { readFileSync, writeFileSync } from "fs"; 2 | 3 | const targetVersion = process.env.npm_package_version; 4 | 5 | // read minAppVersion from manifest.json and bump version to target version 6 | let manifest = JSON.parse(readFileSync("manifest.json", "utf8")); 7 | const { minAppVersion } = manifest; 8 | manifest.version = targetVersion; 9 | writeFileSync("manifest.json", JSON.stringify(manifest, null, "\t")); 10 | 11 | // update versions.json with target version and minAppVersion from manifest.json 12 | let versions = JSON.parse(readFileSync("versions.json", "utf8")); 13 | versions[targetVersion] = minAppVersion; 14 | writeFileSync("versions.json", JSON.stringify(versions, null, "\t")); 15 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "parser": "@typescript-eslint/parser", 4 | "env": { "node": true }, 5 | "plugins": [ 6 | "@typescript-eslint" 7 | ], 8 | "extends": [ 9 | "eslint:recommended", 10 | "plugin:@typescript-eslint/eslint-recommended", 11 | "plugin:@typescript-eslint/recommended" 12 | ], 13 | "parserOptions": { 14 | "sourceType": "module" 15 | }, 16 | "rules": { 17 | "no-unused-vars": "off", 18 | "@typescript-eslint/no-unused-vars": ["error", { "args": "none" }], 19 | "@typescript-eslint/ban-ts-comment": "off", 20 | "no-prototype-builtins": "off", 21 | "@typescript-eslint/no-empty-function": "off" 22 | } 23 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 AB1908 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "obsidian-moon-reader", 3 | "version": "0.2.3", 4 | "description": "Import your Moon+ Reader annotations in Obsidian.", 5 | "main": "main.js", 6 | "scripts": { 7 | "dev": "node esbuild.config.mjs", 8 | "build": "tsc -noEmit -skipLibCheck && node esbuild.config.mjs production", 9 | "version": "node version-bump.mjs && git add manifest.json versions.json", 10 | "release": "standard-version", 11 | "test": "jest" 12 | }, 13 | "standard-version": { 14 | "skip": { 15 | "commit": true 16 | } 17 | }, 18 | "keywords": [], 19 | "author": "AB1908", 20 | "license": "MIT", 21 | "devDependencies": { 22 | "@gxl/epub-parser": "^2.0.4", 23 | "@jest/globals": "^29.3.1", 24 | "@types/node": "^16.11.6", 25 | "@typescript-eslint/eslint-plugin": "^5.2.0", 26 | "@typescript-eslint/parser": "^5.2.0", 27 | "builtin-modules": "^3.2.0", 28 | "esbuild": "0.13.12", 29 | "func-loc": "^0.1.16", 30 | "jest": "^29.3.1", 31 | "obsidian": "^0.16.3", 32 | "standard-version": "^9.5.0", 33 | "ts-jest": "^29.0.3", 34 | "ts-node": "^10.9.1", 35 | "tslib": "2.3.1", 36 | "typescript": "4.4.4" 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/parser.ts: -------------------------------------------------------------------------------- 1 | import {Notice, TFile} from 'obsidian'; 2 | import {Annotation} from 'src/types'; 3 | import {parseMrexptContents} from "./parseMrexptContents"; 4 | 5 | // import {logArgs} from "./devutils"; 6 | 7 | export async function parse( 8 | mrexptChoice: TFile 9 | ): Promise { 10 | try { 11 | const currentTFile = this 12 | .app 13 | .workspace 14 | .getActiveFile() 15 | ; 16 | if (!currentTFile) { 17 | //TODO: Handle by giving file prompt? 18 | new Notice("No active file!"); 19 | return; 20 | } 21 | // todo fix hardcoding 22 | const parsedFileFrontmatter = this 23 | .app 24 | .metadataCache 25 | .getFileCache(currentTFile) 26 | ?.frontmatter 27 | ; 28 | if (!parsedFileFrontmatter) { //todo: refactor 29 | //TODO: Raise exception 30 | new Notice("File Metadata Missing!"); 31 | } 32 | /// todo: add time checking 33 | 34 | const highlightContent = await this 35 | .app 36 | .vault 37 | .read(mrexptChoice) 38 | ;const listOfAnnotations = parseMrexptContents(highlightContent); 39 | // eslint-disable-next-line prefer-rest-params 40 | // logArgs(arguments, listOfAnnotations) 41 | return listOfAnnotations; 42 | } catch (e) { 43 | new Notice("Error: Check console for logs."); 44 | console.log(e); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /esbuild.config.mjs: -------------------------------------------------------------------------------- 1 | import esbuild from "esbuild"; 2 | import process from "process"; 3 | import builtins from 'builtin-modules' 4 | 5 | const banner = 6 | `/* 7 | THIS IS A GENERATED/BUNDLED FILE BY ESBUILD 8 | if you want to view the source, please visit the github repository of this plugin 9 | */ 10 | `; 11 | 12 | const prod = (process.argv[2] === 'production'); 13 | 14 | esbuild.build({ 15 | banner: { 16 | js: banner, 17 | }, 18 | entryPoints: ['src/main.ts'], 19 | bundle: true, 20 | external: [ 21 | 'obsidian', 22 | 'electron', 23 | '@codemirror/autocomplete', 24 | '@codemirror/closebrackets', 25 | '@codemirror/collab', 26 | '@codemirror/commands', 27 | '@codemirror/comment', 28 | '@codemirror/fold', 29 | '@codemirror/gutter', 30 | '@codemirror/highlight', 31 | '@codemirror/history', 32 | '@codemirror/language', 33 | '@codemirror/lint', 34 | '@codemirror/matchbrackets', 35 | '@codemirror/panel', 36 | '@codemirror/rangeset', 37 | '@codemirror/rectangular-selection', 38 | '@codemirror/search', 39 | '@codemirror/state', 40 | '@codemirror/stream-parser', 41 | '@codemirror/text', 42 | '@codemirror/tooltip', 43 | '@codemirror/view', 44 | ...builtins], 45 | format: 'cjs', 46 | watch: !prod, 47 | target: 'es2016', 48 | logLevel: "info", 49 | sourcemap: prod ? false : 'inline', 50 | treeShaking: true, 51 | outfile: 'main.js', 52 | }).catch(() => process.exit(1)); 53 | -------------------------------------------------------------------------------- /src/suggester.ts: -------------------------------------------------------------------------------- 1 | import { App, TFile, FuzzyMatch, FuzzySuggestModal } from 'obsidian'; 2 | 3 | export class ExportSelecter extends FuzzySuggestModal { 4 | suggestions: TFile[]; 5 | private resolve: (value: TFile) => void; 6 | private reject: (reason?: string) => void; 7 | submitted: boolean; 8 | 9 | constructor(app: App, suggestions: TFile[]) { 10 | super(app); 11 | this.setPlaceholder("Choose your export file"); 12 | // TODO: better folder handling 13 | this.suggestions = suggestions; 14 | this.submitted = false; 15 | } 16 | 17 | getItems(): TFile[] { 18 | return this.suggestions; 19 | } 20 | 21 | getItemText(item: TFile): string { 22 | return `${item.basename}`; 23 | } 24 | 25 | onChooseItem(item: TFile, evt: MouseEvent | KeyboardEvent): void { 26 | this.resolve(item); 27 | } 28 | 29 | selectSuggestion(value: FuzzyMatch, evt: MouseEvent | KeyboardEvent): void { 30 | this.submitted = true; 31 | this.onChooseSuggestion(value, evt); 32 | this.close(); 33 | } 34 | 35 | onClose(): void { 36 | if (!this.submitted) { 37 | this.reject(); 38 | } 39 | } 40 | 41 | async openAndGetValue( 42 | ): Promise { 43 | return new Promise( 44 | (resolve, reject) => { 45 | try { 46 | this.resolve = resolve; 47 | this.reject = reject; 48 | this.open(); 49 | } 50 | catch (e) { 51 | console.log(e) 52 | } 53 | } 54 | ) 55 | } 56 | } -------------------------------------------------------------------------------- /src/test/json/howtotakenotes-success/exporter.generateOutput.output-2022-11-19 14-04-30.json: -------------------------------------------------------------------------------- 1 | { 2 | "output": "---\npath: \"Book Exports/Sönke Ahrens - How to Take Smart Notes_ One Simple Technique to Boost Writing, Learning and Thinking-Sönke Ahrens (2022).mrexpt\"\ntitle: \"How to Take Smart Notes. One Simple Technique to Boost Writing, Learning and Thinking\"\nauthor: \nlastExportedTimestamp: 1665321164166\nlastExportedID: 12623\n---\n\n> [!555555FF]\n> INTRODUCTION\n> ***\n> #\n\n> [!555555FF]\n> 1 Everything You Need to Know\n> ***\n> ##\n\n> [!555555FF]\n> 2 Everything You Need to Do\n> \n> ***\n> ##\n\n> [!555555FF]\n> 3 Everything You Need to Have\n> ***\n> ##\n\n> [!555555FF]\n> 4 A Few Things to Keep in Mind\n> ***\n> ##\n\n> [!555555FF]\n> 5 Writing Is the Only Thing That Matters\n> ***\n> ##\n\n> [!555555FF]\n> 6 Simplicity Is Paramount\n> ***\n> ##\n\n> [!555555FF]\n> 7 Nobody Ever Starts From Scratch\n> ***\n> ##\n\n> [!555555FF]\n> 8 Let the Work Carry You Forward\n> ***\n> ##\n\n> [!555555FF]\n> 9 Separate and Interlocking Tasks\n> ***\n> ##\n\n> [!555555FF]\n> 10 Read for Understanding\n> ***\n> ##\n\n> [!555555FF]\n> 11 Take Smart Notes\n> ***\n> ##\n\n> [!555555FF]\n> 12 Develop Ideas\n> ***\n> ##\n\n> [!555555FF]\n> 13 Share Your Insight\n> ***\n> ##\n\n> [!555555FF]\n> 14 Make It a Habit\n> ***\n> ##\n\n> [!555555FF]\n> 1.1 Good Solutions are Simple – and Unexpected\n> ***\n> ###\n\n> [!555555FF]\n> 1.2 The Slip-box\n> ***\n> ###\n\n> [!555555FF]\n> 1.3 The slip-box manual\n> ***\n> ###\n\n" 3 | } 4 | -------------------------------------------------------------------------------- /src/epubExtracter.ts: -------------------------------------------------------------------------------- 1 | import type {Epub} from "@gxl/epub-parser/lib/parseEpub"; 2 | import type {GeneralObject} from "@gxl/epub-parser/lib/types"; 3 | 4 | export interface Section { 5 | name: string, 6 | sectionNumber: number, 7 | level: number 8 | } 9 | 10 | export function flattenStructureOfParsedEpub(parsedEpub: Epub) { 11 | if (!parsedEpub.structure) { 12 | return; 13 | } 14 | return recursiveHelper(parsedEpub.structure) 15 | } 16 | 17 | function recursiveHelper(array: GeneralObject, IR: Section[] = [], level = 0) { 18 | let currentNode; 19 | while(array) { 20 | currentNode = array.shift(); 21 | if (!currentNode) break; 22 | IR.push({ 23 | name: currentNode.name, 24 | sectionNumber: Number(currentNode.playOrder), 25 | level: level 26 | }) 27 | if (currentNode.children) { 28 | IR = recursiveHelper(currentNode.children, IR, level+1); 29 | } 30 | } 31 | return IR; 32 | } 33 | 34 | // Creates a key value pair using section name as the key 35 | function createLookupFromMrexpt(parsedMrexpt: mrexptEntries[]) { 36 | return parsedMrexpt.reduce((acc, curr) => ({...acc, [curr.sectionName.trim()]: curr.sectionNumber}), {}); 37 | } 38 | 39 | interface mrexptEntries { 40 | sectionNumber: number, 41 | sectionName: string, 42 | [key: string]: any 43 | } 44 | 45 | export function exportDifference(parsedMrexpt: mrexptEntries[], epubSections: Section[]): number|null { 46 | const lookupObject: { [key: string]: number } = createLookupFromMrexpt(parsedMrexpt); 47 | for (const section of epubSections) { 48 | if (section.name in lookupObject) { 49 | return section.sectionNumber - lookupObject[section.name]; 50 | } 51 | } 52 | return null; 53 | } 54 | -------------------------------------------------------------------------------- /src/parseMrexptContents.ts: -------------------------------------------------------------------------------- 1 | import {Annotation} from "./types"; 2 | 3 | export function parseMrexptContents(highlightContent: string) { 4 | const listOfAnnotations: Annotation[] = []; 5 | const regexpHighlight = /#\n(?.*)\n(?.*)\n(?<path>.*)\n(?<lpath>.*)\n(?<chapter>.*)\n(?<p1>.*)\n(?<location>.*)\n(?<characters>.*)\n(?<color>.*)\n(?<timestamp>.*)\n(?<bookmarkText>.*)\n(?<noteText>.*)\n(?<highlightText>.*)\n(?<t1>.*)\n(?<t2>.*)\n(?<t3>.*)\n/g; 6 | let currentHighlight = regexpHighlight.exec(highlightContent); 7 | do { 8 | // todo: move to constructor? 9 | const annotation = new Annotation(); 10 | const extractedRegexMatch = currentHighlight.groups; 11 | annotation.sectionNumber = Number(extractedRegexMatch.chapter); 12 | annotation.location = extractedRegexMatch.location; 13 | annotation.highlightText = extractedRegexMatch.highlightText.replaceAll("<BR>", "\n"); 14 | annotation.noteText = extractedRegexMatch.noteText.replaceAll("<BR>", "\n"); 15 | annotation.indexCount = Number(extractedRegexMatch.id); 16 | annotation.annotType1 = Number(extractedRegexMatch.t1); 17 | annotation.annotType2 = Number(extractedRegexMatch.t2); 18 | annotation.annotType3 = Number(extractedRegexMatch.t3); 19 | annotation.bookmarkText = extractedRegexMatch.bookmarkText; 20 | annotation.unixTimestamp = extractedRegexMatch.timestamp; 21 | annotation.signedColor = Number(extractedRegexMatch.color); 22 | annotation.characterCount = Number(extractedRegexMatch.characters); 23 | annotation.bookName = extractedRegexMatch.title; 24 | annotation.bookPath = extractedRegexMatch.path; 25 | listOfAnnotations.push(annotation); 26 | currentHighlight = regexpHighlight.exec(highlightContent) 27 | } while (currentHighlight !== null); 28 | return listOfAnnotations; 29 | } 30 | -------------------------------------------------------------------------------- /src/colorpicker.ts: -------------------------------------------------------------------------------- 1 | import { App, FuzzyMatch, FuzzySuggestModal } from 'obsidian'; 2 | import integerToRGBA from './util'; 3 | 4 | export class ColorPicker extends FuzzySuggestModal<number> { 5 | suggestions: number[]; 6 | private resolve: (value: number) => void; 7 | private reject: (reason?: string) => void; 8 | submitted: boolean; 9 | 10 | constructor(app: App, suggestions: number[]) { 11 | super(app); 12 | this.setPlaceholder("Choose your color"); 13 | // TODO: better folder handling 14 | this.suggestions = suggestions; 15 | this.submitted = false; 16 | } 17 | 18 | getItems(): number[] { 19 | return this.suggestions; 20 | } 21 | 22 | getItemText(item: number): string { 23 | return `${integerToRGBA(item)}`; 24 | } 25 | 26 | onChooseItem(item: number ,_evt: MouseEvent | KeyboardEvent): void { 27 | this.resolve(item); 28 | } 29 | 30 | selectSuggestion(value: FuzzyMatch<number>, evt: MouseEvent | KeyboardEvent): void { 31 | this.submitted = true; 32 | this.onChooseSuggestion(value, evt); 33 | this.close(); 34 | } 35 | 36 | onClose(): void { 37 | if (!this.submitted) { 38 | this.reject(); 39 | } 40 | } 41 | 42 | async openAndGetValue( 43 | ): Promise<number> { 44 | return new Promise( 45 | (resolve, reject) => { 46 | try { 47 | this.resolve = resolve; 48 | this.reject = reject; 49 | this.open(); 50 | } 51 | catch (e) { 52 | console.log(e) 53 | } 54 | } 55 | ) 56 | } 57 | 58 | renderSuggestion(item: FuzzyMatch<number>, el: HTMLElement): void { 59 | el.addClass("colorpicker"); 60 | const colorDiv = el.createDiv("color-box"); 61 | colorDiv.style.backgroundColor = `#${integerToRGBA(item.item).slice(0,6)}`; 62 | const div = el.createDiv(); 63 | div.setText(`${integerToRGBA(item.item).slice(0,6)}`); 64 | } 65 | } -------------------------------------------------------------------------------- /src/settings.ts: -------------------------------------------------------------------------------- 1 | import {App, PluginSettingTab, Setting} from 'obsidian'; 2 | import MoonReader, {MoonReaderSettings} from 'src/main'; 3 | 4 | export class SettingsTab extends PluginSettingTab { 5 | plugin: MoonReader; 6 | 7 | constructor(app: App, plugin: MoonReader) { 8 | super(app, plugin); 9 | this.plugin = plugin; 10 | } 11 | 12 | display(): void { 13 | const {containerEl} = this; 14 | 15 | containerEl.empty(); 16 | 17 | new Setting(containerEl) 18 | .setName('Experimental Support for SRS') 19 | .setDesc(createFragment((frag) => { 20 | frag.appendText("Enable support for "); 21 | frag.createEl( 22 | "a", 23 | { 24 | text: "AB1908's new SRS plugin", 25 | href: "https://github.com/AB1908/obsidian-spaced-repetition/", 26 | }, 27 | (a) => { 28 | a.setAttr("target", "_blank"); 29 | } 30 | ); 31 | frag.appendText( 32 | ". This will change the output format." 33 | ); 34 | })) 35 | .addToggle(toggle => 36 | toggle 37 | .setValue(this.plugin.settings.enableSRSSupport) 38 | .onChange(async value => await this.updateSettings({enableSRSSupport: value})) 39 | ).descEl.innerHTML = "Enable support for <a href=\"https://github.com/AB1908/obsidian-spaced-repetition\">AB1908\'s new SRS plugin</a>. This changes the output format."; 40 | 41 | new Setting(containerEl) 42 | .setName('Book Exports Path') 43 | .setDesc('This is where your mrexpt files are stored.') 44 | .addText(text => text 45 | .setPlaceholder('Book Exports') 46 | .setValue(this.plugin.settings.exportsPath) 47 | .onChange(async (value) => { 48 | // console.log('Secret: ' + value); 49 | this.plugin.settings.exportsPath = value; 50 | await this.plugin.saveSettings(); 51 | })); 52 | } 53 | 54 | async updateSettings(settings: Partial<MoonReaderSettings>) { 55 | Object.assign(this.plugin.settings, settings); 56 | await this.plugin.saveSettings(); 57 | } 58 | } 59 | 60 | -------------------------------------------------------------------------------- /src/test/exporter.test.ts: -------------------------------------------------------------------------------- 1 | import {expect, test} from "@jest/globals"; 2 | import {generateOutput} from "../exporter"; 3 | import { 4 | colorFilter, 5 | listOfAnnotations, 6 | mrexptTFile 7 | } from "./json/howtotakenotes-success/exporter.generateOutput.input-2022-11-19 14-04-30.json"; 8 | import {Annotation} from "../types"; 9 | import {TFile} from "obsidian"; 10 | 11 | test("exporter.generateOutput", () => { 12 | const list = Array.from(listOfAnnotations); 13 | expect(generateOutput(list as Annotation[], mrexptTFile as unknown as TFile, colorFilter, false)).toMatchSnapshot(); 14 | }); 15 | 16 | test("exporter new experimental output", () => { 17 | const list = Array.from(listOfAnnotations); 18 | expect(generateOutput((list as Annotation[]), ((mrexptTFile as unknown) as TFile), colorFilter, true)).toMatchInlineSnapshot(` 19 | "--- 20 | path: "Book Exports/Sönke Ahrens - How to Take Smart Notes_ One Simple Technique to Boost Writing, Learning and Thinking-Sönke Ahrens (2022).mrexpt" 21 | title: "How to Take Smart Notes. One Simple Technique to Boost Writing, Learning and Thinking" 22 | author: 23 | lastExportedTimestamp: 1665321164166 24 | lastExportedID: 12623 25 | --- 26 | 27 | > [!notes] 12585 28 | > INTRODUCTION 29 | > *** 30 | > 31 | 32 | ## 1 Everything You Need to Know 33 | 34 | ## 2 Everything You Need to Do: 35 | 36 | ## 3 Everything You Need to Have 37 | 38 | ## 4 A Few Things to Keep in Mind 39 | 40 | ## 5 Writing Is the Only Thing That Matters 41 | 42 | ## 6 Simplicity Is Paramount 43 | 44 | ## 7 Nobody Ever Starts From Scratch 45 | 46 | ## 8 Let the Work Carry You Forward 47 | 48 | ## 9 Separate and Interlocking Tasks 49 | 50 | ## 10 Read for Understanding 51 | 52 | ## 11 Take Smart Notes 53 | 54 | ## 12 Develop Ideas 55 | 56 | ## 13 Share Your Insight 57 | 58 | ## 14 Make It a Habit 59 | 60 | ### 1.1 Good Solutions are Simple – and Unexpected 61 | 62 | ### 1.2 The Slip-box 63 | 64 | ### 1.3 The slip-box manual 65 | 66 | " 67 | `); 68 | }); 69 | -------------------------------------------------------------------------------- /src/exporter.ts: -------------------------------------------------------------------------------- 1 | import {Annotation} from 'src/types'; 2 | import {TFile} from 'obsidian'; 3 | import integerToRGBA from "./util"; 4 | 5 | export function generateOutput(listOfAnnotations: Annotation[], mrexptTFile: TFile, colorFilter: number, enableNewExporter: boolean): string { 6 | const sample = listOfAnnotations[0]; 7 | //TODO: extract into template 8 | // TODO: last exported ID is likely broken 9 | let output = `--- 10 | path: "${mrexptTFile.path}" 11 | title: "${sample.bookName}" 12 | author: 13 | lastExportedTimestamp: ${mrexptTFile.stat.mtime} 14 | lastExportedID: ${listOfAnnotations[listOfAnnotations.length - 1].indexCount} 15 | tags: 16 | - "review/book" 17 | --- 18 | 19 | `; 20 | 21 | for (const annotation of listOfAnnotations.filter(t=>t.signedColor == colorFilter)) { 22 | let annotationAsString: string; 23 | if (annotation.highlightText) { 24 | annotationAsString = `${template(annotation, enableNewExporter)}\n`; 25 | } 26 | if (annotationAsString) { 27 | output += annotationAsString; 28 | } 29 | } 30 | 31 | return output; 32 | } 33 | 34 | function template(annotation: Annotation, enableNewExporter: boolean) { 35 | let {indexCount, highlightText: highlight, noteText: note} = annotation; 36 | if (enableNewExporter) { 37 | if (note.trim() === "#") { 38 | return `# ${highlight.replace("\n", ": ")}\n`; 39 | } 40 | if (note.trim() === "##") { 41 | return `## ${highlight.replace("\n", ": ")}\n`; 42 | } 43 | if (note.trim() === "###") { 44 | return `### ${highlight.replace("\n", ": ")}\n`; 45 | } 46 | return `> [!notes] ${indexCount} 47 | ${highlight.split("\n").map(t=>`> ${t}`).join("\n")} 48 | > *** 49 | ${note.split("\n").map(t=>`> ${t}`).join("\n")} 50 | `; 51 | } else { 52 | if (highlight.includes("\n")) { 53 | highlight = highlight.replaceAll("\n", "\n> "); 54 | } 55 | return `> [!${(integerToRGBA(annotation.signedColor))}] 56 | > ${highlight} 57 | > *** 58 | > ${note} 59 | `; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/test/__snapshots__/exporter.test.ts.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`exporter.generateOutput 1`] = ` 4 | "--- 5 | path: "Book Exports/Sönke Ahrens - How to Take Smart Notes_ One Simple Technique to Boost Writing, Learning and Thinking-Sönke Ahrens (2022).mrexpt" 6 | title: "How to Take Smart Notes. One Simple Technique to Boost Writing, Learning and Thinking" 7 | author: 8 | lastExportedTimestamp: 1665321164166 9 | lastExportedID: 12623 10 | --- 11 | 12 | > [!555555FF] 13 | > INTRODUCTION 14 | > *** 15 | > 16 | 17 | > [!555555FF] 18 | > 1 Everything You Need to Know 19 | > *** 20 | > ## 21 | 22 | > [!555555FF] 23 | > 2 Everything You Need to Do 24 | > 25 | > *** 26 | > ## 27 | 28 | > [!555555FF] 29 | > 3 Everything You Need to Have 30 | > *** 31 | > ## 32 | 33 | > [!555555FF] 34 | > 4 A Few Things to Keep in Mind 35 | > *** 36 | > ## 37 | 38 | > [!555555FF] 39 | > 5 Writing Is the Only Thing That Matters 40 | > *** 41 | > ## 42 | 43 | > [!555555FF] 44 | > 6 Simplicity Is Paramount 45 | > *** 46 | > ## 47 | 48 | > [!555555FF] 49 | > 7 Nobody Ever Starts From Scratch 50 | > *** 51 | > ## 52 | 53 | > [!555555FF] 54 | > 8 Let the Work Carry You Forward 55 | > *** 56 | > ## 57 | 58 | > [!555555FF] 59 | > 9 Separate and Interlocking Tasks 60 | > *** 61 | > ## 62 | 63 | > [!555555FF] 64 | > 10 Read for Understanding 65 | > *** 66 | > ## 67 | 68 | > [!555555FF] 69 | > 11 Take Smart Notes 70 | > *** 71 | > ## 72 | 73 | > [!555555FF] 74 | > 12 Develop Ideas 75 | > *** 76 | > ## 77 | 78 | > [!555555FF] 79 | > 13 Share Your Insight 80 | > *** 81 | > ## 82 | 83 | > [!555555FF] 84 | > 14 Make It a Habit 85 | > *** 86 | > ## 87 | 88 | > [!555555FF] 89 | > 1.1 Good Solutions are Simple – and Unexpected 90 | > *** 91 | > ### 92 | 93 | > [!555555FF] 94 | > 1.2 The Slip-box 95 | > *** 96 | > ### 97 | 98 | > [!555555FF] 99 | > 1.3 The slip-box manual 100 | > *** 101 | > ### 102 | 103 | " 104 | `; 105 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. 4 | 5 | ### 0.2.3 (2023-09-09) 6 | 7 | 8 | ### Features 9 | 10 | * add CSS ([f927d91](https://github.com/AB1908/obsidian-moon-reader/commit/f927d9192927a67fb6a486c821a73f30de572e0f)) 11 | * add CSS for color boxes ([96b50f4](https://github.com/AB1908/obsidian-moon-reader/commit/96b50f44212103b4d5af87c73f8925d05efecd32)) 12 | * add epub parser logic to generate section trees ([35457cb](https://github.com/AB1908/obsidian-moon-reader/commit/35457cbdfadb14112c967f2fb334f765708ddbb8)) 13 | * add feature flag for exporter for backwards compatibility ([7e7f309](https://github.com/AB1908/obsidian-moon-reader/commit/7e7f3098db628705e7fca659047f8e1f5517f1ce)) 14 | * add new colorpicker modal ([3106c31](https://github.com/AB1908/obsidian-moon-reader/commit/3106c318675cb04e8f0be0b2fa5bf2dbe4337945)) 15 | * add new setting toggle and add partial update method to save it ([303e6a7](https://github.com/AB1908/obsidian-moon-reader/commit/303e6a7eb7cc52d6ffcca19029d9e5f01253cd1c)) 16 | * change export template to use callouts ([cabdbc3](https://github.com/AB1908/obsidian-moon-reader/commit/cabdbc32b85f219e395449d6052623aeca18c22f)) 17 | * change output format ([b186be4](https://github.com/AB1908/obsidian-moon-reader/commit/b186be42fc6d9bf3f672a61494996d6505a4d9e9)) 18 | * pass the new experimental setting to generateOutput ([77c6a11](https://github.com/AB1908/obsidian-moon-reader/commit/77c6a11c3dc75ee510bcbce49ea5a79ec05269a0)) 19 | * update readme ([9bf41a5](https://github.com/AB1908/obsidian-moon-reader/commit/9bf41a55bdb239673ad6aa876245cbf2b302e178)) 20 | 21 | 22 | ### Bug Fixes 23 | 24 | * add css class and use flex for suggest items ([9dc2c07](https://github.com/AB1908/obsidian-moon-reader/commit/9dc2c07e55f7499a9e23c36c2deb2dc2f8ad8c4f)) 25 | * define new setting ([f6788b5](https://github.com/AB1908/obsidian-moon-reader/commit/f6788b5f22a16e1722da96f396d6761874ffd57d)) 26 | * handle ribbon button click and refactor ([c9587a5](https://github.com/AB1908/obsidian-moon-reader/commit/c9587a5a7ad7b328133dca05d119d81a39949124)) 27 | * tags are now correctly set in frontmatter ([4093950](https://github.com/AB1908/obsidian-moon-reader/commit/40939505974d6e428ed92d6066e6d8b1b4d194c8)) 28 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Obsidian Moon Reader 2 | 3 | **NOTE: This plugin is in alpha so please ensure you have _backed up your vault_ and have _file recovery_ turned on!** 4 | 5 | ### How To Use 6 | 7 | 1. Install this plugin using [TfTHacker's BRAT](https://github.com/TfTHacker/obsidian42-brat). 8 | 9 | - Install BRAT from Community Plugins 10 | 11 | - Use this repo's URL (https://github.com/AB1908/obsidian-moon-reader) to install a plugin from URL in BRAT. 12 | 13 | 2. Configure the folder where `.mrexpt` exports from Moon+ Reader are stored. 14 | I use a root folder named "Book Exports". 15 | 16 | **Note: This must be in your Obsidian Vault.** 17 | 18 | 3. Navigate to an open file where you want to dump the markdown. This can be an existing file or a new file. Text will be appended at the end of the file. 19 | 20 | 4. Use the command palette to parse an export from Moon+ Reader. The command is named "Parse an export". 21 | 22 | 5. Choose the color of which annotations you want to import. 23 | 24 | Note that this is a one time processing and will keep being appended to if you rerun it. 25 | Incremental processing (i.e. processing only the change) will come at a later time. 26 | 27 | ### What is currently supported? 28 | 29 | Very little to be honest. 30 | You can only import a single color's worth of highlights at the moment. 31 | The export format uses Obsidian callouts and looks like so: 32 | 33 | ``` 34 | > [!color hexcode] 35 | > highlight text 36 | > *** 37 | > note text 38 | ``` 39 | 40 | Sample output: 41 | ``` 42 | > [!FF33AA] 43 | > Down the rabbit hole 44 | > *** 45 | > Here we go! 46 | ``` 47 | 48 | ### SRS Support 49 | 50 | Turn on the toggle in the settings to enable exports that are compatible with my Card Coverage plugin. 51 | This changes the export format to: 52 | ``` 53 | > [!notes] 39182 54 | > Down the rabbit hole 55 | > *** 56 | > Here we go! 57 | ``` 58 | 59 | where 39182 is an ID generated by Moon+ Reader when exporting. 60 | When annotating, you can mark a header with `#` to turn it into an H1, `##` to turn it into an H2, and so on. 61 | I plan to try fetching these automatically from an EPUB in the future to save me some hassle when reading books. 62 | 63 | ## To do 64 | 65 | This is by no means a guarantee of what will be implemented. There are no timelines whatsoever. 66 | 67 | - [ ] Allow importing all colors of annotations at once 68 | - [ ] Allow filtering by annotation types (underlines vs highlights) 69 | - [ ] Export templates 70 | - [ ] API support 71 | - [ ] Better export file handling (only supports a single folder for now) 72 | - [ ] Use frontmatter more effectively 73 | - [ ] Better incremental exports 74 | -------------------------------------------------------------------------------- /src/devutils.ts: -------------------------------------------------------------------------------- 1 | import {moment, TFile} from "obsidian"; 2 | import {readFile, readdir, writeFile} from "fs/promises"; 3 | 4 | const basePath = "D:\\GitHub\\obsidian-moon-reader"; 5 | const sourcePath = "src"; 6 | const testPath = "src\\test\\json"; 7 | const path = `${basePath}\\${sourcePath}`; 8 | let files: LogFile[]; 9 | 10 | interface LogFile { 11 | fileName: string; 12 | contents: string; 13 | base: string; 14 | } 15 | 16 | function removeCircular(obj: any) { 17 | let copy; 18 | if ((typeof obj) == "object" && !(Array.isArray(obj))) { 19 | copy = Object.assign({}, obj); 20 | for (const key of Object.keys(copy)) { 21 | if (copy[key] instanceof TFile) { 22 | copy[key].vault = {} 23 | copy[key].parent = {} 24 | } 25 | } 26 | } 27 | return copy || {obj}; 28 | } 29 | 30 | async function writeJSON(obj: any, name?: string) { 31 | const normalizedObj = removeCircular(obj); 32 | await writeFile(`${basePath}\\${testPath}\\${name}.json`, JSON.stringify(normalizedObj, undefined, 2)) 33 | } 34 | 35 | const STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg; 36 | const ARGUMENT_NAMES = /([^\s,]+)/g; 37 | 38 | // eslint-disable-next-line @typescript-eslint/ban-types 39 | export function getParamNames(func: Function) { 40 | const fnStr = func.toString().replace(STRIP_COMMENTS, ''); 41 | let result = fnStr.slice(fnStr.indexOf('(') + 1, fnStr.indexOf(')')).match(ARGUMENT_NAMES); 42 | if (result === null) 43 | result = []; 44 | return result; 45 | } 46 | 47 | export async function logArgs(inputArgs: IArguments, outputArgs: any) { 48 | const paramNames = getParamNames(inputArgs.callee); 49 | const args = {}; 50 | // @ts-ignore 51 | paramNames.forEach((elem, index) => args[elem] = inputArgs[index]); 52 | const funcName = inputArgs.callee.name; 53 | // @ts-ignore 54 | const m = moment() 55 | const fileName = (await findWhichFile(funcName)).fileName; 56 | const inputname = `${fileName.replace(".ts", "")}.${funcName}.input-${m.format("YYYY-MM-DD HH-mm-ss")}`; 57 | const outputname = `${fileName.replace(".ts", "")}.${funcName}.output-${m.format("YYYY-MM-DD HH-mm-ss")}`; 58 | await writeJSON(args, inputname); 59 | await writeJSON(outputArgs, outputname); 60 | } 61 | 62 | async function generateFileContentsArray(path: string) { 63 | const listOfFiles = (await readdir(path)).filter(t => t.endsWith(".ts")); 64 | const output = []; 65 | for (const fileName of listOfFiles) { 66 | output.push({fileName: `${fileName}`, contents: (await readFile(`${path}\\${fileName}`)).toString(), base: basePath}); 67 | } 68 | return output; 69 | } 70 | 71 | async function findWhichFile(funcName: string) { 72 | if (!files) { 73 | files = await generateFileContentsArray(path); 74 | } 75 | for (const file of files) { 76 | const index = file.contents.indexOf(`function ${funcName}`); 77 | if (index != -1) { 78 | return {...file, location: index}; 79 | } 80 | } 81 | return null; 82 | } 83 | -------------------------------------------------------------------------------- /src/main.ts: -------------------------------------------------------------------------------- 1 | import { Notice, Plugin, TFolder, TFile, TAbstractFile } from 'obsidian'; 2 | import { ExportSelecter } from 'src/suggester'; 3 | import { parse } from "src/parser"; 4 | import { generateOutput } from 'src/exporter'; 5 | import { SettingsTab } from './settings'; 6 | import { ColorPicker } from 'src/colorpicker'; 7 | 8 | export interface MoonReaderSettings { 9 | exportsPath: string; 10 | enableSRSSupport: boolean; 11 | } 12 | 13 | const MOONREADER_DEFAULT_SETTINGS: MoonReaderSettings = { 14 | exportsPath: 'Book Exports', 15 | enableSRSSupport: false 16 | } 17 | 18 | export default class MoonReader extends Plugin { 19 | settings: MoonReaderSettings; 20 | 21 | async onload() { 22 | await this.loadSettings(); 23 | 24 | this.addRibbonIcon('book', 'Moon Reader', async () => await this.start()); 25 | 26 | this.addCommand({ 27 | id: 'parse-exports', 28 | name: 'Parse an export', 29 | editorCallback: async () => 30 | await this.start() 31 | }); 32 | this.addSettingTab(new SettingsTab(this.app, this)); 33 | } 34 | 35 | async start() { 36 | const currentTFile = this.app.workspace.getActiveFile(); 37 | if (!currentTFile) { 38 | new Notice("No active file!"); 39 | } 40 | const rootPath: string = this.settings.exportsPath; 41 | const exportTFolder: TAbstractFile = this 42 | .app 43 | .vault 44 | .getAbstractFileByPath(rootPath); 45 | let exportedFiles: TFile[]; 46 | if (exportTFolder instanceof TFolder) { 47 | exportedFiles = exportTFolder 48 | .children 49 | ?.filter( 50 | (t) => (t instanceof TFile) && t.basename && t.extension == `mrexpt` 51 | ) 52 | .map(t => t as TFile); 53 | } else { 54 | //sanity check 55 | new Notice("Invalid Folder Path"); 56 | return; 57 | } 58 | if (!exportedFiles.length) { 59 | new Notice("Folder does not have any Moon+ Reader exports!"); 60 | return; 61 | } 62 | const suggesterModal = new ExportSelecter(this.app, exportedFiles); 63 | //TODO: raise error for no input? 64 | const mrexptChoice = await suggesterModal.openAndGetValue().catch(e => { new Notice("Prompt cancelled"); }) as TFile; 65 | if (!mrexptChoice) { 66 | return; 67 | } 68 | const parsedOutput = await parse(mrexptChoice); 69 | if (parsedOutput) { 70 | const colorChoices = new Set<number>(); 71 | parsedOutput.forEach(t => colorChoices.add(t.signedColor)) 72 | const colorModal = new ColorPicker(this.app, Array.from(colorChoices)); 73 | const colorChoice = await colorModal.openAndGetValue() 74 | // .catch(e=>console.log(e)); 75 | await this.app.vault.append(currentTFile, generateOutput(parsedOutput, mrexptChoice, colorChoice, this.settings.enableSRSSupport)); 76 | } else { 77 | new Notice("Nothing added!"); 78 | } 79 | } 80 | 81 | async loadSettings() { 82 | this.settings = Object.assign({}, MOONREADER_DEFAULT_SETTINGS, await this.loadData()); 83 | } 84 | 85 | async saveSettings() { 86 | await this.saveData(this.settings); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/test/json/parseMrexptContents.parseMrexptContents.input-2022-11-25 22-07-41.json: -------------------------------------------------------------------------------- 1 | { 2 | "highlightContent": "1116625\nindent:true\ntrim:false\n#\n13275\nLearning: A Very Short Introduction\n/sdcard/Books/MoonReader/Learning A Very Short Introduction by Mark Haselgrove.epub\n/sdcard/books/moonreader/learning a very short introduction by mark haselgrove.epub\n53\n0\n0\n54\n-11184811\n1669300806081\n\n#\nChapter 7 <BR>Surely there is more to learning than that?\n0\n0\n0\n#\n13276\nLearning: A Very Short Introduction\n/sdcard/Books/MoonReader/Learning A Very Short Introduction by Mark Haselgrove.epub\n/sdcard/books/moonreader/learning a very short introduction by mark haselgrove.epub\n54\n0\n0\n23\n-11184811\n1669300822212\n\n##\nFollow the instructions\n0\n0\n0\n#\n13277\nLearning: A Very Short Introduction\n/sdcard/Books/MoonReader/Learning A Very Short Introduction by Mark Haselgrove.epub\n/sdcard/books/moonreader/learning a very short introduction by mark haselgrove.epub\n53\n0\n55\n125\n-11184811\n1669300836042\n\n\nAt the start of this book, learning was defined as a relatively permanent change in behaviour as a consequence of experience.\n0\n0\n0\n#\n13278\nLearning: A Very Short Introduction\n/sdcard/Books/MoonReader/Learning A Very Short Introduction by Mark Haselgrove.epub\n/sdcard/books/moonreader/learning a very short introduction by mark haselgrove.epub\n53\n0\n121\n63\n-2013331371\n1669300840305\n\n\nrmanent change in behaviour as a consequence of experience. The\n0\n0\n0\n#\n13281\nLearning: A Very Short Introduction\n/sdcard/Books/MoonReader/Learning A Very Short Introduction by Mark Haselgrove.epub\n/sdcard/books/moonreader/learning a very short introduction by mark haselgrove.epub\n53\n0\n218\n35\n-2013266176\n1669300856974\n\nvariety\nhave provided a variety of examples\n0\n0\n0\n#\n13286\nLearning: A Very Short Introduction\n/sdcard/Books/MoonReader/Learning A Very Short Introduction by Mark Haselgrove.epub\n/sdcard/books/moonreader/learning a very short introduction by mark haselgrove.epub\n53\n0\n469\n51\n-2013294080\n1669300876639\n\n\nLearning has been described in the context of space\n0\n0\n1\n#\n13288\nLearning: A Very Short Introduction\n/sdcard/Books/MoonReader/Learning A Very Short Introduction by Mark Haselgrove.epub\n/sdcard/books/moonreader/learning a very short introduction by mark haselgrove.epub\n53\n0\n373\n61\n-2029999361\n1669300889605\n\n\nLearning has been described in cases when stimuli are present\n0\n1\n0\n#\n13289\nLearning: A Very Short Introduction\n/sdcard/Books/MoonReader/Learning A Very Short Introduction by Mark Haselgrove.epub\n/sdcard/books/moonreader/learning a very short introduction by mark haselgrove.epub\n53\n0\n213\n70\n-2013294080\n1669300913885\n\n\nbook have provided a variety of examples of learned behaviour, some of\n0\n1\n0\n#\n13290\nLearning: A Very Short Introduction\n/sdcard/Books/MoonReader/Learning A Very Short Introduction by Mark Haselgrove.epub\n/sdcard/books/moonreader/learning a very short introduction by mark haselgrove.epub\n53\n0\n327\n44\n-2013266176\n1669300925704\n\nsome notes here\nsome helpful, and some downright maladaptive\n1\n0\n0\n#\n13291\nLearning A Very Short Introduction by Mark Haselgrove.epub\n/sdcard/Books/MoonReader/Learning A Very Short Introduction by Mark Haselgrove.epub\n/sdcard/books/moonreader/learning a very short introduction by mark haselgrove.epub\n53\n0\n0\n0\n-2013266176\n1669300939049\n(88.8%) Chapter 7 Surely there is more to learning than that? At the start of this book, learning was...\n\n\n0\n0\n0\n#\n13292\nLearning A Very Short Introduction by Mark Haselgrove.epub\n/sdcard/Books/MoonReader/Learning A Very Short Introduction by Mark Haselgrove.epub\n/sdcard/books/moonreader/learning a very short introduction by mark haselgrove.epub\n53\n0\n550\n0\n-2013266176\n1669300993639\n(89.0%) terms of the social environment. At face value, these various types of learning are very different....\n\n\n0\n0\n0\n#\n13294\nLearning: A Very Short Introduction\n/sdcard/Books/MoonReader/Learning A Very Short Introduction by Mark Haselgrove.epub\n/sdcard/books/moonreader/learning a very short introduction by mark haselgrove.epub\n53\n0\n311\n136\n-2013266176\n1669301153761\n\nthis overlaps two highlights underneath \nwhich is scary; some helpful, and some downright maladaptive. Learning has been described in cases when stimuli are present, as well as \n0\n0\n0\n" 3 | } -------------------------------------------------------------------------------- /src/test/json/parseMrexptContents.parseMrexptContents.output-2022-11-25 22-07-41.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "sectionNumber": 53, 4 | "location": "0", 5 | "highlightText": "Chapter 7 \nSurely there is more to learning than that?", 6 | "noteText": "#", 7 | "indexCount": 13275, 8 | "annotType1": 0, 9 | "annotType2": 0, 10 | "annotType3": 0, 11 | "bookmarkText": "", 12 | "unixTimestamp": "1669300806081", 13 | "signedColor": -11184811, 14 | "characterCount": 54, 15 | "bookName": "Learning: A Very Short Introduction", 16 | "bookPath": "/sdcard/Books/MoonReader/Learning A Very Short Introduction by Mark Haselgrove.epub" 17 | }, 18 | { 19 | "sectionNumber": 54, 20 | "location": "0", 21 | "highlightText": "Follow the instructions", 22 | "noteText": "##", 23 | "indexCount": 13276, 24 | "annotType1": 0, 25 | "annotType2": 0, 26 | "annotType3": 0, 27 | "bookmarkText": "", 28 | "unixTimestamp": "1669300822212", 29 | "signedColor": -11184811, 30 | "characterCount": 23, 31 | "bookName": "Learning: A Very Short Introduction", 32 | "bookPath": "/sdcard/Books/MoonReader/Learning A Very Short Introduction by Mark Haselgrove.epub" 33 | }, 34 | { 35 | "sectionNumber": 53, 36 | "location": "55", 37 | "highlightText": "At the start of this book, learning was defined as a relatively permanent change in behaviour as a consequence of experience.", 38 | "noteText": "", 39 | "indexCount": 13277, 40 | "annotType1": 0, 41 | "annotType2": 0, 42 | "annotType3": 0, 43 | "bookmarkText": "", 44 | "unixTimestamp": "1669300836042", 45 | "signedColor": -11184811, 46 | "characterCount": 125, 47 | "bookName": "Learning: A Very Short Introduction", 48 | "bookPath": "/sdcard/Books/MoonReader/Learning A Very Short Introduction by Mark Haselgrove.epub" 49 | }, 50 | { 51 | "sectionNumber": 53, 52 | "location": "121", 53 | "highlightText": "rmanent change in behaviour as a consequence of experience. The", 54 | "noteText": "", 55 | "indexCount": 13278, 56 | "annotType1": 0, 57 | "annotType2": 0, 58 | "annotType3": 0, 59 | "bookmarkText": "", 60 | "unixTimestamp": "1669300840305", 61 | "signedColor": -2013331371, 62 | "characterCount": 63, 63 | "bookName": "Learning: A Very Short Introduction", 64 | "bookPath": "/sdcard/Books/MoonReader/Learning A Very Short Introduction by Mark Haselgrove.epub" 65 | }, 66 | { 67 | "sectionNumber": 53, 68 | "location": "218", 69 | "highlightText": "have provided a variety of examples", 70 | "noteText": "variety", 71 | "indexCount": 13281, 72 | "annotType1": 0, 73 | "annotType2": 0, 74 | "annotType3": 0, 75 | "bookmarkText": "", 76 | "unixTimestamp": "1669300856974", 77 | "signedColor": -2013266176, 78 | "characterCount": 35, 79 | "bookName": "Learning: A Very Short Introduction", 80 | "bookPath": "/sdcard/Books/MoonReader/Learning A Very Short Introduction by Mark Haselgrove.epub" 81 | }, 82 | { 83 | "sectionNumber": 53, 84 | "location": "469", 85 | "highlightText": "Learning has been described in the context of space", 86 | "noteText": "", 87 | "indexCount": 13286, 88 | "annotType1": 0, 89 | "annotType2": 0, 90 | "annotType3": 1, 91 | "bookmarkText": "", 92 | "unixTimestamp": "1669300876639", 93 | "signedColor": -2013294080, 94 | "characterCount": 51, 95 | "bookName": "Learning: A Very Short Introduction", 96 | "bookPath": "/sdcard/Books/MoonReader/Learning A Very Short Introduction by Mark Haselgrove.epub" 97 | }, 98 | { 99 | "sectionNumber": 53, 100 | "location": "373", 101 | "highlightText": "Learning has been described in cases when stimuli are present", 102 | "noteText": "", 103 | "indexCount": 13288, 104 | "annotType1": 0, 105 | "annotType2": 1, 106 | "annotType3": 0, 107 | "bookmarkText": "", 108 | "unixTimestamp": "1669300889605", 109 | "signedColor": -2029999361, 110 | "characterCount": 61, 111 | "bookName": "Learning: A Very Short Introduction", 112 | "bookPath": "/sdcard/Books/MoonReader/Learning A Very Short Introduction by Mark Haselgrove.epub" 113 | }, 114 | { 115 | "sectionNumber": 53, 116 | "location": "213", 117 | "highlightText": "book have provided a variety of examples of learned behaviour, some of", 118 | "noteText": "", 119 | "indexCount": 13289, 120 | "annotType1": 0, 121 | "annotType2": 1, 122 | "annotType3": 0, 123 | "bookmarkText": "", 124 | "unixTimestamp": "1669300913885", 125 | "signedColor": -2013294080, 126 | "characterCount": 70, 127 | "bookName": "Learning: A Very Short Introduction", 128 | "bookPath": "/sdcard/Books/MoonReader/Learning A Very Short Introduction by Mark Haselgrove.epub" 129 | }, 130 | { 131 | "sectionNumber": 53, 132 | "location": "327", 133 | "highlightText": "some helpful, and some downright maladaptive", 134 | "noteText": "some notes here", 135 | "indexCount": 13290, 136 | "annotType1": 1, 137 | "annotType2": 0, 138 | "annotType3": 0, 139 | "bookmarkText": "", 140 | "unixTimestamp": "1669300925704", 141 | "signedColor": -2013266176, 142 | "characterCount": 44, 143 | "bookName": "Learning: A Very Short Introduction", 144 | "bookPath": "/sdcard/Books/MoonReader/Learning A Very Short Introduction by Mark Haselgrove.epub" 145 | }, 146 | { 147 | "sectionNumber": 53, 148 | "location": "0", 149 | "highlightText": "", 150 | "noteText": "", 151 | "indexCount": 13291, 152 | "annotType1": 0, 153 | "annotType2": 0, 154 | "annotType3": 0, 155 | "bookmarkText": "(88.8%) Chapter 7 Surely there is more to learning than that? At the start of this book, learning was...", 156 | "unixTimestamp": "1669300939049", 157 | "signedColor": -2013266176, 158 | "characterCount": 0, 159 | "bookName": "Learning A Very Short Introduction by Mark Haselgrove.epub", 160 | "bookPath": "/sdcard/Books/MoonReader/Learning A Very Short Introduction by Mark Haselgrove.epub" 161 | }, 162 | { 163 | "sectionNumber": 53, 164 | "location": "550", 165 | "highlightText": "", 166 | "noteText": "", 167 | "indexCount": 13292, 168 | "annotType1": 0, 169 | "annotType2": 0, 170 | "annotType3": 0, 171 | "bookmarkText": "(89.0%) terms of the social environment. At face value, these various types of learning are very different....", 172 | "unixTimestamp": "1669300993639", 173 | "signedColor": -2013266176, 174 | "characterCount": 0, 175 | "bookName": "Learning A Very Short Introduction by Mark Haselgrove.epub", 176 | "bookPath": "/sdcard/Books/MoonReader/Learning A Very Short Introduction by Mark Haselgrove.epub" 177 | }, 178 | { 179 | "sectionNumber": 53, 180 | "location": "311", 181 | "highlightText": "which is scary; some helpful, and some downright maladaptive. Learning has been described in cases when stimuli are present, as well as ", 182 | "noteText": "this overlaps two highlights underneath ", 183 | "indexCount": 13294, 184 | "annotType1": 0, 185 | "annotType2": 0, 186 | "annotType3": 0, 187 | "bookmarkText": "", 188 | "unixTimestamp": "1669301153761", 189 | "signedColor": -2013266176, 190 | "characterCount": 136, 191 | "bookName": "Learning: A Very Short Introduction", 192 | "bookPath": "/sdcard/Books/MoonReader/Learning A Very Short Introduction by Mark Haselgrove.epub" 193 | } 194 | ] 195 | -------------------------------------------------------------------------------- /src/test/json/howtotakenotes-success/exporter.generateOutput.input-2022-11-19 14-04-30.json: -------------------------------------------------------------------------------- 1 | { 2 | "listOfAnnotations": [ 3 | { 4 | "sectionNumber": 5, 5 | "location": "0", 6 | "highlightText": "INTRODUCTION", 7 | "noteText": "", 8 | "indexCount": 12585, 9 | "annotType1": 0, 10 | "annotType2": 0, 11 | "annotType3": 0, 12 | "bookmarkText": "", 13 | "signedColor": -11184811, 14 | "characterCount": 12, 15 | "bookName": "How to Take Smart Notes. One Simple Technique to Boost Writing, Learning and Thinking", 16 | "bookPath": "/sdcard/Books/MoonReader/attachments/Sönke Ahrens - How to Take Smart Notes_ One Simple Technique to Boost Writing, Learning and Thinking-Sönke Ahrens (2022).epub" 17 | }, 18 | { 19 | "sectionNumber": 6, 20 | "location": "0", 21 | "highlightText": "1 Everything You Need to Know", 22 | "noteText": "##", 23 | "indexCount": 12587, 24 | "annotType1": 0, 25 | "annotType2": 0, 26 | "annotType3": 0, 27 | "bookmarkText": "", 28 | "signedColor": -11184811, 29 | "characterCount": 29, 30 | "bookName": "How to Take Smart Notes. One Simple Technique to Boost Writing, Learning and Thinking", 31 | "bookPath": "/sdcard/Books/MoonReader/attachments/Sönke Ahrens - How to Take Smart Notes_ One Simple Technique to Boost Writing, Learning and Thinking-Sönke Ahrens (2022).epub" 32 | }, 33 | { 34 | "sectionNumber": 6, 35 | "location": "176", 36 | "highlightText": "It will present you with the tools of note-taking that turned the son of a brewer into one of the most productive and revered social scientists of the 20th century.", 37 | "noteText": "God I fucking hate this. \"Son of a brewer\".", 38 | "indexCount": 12589, 39 | "annotType1": 0, 40 | "annotType2": 0, 41 | "annotType3": 0, 42 | "bookmarkText": "", 43 | "signedColor": -2029999361, 44 | "characterCount": 164, 45 | "bookName": "How to Take Smart Notes. One Simple Technique to Boost Writing, Learning and Thinking", 46 | "bookPath": "/sdcard/Books/MoonReader/attachments/Sönke Ahrens - How to Take Smart Notes_ One Simple Technique to Boost Writing, Learning and Thinking-Sönke Ahrens (2022).epub" 47 | }, 48 | { 49 | "sectionNumber": 6, 50 | "location": "3139", 51 | "highlightText": "", 52 | "noteText": "", 53 | "indexCount": 12590, 54 | "annotType1": 0, 55 | "annotType2": 0, 56 | "annotType3": 0, 57 | "bookmarkText": "(4.4%) insight. Unfortunately, even universities try to turn students into planners. Sure, planning will...", 58 | "signedColor": -2029999361, 59 | "characterCount": 0, 60 | "bookName": "Sönke Ahrens - How to Take Smart Notes_ One Simple Technique to Boost Writing, Learning and Thinking-Sönke Ahrens (2022).epub", 61 | "bookPath": "/sdcard/Books/MoonReader/attachments/Sönke Ahrens - How to Take Smart Notes_ One Simple Technique to Boost Writing, Learning and Thinking-Sönke Ahrens (2022).epub" 62 | }, 63 | { 64 | "sectionNumber": 7, 65 | "location": "0", 66 | "highlightText": "2 Everything You Need to Do\n", 67 | "noteText": "##", 68 | "indexCount": 12592, 69 | "annotType1": 0, 70 | "annotType2": 0, 71 | "annotType3": 0, 72 | "bookmarkText": "", 73 | "signedColor": -11184811, 74 | "characterCount": 28, 75 | "bookName": "How to Take Smart Notes. One Simple Technique to Boost Writing, Learning and Thinking", 76 | "bookPath": "/sdcard/Books/MoonReader/attachments/Sönke Ahrens - How to Take Smart Notes_ One Simple Technique to Boost Writing, Learning and Thinking-Sönke Ahrens (2022).epub" 77 | }, 78 | { 79 | "sectionNumber": 8, 80 | "location": "0", 81 | "highlightText": "3 Everything You Need to Have", 82 | "noteText": "##", 83 | "indexCount": 12593, 84 | "annotType1": 0, 85 | "annotType2": 0, 86 | "annotType3": 0, 87 | "bookmarkText": "", 88 | "signedColor": -11184811, 89 | "characterCount": 29, 90 | "bookName": "How to Take Smart Notes. One Simple Technique to Boost Writing, Learning and Thinking", 91 | "bookPath": "/sdcard/Books/MoonReader/attachments/Sönke Ahrens - How to Take Smart Notes_ One Simple Technique to Boost Writing, Learning and Thinking-Sönke Ahrens (2022).epub" 92 | }, 93 | { 94 | "sectionNumber": 9, 95 | "location": "0", 96 | "highlightText": "4 A Few Things to Keep in Mind", 97 | "noteText": "##", 98 | "indexCount": 12594, 99 | "annotType1": 0, 100 | "annotType2": 0, 101 | "annotType3": 0, 102 | "bookmarkText": "", 103 | "signedColor": -11184811, 104 | "characterCount": 30, 105 | "bookName": "How to Take Smart Notes. One Simple Technique to Boost Writing, Learning and Thinking", 106 | "bookPath": "/sdcard/Books/MoonReader/attachments/Sönke Ahrens - How to Take Smart Notes_ One Simple Technique to Boost Writing, Learning and Thinking-Sönke Ahrens (2022).epub" 107 | }, 108 | { 109 | "sectionNumber": 11, 110 | "location": "0", 111 | "highlightText": "5 Writing Is the Only Thing That Matters", 112 | "noteText": "##", 113 | "indexCount": 12595, 114 | "annotType1": 0, 115 | "annotType2": 0, 116 | "annotType3": 0, 117 | "bookmarkText": "", 118 | "signedColor": -11184811, 119 | "characterCount": 40, 120 | "bookName": "How to Take Smart Notes. One Simple Technique to Boost Writing, Learning and Thinking", 121 | "bookPath": "/sdcard/Books/MoonReader/attachments/Sönke Ahrens - How to Take Smart Notes_ One Simple Technique to Boost Writing, Learning and Thinking-Sönke Ahrens (2022).epub" 122 | }, 123 | { 124 | "sectionNumber": 12, 125 | "location": "0", 126 | "highlightText": "6 Simplicity Is Paramount", 127 | "noteText": "##", 128 | "indexCount": 12596, 129 | "annotType1": 0, 130 | "annotType2": 0, 131 | "annotType3": 0, 132 | "bookmarkText": "", 133 | "signedColor": -11184811, 134 | "characterCount": 25, 135 | "bookName": "How to Take Smart Notes. One Simple Technique to Boost Writing, Learning and Thinking", 136 | "bookPath": "/sdcard/Books/MoonReader/attachments/Sönke Ahrens - How to Take Smart Notes_ One Simple Technique to Boost Writing, Learning and Thinking-Sönke Ahrens (2022).epub" 137 | }, 138 | { 139 | "sectionNumber": 13, 140 | "location": "0", 141 | "highlightText": "7 Nobody Ever Starts From Scratch", 142 | "noteText": "##", 143 | "indexCount": 12597, 144 | "annotType1": 0, 145 | "annotType2": 0, 146 | "annotType3": 0, 147 | "bookmarkText": "", 148 | "signedColor": -11184811, 149 | "characterCount": 33, 150 | "bookName": "How to Take Smart Notes. One Simple Technique to Boost Writing, Learning and Thinking", 151 | "bookPath": "/sdcard/Books/MoonReader/attachments/Sönke Ahrens - How to Take Smart Notes_ One Simple Technique to Boost Writing, Learning and Thinking-Sönke Ahrens (2022).epub" 152 | }, 153 | { 154 | "sectionNumber": 14, 155 | "location": "0", 156 | "highlightText": "8 Let the Work Carry You Forward", 157 | "noteText": "##", 158 | "indexCount": 12598, 159 | "annotType1": 0, 160 | "annotType2": 0, 161 | "annotType3": 0, 162 | "bookmarkText": "", 163 | "signedColor": -11184811, 164 | "characterCount": 32, 165 | "bookName": "How to Take Smart Notes. One Simple Technique to Boost Writing, Learning and Thinking", 166 | "bookPath": "/sdcard/Books/MoonReader/attachments/Sönke Ahrens - How to Take Smart Notes_ One Simple Technique to Boost Writing, Learning and Thinking-Sönke Ahrens (2022).epub" 167 | }, 168 | { 169 | "sectionNumber": 16, 170 | "location": "0", 171 | "highlightText": "9 Separate and Interlocking Tasks", 172 | "noteText": "##", 173 | "indexCount": 12600, 174 | "annotType1": 0, 175 | "annotType2": 0, 176 | "annotType3": 0, 177 | "bookmarkText": "", 178 | "signedColor": -11184811, 179 | "characterCount": 33, 180 | "bookName": "How to Take Smart Notes. One Simple Technique to Boost Writing, Learning and Thinking", 181 | "bookPath": "/sdcard/Books/MoonReader/attachments/Sönke Ahrens - How to Take Smart Notes_ One Simple Technique to Boost Writing, Learning and Thinking-Sönke Ahrens (2022).epub" 182 | }, 183 | { 184 | "sectionNumber": 17, 185 | "location": "0", 186 | "highlightText": "10 Read for Understanding", 187 | "noteText": "##", 188 | "indexCount": 12601, 189 | "annotType1": 0, 190 | "annotType2": 0, 191 | "annotType3": 0, 192 | "bookmarkText": "", 193 | "signedColor": -11184811, 194 | "characterCount": 25, 195 | "bookName": "How to Take Smart Notes. One Simple Technique to Boost Writing, Learning and Thinking", 196 | "bookPath": "/sdcard/Books/MoonReader/attachments/Sönke Ahrens - How to Take Smart Notes_ One Simple Technique to Boost Writing, Learning and Thinking-Sönke Ahrens (2022).epub" 197 | }, 198 | { 199 | "sectionNumber": 18, 200 | "location": "0", 201 | "highlightText": "11 Take Smart Notes", 202 | "noteText": "##", 203 | "indexCount": 12602, 204 | "annotType1": 0, 205 | "annotType2": 0, 206 | "annotType3": 0, 207 | "bookmarkText": "", 208 | "signedColor": -11184811, 209 | "characterCount": 19, 210 | "bookName": "How to Take Smart Notes. One Simple Technique to Boost Writing, Learning and Thinking", 211 | "bookPath": "/sdcard/Books/MoonReader/attachments/Sönke Ahrens - How to Take Smart Notes_ One Simple Technique to Boost Writing, Learning and Thinking-Sönke Ahrens (2022).epub" 212 | }, 213 | { 214 | "sectionNumber": 19, 215 | "location": "0", 216 | "highlightText": "12 Develop Ideas", 217 | "noteText": "##", 218 | "indexCount": 12603, 219 | "annotType1": 0, 220 | "annotType2": 0, 221 | "annotType3": 0, 222 | "bookmarkText": "", 223 | "signedColor": -11184811, 224 | "characterCount": 16, 225 | "bookName": "How to Take Smart Notes. One Simple Technique to Boost Writing, Learning and Thinking", 226 | "bookPath": "/sdcard/Books/MoonReader/attachments/Sönke Ahrens - How to Take Smart Notes_ One Simple Technique to Boost Writing, Learning and Thinking-Sönke Ahrens (2022).epub" 227 | }, 228 | { 229 | "sectionNumber": 20, 230 | "location": "0", 231 | "highlightText": "13 Share Your Insight", 232 | "noteText": "##", 233 | "indexCount": 12604, 234 | "annotType1": 0, 235 | "annotType2": 0, 236 | "annotType3": 0, 237 | "bookmarkText": "", 238 | "signedColor": -11184811, 239 | "characterCount": 21, 240 | "bookName": "How to Take Smart Notes. One Simple Technique to Boost Writing, Learning and Thinking", 241 | "bookPath": "/sdcard/Books/MoonReader/attachments/Sönke Ahrens - How to Take Smart Notes_ One Simple Technique to Boost Writing, Learning and Thinking-Sönke Ahrens (2022).epub" 242 | }, 243 | { 244 | "sectionNumber": 21, 245 | "location": "0", 246 | "highlightText": "14 Make It a Habit", 247 | "noteText": "##", 248 | "indexCount": 12605, 249 | "annotType1": 0, 250 | "annotType2": 0, 251 | "annotType3": 0, 252 | "bookmarkText": "", 253 | "signedColor": -11184811, 254 | "characterCount": 18, 255 | "bookName": "How to Take Smart Notes. One Simple Technique to Boost Writing, Learning and Thinking", 256 | "bookPath": "/sdcard/Books/MoonReader/attachments/Sönke Ahrens - How to Take Smart Notes_ One Simple Technique to Boost Writing, Learning and Thinking-Sönke Ahrens (2022).epub" 257 | }, 258 | { 259 | "sectionNumber": 6, 260 | "location": "3148", 261 | "highlightText": "", 262 | "noteText": "", 263 | "indexCount": 12606, 264 | "annotType1": 0, 265 | "annotType2": 0, 266 | "annotType3": 0, 267 | "bookmarkText": "(4.4%) Unfortunately, even universities try to turn students into planners. Sure, planning will get you...", 268 | "signedColor": -11184811, 269 | "characterCount": 0, 270 | "bookName": "Sönke Ahrens - How to Take Smart Notes_ One Simple Technique to Boost Writing, Learning and Thinking-Sönke Ahrens (2022).epub", 271 | "bookPath": "/sdcard/Books/MoonReader/attachments/Sönke Ahrens - How to Take Smart Notes_ One Simple Technique to Boost Writing, Learning and Thinking-Sönke Ahrens (2022).epub" 272 | }, 273 | { 274 | "sectionNumber": 6, 275 | "location": "3865", 276 | "highlightText": "And if you are a student seeking help with your writing, the chances are that you already aim high too, because it is usually the best students who struggle the most.", 277 | "noteText": "Citation needed ", 278 | "indexCount": 12609, 279 | "annotType1": 0, 280 | "annotType2": 0, 281 | "annotType3": 0, 282 | "bookmarkText": "", 283 | "signedColor": -2013294080, 284 | "characterCount": 166, 285 | "bookName": "How to Take Smart Notes. One Simple Technique to Boost Writing, Learning and Thinking", 286 | "bookPath": "/sdcard/Books/MoonReader/attachments/Sönke Ahrens - How to Take Smart Notes_ One Simple Technique to Boost Writing, Learning and Thinking-Sönke Ahrens (2022).epub" 287 | }, 288 | { 289 | "sectionNumber": 6, 290 | "location": "6796", 291 | "highlightText": "This book is for you, the good students, ambitious academics and knowledge workers who understand that insight doesn’t come easy and that writing is not only for proclaiming opinions, but the main tool to achieve insight worth sharing. ", 292 | "noteText": "Meh just comes off as elitist and discouraging ", 293 | "indexCount": 12612, 294 | "annotType1": 0, 295 | "annotType2": 0, 296 | "annotType3": 0, 297 | "bookmarkText": "", 298 | "signedColor": -2029999361, 299 | "characterCount": 236, 300 | "bookName": "How to Take Smart Notes. One Simple Technique to Boost Writing, Learning and Thinking", 301 | "bookPath": "/sdcard/Books/MoonReader/attachments/Sönke Ahrens - How to Take Smart Notes_ One Simple Technique to Boost Writing, Learning and Thinking-Sönke Ahrens (2022).epub" 302 | }, 303 | { 304 | "sectionNumber": 6, 305 | "location": "7033", 306 | "highlightText": "1.1 Good Solutions are Simple – and Unexpected", 307 | "noteText": "###", 308 | "indexCount": 12614, 309 | "annotType1": 0, 310 | "annotType2": 0, 311 | "annotType3": 0, 312 | "bookmarkText": "", 313 | "signedColor": -11184811, 314 | "characterCount": 46, 315 | "bookName": "How to Take Smart Notes. One Simple Technique to Boost Writing, Learning and Thinking", 316 | "bookPath": "/sdcard/Books/MoonReader/attachments/Sönke Ahrens - How to Take Smart Notes_ One Simple Technique to Boost Writing, Learning and Thinking-Sönke Ahrens (2022).epub" 317 | }, 318 | { 319 | "sectionNumber": 6, 320 | "location": "11918", 321 | "highlightText": "But it does provide a structure for our everyday work that deals with the fact that most distractions do not come so much from our environment, but our own minds. ", 322 | "noteText": "#meaningful\n\nRelate to this quite a bit", 323 | "indexCount": 12616, 324 | "annotType1": 0, 325 | "annotType2": 0, 326 | "annotType3": 0, 327 | "bookmarkText": "", 328 | "signedColor": -2013331371, 329 | "characterCount": 163, 330 | "bookName": "How to Take Smart Notes. One Simple Technique to Boost Writing, Learning and Thinking", 331 | "bookPath": "/sdcard/Books/MoonReader/attachments/Sönke Ahrens - How to Take Smart Notes_ One Simple Technique to Boost Writing, Learning and Thinking-Sönke Ahrens (2022).epub" 332 | }, 333 | { 334 | "sectionNumber": 6, 335 | "location": "15065", 336 | "highlightText": "1.2 The Slip-box", 337 | "noteText": "###", 338 | "indexCount": 12619, 339 | "annotType1": 0, 340 | "annotType2": 0, 341 | "annotType3": 0, 342 | "bookmarkText": "", 343 | "signedColor": -11184811, 344 | "characterCount": 16, 345 | "bookName": "How to Take Smart Notes. One Simple Technique to Boost Writing, Learning and Thinking", 346 | "bookPath": "/sdcard/Books/MoonReader/attachments/Sönke Ahrens - How to Take Smart Notes_ One Simple Technique to Boost Writing, Learning and Thinking-Sönke Ahrens (2022).epub" 347 | }, 348 | { 349 | "sectionNumber": 6, 350 | "location": "27216", 351 | "highlightText": "1.3 The slip-box manual", 352 | "noteText": "###", 353 | "indexCount": 12622, 354 | "annotType1": 0, 355 | "annotType2": 0, 356 | "annotType3": 0, 357 | "bookmarkText": "", 358 | "signedColor": -11184811, 359 | "characterCount": 23, 360 | "bookName": "How to Take Smart Notes. One Simple Technique to Boost Writing, Learning and Thinking", 361 | "bookPath": "/sdcard/Books/MoonReader/attachments/Sönke Ahrens - How to Take Smart Notes_ One Simple Technique to Boost Writing, Learning and Thinking-Sönke Ahrens (2022).epub" 362 | }, 363 | { 364 | "sectionNumber": 6, 365 | "location": "29089", 366 | "highlightText": "", 367 | "noteText": "", 368 | "indexCount": 12623, 369 | "annotType1": 0, 370 | "annotType2": 0, 371 | "annotType3": 0, 372 | "bookmarkText": "(11.9%) note stay in isolation. He did not just copy ideas or quotes from the texts he read, but made a...", 373 | "signedColor": -11184811, 374 | "characterCount": 0, 375 | "bookName": "Sönke Ahrens - How to Take Smart Notes_ One Simple Technique to Boost Writing, Learning and Thinking-Sönke Ahrens (2022).epub", 376 | "bookPath": "/sdcard/Books/MoonReader/attachments/Sönke Ahrens - How to Take Smart Notes_ One Simple Technique to Boost Writing, Learning and Thinking-Sönke Ahrens (2022).epub" 377 | } 378 | ], 379 | "mrexptTFile": { 380 | "deleted": false, 381 | "vault": {}, 382 | "path": "Book Exports/Sönke Ahrens - How to Take Smart Notes_ One Simple Technique to Boost Writing, Learning and Thinking-Sönke Ahrens (2022).mrexpt", 383 | "name": "Sönke Ahrens - How to Take Smart Notes_ One Simple Technique to Boost Writing, Learning and Thinking-Sönke Ahrens (2022).mrexpt", 384 | "basename": "Sönke Ahrens - How to Take Smart Notes_ One Simple Technique to Boost Writing, Learning and Thinking-Sönke Ahrens (2022)", 385 | "extension": "mrexpt", 386 | "saving": false, 387 | "stat": { 388 | "ctime": 1665407683466, 389 | "mtime": 1665321164166, 390 | "size": 13655 391 | }, 392 | "parent": {} 393 | }, 394 | "colorFilter": -11184811 395 | } --------------------------------------------------------------------------------