feat: initial implementation of backlinks extension
This commit is contained in:
@@ -0,0 +1,26 @@
|
|||||||
|
# Obsidian Local REST API — Backlinks Extension
|
||||||
|
|
||||||
|
This is an extension for the [Obsidian Local REST API](https://github.com/coddingtonbear/obsidian-local-rest-api) plugin. It adds a new endpoint to retrieve backlinks for a specific note.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
- **GET `/extensions/backlinks/{filepath}`**: Returns all notes that link to the specified file.
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
1. Install the [Obsidian Local REST API](https://github.com/coddingtonbear/obsidian-local-rest-api) plugin.
|
||||||
|
2. Download the `main.js` and `manifest.json` from the `/dist` folder of this repository.
|
||||||
|
3. Create a folder named `obsidian-local-rest-api-backlinks` in your vault's `.obsidian/plugins/` directory.
|
||||||
|
4. Place `main.js` and `manifest.json` into that folder.
|
||||||
|
5. Restart Obsidian or reload plugins.
|
||||||
|
6. Enable the plugin in **Settings > Community Plugins**.
|
||||||
|
|
||||||
|
## Usage Example
|
||||||
|
```bash
|
||||||
|
curl -k -H "Authorization: Bearer YOUR_API_KEY" \
|
||||||
|
"https://127.0.0.1:PORT/extensions/backlinks/MyNote.md"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Development
|
||||||
|
```bash
|
||||||
|
npm install
|
||||||
|
npm run build
|
||||||
|
```
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"id": "obsidian-local-rest-api-backlinks",
|
||||||
|
"name": "Local REST API — Backlinks Extension",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"minAppVersion": "1.0.0",
|
||||||
|
"description": "Adds a /extensions/backlinks/ route to Obsidian Local REST API to retrieve backlinks for a specific note.",
|
||||||
|
"author": "Hermes",
|
||||||
|
"isDesktopOnly": false
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
{
|
||||||
|
"name": "obsidian-local-rest-api-backlinks",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "Obsidian Local REST API Backlinks Extension",
|
||||||
|
"main": "main.js",
|
||||||
|
"types": "main.d.ts",
|
||||||
|
"dependencies": {
|
||||||
|
"obsidian": "npm:obsidian@^1.0.0",
|
||||||
|
"obsidian-local-rest-api": "npm:obsidian-local-rest-api@^2.5.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"typescript": "^5.0.0",
|
||||||
|
"esbuild": "^0.19.0"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"build": "esbuild src/main.ts --bundle --outfile=dist/main.js --external:obsidian --platform=node --target=es2020"
|
||||||
|
}
|
||||||
|
}
|
||||||
+77
@@ -0,0 +1,77 @@
|
|||||||
|
import { Plugin, TFile, normalizePath } from "obsidian";
|
||||||
|
import {
|
||||||
|
LocalRestApiPublicApi,
|
||||||
|
Route,
|
||||||
|
Request,
|
||||||
|
Response,
|
||||||
|
} from "obsidian-local-rest-api";
|
||||||
|
|
||||||
|
interface LinkMetadata {
|
||||||
|
displayText: string;
|
||||||
|
link: string;
|
||||||
|
original: string;
|
||||||
|
position: { start: unknown; end: unknown };
|
||||||
|
}
|
||||||
|
|
||||||
|
interface BacklinksData {
|
||||||
|
data: Record<string, LinkMetadata[]>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class BacklinksExtension extends Plugin {
|
||||||
|
async onload() {
|
||||||
|
console.log("Loading Local REST API Backlinks Extension...");
|
||||||
|
|
||||||
|
const api = (this.app as any).plugins.plugins[
|
||||||
|
"obsidian-local-rest-api"
|
||||||
|
]?.api as LocalRestApiPublicApi | undefined;
|
||||||
|
|
||||||
|
if (!api) {
|
||||||
|
console.error("Local REST API plugin not found. Please ensure it is installed and enabled.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const routes: Route[] = [
|
||||||
|
{
|
||||||
|
path: "/extensions/backlinks/{*}",
|
||||||
|
method: "get",
|
||||||
|
handler: async (req: Request, res: Response) => {
|
||||||
|
const filePath = req.params["*"] ?? "";
|
||||||
|
const path = normalizePath(filePath);
|
||||||
|
|
||||||
|
const file = this.app.vault.getAbstractFileByPath(path);
|
||||||
|
if (!file) {
|
||||||
|
return res.status(404).json({
|
||||||
|
errorCode: 40,
|
||||||
|
message: `File not found at path: ${filePath}`,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (!(file instanceof TFile)) {
|
||||||
|
return res.status(400).json({
|
||||||
|
errorCode: 405,
|
||||||
|
message: `Path is a folder, not a file: ${path}`,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const backlinks: BacklinksData =
|
||||||
|
(this.app as any).metadataCache.getBacklinksForFile(file);
|
||||||
|
|
||||||
|
const result: Record<string, LinkMetadata[]> = {};
|
||||||
|
if (backlinks && backlinks.data) {
|
||||||
|
for (const [sourcePath, links] of Object.entries(backlinks.data)) {
|
||||||
|
result[sourcePath] = links;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return res.json({
|
||||||
|
file: path,
|
||||||
|
backlinks: result,
|
||||||
|
count: Object.keys(result).length,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
api.registerRoutes(routes);
|
||||||
|
console.log("Backlinks route registered: GET /extensions/backlinks/{*}");
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user