{"version":3,"file":"video.mjs","names":[],"sources":["../src/macros/env.ts","../src/std/video/web_video.ts","../src/std/fs/mina_fs_shared.ts","../src/std/video/frame-source/mina.ts","../src/std/video/frame-source/web.ts","../src/std/video/frame-source/mod.ts","../src/std/video/mod.ts"],"sourcesContent":["/**\n * @internal\n * 小游戏环境宏模块。\n */\n\n/**\n * 小游戏环境宏。\n *\n * 可通过打包工具在 build 时修改，如 esbuild webpack vite 等。\n */\ndeclare const __MINIGAME_STD_MINA__: boolean;\n\n/**\n * 如果在小游戏环境中返回 true，否则返回 false。\n */\nexport const IS_MINA = __MINIGAME_STD_MINA__;\n","/**\n * @internal\n * Web 平台的视频播放实现。\n */\n\n/**\n * Web平台创建视频播放器。\n * @param options - 视频配置选项。\n * @returns Video对象，模拟WechatMinigame.Video接口。\n */\nexport function createVideo(options: WechatMinigame.CreateVideoOption): WechatMinigame.Video {\n    const {\n        autoplay = false,\n        backgroundColor,\n        controls = false,\n        height,\n        initialTime,\n        loop = false,\n        muted = false,\n        objectFit,\n        playbackRate = 1,\n        poster,\n        src,\n        width,\n        x,\n        y,\n    } = options;\n\n    const video = document.createElement('video');\n\n    // 设置基本属性\n    video.src = src;\n    video.autoplay = autoplay;\n    video.controls = controls;\n    video.loop = loop;\n    video.muted = muted;\n    video.playbackRate = playbackRate;\n\n    // 设置移动端内联播放\n    video.setAttribute('playsinline', 'true');\n    video.setAttribute('webkit-playsinline', 'true');\n\n    if (poster) {\n        video.poster = poster;\n    }\n\n    // 设置尺寸\n    if (height !== undefined) {\n        video.height = height;\n    }\n    if (width !== undefined) {\n        video.width = width;\n    }\n\n    // 设置样式\n    if (backgroundColor) {\n        video.style.backgroundColor = backgroundColor;\n    }\n    if (objectFit) {\n        video.style.objectFit = objectFit;\n    }\n\n    // 设置定位\n    if (x !== undefined || y !== undefined) {\n        video.style.position = 'absolute';\n        if (x !== undefined) {\n            video.style.left = `${x}px`;\n        }\n        if (y !== undefined) {\n            video.style.top = `${y}px`;\n        }\n    }\n\n    // 添加到DOM\n    document.body.appendChild(video);\n\n    // 如果设置了初始播放位置，在元数据加载后跳转\n    if (initialTime !== undefined) {\n        video.addEventListener('loadedmetadata', () => {\n            video.currentTime = initialTime;\n        }, {\n            once: true,\n        });\n    }\n\n    // 事件监听器存储\n    type Callback = (...args: unknown[]) => void;\n    const listeners = {\n        ended: new Set<Callback>(),\n        error: new Set<Callback>(),\n        pause: new Set<Callback>(),\n        play: new Set<Callback>(),\n        progress: new Set<Callback>(),\n        timeupdate: new Set<Callback>(),\n        waiting: new Set<Callback>(),\n    };\n\n    // 绑定原生事件到监听器\n    video.addEventListener('ended', () => {\n        listeners.ended.forEach(cb => {\n            cb();\n        });\n    });\n    video.addEventListener('error', () => {\n        const errMsg = video.error?.message ?? 'MEDIA_ERR_UNKNOWN';\n        listeners.error.forEach(cb => cb({\n            errMsg,\n        }));\n    });\n    video.addEventListener('pause', () => {\n        listeners.pause.forEach(cb => {\n            cb();\n        });\n    });\n    video.addEventListener('play', () => {\n        listeners.play.forEach(cb => {\n            cb();\n        });\n    });\n    video.addEventListener('progress', () => {\n        const buffered = video.buffered;\n        const { duration } = video;\n        const bufferedPercent = buffered.length > 0 && duration > 0\n            ? (buffered.end(buffered.length - 1) / duration) * 100\n            : 0;\n        listeners.progress.forEach(cb => cb({\n            buffered: bufferedPercent,\n        }));\n    });\n    video.addEventListener('timeupdate', () => {\n        listeners.timeupdate.forEach(cb => cb({\n            position: video.currentTime,\n            duration: video.duration,\n        }));\n    });\n    video.addEventListener('waiting', () => {\n        listeners.waiting.forEach(cb => {\n            cb();\n        });\n    });\n\n    // 构建WechatMinigame.Video兼容对象\n    const videoProxy: WechatMinigame.Video = {\n        // 属性\n        get autoplay() {\n            return video.autoplay;\n        },\n        set autoplay(value) {\n            video.autoplay = value;\n        },\n\n        get backgroundColor() {\n            return video.style.backgroundColor;\n        },\n        set backgroundColor(value) {\n            video.style.backgroundColor = value;\n        },\n\n        get controls() {\n            return video.controls;\n        },\n        set controls(value) {\n            video.controls = value;\n        },\n\n        get enablePlayGesture() {\n            return false;\n        },\n        set enablePlayGesture(_value) {\n            /* web不支持 */\n        },\n\n        get enableProgressGesture() {\n            return false;\n        },\n        set enableProgressGesture(_value) {\n            /* web不支持 */\n        },\n\n        get height() {\n            return video.height;\n        },\n        set height(value) {\n            video.height = value;\n        },\n\n        get initialTime() {\n            return initialTime ?? 0;\n        },\n        set initialTime(value) {\n            video.currentTime = value;\n        },\n\n        get live() {\n            return false;\n        },\n        set live(_value) {\n            /* web不支持 */\n        },\n\n        get loop() {\n            return video.loop;\n        },\n        set loop(value) {\n            video.loop = value;\n        },\n\n        get muted() {\n            return video.muted;\n        },\n        set muted(value) {\n            video.muted = value;\n        },\n\n        get obeyMuteSwitch() {\n            return false;\n        },\n        set obeyMuteSwitch(_value) {\n            /* web不支持 */\n        },\n\n        get objectFit() {\n            return video.style.objectFit;\n        },\n        set objectFit(value) {\n            video.style.objectFit = value;\n        },\n\n        get playbackRate() {\n            return video.playbackRate;\n        },\n        set playbackRate(value) {\n            video.playbackRate = value;\n        },\n\n        get poster() {\n            return video.poster;\n        },\n        set poster(value) {\n            video.poster = value;\n        },\n\n        get showCenterPlayBtn() {\n            return false;\n        },\n        set showCenterPlayBtn(_value) {\n            /* web不支持 */\n        },\n\n        get showProgress() {\n            return video.controls;\n        },\n        set showProgress(_value) {\n            /* web通过controls控制 */\n        },\n\n        get showProgressInControlMode() {\n            return video.controls;\n        },\n        set showProgressInControlMode(_value) {\n            /* web通过controls控制 */\n        },\n\n        get src() {\n            return video.src;\n        },\n        set src(value) {\n            video.src = value;\n        },\n\n        get width() {\n            return video.width;\n        },\n        set width(value) {\n            video.width = value;\n        },\n\n        get x() {\n            return parseFloat(video.style.left) || 0;\n        },\n        set x(value) {\n            video.style.position = 'absolute';\n            video.style.left = `${value}px`;\n        },\n\n        get y() {\n            return parseFloat(video.style.top) || 0;\n        },\n        set y(value) {\n            video.style.position = 'absolute';\n            video.style.top = `${value}px`;\n        },\n\n        // on* 属性形式的事件回调\n        get onended() {\n            return video.onended as WechatMinigame.Video['onended'];\n        },\n        set onended(value) {\n            video.onended = value;\n        },\n\n        get onerror() {\n            return video.onerror as WechatMinigame.Video['onerror'];\n        },\n        set onerror(value) {\n            video.onerror = value as HTMLVideoElement['onerror'];\n        },\n\n        get onpause() {\n            return video.onpause as WechatMinigame.Video['onpause'];\n        },\n        set onpause(value) {\n            video.onpause = value;\n        },\n\n        get onplay() {\n            return video.onplay as WechatMinigame.Video['onplay'];\n        },\n        set onplay(value) {\n            video.onplay = value;\n        },\n\n        get onprogress() {\n            return video.onprogress as WechatMinigame.Video['onprogress'];\n        },\n        set onprogress(value) {\n            video.onprogress = value;\n        },\n\n        get ontimeupdate() {\n            return video.ontimeupdate as WechatMinigame.Video['ontimeupdate'];\n        },\n        set ontimeupdate(value) {\n            video.ontimeupdate = value;\n        },\n\n        get onwaiting() {\n            return video.onwaiting as WechatMinigame.Video['onwaiting'];\n        },\n        set onwaiting(value) {\n            video.onwaiting = value;\n        },\n\n        // 方法\n        play(): Promise<void> {\n            return video.play();\n        },\n\n        pause(): Promise<void> {\n            video.pause();\n            return Promise.resolve();\n        },\n\n        stop(): Promise<void> {\n            video.pause();\n            video.currentTime = 0;\n            return Promise.resolve();\n        },\n\n        seek(time: number): Promise<void> {\n            video.currentTime = time;\n            return Promise.resolve();\n        },\n\n        async requestFullScreen(direction: 0 | 90 | -90): Promise<void> {\n            // 先进入全屏\n            await video.requestFullscreen();\n\n            // 根据 direction 参数锁定屏幕方向\n            // 0: 正常竖向 (portrait)\n            // 90: 屏幕逆时针90度 (landscape-secondary，home键在右)\n            // -90: 屏幕顺时针90度 (landscape-primary，home键在左)\n            const orientationApi = screen.orientation as ScreenOrientation & {\n                lock?: (orientation: string) => Promise<void>;\n            };\n\n            if (orientationApi?.lock) {\n                let orientation: string;\n                switch (direction) {\n                    case 0:\n                        orientation = 'portrait';\n                        break;\n                    case 90:\n                        orientation = 'landscape-secondary';\n                        break;\n                    case -90:\n                        orientation = 'landscape-primary';\n                        break;\n                    default:\n                        return;\n                }\n                try {\n                    await orientationApi.lock(orientation);\n                } catch {\n                    // 屏幕方向锁定可能不被支持或被拒绝，忽略错误\n                }\n            }\n        },\n\n        exitFullScreen(): Promise<void> {\n            document.exitFullscreen();\n            return Promise.resolve();\n        },\n\n        destroy(): void {\n            video.pause();\n            video.src = '';\n            video.load();\n            video.remove();\n            // 清理所有监听器\n            Object.values(listeners).forEach(set => set.clear());\n        },\n\n        // on/off 方法形式的事件监听\n        onEnded(listener: WechatMinigame.OnEndedCallback): void {\n            listeners.ended.add(listener as Callback);\n        },\n        offEnded(listener?: WechatMinigame.OffEndedCallback): void {\n            if (listener) {\n                listeners.ended.delete(listener as Callback);\n            } else {\n                listeners.ended.clear();\n            }\n        },\n\n        onError(listener: WechatMinigame.VideoOnErrorCallback): void {\n            listeners.error.add(listener as Callback);\n        },\n        offError(listener?: WechatMinigame.VideoOffErrorCallback): void {\n            if (listener) {\n                listeners.error.delete(listener as Callback);\n            } else {\n                listeners.error.clear();\n            }\n        },\n\n        onPause(listener: WechatMinigame.OnPauseCallback): void {\n            listeners.pause.add(listener as Callback);\n        },\n        offPause(listener?: WechatMinigame.OffPauseCallback): void {\n            if (listener) {\n                listeners.pause.delete(listener as Callback);\n            } else {\n                listeners.pause.clear();\n            }\n        },\n\n        onPlay(listener: WechatMinigame.OnPlayCallback): void {\n            listeners.play.add(listener as Callback);\n        },\n        offPlay(listener?: WechatMinigame.OffPlayCallback): void {\n            if (listener) {\n                listeners.play.delete(listener as Callback);\n            } else {\n                listeners.play.clear();\n            }\n        },\n\n        onProgress(listener: WechatMinigame.OnProgressCallback): void {\n            listeners.progress.add(listener as Callback);\n        },\n        offProgress(listener?: WechatMinigame.OffProgressCallback): void {\n            if (listener) {\n                listeners.progress.delete(listener as Callback);\n            } else {\n                listeners.progress.clear();\n            }\n        },\n\n        onTimeUpdate(listener: WechatMinigame.VideoOnTimeUpdateCallback): void {\n            listeners.timeupdate.add(listener as Callback);\n        },\n        offTimeUpdate(listener?: WechatMinigame.VideoOffTimeUpdateCallback): void {\n            if (listener) {\n                listeners.timeupdate.delete(listener as Callback);\n            } else {\n                listeners.timeupdate.clear();\n            }\n        },\n\n        onWaiting(listener: WechatMinigame.OnWaitingCallback): void {\n            listeners.waiting.add(listener as Callback);\n        },\n        offWaiting(listener?: WechatMinigame.OffWaitingCallback): void {\n            if (listener) {\n                listeners.waiting.delete(listener as Callback);\n            } else {\n                listeners.waiting.clear();\n            }\n        },\n    };\n\n    return videoProxy;\n}","/**\n * @internal\n * 同步/异步的公共代码。\n */\n\nimport { NOT_FOUND_ERROR, NOTHING_TO_ZIP_ERROR, ROOT_DIR, type ExistsOptions } from 'happy-opfs';\nimport { Err, Lazy, Ok, RESULT_FALSE, RESULT_VOID, tryResult, type AsyncIOResult, type IOResult, type Result, type VoidIOResult } from 'happy-rusty';\nimport { bufferSourceToAb, miniGameFailureToError } from '../internal/mod.ts';\nimport { normalize } from '../path/mod.ts';\nimport { asyncResultify } from '../utils/mod.ts';\nimport type { ReadOptions, WriteFileContent } from './fs_define.ts';\n\n// #region Internal Variables\n\n/**\n * 小游戏文件系统管理器实例。\n *\n */\nconst fs = /*#__PURE__*/ Lazy(() => wx.getFileSystemManager());\n\n/**\n * 用户数据根目录，`wxfile://usr` 或 `http://usr`。\n *\n */\nconst usrPath = /*#__PURE__*/ Lazy(() => wx.env.USER_DATA_PATH);\n\n/**\n * 根路径，`wxfile://` 或 `http://`。\n *\n */\nconst rootPath = /*#__PURE__*/ Lazy(() => {\n    const path = usrPath.force();\n    // 剥离 `usr`\n    return `${path.split('://')[0]}://`;\n});\n\n// #endregion\n\n/**\n * zip 操作的结果。\n */\nexport type ZipIOResult = IOResult<Uint8Array<ArrayBuffer> | void>;\n\nexport const EMPTY_BYTES: Uint8Array<ArrayBuffer> = /*#__PURE__*/ new Uint8Array(0);\n\n/**\n * 获取小游戏文件系统管理器实例。\n * @returns 文件系统管理器实例。\n */\nexport function getFs(): WechatMinigame.FileSystemManager {\n    return fs.force();\n}\n\n/**\n * 获取文件系统的根路径。\n * @returns 文件系统的根路径。\n */\nexport function getUsrPath(): string {\n    return usrPath.force();\n}\n\n/**\n * 验证并标准化路径，返回绝对路径。\n *\n * 支持两种输入格式：\n * 1. 完整路径：以 `wxfile://` 或 `http://` 开头（如 `wxfile://usr/test`）\n * 2. 相对路径：以 `/` 开头（如 `/test`），会自动拼接 `wx.env.USER_DATA_PATH`\n *\n * @param path - 待验证的路径。\n * @returns 验证成功返回标准化后的绝对路径，失败返回错误信息。\n */\nexport function validateAbsolutePath(path: string): IOResult<string> {\n    const typeError = validatePathType(path);\n    if (typeError) return typeError;\n\n    // 是否已经是完整路径\n    let isFullPath = false;\n    // 检查是否为完整路径（以 `wxfile://` 或 `http://` 开头）\n    if (path.startsWith(rootPath.force())) {\n        isFullPath = true;\n        // 先剥离协议前缀，避免 normalize 将 `://` 转换为 `:/`\n        path = path.slice(rootPath.force().length);\n        // 传根路径没意义\n        if (!path) {\n            return Err(new Error('Path must not be root directory'));\n        }\n    }\n\n    // 标准化路径（处理 `.`、`..` 等）并去除末尾的 `/`\n    const normalized = normalize(path);\n    path = normalized.length > 1 && normalized[normalized.length - 1] === ROOT_DIR\n        ? normalized.slice(0, -1)\n        : normalized;\n\n    // 完整路径：重新拼接协议前缀\n    if (isFullPath) {\n        // 还是根路径\n        if (path === ROOT_DIR) {\n            return Err(new Error('Path must not be root directory'));\n        }\n        // 确保路径不是以 `/` 开头，避免 `wxfile:///usr` 这样的多斜杠情况\n        if (path[0] === ROOT_DIR) {\n            path = path.slice(1);\n        }\n        return Ok(rootPath.force() + path);\n    }\n\n    // 相对路径：必须以 `/` 开头\n    if (path[0] !== ROOT_DIR) {\n        return Err(new Error(`Path must be absolute (start with '/'): '${path}'`));\n    }\n\n    // 拼接用户数据根目录\n    return Ok(usrPath.force() + path);\n}\n\n/**\n * 验证可读路径（用于只读操作：readFile、stat、readDir）。\n *\n * 支持三种输入格式：\n * 1. 完整路径：以 `wxfile://` 或 `http://` 开头（如 `wxfile://usr/test`）\n * 2. 用户数据相对路径：以 `/` 开头（如 `/test`），会自动拼接 `wx.env.USER_DATA_PATH`\n * 3. 代码包路径：不以 `./`、`../` 开头的相对路径（如 `images/logo.png`），直接返回原路径\n *\n * @param path - 待验证的路径。\n * @returns 验证成功返回标准化后的路径，失败返回错误信息。\n */\nexport function validateReadablePath(path: string): IOResult<string> {\n    const typeError = validatePathType(path);\n    if (typeError) return typeError;\n\n    // 对于完整路径和以 / 开头的路径，使用现有的绝对路径验证\n    if (path.startsWith(rootPath.force()) || path.startsWith(ROOT_DIR)) {\n        return validateAbsolutePath(path);\n    }\n\n    // 既不是完整路径，也不以 / 开头，检查是否为代码包路径（不以 ./、../ 开头）\n    if (path.startsWith('./') || path.startsWith('../')) {\n        return Err(new Error(`Invalid path: '${path}'. Code package paths must not start with './' or '../'`));\n    }\n\n    // 代码包路径返回标准化后的结果\n    const normalized = normalize(path);\n    return Ok(normalized);\n}\n\n/**\n * 验证提供的 ExistsOptions 是否有效。\n * `isDirectory` 和 `isFile` 不能同时为 `true`。\n *\n * @param options - 要验证的 ExistsOptions。\n * @returns 表示成功或错误的 VoidIOResult。\n */\nexport function validateExistsOptions(options?: ExistsOptions): VoidIOResult {\n    const { isDirectory = false, isFile = false } = options ?? {};\n\n    return isDirectory && isFile\n        ? Err(new Error('isDirectory and isFile cannot both be true'))\n        : RESULT_VOID;\n}\n\n/**\n * 判断错误是否为 `NotFoundError`。\n * @param error - 要检查的错误。\n * @returns 如果是 `NotFoundError` 返回 `true`，否则返回 `false`。\n */\nexport function isNotFoundError(error: Error): boolean {\n    return error.name === NOT_FOUND_ERROR;\n}\n\n/**\n * 将错误对象转换为 IOResult 类型。\n * @typeParam T - Result 的 Ok 类型。\n * @param error - IO 操作的错误对象, 可以是同步(Error)或者异步(WechatMinigame.FileError)的。\n * @returns 转换后的 IOResult 对象。\n */\nexport function fileErrorToResult<T>(error: FileError): IOResult<T> {\n    const err = miniGameFailureToError(error);\n\n    if (isNotFoundFileError(err)) {\n        err.name = NOT_FOUND_ERROR;\n    }\n\n    return Err(err);\n}\n\n/**\n * 处理 `mkdir` 的错误。\n */\nexport function fileErrorToMkdirResult(error: FileError): VoidIOResult {\n    // 已存在当做成功\n    return isAlreadyExistsFileError(error) ? RESULT_VOID : fileErrorToResult(error);\n}\n\n/**\n * 处理 `remove` 的错误。\n */\nexport function fileErrorToRemoveResult(error: FileError): VoidIOResult {\n    // 目标 path 本就不存在，当做成功\n    return isNotFoundFileError(error) ? RESULT_VOID : fileErrorToResult(error);\n}\n\n/*\n * 创建 `NothingToZipError` 错误。\n */\nexport function createNothingToZipError(): IOResult<never> {\n    const error = new Error('Nothing to zip');\n    error.name = NOTHING_TO_ZIP_ERROR;\n\n    return Err(error);\n}\n\n/*\n * 创建\"文件不存在且 create 为 false\"的错误。\n * @param filePath - 文件路径。\n * @returns 错误结果。\n */\nexport function createFileNotExistsError(filePath: string): IOResult<never> {\n    return Err(new Error(`Cannot append to non-existent file: ${filePath}`));\n}\n\n/*\n * 创建\"目录已存在但是文件\"的错误。\n * @param dirPath - 目录路径。\n * @returns 错误结果。\n */\nexport function createDirIsFileError(dirPath: string): IOResult<never> {\n    return Err(new Error(`Path already exists but is a file: ${dirPath}`));\n}\n\n/**\n * 获取读取文件的编码。\n * @returns 返回 `'utf8'` 或 `undefined`（读取二进制时不传 encoding）。\n */\nexport function getReadFileEncoding(options?: ReadOptions): 'utf8' | undefined {\n    // NOTE: 想要读取 ArrayBuffer 就不能传 encoding\n    // 如果传了 'bytes' 或不传，返回 undefined\n    return options?.encoding === 'utf8' ? 'utf8' : undefined;\n}\n\n/**\n * 获取写入文件的参数。\n */\nexport function getWriteFileContents(contents: WriteFileContent): IOResult<GetWriteFileContents> {\n    const isBin = typeof contents !== 'string';\n\n    let data: string | ArrayBuffer;\n\n    if (isBin) {\n        const result = tryResult(() => bufferSourceToAb(contents));\n        if (result.isErr()) return result.asErr();\n\n        data = result.unwrap();\n    } else {\n        data = contents;\n    }\n\n    const encoding = isBin ? undefined : 'utf8';\n\n    return Ok({\n        data,\n        encoding,\n    });\n}\n\n/**\n * 获取 `exists` 的结果。\n *\n * 注意：Windows 和 Mac 平台 `stat` 代码包内不存在的文件时, 平台会误报成功并返回 `stats.size = -1`。\n * 此处通过 `stats.size < 0` 判断并视为不存在, 以兼容该平台 bug。\n *\n * TODO(platform-wx): 待微信 Windows/Mac 平台修复该 stat 误报 bug 后, 移除 `stats.size < 0` 判断。\n * 跟踪点: `mina_fs_shared.ts` getExistsResult。\n */\nexport function getExistsResult(statResult: IOResult<WechatMinigame.Stats>, options?: ExistsOptions): IOResult<boolean> {\n    return statResult.map(stats => {\n        const { isDirectory = false, isFile = false } = options ?? {};\n\n        const notExist =\n            stats.size < 0 // TODO(platform-wx): Windows/Mac 平台 stat 代码包不存在文件时的误报, 待平台修复后移除\n            || (isDirectory && stats.isFile())\n            || (isFile && stats.isDirectory());\n\n        return !notExist;\n    }).orElse(err => {\n        return isNotFoundError(err) ? RESULT_FALSE : statResult.asErr();\n    });\n}\n\n/**\n * 判断文件/目录是否存在（不区分类型）。\n *\n * 相比 `stat` + `getExistsResult`，使用底层 `access` 接口开销更小，不会构造 `Stats` 对象。\n * 当 `ExistsOptions` 不需要检查 `isDirectory`/`isFile` 时使用此实现。\n *\n * @param path - 文件或目录路径。\n * @returns 存在返回 `true`，不存在返回 `false`，其他错误透传。\n */\nexport async function accessExists(path: string): AsyncIOResult<boolean> {\n    const pathRes = validateReadablePath(path);\n    if (pathRes.isErr()) return pathRes.asErr();\n    path = pathRes.unwrap();\n\n    const accessRes = await asyncResultify(getFs().access)({ path });\n    return accessResultToExists(accessRes);\n}\n\n/**\n * `accessExists` 的同步版本。\n *\n * @param path - 文件或目录路径。\n * @returns 存在返回 `true`，不存在返回 `false`，其他错误透传。\n */\nexport function accessExistsSync(path: string): IOResult<boolean> {\n    const pathRes = validateReadablePath(path);\n    if (pathRes.isErr()) return pathRes.asErr();\n    path = pathRes.unwrap();\n\n    const accessRes = tryResult(() => getFs().accessSync(path));\n    return accessResultToExists(accessRes);\n}\n\n\n/**\n * 根据 `recursive` 不同标准化 `stat` 的结果(recursive=true 的时候开发者工具对于文件和空文件夹会返回单个 Stats)。\n * - `recursive=false`: 返回单个 `Stats` 或 `FileStats[]`\n * - `recursive=true`: 始终返回 `FileStats[]`，即使是单个文件或空目录\n *   - 如果是单个 `Stats`，包装成数组，path 设为 '' 表示当前项目\n */\nexport function normalizeStats(statsOrFileStats: WechatMinigame.Stats | WechatMinigame.FileStats[], recursive: boolean): WechatMinigame.Stats | WechatMinigame.FileStats[] {\n    if (Array.isArray(statsOrFileStats)) {\n        return statsOrFileStats.map(({ path, stats }) => ({\n            path: path.replace(/^\\/+/, ''), // 返回相对路径, 去掉开头的 `/`(安卓子项目 path 不以 `/` 开头)\n            stats,\n        })).sort((a, b) => a.path.localeCompare(b.path)); // 按 path 排序\n    }\n\n    // 只要是 recursive 就返回数组(即使是文件或者空目录))\n    return recursive\n        ? [{\n            path: '', // 当前文件夹本身的相对路径\n            stats: statsOrFileStats,\n        }]\n        : statsOrFileStats;\n}\n\n// #region Internal Types\n\ntype FileError = WechatMinigame.FileError | (Error & {\n    errno?: number;\n});\n\ninterface GetWriteFileContents {\n    data: string | ArrayBuffer;\n    encoding?: 'utf8';\n}\n\n// #endregion\n\n// #region Internal Functions\n\n/**\n * 标准化同步或异步的文件错误对象。\n * @param error - IO 操作的错误对象, 可以是同步(Error)或者异步(WechatMinigame.FileError)的。\n */\nfunction normalizeFileError(error: FileError): WechatMinigame.FileError {\n    return error instanceof Error\n        ? {\n            errCode: error.errno ?? 0,\n            errMsg: error.message,\n        }\n        : error;\n}\n\n/**\n * 判断是否文件或者文件夹不存在。\n * @param error - IO 操作的错误对象, 可以是同步(Error)或者异步(WechatMinigame.FileError)的。\n */\nfunction isNotFoundFileError(error: FileError): boolean {\n    // 1300002\tno such file or directory ${path}\n    const { errCode, errMsg } = normalizeFileError(error);\n    // 可能没有errCode\n    return errCode === 1300002\n        || errMsg.includes('no such file or directory');\n}\n\n/**\n * 判断是否文件或者文件夹已存在。\n * @param error - IO 操作的错误对象, 可以是同步(Error)或者异步(WechatMinigame.FileError)的。\n */\nfunction isAlreadyExistsFileError(error: FileError): boolean {\n    // 1301005\tfile already exists ${dirPath}\t已有同名文件或目录\n    const { errCode, errMsg } = normalizeFileError(error);\n    // 可能没有errCode\n    return errCode === 1301005\n        || errMsg.includes('already exists');\n}\n\n/**\n * 验证 path 是否为字符串类型。\n * @param path - 待验证的路径。\n * @returns 如果不是字符串返回错误，否则返回 undefined。\n */\nfunction validatePathType(path: unknown): IOResult<never> | undefined {\n    if (typeof path !== 'string') {\n        return Err(new TypeError(`Path must be a string but received ${typeof path}`));\n    }\n}\n\n/**\n * 将 `access`/`accessSync` 调用的结果转换为存在性结果。\n * - 成功 → `true`\n * - NotFound → `false`\n * - 其他错误 → 透传\n */\nfunction accessResultToExists<T, E>(accessRes: Result<T, E>): IOResult<boolean> {\n    return accessRes\n        .map(() => true)\n        .orElse(err => {\n            // 归一化错误（识别 not found 并设置 name），再判断是否为不存在\n            const normalized = fileErrorToResult<boolean>(err as FileError).unwrapErr();\n            return isNotFoundError(normalized) ? RESULT_FALSE : Err(normalized);\n        });\n}\n\n// #endregion\n","/**\n * @internal\n * 小游戏平台的视频帧源实现。\n */\n\nimport { Err, Ok, tryAsyncResult, type AsyncVoidIOResult, type IOResult } from 'happy-rusty';\nimport { validateReadablePath } from '../../fs/mina_fs_shared.ts';\nimport type { CreateVideoFrameSourceFromFileOptions, CreateVideoFrameSourceOptions, PixelVideoFrame, VideoFrameSource, VideoFrameSourceFrame, VideoFrameSourceState } from './defines.ts';\n\n// #region Exports\n\n/**\n * 判断小游戏平台是否支持视频帧源。\n *\n * @returns 是否支持视频帧源。\n */\nexport function isVideoFrameSourceSupported(): boolean {\n    return typeof wx.createVideoDecoder === 'function';\n}\n\n/**\n * 创建小游戏平台视频帧源。\n *\n * @param options - 视频帧源创建选项。\n * @returns 视频帧源创建结果。\n */\nexport function createVideoFrameSource(options: CreateVideoFrameSourceOptions): IOResult<VideoFrameSource> {\n    if (!isVideoFrameSourceSupported()) {\n        return Err(new Error('VideoFrameSource is not supported on this minigame platform'));\n    }\n\n    const decoder = wx.createVideoDecoder();\n    let state: VideoFrameSourceState = 'idle';\n    let lastFrame: PixelVideoFrame | null = null;\n    let currentTime = 0;\n    let width = options.width ?? 0;\n    let height = options.height ?? 0;\n\n    const frameListeners = new Set<FrameListener>();\n    const endedListeners = new Set<EndedListener>();\n    const errorListeners = new Set<ErrorListener>();\n\n    const pullFrame = (): PixelVideoFrame | null => {\n        const frameData = decoder.getFrameData() as WechatMinigame.FrameDataOptions | null;\n        if (frameData == null) return null;\n\n        const frame = toPixelFrame(frameData);\n        currentTime = frame.timestamp;\n        width = frame.width;\n        height = frame.height;\n        return frame;\n    };\n\n    const handleEnded = () => {\n        if (state !== 'destroyed') state = 'ended';\n        endedListeners.forEach(listener => listener());\n    };\n\n    decoder.on('ended', handleEnded);\n\n    return Ok({\n        get state() {\n            return state;\n        },\n        get currentTime() {\n            return currentTime;\n        },\n        get duration() {\n            return Number.NaN;\n        },\n        get width() {\n            return width;\n        },\n        get height() {\n            return height;\n        },\n        async play(): AsyncVoidIOResult {\n            const result = await tryAsyncResult(decoder.start({ source: options.source }));\n            return result.inspect(() => {\n                state = 'playing';\n            });\n        },\n        async pause(): AsyncVoidIOResult {\n            const result = await tryAsyncResult(() => decoder.stop());\n            return result.inspect(() => {\n                state = 'paused';\n            });\n        },\n        async stop(): AsyncVoidIOResult {\n            const result = await tryAsyncResult(() => decoder.stop());\n            return result.inspect(() => {\n                state = 'paused';\n                currentTime = 0;\n            });\n        },\n        async seek(time: number): AsyncVoidIOResult {\n            // wx.VideoDecoder.seek 的 position 单位为 ms，公开 API 单位为秒，需转换\n            const result = await tryAsyncResult(() => decoder.seek(time * 1000));\n            return result.inspect(() => {\n                currentTime = time;\n            });\n        },\n        getFrame(): IOResult<VideoFrameSourceFrame | null> {\n            lastFrame = pullFrame();\n            if (lastFrame != null) {\n                frameListeners.forEach(listener => listener(lastFrame as PixelVideoFrame));\n            }\n            const frame = lastFrame;\n            lastFrame = null;\n            return Ok(frame);\n        },\n        onFrame(listener: FrameListener): void {\n            frameListeners.add(listener);\n        },\n        offFrame(listener?: FrameListener): void {\n            if (listener) frameListeners.delete(listener);\n            else frameListeners.clear();\n        },\n        onEnded(listener: EndedListener): void {\n            endedListeners.add(listener);\n        },\n        offEnded(listener?: EndedListener): void {\n            if (listener) endedListeners.delete(listener);\n            else endedListeners.clear();\n        },\n        onError(listener: ErrorListener): void {\n            errorListeners.add(listener);\n        },\n        offError(listener?: ErrorListener): void {\n            if (listener) errorListeners.delete(listener);\n            else errorListeners.clear();\n        },\n        destroy(): void {\n            if (state === 'destroyed') return;\n            state = 'destroyed';\n            decoder.off('ended', handleEnded);\n            void tryAsyncResult(decoder.remove());\n            frameListeners.clear();\n            endedListeners.clear();\n            errorListeners.clear();\n        },\n    });\n}\n\n/**\n * 从小游戏本地文件创建视频帧源。\n *\n * @param filePath - 视频文件路径。\n * @param options - 视频帧源创建选项。\n * @returns 视频帧源创建结果。\n */\nexport function createVideoFrameSourceFromFile(filePath: string, options?: CreateVideoFrameSourceFromFileOptions): IOResult<VideoFrameSource> {\n    return validateReadablePath(filePath)\n        .andThen(source => createVideoFrameSource({\n            ...options,\n            source,\n        }));\n}\n\n// #endregion\n\n// #region Internal Types\n\ntype FrameListener = (frame: VideoFrameSourceFrame) => void;\ntype EndedListener = () => void;\ntype ErrorListener = (error: Error) => void;\n\n// #endregion\n\n// #region Internal Functions\n\nfunction toPixelFrame(frameData: WechatMinigame.FrameDataOptions): PixelVideoFrame {\n    return {\n        kind: 'pixels',\n        format: 'rgba',\n        data: new Uint8Array(frameData.data),\n        width: frameData.width,\n        height: frameData.height,\n        timestamp: frameData.pkPts / 1000,\n        release(): void {\n            return undefined;\n        },\n    };\n}\n\n// #endregion\n","/**\n * @internal\n * Web 平台的视频帧源实现。\n */\n\nimport { readBlobFile } from 'happy-opfs';\nimport { Ok, tryAsyncResult, type AsyncIOResult, type AsyncVoidIOResult, type IOResult } from 'happy-rusty';\nimport type { CreateVideoFrameSourceFromFileOptions, CreateVideoFrameSourceOptions, ElementVideoFrame, VideoFrameSource, VideoFrameSourceFrame, VideoFrameSourceState } from './defines.ts';\n\n// #region Exports\n\n/**\n * 判断 Web 平台是否支持视频帧源。\n *\n * @returns 是否支持视频帧源。\n */\nexport function isVideoFrameSourceSupported(): boolean {\n    return typeof document !== 'undefined' && typeof document.createElement === 'function';\n}\n\n/**\n * 创建 Web 平台视频帧源。\n *\n * @param options - 视频帧源创建选项。\n * @returns 视频帧源。\n */\nexport function createVideoFrameSource(options: CreateVideoFrameSourceOptions): VideoFrameSource {\n    const video = document.createElement('video') as VideoElementWithFrameCallback;\n    let state: VideoFrameSourceState = 'idle';\n    let hasNewFrame = false;\n    let frameCallbackId: number | undefined;\n    let rafId: number | undefined;\n    let lastFrameTime = -1;\n\n    const frameListeners = new Set<FrameListener>();\n    const endedListeners = new Set<EndedListener>();\n    const errorListeners = new Set<ErrorListener>();\n\n    const createFrame = (): ElementVideoFrame => ({\n        kind: 'element',\n        element: video,\n        width: video.videoWidth || video.width,\n        height: video.videoHeight || video.height,\n        timestamp: video.currentTime,\n        release(): void {\n            return undefined;\n        },\n    });\n\n    const emitFrame = () => {\n        if (state === 'destroyed') return;\n        hasNewFrame = true;\n        const frame = createFrame();\n        frameListeners.forEach(listener => listener(frame));\n    };\n\n    const requestNextFrame = () => {\n        if (state === 'destroyed') return;\n\n        if (typeof video.requestVideoFrameCallback === 'function') {\n            frameCallbackId = video.requestVideoFrameCallback((_now, metadata) => {\n                lastFrameTime = metadata.mediaTime;\n                emitFrame();\n                requestNextFrame();\n            });\n            return;\n        }\n\n        rafId = requestAnimationFrame(() => {\n            if (video.currentTime !== lastFrameTime) {\n                lastFrameTime = video.currentTime;\n                emitFrame();\n            }\n            requestNextFrame();\n        });\n    };\n\n    const cancelFrameRequest = () => {\n        if (frameCallbackId != null && typeof video.cancelVideoFrameCallback === 'function') {\n            video.cancelVideoFrameCallback(frameCallbackId);\n            frameCallbackId = undefined;\n        }\n        if (rafId != null) {\n            cancelAnimationFrame(rafId);\n            rafId = undefined;\n        }\n    };\n\n    video.src = options.source;\n    video.loop = options.loop ?? false;\n    video.muted = options.muted ?? false;\n    video.autoplay = options.autoplay ?? false;\n    video.preload = 'auto';\n    video.setAttribute('playsinline', 'true');\n    video.setAttribute('webkit-playsinline', 'true');\n\n    if (options.crossOrigin !== undefined) {\n        video.crossOrigin = options.crossOrigin;\n    }\n    if (options.width !== undefined) {\n        video.width = options.width;\n    }\n    if (options.height !== undefined) {\n        video.height = options.height;\n    }\n\n    video.style.display = 'none';\n    document.body.appendChild(video);\n    state = 'loading';\n\n    video.addEventListener('loadedmetadata', () => {\n        if (state !== 'destroyed') state = 'ready';\n    });\n    video.addEventListener('ended', () => {\n        if (state !== 'destroyed') state = 'ended';\n        endedListeners.forEach(listener => listener());\n    });\n    video.addEventListener('error', () => {\n        if (state !== 'destroyed') state = 'error';\n        const error = new Error(video.error?.message ?? 'Video frame source error');\n        errorListeners.forEach(listener => listener(error));\n    });\n\n    requestNextFrame();\n\n    const source: VideoFrameSource = {\n        get state() {\n            return state;\n        },\n        get currentTime() {\n            return video.currentTime;\n        },\n        get duration() {\n            return video.duration;\n        },\n        get width() {\n            return video.videoWidth || video.width;\n        },\n        get height() {\n            return video.videoHeight || video.height;\n        },\n        async play(): AsyncVoidIOResult {\n            const result = await tryAsyncResult(video.play());\n            return result.inspect(() => {\n                state = 'playing';\n            });\n        },\n        async pause(): AsyncVoidIOResult {\n            return tryAsyncResult(() => {\n                video.pause();\n                state = 'paused';\n            });\n        },\n        async stop(): AsyncVoidIOResult {\n            return tryAsyncResult(() => {\n                video.pause();\n                video.currentTime = 0;\n                state = 'paused';\n            });\n        },\n        async seek(time: number): AsyncVoidIOResult {\n            return tryAsyncResult(() => {\n                video.currentTime = time;\n            });\n        },\n        getFrame(): IOResult<VideoFrameSourceFrame | null> {\n            if (!hasNewFrame || state === 'destroyed') {\n                return Ok(null);\n            }\n            hasNewFrame = false;\n            return Ok(createFrame());\n        },\n        onFrame(listener: FrameListener): void {\n            frameListeners.add(listener);\n        },\n        offFrame(listener?: FrameListener): void {\n            if (listener) frameListeners.delete(listener);\n            else frameListeners.clear();\n        },\n        onEnded(listener: EndedListener): void {\n            endedListeners.add(listener);\n        },\n        offEnded(listener?: EndedListener): void {\n            if (listener) endedListeners.delete(listener);\n            else endedListeners.clear();\n        },\n        onError(listener: ErrorListener): void {\n            errorListeners.add(listener);\n        },\n        offError(listener?: ErrorListener): void {\n            if (listener) errorListeners.delete(listener);\n            else errorListeners.clear();\n        },\n        destroy(): void {\n            if (state === 'destroyed') return;\n            state = 'destroyed';\n            cancelFrameRequest();\n            video.pause();\n            video.src = '';\n            video.load();\n            video.remove();\n            frameListeners.clear();\n            endedListeners.clear();\n            errorListeners.clear();\n        },\n    };\n\n    if (options.autoplay) {\n        void source.play();\n    }\n\n    return source;\n}\n\n/**\n * 从 Web 本地文件创建视频帧源。\n *\n * @param filePath - 视频文件路径。\n * @param options - 视频帧源创建选项。\n * @returns 视频帧源创建结果。\n */\nexport async function createVideoFrameSourceFromFile(filePath: string, options?: CreateVideoFrameSourceFromFileOptions): AsyncIOResult<VideoFrameSource> {\n    const readRes = await readBlobFile(filePath);\n\n    return readRes.andThen(blob => {\n        const url = URL.createObjectURL(blob);\n        const source = createVideoFrameSource({\n            ...options,\n            source: url,\n        });\n        const destroy = source.destroy.bind(source);\n\n        source.destroy = () => {\n            destroy();\n            URL.revokeObjectURL(url);\n        };\n\n        return Ok(source);\n    });\n}\n\n// #endregion\n\n// #region Internal Types\n\ntype FrameListener = (frame: VideoFrameSourceFrame) => void;\ntype EndedListener = () => void;\ntype ErrorListener = (error: Error) => void;\ntype RequestVideoFrameCallback = (now: number, metadata: RequestVideoFrameCallbackMetadata) => void;\ntype VideoElementWithFrameCallback = HTMLVideoElement & {\n    requestVideoFrameCallback?: (callback: RequestVideoFrameCallback) => number;\n    cancelVideoFrameCallback?: (id: number) => void;\n};\n\ninterface RequestVideoFrameCallbackMetadata {\n    mediaTime: number;\n}\n\n// #endregion\n","import { Ok, type AsyncIOResult, type IOResult } from 'happy-rusty';\nimport { IS_MINA } from '../../../macros/env.ts';\nimport type { CreateVideoFrameSourceFromFileOptions, CreateVideoFrameSourceOptions, VideoFrameSource } from './defines.ts';\nimport {\n    isVideoFrameSourceSupported as isMinaVideoFrameSourceSupported,\n    createVideoFrameSource as minaCreateVideoFrameSource,\n    createVideoFrameSourceFromFile as minaCreateVideoFrameSourceFromFile,\n} from './mina.ts';\nimport {\n    isVideoFrameSourceSupported as isWebVideoFrameSourceSupported,\n    createVideoFrameSource as webCreateVideoFrameSource,\n    createVideoFrameSourceFromFile as webCreateVideoFrameSourceFromFile,\n} from './web.ts';\n\nexport * from './defines.ts';\n\n// #region Exports\n\n/**\n * 判断当前平台是否支持视频帧源。\n *\n * @returns 是否支持创建 VideoFrameSource。\n * @since 2.2.0\n * @example\n * ```ts\n * if (video.isVideoFrameSourceSupported()) {\n *     const sourceRes = video.createVideoFrameSource({ source: 'https://example.com/video.mp4' });\n * }\n * ```\n */\nexport function isVideoFrameSourceSupported(): boolean {\n    return IS_MINA ? isMinaVideoFrameSourceSupported() : isWebVideoFrameSourceSupported();\n}\n\n/**\n * 创建视频帧源，用于将视频帧上传到 RenderTexture/WebGL 纹理。\n *\n * @param options - 视频帧源创建选项。\n * @returns 视频帧源创建结果。\n * @since 2.2.0\n * @example\n * ```ts\n * const sourceRes = video.createVideoFrameSource({\n *     source: 'https://example.com/video.mp4',\n *     muted: true,\n *     loop: true,\n * });\n * if (sourceRes.isOk()) {\n *     const source = sourceRes.unwrap();\n *     await source.play();\n * }\n * ```\n */\nexport function createVideoFrameSource(options: CreateVideoFrameSourceOptions): IOResult<VideoFrameSource> {\n    return IS_MINA\n        ? minaCreateVideoFrameSource(options)\n        : Ok(webCreateVideoFrameSource(options));\n}\n\n/**\n * 从本地文件创建视频帧源。\n *\n * 小游戏平台会直接使用文件路径；Web 平台会从 OPFS 读取文件并创建 Blob URL。\n *\n * @param filePath - 视频文件路径。\n * @param options - 视频帧源创建选项。\n * @returns 视频帧源创建结果。\n * @since 2.2.0\n * @example\n * ```ts\n * const sourceRes = await video.createVideoFrameSourceFromFile('/videos/demo.mp4', {\n *     muted: true,\n * });\n * if (sourceRes.isOk()) {\n *     const source = sourceRes.unwrap();\n *     await source.play();\n * }\n * ```\n */\nexport function createVideoFrameSourceFromFile(filePath: string, options?: CreateVideoFrameSourceFromFileOptions): AsyncIOResult<VideoFrameSource> {\n    return IS_MINA\n        ? Promise.resolve(minaCreateVideoFrameSourceFromFile(filePath, options))\n        : webCreateVideoFrameSourceFromFile(filePath, options);\n}\n\n// #endregion\n","/**\n * 视频播放模块，提供创建和控制视频播放器的功能。\n * @module video\n */\nimport { IS_MINA } from '../../macros/env.ts';\nimport { createVideo as webCreateVideo } from './web_video.ts';\n\nexport * from './frame-source/mod.ts';\n\n/**\n * 创建视频播放器。\n * @param options - 视频配置选项。\n * @returns Video对象。\n * @since 2.0.0\n * @example\n * ```ts\n * const video = createVideo({\n *     src: 'https://example.com/video.mp4',\n *     width: 640,\n *     height: 360,\n *     autoplay: false,\n * });\n * video.play();\n * // 销毁视频\n * video.destroy();\n * ```\n */\nexport function createVideo(options: WechatMinigame.CreateVideoOption): WechatMinigame.Video {\n    return (IS_MINA ? wx.createVideo : webCreateVideo)(options);\n}\n"],"mappings":"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"}