Update IMPLEMENTATION.md and fix Phase 2 issues

Add dependency validation, batching, and progress feedback to OCR pipeline
Improve error handling and cross-platform compatibility
Refactor GLM-OCR client to use file-based requests with auth
Remove base64 dependency and use native Node.js file operations
Optimize notebook detection and page file discovery
Cache sync tracker data to reduce disk I/O
Update default settings to use localhost endpoints
Fix manifest.json and increase build size to 17 KB
This commit is contained in:
2026-05-31 14:44:21 +02:00
parent 0211cf33f3
commit 3307d09b79
10 changed files with 182 additions and 203 deletions
+24 -27
View File
@@ -1,25 +1,21 @@
import { RmapiNode } from "../types";
import RemarkablePlugin from "../main";
import { RmapiBridge } from "../rmapi/bridge";
import { SyncTracker } from "./tracker";
import { OcrPipeline } from "../ocr/pipeline";
import { Notice } from "obsidian";
function sanitizeFileName(name: string): string {
return name.replace(/[\\/:*?"<>|]/g, "_");
}
interface DocumentEntry {
node: RmapiNode;
remotePath: string;
}
export class DocumentDownloader {
plugin: RemarkablePlugin;
rmapi: RmapiBridge;
tracker: SyncTracker;
ocrPipeline: OcrPipeline;
constructor(plugin: RemarkablePlugin) {
this.plugin = plugin;
this.rmapi = new RmapiBridge(plugin);
this.tracker = new SyncTracker(plugin);
this.ocrPipeline = new OcrPipeline(plugin);
}
async syncAll(): Promise<void> {
@@ -27,8 +23,8 @@ export class DocumentDownloader {
new Notice("Syncing from reMarkable...");
const allDocs = await this.listAllDocuments("/");
for (const doc of allDocs) {
await this.downloadDocument(doc);
for (const entry of allDocs) {
await this.downloadDocument(entry);
}
new Notice(`Sync completed! ${allDocs.length} document(s) synced.`);
@@ -38,9 +34,14 @@ export class DocumentDownloader {
}
}
async listAllDocuments(path: string): Promise<RmapiNode[]> {
const nodes = await this.rmapi.list(path);
let docs = nodes.filter((n) => n.type === "DocumentType");
async listAllDocuments(path: string): Promise<DocumentEntry[]> {
const nodes = await this.plugin.rmapi.list(path);
let docs: DocumentEntry[] = nodes
.filter((n) => n.type === "DocumentType")
.map((n) => ({
node: n,
remotePath: path === "/" ? `/${n.name}` : `${path}/${n.name}`,
}));
for (const col of nodes.filter((n) => n.type === "CollectionType")) {
const subPath = path === "/" ? `/${col.name}` : `${path}/${col.name}`;
@@ -51,9 +52,10 @@ export class DocumentDownloader {
return docs;
}
async downloadDocument(doc: RmapiNode): Promise<void> {
// Incremental sync: skip if already synced and not modified
const synced = await this.tracker.getSyncedDocument(doc.id);
async downloadDocument(entry: DocumentEntry): Promise<void> {
const { node: doc, remotePath } = entry;
const synced = await this.plugin.tracker.getSyncedDocument(doc.id);
if (synced && synced.lastSynced >= doc.modifiedClient) {
return;
}
@@ -62,33 +64,28 @@ export class DocumentDownloader {
const localDir = this.plugin.settings.downloadPath;
const localPath = `${localDir}/${safeName}`;
// Ensure directory exists
try {
await this.plugin.app.vault.adapter.mkdir(localDir);
} catch (err) {
console.warn("mkdir failed (may already exist):", err);
}
// Download raw .rm file
await this.rmapi.downloadFile(doc.name, localPath);
await this.plugin.rmapi.downloadFile(remotePath, localPath);
// Convert to PDF if enabled
let hasPdf = false;
if (this.plugin.settings.convertToPdf) {
const pdfPath = `${localDir}/${safeName}.pdf`;
await this.rmapi.downloadAnnotatedPdf(doc.name, pdfPath);
await this.plugin.rmapi.downloadAnnotatedPdf(remotePath, pdfPath);
hasPdf = true;
}
// Track document
await this.tracker.trackDocument(doc.id, doc.name, localPath, hasPdf, false);
await this.plugin.tracker.trackDocument(doc.id, doc.name, localPath, hasPdf, false);
// Convert handwriting to Markdown if enabled
if (this.plugin.settings.enableHandwritingMd) {
const mdPath = `${localDir}/${safeName}.md`;
const mdResult = await this.ocrPipeline.processDocument(localPath, mdPath);
const mdResult = await this.plugin.ocrPipeline.processDocument(localPath, mdPath);
if (mdResult) {
await this.tracker.trackDocument(doc.id, doc.name, localPath, hasPdf, true);
await this.plugin.tracker.trackDocument(doc.id, doc.name, localPath, hasPdf, true);
}
}
}