mirror of
https://github.com/lukmay/simple-anki-sync.git
synced 2026-07-22 13:00:24 +00:00
feat: Exact URL backlinking via Obsidian URI custom protocol
This commit is contained in:
parent
5f4ed17569
commit
79587eb2ec
4 changed files with 47 additions and 9 deletions
|
|
@ -134,10 +134,10 @@ This removes all Anki note references from the file and deletes the correspondin
|
|||
Embed `.excalidraw` drawings seamlessly. They are automatically converted to images on sync.
|
||||
- **Math auto-formatting**
|
||||
Dollar-delimited LaTeX in Obsidian becomes nicely rendered in Anki.
|
||||
- **Automatic deletion**
|
||||
- [x] Automatic deletion
|
||||
Delete a card in Obsidian and the corresponding Anki card is removed on sync. **IMPORTANT: don't delete the Anki-ID below manually**
|
||||
- **Backlinks**
|
||||
Each card carries a URL back to its source note for easy context retrieval.
|
||||
- **Precise Backlinks**
|
||||
Each card carries a URL back to its source note. Clicking it from Anki will open Obsidian and scroll you down directly to the flashcard's exact row!
|
||||
- **Anki-Tags**
|
||||
Each card in Anki has a assigned tag `obsidian_simple_anki_sync_created` to easely filter for this automatically created cards.
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"id": "simple-anki-sync",
|
||||
"name": "Simple Anki Sync",
|
||||
"version": "1.5.0",
|
||||
"version": "1.5.1",
|
||||
"minAppVersion": "0.15.0",
|
||||
"description": "The simplest way of syncing simple Flashchards with Anki.",
|
||||
"author": "Lukas Mayr",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "simple-anki-sync",
|
||||
"version": "1.5.0",
|
||||
"version": "1.5.1",
|
||||
"description": "Personal Anki Sync Plugin for Obsidian.",
|
||||
"main": "main.js",
|
||||
"scripts": {
|
||||
|
|
|
|||
46
src/main.ts
46
src/main.ts
|
|
@ -1,4 +1,4 @@
|
|||
import { Plugin, TFile, MarkdownView, Notice, arrayBufferToBase64 } from 'obsidian';
|
||||
import { Plugin, TFile, MarkdownView, Notice, arrayBufferToBase64, ObsidianProtocolData } from 'obsidian';
|
||||
import { AnkiService } from './anki-service';
|
||||
import { ObsidianNote, ProcessedMediaResult } from './types';
|
||||
import { DEFAULT_SETTINGS, SimpleAnkiSyncSettingTab, SimpleAnkiSyncSettings } from './settings';
|
||||
|
|
@ -114,6 +114,40 @@ export default class SimpleAnkiSyncPlugin extends Plugin {
|
|||
return;
|
||||
},
|
||||
});
|
||||
|
||||
this.registerObsidianProtocolHandler('simple-anki-sync', this.handleCustomProtocol.bind(this));
|
||||
}
|
||||
|
||||
private async handleCustomProtocol(params: ObsidianProtocolData) {
|
||||
if (params.action === 'simple-anki-sync') {
|
||||
const { file, noteId } = params;
|
||||
if (!file || !noteId) return;
|
||||
|
||||
const abstractFile = this.app.vault.getAbstractFileByPath(file);
|
||||
if (!(abstractFile instanceof TFile)) return;
|
||||
|
||||
const leaf = this.app.workspace.getLeaf(false);
|
||||
await leaf.openFile(abstractFile);
|
||||
|
||||
const content = await this.app.vault.read(abstractFile);
|
||||
const lines = content.split('\n');
|
||||
|
||||
const searchFor = `<!--ANKI_NOTE_ID:${noteId}-->`;
|
||||
const lineNumber = lines.findIndex(line => line.includes(searchFor));
|
||||
|
||||
if (lineNumber !== -1) {
|
||||
// Find where the trailing Anki comment or `<br>` tags start, so we can place the cursor exactly there
|
||||
const line = lines[lineNumber];
|
||||
const match = line.match(/(?:<br\s*\/?>\s*)*<!--ANKI_NOTE_ID:\d+-->/i);
|
||||
const column = match ? match.index || 0 : 0;
|
||||
|
||||
const view = this.app.workspace.getActiveViewOfType(MarkdownView);
|
||||
if (view && view.editor) { // only if in edit mode
|
||||
view.editor.setCursor(lineNumber, column);
|
||||
view.editor.scrollIntoView({ from: { line: lineNumber, ch: 0 }, to: { line: lineNumber, ch: 0 } }, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onunload() {
|
||||
|
|
@ -472,9 +506,13 @@ export default class SimpleAnkiSyncPlugin extends Plugin {
|
|||
|
||||
// Obsidian-Link
|
||||
const vault = this.app.vault.getName();
|
||||
const url = `obsidian://open?vault=${encodeURIComponent(vault)}&file=${encodeURIComponent(
|
||||
file.path
|
||||
)}`;
|
||||
let url = '';
|
||||
if (note.noteId) {
|
||||
url = `obsidian://simple-anki-sync?vault=${encodeURIComponent(vault)}&file=${encodeURIComponent(file.path)}¬eId=${note.noteId}`;
|
||||
} else {
|
||||
url = `obsidian://open?vault=${encodeURIComponent(vault)}&file=${encodeURIComponent(file.path)}`;
|
||||
}
|
||||
|
||||
backHtml += `<br><small><a href="${url}" style="text-decoration:none;color:grey;font-size:0.8em;">Obsidian Note</a></small>`;
|
||||
|
||||
const fields = { Front: frontHtml, Back: backHtml };
|
||||
|
|
|
|||
Loading…
Reference in a new issue