@huyooo/file-explorer-core 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/types.ts","../src/utils/file-type.ts","../src/utils/formatters.ts","../src/operations/read.ts","../src/operations/write.ts","../src/operations/delete.ts","../src/operations/rename.ts","../src/operations/copy.ts","../src/operations/info.ts","../src/system-paths.ts","../src/search.ts","../src/hash.ts","../src/clipboard.ts","../src/application-icon.ts","../src/thumbnail/service.ts","../src/thumbnail/database.ts","../src/thumbnail/processors.ts"],"sourcesContent":["// Types\nexport * from './types';\n\n// Utils\nexport { getFileType, isMediaFile, isPreviewable } from './utils/file-type';\nexport { formatFileSize, formatDate, formatDateTime } from './utils/formatters';\n\n// Operations\nexport { readDirectory, readFileContent, readImageAsBase64 } from './operations/read';\nexport type { ReadDirectoryOptions, UrlEncoder } from './operations/read';\n\nexport { writeFileContent, createFolder, createFile } from './operations/write';\n\nexport { deleteFiles } from './operations/delete';\nexport type { DeleteOptions } from './operations/delete';\n\nexport { renameFile } from './operations/rename';\nexport type { RenameOptions } from './operations/rename';\n\nexport { copyFiles, moveFiles } from './operations/copy';\n\nexport { getFileInfo, exists, isDirectory } from './operations/info';\n\n// System paths\nexport { \n getSystemPath, \n getAllSystemPaths, \n getHomeDirectory, \n getPlatform \n} from './system-paths';\n\n// Search\nexport { searchFiles, searchFilesSync, searchFilesStream } from './search';\n\n// Hash\nexport { getFileHash, getFileHashes } from './hash';\n\n// Clipboard\nexport { copyFilesToClipboard, getClipboardFiles, pasteFiles } from './clipboard';\nexport type { ClipboardAdapter } from './clipboard';\n\n// Application Icon (macOS)\nexport { getApplicationIcon } from './application-icon';\n\n// Thumbnail\nexport {\n ThumbnailService,\n initThumbnailService,\n getThumbnailService,\n // Database implementation\n SqliteThumbnailDatabase,\n createSqliteThumbnailDatabase,\n getSqliteThumbnailDatabase,\n // Processor factories\n createSharpImageProcessor,\n createFfmpegVideoProcessor,\n} from './thumbnail';\nexport type {\n ThumbnailDatabase,\n ImageProcessor,\n VideoProcessor,\n ThumbnailServiceOptions,\n} from './thumbnail';\n","/**\n * 文件类型枚举\n */\nexport enum FileType {\n FOLDER = 'folder',\n FILE = 'file',\n IMAGE = 'image',\n VIDEO = 'video',\n MUSIC = 'music',\n DOCUMENT = 'document',\n CODE = 'code',\n TEXT = 'text',\n ARCHIVE = 'archive',\n APPLICATION = 'application',\n UNKNOWN = 'unknown'\n}\n\n/**\n * 文件系统项\n */\nexport interface FileItem {\n /** 唯一标识(通常是完整路径) */\n id: string;\n /** 文件名 */\n name: string;\n /** 文件类型 */\n type: FileType;\n /** 文件大小(格式化后的字符串) */\n size?: string;\n /** 修改日期(格式化后的字符串) */\n dateModified?: string;\n /** 文件 URL(用于加载) */\n url?: string;\n /** 缩略图 URL */\n thumbnailUrl?: string;\n /** 子项(仅文件夹) */\n children?: FileItem[];\n}\n\n/**\n * 文件信息\n */\nexport interface FileInfo {\n path: string;\n name: string;\n size: number;\n isFile: boolean;\n isDirectory: boolean;\n createdAt: Date;\n updatedAt: Date;\n extension?: string;\n}\n\n/**\n * 操作结果\n */\nexport interface OperationResult<T = void> {\n success: boolean;\n data?: T;\n error?: string;\n message?: string;\n}\n\n/**\n * 系统路径 ID\n */\nexport type SystemPathId = \n | 'desktop' \n | 'documents' \n | 'downloads' \n | 'pictures' \n | 'music'\n | 'videos'\n | 'applications' \n | 'home' \n | 'root';\n\n/**\n * 平台适配器接口\n * 用于处理平台特定的操作(如 Electron 的 shell.trashItem)\n */\nexport interface PlatformAdapter {\n /** 删除文件到回收站 */\n trashItem?: (path: string) => Promise<void>;\n /** 打开文件 */\n openPath?: (path: string) => Promise<void>;\n /** 使用指定应用打开 */\n openWith?: (path: string, appPath: string) => Promise<void>;\n}\n\n/**\n * 文件操作选项\n */\nexport interface FileOperationOptions {\n /** 平台适配器 */\n adapter?: PlatformAdapter;\n /** 是否自动重命名(当目标存在时) */\n autoRename?: boolean;\n}\n","import path from 'node:path';\nimport type { Stats } from 'node:fs';\nimport { FileType } from '../types';\n\n/** 图片扩展名 */\nconst IMAGE_EXTENSIONS = new Set([\n '.jpg', '.jpeg', '.png', '.gif', '.bmp', '.webp', '.svg', '.ico', '.tiff', '.tif', '.heic', '.heif'\n]);\n\n/** 视频扩展名 */\nconst VIDEO_EXTENSIONS = new Set([\n '.mp4', '.mov', '.avi', '.mkv', '.wmv', '.flv', '.webm', '.m4v', '.3gp', '.mpeg', '.mpg'\n]);\n\n/** 音频扩展名 */\nconst MUSIC_EXTENSIONS = new Set([\n '.mp3', '.wav', '.flac', '.aac', '.ogg', '.wma', '.m4a', '.aiff', '.alac'\n]);\n\n/** 文档扩展名 */\nconst DOCUMENT_EXTENSIONS = new Set([\n '.pdf', '.doc', '.docx', '.xls', '.xlsx', '.ppt', '.pptx', '.odt', '.ods', '.odp', '.rtf', '.pages', '.numbers', '.key'\n]);\n\n/** 代码扩展名 */\nconst CODE_EXTENSIONS = new Set([\n '.js', '.ts', '.jsx', '.tsx', '.vue', '.svelte',\n '.py', '.rb', '.go', '.rs', '.java', '.kt', '.swift', '.c', '.cpp', '.h', '.hpp',\n '.html', '.css', '.scss', '.sass', '.less',\n '.json', '.yaml', '.yml', '.toml', '.xml',\n '.sh', '.bash', '.zsh', '.fish', '.ps1',\n '.sql', '.graphql', '.prisma'\n]);\n\n/** 文本扩展名 */\nconst TEXT_EXTENSIONS = new Set([\n '.txt', '.md', '.markdown', '.log', '.ini', '.conf', '.cfg', '.env'\n]);\n\n/** 压缩包扩展名 */\nconst ARCHIVE_EXTENSIONS = new Set([\n '.zip', '.rar', '.7z', '.tar', '.gz', '.bz2', '.xz', '.dmg', '.iso'\n]);\n\n/** 应用程序扩展名 */\nconst APPLICATION_EXTENSIONS = new Set([\n '.app', '.exe', '.msi', '.deb', '.rpm', '.pkg', '.apk', '.ipa'\n]);\n\n/**\n * 根据文件路径和状态获取文件类型\n */\nexport function getFileType(filePath: string, stats: Stats): FileType {\n if (stats.isDirectory()) {\n // 检查是否是 macOS 应用程序包\n if (filePath.endsWith('.app')) {\n return FileType.APPLICATION;\n }\n return FileType.FOLDER;\n }\n\n const ext = path.extname(filePath).toLowerCase();\n\n if (IMAGE_EXTENSIONS.has(ext)) return FileType.IMAGE;\n if (VIDEO_EXTENSIONS.has(ext)) return FileType.VIDEO;\n if (MUSIC_EXTENSIONS.has(ext)) return FileType.MUSIC;\n if (DOCUMENT_EXTENSIONS.has(ext)) return FileType.DOCUMENT;\n if (CODE_EXTENSIONS.has(ext)) return FileType.CODE;\n if (TEXT_EXTENSIONS.has(ext)) return FileType.TEXT;\n if (ARCHIVE_EXTENSIONS.has(ext)) return FileType.ARCHIVE;\n if (APPLICATION_EXTENSIONS.has(ext)) return FileType.APPLICATION;\n\n return FileType.FILE;\n}\n\n/**\n * 判断是否为媒体文件\n */\nexport function isMediaFile(type: FileType): boolean {\n return type === FileType.IMAGE || type === FileType.VIDEO || type === FileType.MUSIC;\n}\n\n/**\n * 判断是否为可预览的文件\n */\nexport function isPreviewable(type: FileType): boolean {\n return type === FileType.IMAGE || type === FileType.VIDEO || type === FileType.MUSIC || \n type === FileType.TEXT || type === FileType.CODE;\n}\n","/**\n * 格式化文件大小\n */\nexport function formatFileSize(bytes: number): string {\n if (bytes === 0) return '0 B';\n \n const units = ['B', 'KB', 'MB', 'GB', 'TB'];\n const k = 1024;\n const i = Math.floor(Math.log(bytes) / Math.log(k));\n \n return `${parseFloat((bytes / Math.pow(k, i)).toFixed(1))} ${units[i]}`;\n}\n\n/**\n * 格式化日期\n */\nexport function formatDate(date: Date): string {\n const now = new Date();\n const diff = now.getTime() - date.getTime();\n const days = Math.floor(diff / (1000 * 60 * 60 * 24));\n \n if (days === 0) {\n return date.toLocaleTimeString('zh-CN', { hour: '2-digit', minute: '2-digit' });\n } else if (days === 1) {\n return '昨天';\n } else if (days < 7) {\n return `${days} 天前`;\n } else {\n return date.toLocaleDateString('zh-CN', { \n year: 'numeric', \n month: '2-digit', \n day: '2-digit' \n });\n }\n}\n\n/**\n * 格式化日期时间\n */\nexport function formatDateTime(date: Date): string {\n return date.toLocaleString('zh-CN', {\n year: 'numeric',\n month: '2-digit',\n day: '2-digit',\n hour: '2-digit',\n minute: '2-digit'\n });\n}\n","import { promises as fs } from 'node:fs';\nimport path from 'node:path';\nimport type { FileItem } from '../types';\nimport { FileType } from '../types';\nimport { getFileType } from '../utils/file-type';\nimport { formatFileSize, formatDate } from '../utils/formatters';\n\n/**\n * URL 编码器(可由外部注入)\n */\nexport type UrlEncoder = (filePath: string) => string;\n\n/** 默认 URL 编码器 */\nconst defaultUrlEncoder: UrlEncoder = (filePath) => `file://${encodeURIComponent(filePath)}`;\n\n/**\n * 读取目录配置\n */\nexport interface ReadDirectoryOptions {\n /** URL 编码器 */\n urlEncoder?: UrlEncoder;\n /** 是否包含隐藏文件 */\n includeHidden?: boolean;\n /** 缩略图 URL 获取器(同步获取缓存的缩略图,没有则返回 null 并异步生成) */\n getThumbnailUrl?: (filePath: string) => Promise<string | null>;\n}\n\n/**\n * 读取目录内容\n */\nexport async function readDirectory(\n dirPath: string, \n options: ReadDirectoryOptions = {}\n): Promise<FileItem[]> {\n const { \n urlEncoder = defaultUrlEncoder,\n includeHidden = false,\n getThumbnailUrl\n } = options;\n\n try {\n const entries = await fs.readdir(dirPath, { withFileTypes: true });\n const items: FileItem[] = [];\n\n for (const entry of entries) {\n // 跳过隐藏文件(以 . 开头)\n if (!includeHidden && entry.name.startsWith('.')) {\n continue;\n }\n\n const fullPath = path.join(dirPath, entry.name);\n\n try {\n // 使用 lstat 避免跟随符号链接\n let stats;\n try {\n stats = await fs.lstat(fullPath);\n } catch {\n try {\n stats = await fs.stat(fullPath);\n } catch (statError: unknown) {\n const err = statError as NodeJS.ErrnoException;\n if (err.code !== 'ENOENT') {\n console.warn(`Cannot access file ${fullPath}:`, err.message);\n }\n continue;\n }\n }\n\n const fileType = getFileType(fullPath, stats);\n const fileUrl = urlEncoder(fullPath);\n\n const item: FileItem = {\n id: fullPath,\n name: entry.name,\n type: fileType,\n dateModified: formatDate(stats.mtime),\n url: fileUrl,\n };\n\n if (stats.isDirectory()) {\n item.children = []; // 延迟加载\n } else {\n item.size = formatFileSize(stats.size);\n\n // 同步获取缩略图 URL(如果已缓存)\n if (getThumbnailUrl && (fileType === FileType.IMAGE || fileType === FileType.VIDEO)) {\n const thumbUrl = await getThumbnailUrl(fullPath);\n if (thumbUrl) {\n item.thumbnailUrl = thumbUrl;\n }\n }\n }\n\n items.push(item);\n } catch (itemError: unknown) {\n const err = itemError as NodeJS.ErrnoException;\n if (err.code !== 'ENOENT') {\n console.warn(`Error processing file ${fullPath}:`, err.message);\n }\n continue;\n }\n }\n\n // 排序:文件夹优先,然后按名称\n items.sort((a, b) => {\n if (a.type === FileType.FOLDER && b.type !== FileType.FOLDER) return -1;\n if (a.type !== FileType.FOLDER && b.type === FileType.FOLDER) return 1;\n return a.name.localeCompare(b.name, 'zh-CN');\n });\n\n return items;\n } catch (error) {\n console.error(`Error reading directory ${dirPath}:`, error);\n return [];\n }\n}\n\n/**\n * 读取文件内容\n */\nexport async function readFileContent(filePath: string): Promise<string> {\n return await fs.readFile(filePath, 'utf-8');\n}\n\n/**\n * 读取图片为 Base64\n */\nexport async function readImageAsBase64(imagePath: string): Promise<{\n success: boolean;\n base64?: string;\n mimeType?: string;\n error?: string;\n}> {\n try {\n // 处理各种 URL 格式\n let actualPath = imagePath;\n if (imagePath.startsWith('app://file')) {\n actualPath = decodeURIComponent(imagePath.replace('app://file', ''));\n } else if (imagePath.startsWith('file://')) {\n actualPath = decodeURIComponent(imagePath.replace('file://', ''));\n }\n\n const stats = await fs.stat(actualPath);\n if (!stats.isFile()) {\n return { success: false, error: `路径不是文件: ${actualPath}` };\n }\n\n const buffer = await fs.readFile(actualPath);\n const base64 = buffer.toString('base64');\n const ext = path.extname(actualPath).toLowerCase().slice(1);\n \n const mimeTypes: Record<string, string> = {\n jpg: 'image/jpeg',\n jpeg: 'image/jpeg',\n png: 'image/png',\n gif: 'image/gif',\n webp: 'image/webp',\n bmp: 'image/bmp',\n svg: 'image/svg+xml',\n };\n \n const mimeType = mimeTypes[ext] || 'image/jpeg';\n return { success: true, base64, mimeType };\n } catch (error) {\n return { success: false, error: String(error) };\n }\n}\n","import { promises as fs } from 'node:fs';\nimport path from 'node:path';\nimport type { OperationResult } from '../types';\n\n/**\n * 写入文件内容\n */\nexport async function writeFileContent(\n filePath: string, \n content: string\n): Promise<OperationResult> {\n try {\n await fs.writeFile(filePath, content, 'utf-8');\n return { success: true };\n } catch (error) {\n return { success: false, error: String(error) };\n }\n}\n\n/**\n * 创建文件夹(自动处理同名文件夹)\n */\nexport async function createFolder(\n folderPath: string\n): Promise<OperationResult<{ finalPath: string }>> {\n try {\n // 检查是否存在\n try {\n await fs.access(folderPath);\n // 存在,需要自动重命名\n } catch {\n // 不存在,直接创建\n await fs.mkdir(folderPath, { recursive: true });\n return { success: true, data: { finalPath: folderPath } };\n }\n\n // 自动重命名\n const dir = path.dirname(folderPath);\n const baseName = path.basename(folderPath);\n let counter = 2;\n let finalPath = path.join(dir, `${baseName} ${counter}`);\n\n while (true) {\n try {\n await fs.access(finalPath);\n counter++;\n finalPath = path.join(dir, `${baseName} ${counter}`);\n } catch {\n break;\n }\n }\n\n await fs.mkdir(finalPath, { recursive: true });\n return { success: true, data: { finalPath } };\n } catch (error) {\n return { success: false, error: String(error) };\n }\n}\n\n/**\n * 创建文件(自动处理同名文件)\n */\nexport async function createFile(\n filePath: string,\n content: string = ''\n): Promise<OperationResult<{ finalPath: string }>> {\n try {\n // 确保父目录存在\n const dir = path.dirname(filePath);\n await fs.mkdir(dir, { recursive: true });\n\n // 检查是否存在\n try {\n await fs.access(filePath);\n // 存在,需要自动重命名\n } catch {\n // 不存在,直接创建\n await fs.writeFile(filePath, content, 'utf-8');\n return { success: true, data: { finalPath: filePath } };\n }\n\n // 自动重命名(保留扩展名)\n const dirname = path.dirname(filePath);\n const ext = path.extname(filePath);\n const basename = path.basename(filePath, ext);\n let counter = 2;\n let finalPath = path.join(dirname, `${basename} ${counter}${ext}`);\n\n while (true) {\n try {\n await fs.access(finalPath);\n counter++;\n finalPath = path.join(dirname, `${basename} ${counter}${ext}`);\n } catch {\n break;\n }\n }\n\n await fs.writeFile(finalPath, content, 'utf-8');\n return { success: true, data: { finalPath } };\n } catch (error) {\n return { success: false, error: String(error) };\n }\n}\n","import { promises as fs } from 'node:fs';\nimport type { OperationResult, PlatformAdapter } from '../types';\n\n/**\n * 删除文件选项\n */\nexport interface DeleteOptions {\n /** 平台适配器(用于移到回收站) */\n adapter?: PlatformAdapter;\n /** 是否使用回收站(默认 true) */\n useTrash?: boolean;\n /** 删除后回调(用于清理缩略图等) */\n onDeleted?: (path: string) => void;\n}\n\n/**\n * 删除文件/文件夹\n * \n * 如果提供了 adapter.trashItem,则移到回收站\n * 否则直接删除(危险操作)\n */\nexport async function deleteFiles(\n paths: string[],\n options: DeleteOptions = {}\n): Promise<OperationResult> {\n const { adapter, useTrash = true, onDeleted } = options;\n\n try {\n for (const filePath of paths) {\n if (useTrash && adapter?.trashItem) {\n // 使用平台特定的回收站功能\n await adapter.trashItem(filePath);\n } else {\n // 直接删除(谨慎使用)\n const stats = await fs.stat(filePath);\n if (stats.isDirectory()) {\n await fs.rm(filePath, { recursive: true, force: true });\n } else {\n await fs.unlink(filePath);\n }\n }\n\n // 回调\n onDeleted?.(filePath);\n }\n\n return { \n success: true, \n message: useTrash ? '文件已移动到回收站' : '文件已删除' \n };\n } catch (error) {\n return { success: false, error: String(error) };\n }\n}\n","import { promises as fs } from 'node:fs';\nimport type { OperationResult } from '../types';\n\n/**\n * 重命名选项\n */\nexport interface RenameOptions {\n /** 重命名后回调 */\n onRenamed?: (oldPath: string, newPath: string) => void;\n}\n\n/**\n * 重命名文件/文件夹\n */\nexport async function renameFile(\n oldPath: string,\n newPath: string,\n options: RenameOptions = {}\n): Promise<OperationResult> {\n const { onRenamed } = options;\n\n try {\n await fs.rename(oldPath, newPath);\n onRenamed?.(oldPath, newPath);\n return { success: true };\n } catch (error) {\n return { success: false, error: String(error) };\n }\n}\n","import { promises as fs } from 'node:fs';\nimport path from 'node:path';\nimport type { OperationResult } from '../types';\n\n/**\n * 复制文件到目标目录\n */\nexport async function copyFiles(\n sourcePaths: string[],\n targetDir: string\n): Promise<OperationResult<{ copiedPaths: string[] }>> {\n try {\n const copiedPaths: string[] = [];\n\n for (const sourcePath of sourcePaths) {\n const fileName = path.basename(sourcePath);\n let destPath = path.join(targetDir, fileName);\n let counter = 1;\n\n // 自动重命名\n while (true) {\n try {\n await fs.access(destPath);\n const ext = path.extname(fileName);\n const baseName = path.basename(fileName, ext);\n destPath = path.join(targetDir, `${baseName} ${++counter}${ext}`);\n } catch {\n break;\n }\n }\n\n // 复制\n const stats = await fs.stat(sourcePath);\n if (stats.isDirectory()) {\n await copyDirectory(sourcePath, destPath);\n } else {\n await fs.copyFile(sourcePath, destPath);\n }\n\n copiedPaths.push(destPath);\n }\n\n return { success: true, data: { copiedPaths } };\n } catch (error) {\n return { success: false, error: String(error) };\n }\n}\n\n/**\n * 移动文件到目标目录\n */\nexport async function moveFiles(\n sourcePaths: string[],\n targetDir: string\n): Promise<OperationResult<{ movedPaths: string[] }>> {\n try {\n const movedPaths: string[] = [];\n\n for (const sourcePath of sourcePaths) {\n const fileName = path.basename(sourcePath);\n let destPath = path.join(targetDir, fileName);\n let counter = 1;\n\n // 自动重命名\n while (true) {\n try {\n await fs.access(destPath);\n const ext = path.extname(fileName);\n const baseName = path.basename(fileName, ext);\n destPath = path.join(targetDir, `${baseName} ${++counter}${ext}`);\n } catch {\n break;\n }\n }\n\n // 移动(使用 rename,如果跨磁盘则先复制后删除)\n try {\n await fs.rename(sourcePath, destPath);\n } catch {\n const stats = await fs.stat(sourcePath);\n if (stats.isDirectory()) {\n await copyDirectory(sourcePath, destPath);\n } else {\n await fs.copyFile(sourcePath, destPath);\n }\n await fs.rm(sourcePath, { recursive: true, force: true });\n }\n\n movedPaths.push(destPath);\n }\n\n return { success: true, data: { movedPaths } };\n } catch (error) {\n return { success: false, error: String(error) };\n }\n}\n\n/**\n * 递归复制目录\n */\nasync function copyDirectory(source: string, dest: string): Promise<void> {\n await fs.mkdir(dest, { recursive: true });\n const entries = await fs.readdir(source, { withFileTypes: true });\n\n for (const entry of entries) {\n const sourcePath = path.join(source, entry.name);\n const destPath = path.join(dest, entry.name);\n\n if (entry.isDirectory()) {\n await copyDirectory(sourcePath, destPath);\n } else {\n await fs.copyFile(sourcePath, destPath);\n }\n }\n}\n","import { promises as fs } from 'node:fs';\nimport path from 'node:path';\nimport type { FileInfo, OperationResult } from '../types';\n\n/**\n * 获取文件信息\n */\nexport async function getFileInfo(\n filePath: string\n): Promise<OperationResult<FileInfo>> {\n try {\n const stats = await fs.stat(filePath);\n const name = path.basename(filePath);\n const ext = path.extname(name);\n\n return {\n success: true,\n data: {\n path: filePath,\n name,\n size: stats.size,\n isFile: stats.isFile(),\n isDirectory: stats.isDirectory(),\n createdAt: stats.birthtime,\n updatedAt: stats.mtime,\n extension: ext || undefined,\n },\n };\n } catch (error) {\n return { success: false, error: String(error) };\n }\n}\n\n/**\n * 检查文件/目录是否存在\n */\nexport async function exists(filePath: string): Promise<boolean> {\n try {\n await fs.access(filePath);\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * 检查是否为目录\n */\nexport async function isDirectory(filePath: string): Promise<boolean> {\n try {\n const stats = await fs.stat(filePath);\n return stats.isDirectory();\n } catch {\n return false;\n }\n}\n","import path from 'node:path';\nimport os from 'node:os';\nimport type { SystemPathId } from './types';\n\nconst platform = process.platform;\n\n/**\n * 获取系统路径\n */\nexport function getSystemPath(pathId: SystemPathId): string | null {\n const homeDir = os.homedir();\n\n switch (pathId) {\n case 'desktop':\n return path.join(homeDir, 'Desktop');\n case 'documents':\n return path.join(homeDir, 'Documents');\n case 'downloads':\n return path.join(homeDir, 'Downloads');\n case 'pictures':\n return path.join(homeDir, 'Pictures');\n case 'music':\n return path.join(homeDir, 'Music');\n case 'videos':\n return platform === 'darwin'\n ? path.join(homeDir, 'Movies')\n : path.join(homeDir, 'Videos');\n case 'applications':\n return platform === 'darwin'\n ? '/Applications'\n : platform === 'win32'\n ? process.env.ProgramFiles || 'C:\\\\Program Files'\n : '/usr/share/applications';\n case 'home':\n return homeDir;\n case 'root':\n return platform === 'darwin' ? '/' : platform === 'win32' ? 'C:\\\\' : '/';\n default:\n return null;\n }\n}\n\n/**\n * 获取所有系统路径\n */\nexport function getAllSystemPaths(): Record<SystemPathId, string | null> {\n const pathIds: SystemPathId[] = [\n 'desktop', 'documents', 'downloads', 'pictures', \n 'music', 'videos', 'applications', 'home', 'root'\n ];\n\n const result = {} as Record<SystemPathId, string | null>;\n for (const id of pathIds) {\n result[id] = getSystemPath(id);\n }\n return result;\n}\n\n/**\n * 获取用户主目录\n */\nexport function getHomeDirectory(): string {\n return os.homedir();\n}\n\n/**\n * 获取当前平台\n */\nexport function getPlatform(): NodeJS.Platform {\n return process.platform;\n}\n","import { fdir } from 'fdir';\nimport path from 'node:path';\nimport { promises as fs } from 'node:fs';\n\n/**\n * 将通配符模式转为正则表达式\n */\nfunction patternToRegex(pattern: string): RegExp {\n return new RegExp(pattern.replace(/\\*/g, '.*'), 'i');\n}\n\n/**\n * 使用 fdir 快速搜索文件和文件夹\n * fdir 可以在 1 秒内扫描 100 万个文件\n * \n * @param searchPath 搜索路径\n * @param pattern 搜索模式(支持 * 通配符,忽略大小写)\n * @param maxDepth 最大递归深度\n */\nexport async function searchFiles(\n searchPath: string,\n pattern?: string,\n maxDepth?: number\n): Promise<string[]> {\n const builder = new fdir()\n .withFullPaths()\n .withDirs(); // 包含文件夹\n \n // maxDepth 为 0 或 undefined 时不限制深度\n if (maxDepth && maxDepth > 0) {\n builder.withMaxDepth(maxDepth);\n }\n \n const api = builder.crawl(searchPath);\n\n const files = await api.withPromise();\n\n if (pattern) {\n // 通配符转正则,忽略大小写\n const regex = patternToRegex(pattern);\n return (files as string[]).filter((file: string) => regex.test(path.basename(file)));\n }\n\n return files as string[];\n}\n\n/**\n * 流式搜索文件(逐层搜索,边搜边返回)\n * \n * @param searchPath 搜索路径\n * @param pattern 搜索模式\n * @param onResults 找到结果时的回调\n * @param maxResults 最大结果数\n */\nexport async function searchFilesStream(\n searchPath: string,\n pattern: string,\n onResults: (paths: string[], done: boolean) => void,\n maxResults: number = 100\n): Promise<void> {\n const regex = patternToRegex(pattern);\n const results: string[] = [];\n let stopped = false;\n \n // 递归搜索目录\n async function searchDir(dirPath: string): Promise<void> {\n if (stopped) return;\n \n try {\n const entries = await fs.readdir(dirPath, { withFileTypes: true });\n const matched: string[] = [];\n const subdirs: string[] = [];\n \n for (const entry of entries) {\n if (stopped) return;\n \n const fullPath = path.join(dirPath, entry.name);\n \n // 检查是否匹配\n if (regex.test(entry.name)) {\n matched.push(fullPath);\n results.push(fullPath);\n \n // 达到最大数量时停止\n if (results.length >= maxResults) {\n stopped = true;\n onResults(matched, true);\n return;\n }\n }\n \n // 收集子目录\n if (entry.isDirectory()) {\n subdirs.push(fullPath);\n }\n }\n \n // 如果有匹配,立即推送\n if (matched.length > 0) {\n onResults(matched, false);\n }\n \n // 递归搜索子目录\n for (const subdir of subdirs) {\n await searchDir(subdir);\n }\n } catch {\n // 忽略无权限的目录\n }\n }\n \n await searchDir(searchPath);\n \n // 搜索完成\n if (!stopped) {\n onResults([], true);\n }\n}\n\n/**\n * 同步搜索(用于小目录)\n */\nexport function searchFilesSync(\n searchPath: string,\n pattern?: string,\n maxDepth?: number\n): string[] {\n const builder = new fdir()\n .withFullPaths()\n .withDirs(); // 包含文件夹\n \n // maxDepth 为 0 或 undefined 时不限制深度\n if (maxDepth && maxDepth > 0) {\n builder.withMaxDepth(maxDepth);\n }\n \n const api = builder.crawl(searchPath);\n const files = api.sync();\n\n if (pattern) {\n const regex = new RegExp(pattern.replace(/\\*/g, '.*'), 'i');\n return (files as string[]).filter((file: string) => regex.test(path.basename(file)));\n }\n\n return files as string[];\n}\n","import { createHash } from 'node:crypto';\nimport { stat } from 'node:fs/promises';\n\n/**\n * 计算文件的快速 hash(使用文件大小和修改时间)\n * 这比计算完整文件 hash 快得多,适合用于缓存判断\n */\nexport async function getFileHash(filePath: string): Promise<string> {\n try {\n const stats = await stat(filePath);\n // 使用文件大小、修改时间和路径的组合\n const hashInput = `${filePath}:${stats.size}:${stats.mtime.getTime()}`;\n return createHash('md5').update(hashInput).digest('hex');\n } catch (error) {\n console.error(`Error computing hash for ${filePath}:`, error);\n // 如果出错,返回基于路径的简单 hash\n return createHash('md5').update(filePath).digest('hex');\n }\n}\n\n/**\n * 批量计算文件 hash\n */\nexport async function getFileHashes(filePaths: string[]): Promise<Map<string, string>> {\n const hashMap = new Map<string, string>();\n \n await Promise.allSettled(\n filePaths.map(async (filePath) => {\n const hash = await getFileHash(filePath);\n hashMap.set(filePath, hash);\n })\n );\n \n return hashMap;\n}\n","import { promises as fs } from 'node:fs';\nimport path from 'node:path';\nimport type { OperationResult } from './types';\n\n/**\n * 剪贴板文件操作接口\n * 由于 clipboard-files 是 native 模块,由使用者在 Electron 主进程中注入\n */\nexport interface ClipboardAdapter {\n writeFiles: (paths: string[]) => void;\n readFiles: () => string[];\n}\n\n/**\n * 复制文件到剪贴板\n */\nexport async function copyFilesToClipboard(\n filePaths: string[],\n clipboard: ClipboardAdapter\n): Promise<OperationResult> {\n try {\n // 验证文件是否存在\n const cleanPaths: string[] = [];\n for (const p of filePaths) {\n try {\n await fs.access(p);\n cleanPaths.push(p);\n } catch {\n // 文件不存在,跳过\n }\n }\n\n if (cleanPaths.length === 0) {\n return { success: false, error: '没有找到有效的文件' };\n }\n\n clipboard.writeFiles(cleanPaths);\n return { success: true };\n } catch (error) {\n return { success: false, error: String(error) };\n }\n}\n\n/**\n * 从剪贴板读取文件路径\n */\nexport function getClipboardFiles(\n clipboard: ClipboardAdapter\n): OperationResult<{ files: string[] }> {\n try {\n const files = clipboard.readFiles();\n if (files && Array.isArray(files) && files.length > 0) {\n return { success: true, data: { files } };\n }\n return { success: false, error: '剪贴板中没有文件' };\n } catch (error) {\n return { success: false, error: String(error) };\n }\n}\n\n/**\n * 粘贴文件到目标目录\n */\nexport async function pasteFiles(\n targetDir: string,\n sourcePaths: string[]\n): Promise<OperationResult<{ pastedPaths: string[] }>> {\n try {\n if (!targetDir || typeof targetDir !== 'string') {\n return { success: false, error: '目标目录路径无效' };\n }\n\n if (!sourcePaths || !Array.isArray(sourcePaths) || sourcePaths.length === 0) {\n return { success: false, error: '源文件路径列表无效' };\n }\n\n const pastedPaths: string[] = [];\n\n for (const sourcePath of sourcePaths) {\n const fileName = path.basename(sourcePath);\n let destPath = path.join(targetDir, fileName);\n let counter = 1;\n\n // 自动重命名\n while (true) {\n try {\n await fs.access(destPath);\n const ext = path.extname(fileName);\n const baseName = path.basename(fileName, ext);\n destPath = path.join(targetDir, `${baseName} ${++counter}${ext}`);\n } catch {\n break;\n }\n }\n\n // 复制\n const stats = await fs.stat(sourcePath);\n if (stats.isDirectory()) {\n await copyDirectory(sourcePath, destPath);\n } else {\n await fs.copyFile(sourcePath, destPath);\n }\n\n pastedPaths.push(destPath);\n }\n\n return { success: true, data: { pastedPaths } };\n } catch (error) {\n return { success: false, error: String(error) };\n }\n}\n\n/**\n * 递归复制目录\n */\nasync function copyDirectory(source: string, dest: string): Promise<void> {\n await fs.mkdir(dest, { recursive: true });\n const entries = await fs.readdir(source, { withFileTypes: true });\n\n for (const entry of entries) {\n const sourcePath = path.join(source, entry.name);\n const destPath = path.join(dest, entry.name);\n\n if (entry.isDirectory()) {\n await copyDirectory(sourcePath, destPath);\n } else {\n await fs.copyFile(sourcePath, destPath);\n }\n }\n}\n","/**\n * 应用程序图标获取(macOS)\n * \n * 纯 Node.js 实现,使用 sips 命令转换 icns 为 PNG\n */\n\nimport { promises as fs } from 'node:fs';\nimport path from 'node:path';\nimport os from 'node:os';\nimport { exec } from 'node:child_process';\nimport { promisify } from 'node:util';\n\nconst execAsync = promisify(exec);\n\n/**\n * 从应用程序包中查找图标文件路径\n */\nasync function findAppIconPath(appPath: string): Promise<string | null> {\n const resourcesPath = path.join(appPath, 'Contents', 'Resources');\n \n try {\n // 常见的图标文件名\n const commonIconNames = [\n 'AppIcon.icns',\n 'app.icns',\n 'application.icns',\n 'icon.icns',\n ];\n \n // 先尝试读取 Info.plist 来获取图标文件名\n const infoPlistPath = path.join(appPath, 'Contents', 'Info.plist');\n try {\n const infoPlistContent = await fs.readFile(infoPlistPath, 'utf-8');\n const iconFileMatch = infoPlistContent.match(/<key>CFBundleIconFile<\\/key>\\s*<string>([^<]+)<\\/string>/);\n if (iconFileMatch && iconFileMatch[1]) {\n let iconFileName = iconFileMatch[1].trim();\n if (!iconFileName.endsWith('.icns')) {\n iconFileName += '.icns';\n }\n const iconPath = path.join(resourcesPath, iconFileName);\n try {\n await fs.access(iconPath);\n return iconPath;\n } catch {\n // 继续尝试其他方法\n }\n }\n } catch {\n // Info.plist 读取失败\n }\n \n // 尝试常见文件名\n for (const iconName of commonIconNames) {\n const iconPath = path.join(resourcesPath, iconName);\n try {\n await fs.access(iconPath);\n return iconPath;\n } catch {\n continue;\n }\n }\n \n // 列出 Resources 目录,查找 .icns 文件\n try {\n const entries = await fs.readdir(resourcesPath);\n const icnsFile = entries.find(entry => entry.toLowerCase().endsWith('.icns'));\n if (icnsFile) {\n return path.join(resourcesPath, icnsFile);\n }\n } catch {\n // 目录读取失败\n }\n \n return null;\n } catch {\n return null;\n }\n}\n\n/**\n * 获取应用程序图标(仅 macOS)\n * \n * 使用 sips 命令将 .icns 转换为 PNG,返回 base64 data URL\n */\nexport async function getApplicationIcon(appPath: string): Promise<string | null> {\n if (process.platform !== 'darwin') {\n return null;\n }\n \n // 验证路径\n try {\n const stats = await fs.stat(appPath);\n if (!stats.isDirectory() || !appPath.endsWith('.app')) {\n return null;\n }\n } catch {\n return null;\n }\n \n // 从应用程序包中读取 .icns 文件\n const iconPath = await findAppIconPath(appPath);\n if (!iconPath) {\n return null;\n }\n \n try {\n // 使用 macOS sips 命令转换为 PNG\n const tempPngPath = path.join(os.tmpdir(), `app-icon-${Date.now()}.png`);\n await execAsync(\n `sips -s format png \"${iconPath}\" --out \"${tempPngPath}\" --resampleHeightWidthMax 128`\n );\n \n const pngBuffer = await fs.readFile(tempPngPath);\n \n // 删除临时文件\n try {\n await fs.unlink(tempPngPath);\n } catch {\n // 忽略\n }\n \n const base64 = pngBuffer.toString('base64');\n return `data:image/png;base64,${base64}`;\n } catch {\n return null;\n }\n}\n","import { promises as fs } from 'node:fs';\nimport path from 'node:path';\nimport { getFileType } from '../utils/file-type';\nimport { getFileHash } from '../hash';\nimport { FileType } from '../types';\nimport type { \n ThumbnailDatabase, \n ImageProcessor, \n VideoProcessor,\n ThumbnailServiceOptions \n} from './types';\n\n/** 图片扩展名 */\nconst IMAGE_EXTENSIONS = ['.jpg', '.jpeg', '.png', '.gif', '.webp', '.bmp'];\n\n/** 视频扩展名 */\nconst VIDEO_EXTENSIONS = ['.mp4', '.mov', '.avi', '.mkv', '.webm', '.flv', '.wmv'];\n\n/**\n * 缩略图服务\n */\nexport class ThumbnailService {\n private database: ThumbnailDatabase;\n private imageProcessor: ImageProcessor | null;\n private videoProcessor: VideoProcessor | null;\n private urlEncoder: (filePath: string) => string;\n private getApplicationIcon: ((appPath: string) => Promise<string | null>) | null;\n\n constructor(options: ThumbnailServiceOptions) {\n this.database = options.database;\n this.imageProcessor = options.imageProcessor || null;\n this.videoProcessor = options.videoProcessor || null;\n this.urlEncoder = options.urlEncoder || ((p) => `file://${encodeURIComponent(p)}`);\n this.getApplicationIcon = options.getApplicationIcon || null;\n }\n\n /**\n * 获取缓存的缩略图 URL(不生成新的)\n */\n async getCachedThumbnailUrl(filePath: string): Promise<string | null> {\n try {\n const stats = await fs.stat(filePath);\n const fileType = getFileType(filePath, stats);\n \n // 如果是应用程序,获取应用程序图标(macOS)\n if (fileType === FileType.APPLICATION && this.getApplicationIcon) {\n return await this.getApplicationIcon(filePath);\n }\n \n // 只处理图片和视频\n if (fileType !== FileType.IMAGE && fileType !== FileType.VIDEO) {\n return null;\n }\n \n const mtime = stats.mtime.getTime();\n \n // 快速查询缓存(不计算哈希)\n const cachedPath = this.database.getThumbnailPathFast(filePath, mtime);\n if (cachedPath) {\n return this.urlEncoder(cachedPath);\n }\n \n // 没有缓存,异步触发生成(不阻塞)\n getFileHash(filePath).then(fileHash => {\n this.generateThumbnail(filePath, fileHash, mtime).catch(() => {});\n }).catch(() => {});\n \n return null;\n } catch (error) {\n return null;\n }\n }\n\n /**\n * 获取缩略图 URL(如果没有缓存则生成)\n */\n async getThumbnailUrl(filePath: string): Promise<string | null> {\n try {\n const stats = await fs.stat(filePath);\n const fileType = getFileType(filePath, stats);\n \n // 如果是应用程序,获取应用程序图标(macOS)\n if (fileType === FileType.APPLICATION && this.getApplicationIcon) {\n return await this.getApplicationIcon(filePath);\n }\n \n // 只处理图片和视频\n if (fileType !== FileType.IMAGE && fileType !== FileType.VIDEO) {\n return null;\n }\n \n const mtime = stats.mtime.getTime();\n \n // 快速查询缓存(不计算哈希)\n const cachedPath = this.database.getThumbnailPathFast(filePath, mtime);\n if (cachedPath) {\n return this.urlEncoder(cachedPath);\n }\n \n // 缓存未命中,计算哈希并生成缩略图\n const fileHash = await getFileHash(filePath);\n const thumbnailPath = await this.generateThumbnail(filePath, fileHash, mtime);\n if (thumbnailPath) {\n return this.urlEncoder(thumbnailPath);\n }\n \n return null;\n } catch (error) {\n console.error(`Error getting thumbnail for ${filePath}:`, error);\n return null;\n }\n }\n\n /**\n * 生成缩略图\n */\n async generateThumbnail(\n filePath: string,\n fileHash: string,\n mtime: number\n ): Promise<string | null> {\n // 检查缓存\n const cachedPath = this.database.getThumbnailPath(filePath, fileHash, mtime);\n if (cachedPath) {\n return cachedPath;\n }\n\n try {\n const ext = path.extname(filePath).toLowerCase();\n \n // 生成缩略图文件名\n const hashPrefix = fileHash.substring(0, 16);\n const thumbnailFileName = `${hashPrefix}.jpg`;\n const thumbnailPath = path.join(this.database.getCacheDir(), thumbnailFileName);\n\n // 根据文件类型选择不同的生成方法\n if (IMAGE_EXTENSIONS.includes(ext) && this.imageProcessor) {\n await this.imageProcessor.resize(filePath, thumbnailPath, 256);\n } else if (VIDEO_EXTENSIONS.includes(ext) && this.videoProcessor) {\n await this.videoProcessor.screenshot(filePath, thumbnailPath, '00:00:01', '256x256');\n } else {\n return null;\n }\n\n // 保存到数据库\n this.database.saveThumbnail(filePath, fileHash, mtime, thumbnailPath);\n\n return thumbnailPath;\n } catch (error) {\n console.debug(`Error generating thumbnail for ${filePath}:`, error);\n return null;\n }\n }\n\n /**\n * 批量生成缩略图\n */\n async generateThumbnailsBatch(\n files: Array<{ path: string; hash: string; mtime: number }>\n ): Promise<void> {\n await Promise.allSettled(\n files.map(file => this.generateThumbnail(file.path, file.hash, file.mtime))\n );\n }\n\n /**\n * 删除缩略图\n */\n deleteThumbnail(filePath: string): void {\n this.database.deleteThumbnail(filePath);\n }\n\n /**\n * 清理旧缩略图\n */\n cleanupOldThumbnails(): void {\n this.database.cleanupOldThumbnails();\n }\n}\n\n// 全局单例\nlet thumbnailService: ThumbnailService | null = null;\n\n/**\n * 初始化缩略图服务\n */\nexport function initThumbnailService(options: ThumbnailServiceOptions): ThumbnailService {\n thumbnailService = new ThumbnailService(options);\n return thumbnailService;\n}\n\n/**\n * 获取缩略图服务实例\n */\nexport function getThumbnailService(): ThumbnailService | null {\n return thumbnailService;\n}\n","/**\n * SQLite 缩略图数据库实现\n * \n * 需要安装 better-sqlite3:npm install better-sqlite3\n */\n\nimport Database from 'better-sqlite3';\nimport path from 'node:path';\nimport { existsSync, mkdirSync } from 'node:fs';\nimport type { ThumbnailDatabase } from './types';\n\n/**\n * SQLite 缩略图数据库实现\n */\nexport class SqliteThumbnailDatabase implements ThumbnailDatabase {\n private db: Database.Database | null = null;\n private cacheDir: string;\n\n constructor(userDataPath: string) {\n this.cacheDir = path.join(userDataPath, 'cache');\n \n if (!existsSync(this.cacheDir)) {\n mkdirSync(this.cacheDir, { recursive: true });\n }\n }\n\n /**\n * 初始化数据库\n */\n init(): void {\n if (this.db) return;\n\n const dbPath = path.join(this.cacheDir, 'thumbnails.db');\n \n // 使用 WAL 模式提高并发性能,避免锁定问题\n this.db = new Database(dbPath, { \n fileMustExist: false,\n });\n \n // 启用 WAL 模式\n this.db.pragma('journal_mode = WAL');\n\n this.db.exec(`\n CREATE TABLE IF NOT EXISTS thumbnails (\n file_path TEXT PRIMARY KEY,\n file_hash TEXT NOT NULL,\n mtime INTEGER NOT NULL,\n thumbnail_path TEXT NOT NULL,\n created_at INTEGER NOT NULL\n );\n \n CREATE INDEX IF NOT EXISTS idx_file_hash ON thumbnails(file_hash);\n CREATE INDEX IF NOT EXISTS idx_mtime ON thumbnails(mtime);\n `);\n }\n\n getCacheDir(): string {\n return this.cacheDir;\n }\n\n /**\n * 快速查询缩略图(用路径和修改时间,不需要哈希)\n * 比计算文件哈希快很多\n */\n getThumbnailPathFast(filePath: string, mtime: number): string | null {\n if (!this.db) this.init();\n\n const stmt = this.db!.prepare(`\n SELECT thumbnail_path \n FROM thumbnails \n WHERE file_path = ? AND mtime = ?\n `);\n\n const row = stmt.get(filePath, mtime) as { thumbnail_path: string } | undefined;\n\n if (row && existsSync(row.thumbnail_path)) {\n return row.thumbnail_path;\n }\n\n return null;\n }\n\n getThumbnailPath(filePath: string, fileHash: string, mtime: number): string | null {\n if (!this.db) this.init();\n\n const stmt = this.db!.prepare(`\n SELECT thumbnail_path, mtime \n FROM thumbnails \n WHERE file_path = ? AND file_hash = ?\n `);\n\n const row = stmt.get(filePath, fileHash) as { thumbnail_path: string; mtime: number } | undefined;\n\n if (row && row.mtime === mtime && existsSync(row.thumbnail_path)) {\n return row.thumbnail_path;\n }\n\n return null;\n }\n\n saveThumbnail(filePath: string, fileHash: string, mtime: number, thumbnailPath: string): void {\n if (!this.db) this.init();\n\n const stmt = this.db!.prepare(`\n INSERT OR REPLACE INTO thumbnails \n (file_path, file_hash, mtime, thumbnail_path, created_at)\n VALUES (?, ?, ?, ?, ?)\n `);\n\n stmt.run(filePath, fileHash, mtime, thumbnailPath, Date.now());\n }\n\n deleteThumbnail(filePath: string): void {\n if (!this.db) this.init();\n\n const stmt = this.db!.prepare('DELETE FROM thumbnails WHERE file_path = ?');\n stmt.run(filePath);\n }\n\n cleanupOldThumbnails(): void {\n if (!this.db) this.init();\n\n const thirtyDaysAgo = Date.now() - 30 * 24 * 60 * 60 * 1000;\n const stmt = this.db!.prepare('DELETE FROM thumbnails WHERE created_at < ?');\n stmt.run(thirtyDaysAgo);\n }\n\n close(): void {\n if (this.db) {\n this.db.close();\n this.db = null;\n }\n }\n}\n\n// 单例\nlet thumbnailDb: SqliteThumbnailDatabase | null = null;\n\n/**\n * 创建 SQLite 缩略图数据库\n */\nexport function createSqliteThumbnailDatabase(userDataPath: string): SqliteThumbnailDatabase {\n if (!thumbnailDb) {\n thumbnailDb = new SqliteThumbnailDatabase(userDataPath);\n thumbnailDb.init();\n }\n return thumbnailDb;\n}\n\n/**\n * 获取缩略图数据库实例\n */\nexport function getSqliteThumbnailDatabase(): SqliteThumbnailDatabase | null {\n return thumbnailDb;\n}\n","/**\n * 缩略图处理器工厂函数\n * \n * 需要安装:\n * - sharp: npm install sharp\n * - ffmpeg-static: npm install ffmpeg-static\n */\n\nimport { execFile } from 'node:child_process';\nimport { promisify } from 'node:util';\nimport type { ImageProcessor, VideoProcessor } from './types';\n\nconst execFileAsync = promisify(execFile);\n\n/**\n * Sharp 类型定义(宽松类型,兼容 sharp 模块)\n */\ninterface SharpInstance {\n resize(width: number, height: number, options?: { fit?: string; withoutEnlargement?: boolean }): SharpInstance;\n jpeg(options?: { quality?: number }): SharpInstance;\n toFile(outputPath: string): Promise<unknown>;\n}\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype SharpModule = (input: string, options?: any) => SharpInstance;\n\n/**\n * 创建 Sharp 图片处理器\n * \n * @example\n * ```ts\n * import sharp from 'sharp';\n * import { createSharpImageProcessor } from '@huyooo/file-explorer-core';\n * \n * const imageProcessor = createSharpImageProcessor(sharp);\n * ```\n */\nexport function createSharpImageProcessor(sharp: SharpModule): ImageProcessor {\n return {\n async resize(filePath: string, outputPath: string, size: number) {\n await sharp(filePath)\n .resize(size, size, {\n fit: 'inside',\n withoutEnlargement: true,\n })\n .jpeg({ quality: 85 })\n .toFile(outputPath);\n }\n };\n}\n\n/**\n * 创建 FFmpeg 视频处理器(使用 child_process 直接调用 ffmpeg)\n * \n * @param ffmpegPath - ffmpeg 可执行文件路径(来自 ffmpeg-static)\n * \n * @example\n * ```ts\n * import ffmpegStatic from 'ffmpeg-static';\n * import { createFfmpegVideoProcessor } from '@huyooo/file-explorer-core';\n * \n * const videoProcessor = ffmpegStatic \n * ? createFfmpegVideoProcessor(ffmpegStatic) \n * : undefined;\n * ```\n */\nexport function createFfmpegVideoProcessor(ffmpegPath: string): VideoProcessor {\n return {\n async screenshot(filePath: string, outputPath: string, timestamp: string, size: string): Promise<void> {\n // 解析尺寸 \"200x200\" -> \"200:200\"\n const scaleSize = size.replace('x', ':');\n \n await execFileAsync(ffmpegPath, [\n '-i', filePath,\n '-ss', timestamp,\n '-vframes', '1',\n '-vf', `scale=${scaleSize}:force_original_aspect_ratio=decrease`,\n '-y',\n outputPath\n ]);\n }\n };\n}\n"],"mappings":"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","names":["FileType","path","import_node_path","fs","path","import_node_fs","import_node_path","fs","path","import_node_fs","fs","import_node_fs","fs","import_node_fs","import_node_path","path","fs","import_node_fs","import_node_path","fs","path","import_node_path","os","path","import_node_path","import_node_fs","path","fs","import_node_fs","import_node_path","fs","path","copyDirectory","import_node_fs","import_node_path","import_node_os","path","fs","os","import_node_fs","import_node_path","IMAGE_EXTENSIONS","VIDEO_EXTENSIONS","fs","path","import_node_path","import_node_fs","path","Database","import_node_child_process","import_node_util"]}
@@ -0,0 +1,492 @@
1
+ import { Stats } from 'node:fs';
2
+
3
+ /**
4
+ * 文件类型枚举
5
+ */
6
+ declare enum FileType {
7
+ FOLDER = "folder",
8
+ FILE = "file",
9
+ IMAGE = "image",
10
+ VIDEO = "video",
11
+ MUSIC = "music",
12
+ DOCUMENT = "document",
13
+ CODE = "code",
14
+ TEXT = "text",
15
+ ARCHIVE = "archive",
16
+ APPLICATION = "application",
17
+ UNKNOWN = "unknown"
18
+ }
19
+ /**
20
+ * 文件系统项
21
+ */
22
+ interface FileItem {
23
+ /** 唯一标识(通常是完整路径) */
24
+ id: string;
25
+ /** 文件名 */
26
+ name: string;
27
+ /** 文件类型 */
28
+ type: FileType;
29
+ /** 文件大小(格式化后的字符串) */
30
+ size?: string;
31
+ /** 修改日期(格式化后的字符串) */
32
+ dateModified?: string;
33
+ /** 文件 URL(用于加载) */
34
+ url?: string;
35
+ /** 缩略图 URL */
36
+ thumbnailUrl?: string;
37
+ /** 子项(仅文件夹) */
38
+ children?: FileItem[];
39
+ }
40
+ /**
41
+ * 文件信息
42
+ */
43
+ interface FileInfo {
44
+ path: string;
45
+ name: string;
46
+ size: number;
47
+ isFile: boolean;
48
+ isDirectory: boolean;
49
+ createdAt: Date;
50
+ updatedAt: Date;
51
+ extension?: string;
52
+ }
53
+ /**
54
+ * 操作结果
55
+ */
56
+ interface OperationResult<T = void> {
57
+ success: boolean;
58
+ data?: T;
59
+ error?: string;
60
+ message?: string;
61
+ }
62
+ /**
63
+ * 系统路径 ID
64
+ */
65
+ type SystemPathId = 'desktop' | 'documents' | 'downloads' | 'pictures' | 'music' | 'videos' | 'applications' | 'home' | 'root';
66
+ /**
67
+ * 平台适配器接口
68
+ * 用于处理平台特定的操作(如 Electron 的 shell.trashItem)
69
+ */
70
+ interface PlatformAdapter {
71
+ /** 删除文件到回收站 */
72
+ trashItem?: (path: string) => Promise<void>;
73
+ /** 打开文件 */
74
+ openPath?: (path: string) => Promise<void>;
75
+ /** 使用指定应用打开 */
76
+ openWith?: (path: string, appPath: string) => Promise<void>;
77
+ }
78
+ /**
79
+ * 文件操作选项
80
+ */
81
+ interface FileOperationOptions {
82
+ /** 平台适配器 */
83
+ adapter?: PlatformAdapter;
84
+ /** 是否自动重命名(当目标存在时) */
85
+ autoRename?: boolean;
86
+ }
87
+
88
+ /**
89
+ * 根据文件路径和状态获取文件类型
90
+ */
91
+ declare function getFileType(filePath: string, stats: Stats): FileType;
92
+ /**
93
+ * 判断是否为媒体文件
94
+ */
95
+ declare function isMediaFile(type: FileType): boolean;
96
+ /**
97
+ * 判断是否为可预览的文件
98
+ */
99
+ declare function isPreviewable(type: FileType): boolean;
100
+
101
+ /**
102
+ * 格式化文件大小
103
+ */
104
+ declare function formatFileSize(bytes: number): string;
105
+ /**
106
+ * 格式化日期
107
+ */
108
+ declare function formatDate(date: Date): string;
109
+ /**
110
+ * 格式化日期时间
111
+ */
112
+ declare function formatDateTime(date: Date): string;
113
+
114
+ /**
115
+ * URL 编码器(可由外部注入)
116
+ */
117
+ type UrlEncoder = (filePath: string) => string;
118
+ /**
119
+ * 读取目录配置
120
+ */
121
+ interface ReadDirectoryOptions {
122
+ /** URL 编码器 */
123
+ urlEncoder?: UrlEncoder;
124
+ /** 是否包含隐藏文件 */
125
+ includeHidden?: boolean;
126
+ /** 缩略图 URL 获取器(同步获取缓存的缩略图,没有则返回 null 并异步生成) */
127
+ getThumbnailUrl?: (filePath: string) => Promise<string | null>;
128
+ }
129
+ /**
130
+ * 读取目录内容
131
+ */
132
+ declare function readDirectory(dirPath: string, options?: ReadDirectoryOptions): Promise<FileItem[]>;
133
+ /**
134
+ * 读取文件内容
135
+ */
136
+ declare function readFileContent(filePath: string): Promise<string>;
137
+ /**
138
+ * 读取图片为 Base64
139
+ */
140
+ declare function readImageAsBase64(imagePath: string): Promise<{
141
+ success: boolean;
142
+ base64?: string;
143
+ mimeType?: string;
144
+ error?: string;
145
+ }>;
146
+
147
+ /**
148
+ * 写入文件内容
149
+ */
150
+ declare function writeFileContent(filePath: string, content: string): Promise<OperationResult>;
151
+ /**
152
+ * 创建文件夹(自动处理同名文件夹)
153
+ */
154
+ declare function createFolder(folderPath: string): Promise<OperationResult<{
155
+ finalPath: string;
156
+ }>>;
157
+ /**
158
+ * 创建文件(自动处理同名文件)
159
+ */
160
+ declare function createFile(filePath: string, content?: string): Promise<OperationResult<{
161
+ finalPath: string;
162
+ }>>;
163
+
164
+ /**
165
+ * 删除文件选项
166
+ */
167
+ interface DeleteOptions {
168
+ /** 平台适配器(用于移到回收站) */
169
+ adapter?: PlatformAdapter;
170
+ /** 是否使用回收站(默认 true) */
171
+ useTrash?: boolean;
172
+ /** 删除后回调(用于清理缩略图等) */
173
+ onDeleted?: (path: string) => void;
174
+ }
175
+ /**
176
+ * 删除文件/文件夹
177
+ *
178
+ * 如果提供了 adapter.trashItem,则移到回收站
179
+ * 否则直接删除(危险操作)
180
+ */
181
+ declare function deleteFiles(paths: string[], options?: DeleteOptions): Promise<OperationResult>;
182
+
183
+ /**
184
+ * 重命名选项
185
+ */
186
+ interface RenameOptions {
187
+ /** 重命名后回调 */
188
+ onRenamed?: (oldPath: string, newPath: string) => void;
189
+ }
190
+ /**
191
+ * 重命名文件/文件夹
192
+ */
193
+ declare function renameFile(oldPath: string, newPath: string, options?: RenameOptions): Promise<OperationResult>;
194
+
195
+ /**
196
+ * 复制文件到目标目录
197
+ */
198
+ declare function copyFiles(sourcePaths: string[], targetDir: string): Promise<OperationResult<{
199
+ copiedPaths: string[];
200
+ }>>;
201
+ /**
202
+ * 移动文件到目标目录
203
+ */
204
+ declare function moveFiles(sourcePaths: string[], targetDir: string): Promise<OperationResult<{
205
+ movedPaths: string[];
206
+ }>>;
207
+
208
+ /**
209
+ * 获取文件信息
210
+ */
211
+ declare function getFileInfo(filePath: string): Promise<OperationResult<FileInfo>>;
212
+ /**
213
+ * 检查文件/目录是否存在
214
+ */
215
+ declare function exists(filePath: string): Promise<boolean>;
216
+ /**
217
+ * 检查是否为目录
218
+ */
219
+ declare function isDirectory(filePath: string): Promise<boolean>;
220
+
221
+ /**
222
+ * 获取系统路径
223
+ */
224
+ declare function getSystemPath(pathId: SystemPathId): string | null;
225
+ /**
226
+ * 获取所有系统路径
227
+ */
228
+ declare function getAllSystemPaths(): Record<SystemPathId, string | null>;
229
+ /**
230
+ * 获取用户主目录
231
+ */
232
+ declare function getHomeDirectory(): string;
233
+ /**
234
+ * 获取当前平台
235
+ */
236
+ declare function getPlatform(): NodeJS.Platform;
237
+
238
+ /**
239
+ * 使用 fdir 快速搜索文件和文件夹
240
+ * fdir 可以在 1 秒内扫描 100 万个文件
241
+ *
242
+ * @param searchPath 搜索路径
243
+ * @param pattern 搜索模式(支持 * 通配符,忽略大小写)
244
+ * @param maxDepth 最大递归深度
245
+ */
246
+ declare function searchFiles(searchPath: string, pattern?: string, maxDepth?: number): Promise<string[]>;
247
+ /**
248
+ * 流式搜索文件(逐层搜索,边搜边返回)
249
+ *
250
+ * @param searchPath 搜索路径
251
+ * @param pattern 搜索模式
252
+ * @param onResults 找到结果时的回调
253
+ * @param maxResults 最大结果数
254
+ */
255
+ declare function searchFilesStream(searchPath: string, pattern: string, onResults: (paths: string[], done: boolean) => void, maxResults?: number): Promise<void>;
256
+ /**
257
+ * 同步搜索(用于小目录)
258
+ */
259
+ declare function searchFilesSync(searchPath: string, pattern?: string, maxDepth?: number): string[];
260
+
261
+ /**
262
+ * 计算文件的快速 hash(使用文件大小和修改时间)
263
+ * 这比计算完整文件 hash 快得多,适合用于缓存判断
264
+ */
265
+ declare function getFileHash(filePath: string): Promise<string>;
266
+ /**
267
+ * 批量计算文件 hash
268
+ */
269
+ declare function getFileHashes(filePaths: string[]): Promise<Map<string, string>>;
270
+
271
+ /**
272
+ * 剪贴板文件操作接口
273
+ * 由于 clipboard-files 是 native 模块,由使用者在 Electron 主进程中注入
274
+ */
275
+ interface ClipboardAdapter {
276
+ writeFiles: (paths: string[]) => void;
277
+ readFiles: () => string[];
278
+ }
279
+ /**
280
+ * 复制文件到剪贴板
281
+ */
282
+ declare function copyFilesToClipboard(filePaths: string[], clipboard: ClipboardAdapter): Promise<OperationResult>;
283
+ /**
284
+ * 从剪贴板读取文件路径
285
+ */
286
+ declare function getClipboardFiles(clipboard: ClipboardAdapter): OperationResult<{
287
+ files: string[];
288
+ }>;
289
+ /**
290
+ * 粘贴文件到目标目录
291
+ */
292
+ declare function pasteFiles(targetDir: string, sourcePaths: string[]): Promise<OperationResult<{
293
+ pastedPaths: string[];
294
+ }>>;
295
+
296
+ /**
297
+ * 应用程序图标获取(macOS)
298
+ *
299
+ * 纯 Node.js 实现,使用 sips 命令转换 icns 为 PNG
300
+ */
301
+ /**
302
+ * 获取应用程序图标(仅 macOS)
303
+ *
304
+ * 使用 sips 命令将 .icns 转换为 PNG,返回 base64 data URL
305
+ */
306
+ declare function getApplicationIcon(appPath: string): Promise<string | null>;
307
+
308
+ /**
309
+ * 缩略图数据库接口
310
+ */
311
+ interface ThumbnailDatabase {
312
+ /** 获取缓存目录 */
313
+ getCacheDir(): string;
314
+ /** 快速查询缩略图(只用路径和修改时间) */
315
+ getThumbnailPathFast(filePath: string, mtime: number): string | null;
316
+ /** 获取缩略图路径(如果缓存有效) */
317
+ getThumbnailPath(filePath: string, fileHash: string, mtime: number): string | null;
318
+ /** 保存缩略图信息 */
319
+ saveThumbnail(filePath: string, fileHash: string, mtime: number, thumbnailPath: string): void;
320
+ /** 删除缩略图记录 */
321
+ deleteThumbnail(filePath: string): void;
322
+ /** 清理旧缩略图 */
323
+ cleanupOldThumbnails(): void;
324
+ }
325
+ /**
326
+ * 图片处理器接口
327
+ */
328
+ interface ImageProcessor {
329
+ /** 缩放图片 */
330
+ resize(filePath: string, outputPath: string, size: number): Promise<void>;
331
+ }
332
+ /**
333
+ * 视频处理器接口
334
+ */
335
+ interface VideoProcessor {
336
+ /** 截取视频帧 */
337
+ screenshot(filePath: string, outputPath: string, timestamp: string, size: string): Promise<void>;
338
+ }
339
+ /**
340
+ * 缩略图服务配置
341
+ */
342
+ interface ThumbnailServiceOptions {
343
+ /** 数据库实例 */
344
+ database: ThumbnailDatabase;
345
+ /** 图片处理器(可选) */
346
+ imageProcessor?: ImageProcessor;
347
+ /** 视频处理器(可选) */
348
+ videoProcessor?: VideoProcessor;
349
+ /** URL 编码器(将本地路径转为 URL) */
350
+ urlEncoder?: (filePath: string) => string;
351
+ /** 应用图标获取器(macOS) */
352
+ getApplicationIcon?: (appPath: string) => Promise<string | null>;
353
+ }
354
+
355
+ /**
356
+ * 缩略图服务
357
+ */
358
+ declare class ThumbnailService {
359
+ private database;
360
+ private imageProcessor;
361
+ private videoProcessor;
362
+ private urlEncoder;
363
+ private getApplicationIcon;
364
+ constructor(options: ThumbnailServiceOptions);
365
+ /**
366
+ * 获取缓存的缩略图 URL(不生成新的)
367
+ */
368
+ getCachedThumbnailUrl(filePath: string): Promise<string | null>;
369
+ /**
370
+ * 获取缩略图 URL(如果没有缓存则生成)
371
+ */
372
+ getThumbnailUrl(filePath: string): Promise<string | null>;
373
+ /**
374
+ * 生成缩略图
375
+ */
376
+ generateThumbnail(filePath: string, fileHash: string, mtime: number): Promise<string | null>;
377
+ /**
378
+ * 批量生成缩略图
379
+ */
380
+ generateThumbnailsBatch(files: Array<{
381
+ path: string;
382
+ hash: string;
383
+ mtime: number;
384
+ }>): Promise<void>;
385
+ /**
386
+ * 删除缩略图
387
+ */
388
+ deleteThumbnail(filePath: string): void;
389
+ /**
390
+ * 清理旧缩略图
391
+ */
392
+ cleanupOldThumbnails(): void;
393
+ }
394
+ /**
395
+ * 初始化缩略图服务
396
+ */
397
+ declare function initThumbnailService(options: ThumbnailServiceOptions): ThumbnailService;
398
+ /**
399
+ * 获取缩略图服务实例
400
+ */
401
+ declare function getThumbnailService(): ThumbnailService | null;
402
+
403
+ /**
404
+ * SQLite 缩略图数据库实现
405
+ *
406
+ * 需要安装 better-sqlite3:npm install better-sqlite3
407
+ */
408
+
409
+ /**
410
+ * SQLite 缩略图数据库实现
411
+ */
412
+ declare class SqliteThumbnailDatabase implements ThumbnailDatabase {
413
+ private db;
414
+ private cacheDir;
415
+ constructor(userDataPath: string);
416
+ /**
417
+ * 初始化数据库
418
+ */
419
+ init(): void;
420
+ getCacheDir(): string;
421
+ /**
422
+ * 快速查询缩略图(用路径和修改时间,不需要哈希)
423
+ * 比计算文件哈希快很多
424
+ */
425
+ getThumbnailPathFast(filePath: string, mtime: number): string | null;
426
+ getThumbnailPath(filePath: string, fileHash: string, mtime: number): string | null;
427
+ saveThumbnail(filePath: string, fileHash: string, mtime: number, thumbnailPath: string): void;
428
+ deleteThumbnail(filePath: string): void;
429
+ cleanupOldThumbnails(): void;
430
+ close(): void;
431
+ }
432
+ /**
433
+ * 创建 SQLite 缩略图数据库
434
+ */
435
+ declare function createSqliteThumbnailDatabase(userDataPath: string): SqliteThumbnailDatabase;
436
+ /**
437
+ * 获取缩略图数据库实例
438
+ */
439
+ declare function getSqliteThumbnailDatabase(): SqliteThumbnailDatabase | null;
440
+
441
+ /**
442
+ * 缩略图处理器工厂函数
443
+ *
444
+ * 需要安装:
445
+ * - sharp: npm install sharp
446
+ * - ffmpeg-static: npm install ffmpeg-static
447
+ */
448
+
449
+ /**
450
+ * Sharp 类型定义(宽松类型,兼容 sharp 模块)
451
+ */
452
+ interface SharpInstance {
453
+ resize(width: number, height: number, options?: {
454
+ fit?: string;
455
+ withoutEnlargement?: boolean;
456
+ }): SharpInstance;
457
+ jpeg(options?: {
458
+ quality?: number;
459
+ }): SharpInstance;
460
+ toFile(outputPath: string): Promise<unknown>;
461
+ }
462
+ type SharpModule = (input: string, options?: any) => SharpInstance;
463
+ /**
464
+ * 创建 Sharp 图片处理器
465
+ *
466
+ * @example
467
+ * ```ts
468
+ * import sharp from 'sharp';
469
+ * import { createSharpImageProcessor } from '@huyooo/file-explorer-core';
470
+ *
471
+ * const imageProcessor = createSharpImageProcessor(sharp);
472
+ * ```
473
+ */
474
+ declare function createSharpImageProcessor(sharp: SharpModule): ImageProcessor;
475
+ /**
476
+ * 创建 FFmpeg 视频处理器(使用 child_process 直接调用 ffmpeg)
477
+ *
478
+ * @param ffmpegPath - ffmpeg 可执行文件路径(来自 ffmpeg-static)
479
+ *
480
+ * @example
481
+ * ```ts
482
+ * import ffmpegStatic from 'ffmpeg-static';
483
+ * import { createFfmpegVideoProcessor } from '@huyooo/file-explorer-core';
484
+ *
485
+ * const videoProcessor = ffmpegStatic
486
+ * ? createFfmpegVideoProcessor(ffmpegStatic)
487
+ * : undefined;
488
+ * ```
489
+ */
490
+ declare function createFfmpegVideoProcessor(ffmpegPath: string): VideoProcessor;
491
+
492
+ export { type ClipboardAdapter, type DeleteOptions, type FileInfo, type FileItem, type FileOperationOptions, FileType, type ImageProcessor, type OperationResult, type PlatformAdapter, type ReadDirectoryOptions, type RenameOptions, SqliteThumbnailDatabase, type SystemPathId, type ThumbnailDatabase, ThumbnailService, type ThumbnailServiceOptions, type UrlEncoder, type VideoProcessor, copyFiles, copyFilesToClipboard, createFfmpegVideoProcessor, createFile, createFolder, createSharpImageProcessor, createSqliteThumbnailDatabase, deleteFiles, exists, formatDate, formatDateTime, formatFileSize, getAllSystemPaths, getApplicationIcon, getClipboardFiles, getFileHash, getFileHashes, getFileInfo, getFileType, getHomeDirectory, getPlatform, getSqliteThumbnailDatabase, getSystemPath, getThumbnailService, initThumbnailService, isDirectory, isMediaFile, isPreviewable, moveFiles, pasteFiles, readDirectory, readFileContent, readImageAsBase64, renameFile, searchFiles, searchFilesStream, searchFilesSync, writeFileContent };