Files
obsidian-remarkable/src/utils/zip.ts
T
fegger 49278723b1 Update build system and path handling
- Use Node filesystem APIs instead of shell commands for temp cleanup
- Add absolute path helpers for cross-platform compatibility
- Generate both main.js and dist/main.js artifacts
- Improve error handling in document downloader
- Track additional document metadata in sync tracker
- Replace Unix-specific `find` with recursive directory traversal

The build system now generates two output files (main.js and dist/main.js) for
better compatibility with Obsidian's plugin loading. Path handling has been
centralized in new utilities to ensure cross-platform behavior, replacing shell
commands that had Windows compatibility issues.
2026-05-31 16:01:44 +02:00

62 lines
2.1 KiB
TypeScript

import { runCommand } from "./process";
import { readdir } from "fs/promises";
import { join } from "path";
/**
* Extract a .rm file (which is a zip archive) to a temporary directory.
* Returns the path to the extraction directory.
*/
export async function extractRmFile(rmPath: string, outputDir: string): Promise<string> {
// .rm files are zip archives
const { code, stderr } = await runCommand("unzip", ["-o", rmPath, "-d", outputDir]);
if (code !== 0) {
throw new Error(`Failed to extract .rm file: ${stderr}`);
}
return outputDir;
}
/**
* List the contents of the extracted .rm archive.
*/
export async function listRmContents(extractedDir: string): Promise<string[]> {
const files: string[] = [];
async function walk(dir: string): Promise<void> {
const entries = await readdir(dir, { withFileTypes: true });
for (const entry of entries) {
const entryPath = join(dir, entry.name);
if (entry.isDirectory()) {
await walk(entryPath);
} else if (entry.isFile()) {
files.push(entryPath);
}
}
}
await walk(extractedDir);
return files;
}
/**
* Check if a document is a notebook (handwritten) or a PDF/ebook.
* On reMarkable v3.x, notebooks have .rm page files and no content.pdf.
* Falls back to rendering a test page if ambiguous.
*/
export async function isNotebook(extractedDir: string): Promise<boolean> {
const contents = await listRmContents(extractedDir);
const hasRmPages = contents.some((f) => f.endsWith(".rm") && !f.endsWith(".zip"));
const hasContentPdf = contents.some((f) => f.endsWith("content.pdf") || f.endsWith(".pdf"));
// PDF-with-annotations documents have both; treat them as non-notebooks since the PDF is the source
return hasRmPages && !hasContentPdf;
}
/**
* Get the list of page .rm files from an extracted notebook.
* Returns basenames only.
* Recursively searches for .rm files (not just root).
*/
export async function getPageFiles(extractedDir: string): Promise<string[]> {
const contents = await listRmContents(extractedDir);
return contents.filter((f) => f.endsWith(".rm") && !f.endsWith(".zip")).sort();
}