diff --git a/data/plugins.json b/data/plugins.json new file mode 100644 index 0000000..7e7b58f --- /dev/null +++ b/data/plugins.json @@ -0,0 +1,3 @@ +{ + "disabled": [] +} \ No newline at end of file diff --git a/public/index.php b/public/index.php index ddb4ce7..7881435 100644 --- a/public/index.php +++ b/public/index.php @@ -674,132 +674,6 @@ if (str_starts_with($route, '/api/')) { exit; } - // Import Logseq vault - if ($route === '/api/import-logseq' && $method === 'POST') { - if (empty($_FILES['file']) || $_FILES['file']['error'] !== UPLOAD_ERR_OK) { - http_response_code(400); echo json_encode(['error' => 'no file']); exit; - } - $zip = new ZipArchive(); - if ($zip->open($_FILES['file']['tmp_name']) !== true) { - http_response_code(400); echo json_encode(['error' => 'invalid zip']); exit; - } - - $uploadDir = __DIR__ . '/uploads'; - if (!is_dir($uploadDir)) mkdir($uploadDir, 0777, true); - - // Find the vault root (directory containing journals/ or pages/) - $prefix = ''; - for ($i = 0; $i < $zip->numFiles; $i++) { - $name = $zip->getNameIndex($i); - if (preg_match('#^(.*/)?journals/#', $name, $m)) { $prefix = $m[1] ?? ''; break; } - if (preg_match('#^(.*/)?pages/#', $name, $m)) { $prefix = $m[1] ?? ''; break; } - } - - // 1. Copy assets → uploads with name mapping - $assetMap = []; // original filename → new hex filename - for ($i = 0; $i < $zip->numFiles; $i++) { - $name = $zip->getNameIndex($i); - if (!str_starts_with($name, $prefix . 'assets/')) continue; - if (str_ends_with($name, '/')) continue; - $content = $zip->getFromIndex($i); - if ($content === false) continue; - $origName = basename($name); - $ext = pathinfo($origName, PATHINFO_EXTENSION) ?: 'bin'; - $newName = bin2hex(random_bytes(16)) . '.' . strtolower($ext); - file_put_contents($uploadDir . '/' . $newName, $content); - $assetMap[$origName] = $newName; - } - - // Helper: rewrite image references in markdown body - $rewriteImages = function($body) use ($assetMap) { - // Logseq patterns: ![desc](../assets/file.png), ![desc](/assets/file.png), ![desc](assets/file.png) - $body = preg_replace_callback('#!\[([^\]]*)\]\((?:\.\./)?(?:assets/)?([^)]+)\)#', function($m) use ($assetMap) { - $file = basename($m[2]); - if (isset($assetMap[$file])) return '![' . $m[1] . '](uploads/' . $assetMap[$file] . ')'; - return $m[0]; - }, $body); - // Logseq block-level image embed: {{embed ((image))}} or just bare refs - // Also handle: ![image.png](../assets/image.png) with URL-encoded filenames - $body = preg_replace_callback('#!\[([^\]]*)\]\((?:\.\./)?assets/([^)]+)\)#', function($m) use ($assetMap) { - $file = urldecode(basename($m[2])); - if (isset($assetMap[$file])) return '![' . $m[1] . '](uploads/' . $assetMap[$file] . ')'; - return $m[0]; - }, $body); - return $body; - }; - - // Helper: clean Logseq markdown (remove bullet prefixes, properties) - $cleanBody = function($body) { - $lines = explode("\n", $body); - $cleaned = []; - foreach ($lines as $line) { - // Skip Logseq properties (key:: value at start) - if (preg_match('/^[a-z_-]+::\s/', $line)) continue; - // Remove leading "- " bullet outline format (Logseq default) - $line = preg_replace('/^(\t*)- /', '$1', $line); - $cleaned[] = $line; - } - return implode("\n", $cleaned); - }; - - // Get or create "import" bucket - $importBucket = $db->query("SELECT id FROM buckets WHERE name = 'import'")->fetchColumn(); - if (!$importBucket) { - $db->prepare("INSERT INTO buckets (name, position) VALUES ('import', 999)")->execute(); - $importBucket = $db->lastInsertId(); - } - - $imported = 0; - - // 2. Import journals → cards with date title - for ($i = 0; $i < $zip->numFiles; $i++) { - $name = $zip->getNameIndex($i); - if (!str_starts_with($name, $prefix . 'journals/')) continue; - if (!str_ends_with($name, '.md')) continue; - $content = $zip->getFromIndex($i); - if ($content === false || !trim($content)) continue; - - $basename = pathinfo(basename($name), PATHINFO_FILENAME); - // 2025_06_18 → 2025-06-18 - $title = str_replace('_', '-', $basename); - if (!preg_match('/^\d{4}-\d{2}-\d{2}$/', $title)) continue; - - $body = $rewriteImages($cleanBody($content)); - // Extract tags - preg_match_all('/(?<=\s|^)#([a-zA-Z0-9_\/-]+)/m', $body, $tm); - $tags = implode(',', array_unique(array_map('strtolower', $tm[1] ?? []))); - - $db->prepare('INSERT INTO cards (title, body, color, tags, position, bucket_id, created_at) VALUES (?, ?, ?, ?, -1, ?, ?)') - ->execute([$title, trim($body), '#38bdf8', $tags, $importBucket, $title . ' 00:00:00']); - $imported++; - } - - // 3. Import pages → cards with page name as title - for ($i = 0; $i < $zip->numFiles; $i++) { - $name = $zip->getNameIndex($i); - if (!str_starts_with($name, $prefix . 'pages/')) continue; - if (!str_ends_with($name, '.md')) continue; - $content = $zip->getFromIndex($i); - if ($content === false || !trim($content)) continue; - - $title = pathinfo(basename($name), PATHINFO_FILENAME); - // Skip Logseq internal pages - if (in_array(strtolower($title), ['contents', 'favorites'])) continue; - - $body = $rewriteImages($cleanBody($content)); - preg_match_all('/(?<=\s|^)#([a-zA-Z0-9_\/-]+)/m', $body, $tm); - $tags = implode(',', array_unique(array_map('strtolower', $tm[1] ?? []))); - - $db->prepare('INSERT INTO cards (title, body, color, tags, position, bucket_id) VALUES (?, ?, ?, ?, -1, ?)') - ->execute([$title, trim($body), '#8b5cf6', $tags, $importBucket]); - $imported++; - } - - $zip->close(); - echo json_encode(['ok' => true, 'imported' => $imported, 'assets' => count($assetMap)]); - exit; - } - // CalDAV endpoints $caldav = new CalDavSync($db); @@ -1251,7 +1125,6 @@ if (str_starts_with($route, '/api/')) {